Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ app/
│ │ │ ├── lightning-address/route.ts # POST/DELETE /me/lightning-address
│ │ │ ├── push-subscriptions/route.ts # POST/DELETE /me/push-subscriptions
│ │ │ ├── forum-laws-dismissed/route.ts # POST /me/forum-laws-dismissed
│ │ │ ├── notification-level/route.ts # POST /me/notification-level
│ │ │ └── activity/route.ts # GET /me/activity → api GET /me/activity
│ │ ├── push/
│ │ │ └── vapid-public/route.ts # GET /push/vapid-public same-origin proxy
Expand Down Expand Up @@ -118,7 +119,7 @@ app/
│ │ ├── donate/
│ │ │ └── page.tsx # GET /donate — Send help explainer, CTA to /welcome
│ │ ├── profile/
│ │ │ └── page.tsx # GET /profile — signed-in name + location + address + push bell
│ │ │ └── page.tsx # GET /profile — signed-in name + location + address + notification level + optional push bell
│ │ ├── members/
│ │ │ └── [accountId]/page.tsx # GET /members/:id — signed-in member profile
│ │ ├── moderate/
Expand Down Expand Up @@ -154,15 +155,15 @@ app/
│ │ ├── NoteTranslate.tsx # Labeled public note/reply translation control
│ │ ├── AccountActivityChart.tsx # Compact Given/Received SVG from account activity series
│ │ ├── AboutMeSection.tsx # About me heading + text or empty prompt; owner edit + copy-link
│ │ ├── ProfileScreen.tsx # Signed-in profile card (totals + About me + name/location/address + push bell + language + theme + fiat + number format)
│ │ ├── ProfileScreen.tsx # Signed-in profile card (totals + About me + name/location/address + notification level + optional push bell + language + theme + fiat + number format)
│ │ ├── TrustChainDiagram.tsx # SVG Trust Chain graph (click hop, drag, stacked neighbors)
│ │ ├── TrustChainScreen.tsx # Signed-in /trust-chain body
│ │ ├── ModerateScreen.tsx # Signed-in /moderate hub (Hidden notes + Open proposals)
│ │ ├── HiddenNotesScreen.tsx # Signed-in /moderate/hidden list
│ │ ├── ProposalsScreen.tsx # Signed-in /moderate/proposals confirm queue
│ │ ├── MemberTrustActions.tsx # Staff verify / propose / confirm / appoint on a member card
│ │ ├── LocationForm.tsx # Profile free-text location row (pencil / clear)
│ │ ├── PushToggle.tsx # IconButton Bell with visible On/Off value (button stays icon-only)
│ │ ├── PushToggle.tsx # Three-stage All/Active/Mentions control plus icon-only Bell
│ │ ├── InAppBrowserView.tsx # Shared in-app escape card (Open in browser + Copy link)
│ │ ├── ViewProfileClaim.tsx # Public view Activate banner or in-app escape under the card
│ │ ├── ViewProfileLoader.tsx # Public view fetch states + GET /view-key/:viewKey/activity
Expand Down
7 changes: 7 additions & 0 deletions docs/handbook/endpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@
- **Used by:** `dismissForumLaws`.
- **Auth:** Bearer.

## Endpoint: POST /me/notification-level

- **Purpose:** Same-origin Bearer proxy of api POST `/me/notification-level`. JSON body `{ level: "all"|"active"|"mentions" }` returns the owner Account.
- **Errors:** Upstream 401, 400 invalid level, or 502 if the api is unreachable.
- **Used by:** `postNotificationLevel`.
- **Auth:** Bearer.

## Endpoint: POST /me/rules-agreement

- **Purpose:** Same-origin proxy to record living-room rules agreement on the signed-in account (`rulesAgreedAt`).
Expand Down
35 changes: 28 additions & 7 deletions docs/handbook/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,9 +356,9 @@

## Function: ProfileScreen

- **Purpose:** Signed-in profile: single `max-w-sm` identity card with a compact Given/Received activity chart, About me (`AboutMeSection` owner: empty prompt + **Write your About me**, or filled text and/or photo + edit; copy-profile-link on the card — never a forum post), name, location, and Wallet of Satoshi address forms, an icon-only Web Push bell (`PushToggle`), a language settings row (`LanguagePreferenceSwitcher`) after push and before theme, a theme settings row (`ThemeSwitcher`), a fiat settings row (`FiatPreferenceSwitcher`), and a number-format settings row (`NumberFormatSwitcher`) last. Never shows `forum.loading` on the card. Menu icon+amount totals stay in `SignedInChrome`. Back + wordmark live in `ProfileChromeLeft`.
- **Purpose:** Signed-in profile: single `max-w-sm` identity card with a compact Given/Received activity chart, About me (`AboutMeSection` owner: empty prompt + **Write your About me**, or filled text and/or photo + edit; copy-profile-link on the card — never a forum post), name, location, and Wallet of Satoshi address forms, a three-stage notification level plus optional Web Push bell (`PushToggle`), a language settings row (`LanguagePreferenceSwitcher`) after push and before theme, a theme settings row (`ThemeSwitcher`), a fiat settings row (`FiatPreferenceSwitcher`), and a number-format settings row (`NumberFormatSwitcher`) last. Never shows `forum.loading` on the card. Menu icon+amount totals stay in `SignedInChrome`. Back + wordmark live in `ProfileChromeLeft`.
- **Inputs:** `useAccountTotals` for both `receiveOverTime` and `donateOverTime`; pass both to `AccountActivityChart`; `AboutMeSection` (`putAboutMe` text plus optional photo, `fetchAboutMePhoto` when `aboutMeHasPhoto`, `name={account.name}`); `NameForm`, `LocationForm`, and `LightningAddressForm` for edits; `PushToggle`; `LanguagePreferenceSwitcher`; `ThemeSwitcher`; `FiatPreferenceSwitcher`; `NumberFormatSwitcher`; catalog via `useTranslations`.
- **Returns / side effects:** Heading **Profile**, compact chart (empty: FiatPicker + `profile.chartEmpty` with no SVG / no ₿|fiat scale; populated: legend + ₿ | selected fiat + SVG), About me, name form, location form, address form, push bell under the address form, Language (English / Deutsch / Español / Filipino), Theme (System / Light / Dark), Fiat currency (CHF|EUR|USD|PHP), and Number format (`10'000.23` / `10,000.23` / `23.000,33`) as the last settings row — all inside one identity card (no second panel). Back + wordmark live in `ProfileChromeLeft`.
- **Returns / side effects:** Heading **Profile**, compact chart (empty: FiatPicker + `profile.chartEmpty` with no SVG / no ₿|fiat scale; populated: legend + ₿ | selected fiat + SVG), About me, name form, location form, address form, three-stage notification level plus optional Web Push bell (`PushToggle`) under the address form, Language (English / Deutsch / Español / Filipino), Theme (System / Light / Dark), Fiat currency (CHF|EUR|USD|PHP), and Number format (`10'000.23` / `10,000.23` / `23.000,33`) as the last settings row — all inside one identity card (no second panel). Back + wordmark live in `ProfileChromeLeft`.
- **Used by:** `ProfilePage`.

## Function: AboutMeSection
Expand All @@ -370,9 +370,9 @@

## Function: PushToggle

- **Purpose:** Profile identity-card row matching name/address: heading `profile.push.heading`, visible On/Off value (`profile.push.on` / `profile.push.off`), and an icon-only `IconButton` (same circle as profile name/address actions) to enable or disable Web Push for the signed-in member. Off is `variant="secondary"` with an outline BellOff; on is `variant="primary"` with a filled Bell (`fill="currentColor"`). The button stays icon-only — On/Off is the value, not a labeled button. Renders nothing without a session or when `serviceWorker` / `PushManager` are missing. On iPhone Safari outside standalone, shows `profile.push.installHint` above the value row.
- **Inputs:** Session from `useAuthStore`; catalog via `useTranslations`; `enablePush` / `disablePush` / `isIosSafari` / `isStandaloneDisplay`.
- **Returns / side effects:** Heading, On/Off value, and icon-only `IconButton` named from `profile.push.enable` or `profile.push.disable` (`aria-pressed` when subscribed). User gesture calls enable/disable; may show `profile.push.unavailable` on failure.
- **Purpose:** Profile identity-card Notifications section: uppercase heading `profile.push.heading`, a `SegmentedControl tone="neutral"` All / Active / Mentions (`profile.push.level.all` / `active` / `mentions`, group `profile.push.level.label`) whenever a session exists, a muted hint (`profile.push.level.hint`), and an icon-only Bell `IconButton` with visible On/Off (`profile.push.on` / `profile.push.off`) only when `serviceWorker` / `PushManager` are ready. Off is `variant="secondary"` with an outline BellOff; on is `variant="primary"` with a filled Bell (`fill="currentColor"`). The button stays icon-only — On/Off is the value, not a labeled button. Changing the level POSTs `/me/notification-level` via `postNotificationLevel` and merges `notificationLevel` into the current store account when the session still matches; a second change while the POST is in flight is ignored; failure keeps the previous value and shows `profile.push.level.error`. Renders nothing without a session. On iPhone Safari outside standalone, shows `profile.push.installHint` above the bell row.
- **Inputs:** Session and account from `useAuthStore`; catalog via `useTranslations`; `postNotificationLevel` / `accountNotificationLevel` / `setAccount`; `enablePush` / `disablePush` / `isIosSafari` / `isStandaloneDisplay`.
- **Returns / side effects:** Heading, All/Active/Mentions control, muted hint, and (when Push APIs are ready) On/Off value plus icon-only `IconButton` named from `profile.push.enable` or `profile.push.disable` (`aria-pressed` when subscribed). Level change calls `postNotificationLevel` then merges `notificationLevel`; user gesture on the bell calls enable/disable; may show `profile.push.unavailable` on push failure or `profile.push.level.error` on level failure.
- **Used by:** `ProfileScreen`.

## Function: useUnreadCount
Expand Down Expand Up @@ -1593,6 +1593,20 @@ The No gifts yet mode keeps only loaded messages with exactly zero sats, includi
- **Returns / side effects:** Updated `Account` with `forumLawsDismissed: true`. No request body.
- **Used by:** `ForumLoader`.

## Function: postNotificationLevel

- **Purpose:** POST `/me/notification-level` with JSON `{ level }` (`all` | `active` | `mentions`) and Bearer session.
- **Inputs:** `session` (bearer token), `level` (`NotificationLevel`).
- **Returns / side effects:** Updated `Account`. Throws `'Could not save notification level.'` on a non-ok response; a 2xx body that fails `accountSchema` throws the schema error.
- **Used by:** `PushToggle`.

## Function: accountNotificationLevel

- **Purpose:** Read `account.notificationLevel ?? 'all'` so omitted API fields still mean All.
- **Inputs:** Parsed `Account` (the field may be missing).
- **Returns / side effects:** `'all'`, `'active'`, or `'mentions'`. No network.
- **Used by:** `PushToggle`.

## Function: agreeToRules

- **Purpose:** POST `/me/rules-agreement` with Bearer and no JSON body.
Expand Down Expand Up @@ -1714,10 +1728,10 @@ The No gifts yet mode keeps only loaded messages with exactly zero sats, includi

## Function: POST

- **Purpose:** Shared App Router POST export name. `/me/name` re-exports `proxyMeNamePost`; `/me/location` re-exports `proxyMeLocationPost`; `/me/forum-laws-dismissed` re-exports `proxyMeForumLawsDismissedPost`; `/me/rules-agreement` re-exports `proxyMeRulesAgreementPost`; `/me/lightning-address` re-exports `proxyMeLightningAddressPost`; `/me/push-subscriptions` re-exports `proxyMePushSubscriptionsPost`; `/auth/passkey/{register,authenticate}/{begin,finish}` re-export the four passkey proxy POSTs; `/forum/messages` re-exports `proxyMessagesPost`; `/messages/[id]/invoice` re-exports `proxyMessagesInvoicePost`; `/conversations` re-exports `proxyConversationsPost`; `/conversations/[id]` re-exports `proxyConversationPost`; `/conversations/[id]/invoice` re-exports `proxyConversationInvoicePost`; `/forum/notifications/read-all` re-exports `proxyNotificationsReadAllPost`; `/forum/notifications/[id]/read` re-exports `proxyNotificationReadPost`; `/contact/submit` re-exports `proxyContactPost`; `/translate` re-exports `proxyTranslatePost`; `/trust/verify` re-exports `proxyTrustVerifyPost`; `/trust/propose-moderator` re-exports `proxyTrustProposeModeratorPost`; `/trust/confirm-moderator` re-exports `proxyTrustConfirmModeratorPost`; `/trust/appoint-moderator` re-exports `proxyTrustAppointModeratorPost`. HTML `/messages` is the inbox page, not a POST proxy.
- **Purpose:** Shared App Router POST export name. `/me/name` re-exports `proxyMeNamePost`; `/me/location` re-exports `proxyMeLocationPost`; `/me/forum-laws-dismissed` re-exports `proxyMeForumLawsDismissedPost`; `/me/notification-level` re-exports `proxyMeNotificationLevelPost`; `/me/rules-agreement` re-exports `proxyMeRulesAgreementPost`; `/me/lightning-address` re-exports `proxyMeLightningAddressPost`; `/me/push-subscriptions` re-exports `proxyMePushSubscriptionsPost`; `/auth/passkey/{register,authenticate}/{begin,finish}` re-export the four passkey proxy POSTs; `/forum/messages` re-exports `proxyMessagesPost`; `/messages/[id]/invoice` re-exports `proxyMessagesInvoicePost`; `/conversations` re-exports `proxyConversationsPost`; `/conversations/[id]` re-exports `proxyConversationPost`; `/conversations/[id]/invoice` re-exports `proxyConversationInvoicePost`; `/forum/notifications/read-all` re-exports `proxyNotificationsReadAllPost`; `/forum/notifications/[id]/read` re-exports `proxyNotificationReadPost`; `/contact/submit` re-exports `proxyContactPost`; `/translate` re-exports `proxyTranslatePost`; `/trust/verify` re-exports `proxyTrustVerifyPost`; `/trust/propose-moderator` re-exports `proxyTrustProposeModeratorPost`; `/trust/confirm-moderator` re-exports `proxyTrustConfirmModeratorPost`; `/trust/appoint-moderator` re-exports `proxyTrustAppointModeratorPost`. HTML `/messages` is the inbox page, not a POST proxy.
- **Inputs:** Incoming `Request`.
- **Returns / side effects:** Upstream api `Response` on api proxies; `/translate` returns `{ translatedText }` or 400/502/503 JSON (LibreTranslate-compatible, not the 21.gifts api).
- **Used by:** Same-origin name save, location save (`POST /me/location`), forum laws dismiss, living-room rules agreement (`POST /me/rules-agreement`), address link, Web Push subscribe (`POST /me/push-subscriptions`), passkey begin/finish, forum message create (`POST /forum/messages`), pay-on-note (`POST /messages/[id]/invoice`), inbox open (`POST /conversations`) and reply (`POST /conversations/[id]`), mark-all notifications (`POST /forum/notifications/read-all`) and mark-one (`POST /forum/notifications/[id]/read`), in-app contact (`POST /contact/submit`), `translateNote` via `POST /translate`, and staff Trust Chain actions (`POST /trust/verify`, `POST /trust/propose-moderator`, `POST /trust/confirm-moderator`, `POST /trust/appoint-moderator`).
- **Used by:** Same-origin name save, location save (`POST /me/location`), forum laws dismiss, notification-level save (`POST /me/notification-level`), living-room rules agreement (`POST /me/rules-agreement`), address link, Web Push subscribe (`POST /me/push-subscriptions`), passkey begin/finish, forum message create (`POST /forum/messages`), pay-on-note (`POST /messages/[id]/invoice`), inbox open (`POST /conversations`) and reply (`POST /conversations/[id]`), mark-all notifications (`POST /forum/notifications/read-all`) and mark-one (`POST /forum/notifications/[id]/read`), in-app contact (`POST /contact/submit`), `translateNote` via `POST /translate`, and staff Trust Chain actions (`POST /trust/verify`, `POST /trust/propose-moderator`, `POST /trust/confirm-moderator`, `POST /trust/appoint-moderator`).

## Function: PUT

Expand Down Expand Up @@ -1852,6 +1866,13 @@ The No gifts yet mode keeps only loaded messages with exactly zero sats, includi
- **Returns / side effects:** Upstream `Response`.
- **Used by:** Route POST `/me/forum-laws-dismissed`.

## Function: proxyMeNotificationLevelPost

- **Purpose:** Same-origin Bearer proxy of api POST `/me/notification-level` with JSON `{ level }`.
- **Inputs:** Incoming `Request` with Bearer session and JSON `{ level }`.
- **Returns / side effects:** Upstream `Response` via `proxyApiRequest`.
- **Used by:** Route POST `/me/notification-level`.

## Function: proxyMeRulesAgreementPost

- **Purpose:** Proxies POST `/me/rules-agreement`.
Expand Down
Loading
Loading