@remit/web-client 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. package/harness/build.mjs +84 -0
  2. package/harness/index.html +37 -0
  3. package/harness/vite-preset.ts +29 -0
  4. package/index.html +47 -0
  5. package/package.json +147 -0
  6. package/public/config.js +5 -0
  7. package/public/locales/de/common.json +1 -0
  8. package/public/locales/de/errors.json +1 -0
  9. package/public/locales/de/mail.json +13 -0
  10. package/public/locales/de/settings.json +1 -0
  11. package/public/locales/en/common.json +26 -0
  12. package/public/locales/en/errors.json +1 -0
  13. package/public/locales/en/mail.json +69 -0
  14. package/public/locales/en/settings.json +1 -0
  15. package/public/locales/fr/common.json +1 -0
  16. package/public/locales/fr/errors.json +1 -0
  17. package/public/locales/fr/mail.json +13 -0
  18. package/public/locales/fr/settings.json +1 -0
  19. package/public/locales/nl/common.json +1 -0
  20. package/public/locales/nl/errors.json +1 -0
  21. package/public/locales/nl/mail.json +13 -0
  22. package/public/locales/nl/settings.json +1 -0
  23. package/src/auth/AccountMenu.tsx +58 -0
  24. package/src/auth/AccountSession.tsx +19 -0
  25. package/src/auth/BetterAuthShell.tsx +198 -0
  26. package/src/auth/account-menu-mode.test.ts +64 -0
  27. package/src/auth/account-menu-mode.ts +28 -0
  28. package/src/auth/amplify-config.test.ts +158 -0
  29. package/src/auth/amplify-config.ts +60 -0
  30. package/src/auth/auth-error.test.ts +109 -0
  31. package/src/auth/auth-error.ts +107 -0
  32. package/src/auth/auth-interceptor.test.ts +86 -0
  33. package/src/auth/auth-interceptor.ts +23 -0
  34. package/src/auth/auth.css +334 -0
  35. package/src/auth/better-auth/BetterAuthAccount.tsx +25 -0
  36. package/src/auth/better-auth-config.ts +85 -0
  37. package/src/auth/better-auth-provider.tsx +20 -0
  38. package/src/auth/cognito/CognitoAccount.tsx +48 -0
  39. package/src/auth/cognito/CognitoShell.tsx +266 -0
  40. package/src/auth/cognito/cognito-token.test.ts +110 -0
  41. package/src/auth/cognito/cognito-token.ts +47 -0
  42. package/src/auth/cognito/cognito.css +21 -0
  43. package/src/auth/cognito-provider.tsx +22 -0
  44. package/src/auth/combined-provider.tsx +42 -0
  45. package/src/auth/composition.test.ts +136 -0
  46. package/src/auth/provider.tsx +63 -0
  47. package/src/auth/sign-out-visibility.test.ts +40 -0
  48. package/src/auth/sign-out-visibility.ts +10 -0
  49. package/src/auth/sign-up-disabled.test.ts +23 -0
  50. package/src/components/compose/AddressField.tsx +237 -0
  51. package/src/components/compose/ComposeBody.tsx +36 -0
  52. package/src/components/compose/ComposeForm.tsx +676 -0
  53. package/src/components/compose/ComposeProvider.tsx +133 -0
  54. package/src/components/compose/ComposeSmtpMissingBanner.tsx +49 -0
  55. package/src/components/compose/FromSelector.tsx +67 -0
  56. package/src/components/compose/FullCompose.tsx +82 -0
  57. package/src/components/compose/InlineCompose.tsx +29 -0
  58. package/src/components/compose/MobileComposeSheet.tsx +152 -0
  59. package/src/components/compose/PlateEditor.tsx +86 -0
  60. package/src/components/compose/PlateToolbar.tsx +110 -0
  61. package/src/components/compose/SubjectField.tsx +19 -0
  62. package/src/components/compose/draft-discard-banner.test.ts +76 -0
  63. package/src/components/compose/index.ts +6 -0
  64. package/src/components/compose/sanitize-quote-html.ts +23 -0
  65. package/src/components/layout/AppShellSkeleton.tsx +53 -0
  66. package/src/components/layout/ComposeFab.tsx +86 -0
  67. package/src/components/layout/Drawer.tsx +105 -0
  68. package/src/components/mail/AutoMovedIndicator.tsx +48 -0
  69. package/src/components/mail/BlockedImagesNotice.render.test.ts +65 -0
  70. package/src/components/mail/BlockedImagesNotice.tsx +41 -0
  71. package/src/components/mail/BriefPane.tsx +289 -0
  72. package/src/components/mail/ConversationView.tsx +462 -0
  73. package/src/components/mail/DailyBrief.tsx +451 -0
  74. package/src/components/mail/DraftsView.tsx +279 -0
  75. package/src/components/mail/FlaggedList.tsx +170 -0
  76. package/src/components/mail/FlaggedPane.tsx +217 -0
  77. package/src/components/mail/IntelligencePane.test.ts +123 -0
  78. package/src/components/mail/IntelligencePane.tsx +441 -0
  79. package/src/components/mail/MailListHeader.tsx +187 -0
  80. package/src/components/mail/MailNav.tsx +70 -0
  81. package/src/components/mail/MailSidebarAdapter.tsx +351 -0
  82. package/src/components/mail/MailViewChrome.tsx +95 -0
  83. package/src/components/mail/MailboxPane.tsx +1219 -0
  84. package/src/components/mail/MessageActionMenu.tsx +368 -0
  85. package/src/components/mail/MessageBody.tsx +207 -0
  86. package/src/components/mail/MessageBodyErrorBanner.render.test.ts +85 -0
  87. package/src/components/mail/MessageBodyErrorBanner.test.ts +86 -0
  88. package/src/components/mail/MessageBodyErrorBanner.tsx +90 -0
  89. package/src/components/mail/MessageCard.tsx +401 -0
  90. package/src/components/mail/MessageDetail.tsx +153 -0
  91. package/src/components/mail/MessageList.tsx +804 -0
  92. package/src/components/mail/MessageListItem.tsx +267 -0
  93. package/src/components/mail/MessageToolbar.render.test.ts +57 -0
  94. package/src/components/mail/MessageToolbar.tsx +166 -0
  95. package/src/components/mail/MobileMessageBar.tsx +142 -0
  96. package/src/components/mail/MoveToTrigger.tsx +250 -0
  97. package/src/components/mail/NavMenuButton.tsx +25 -0
  98. package/src/components/mail/OutboxPane.tsx +531 -0
  99. package/src/components/mail/PullToRefresh.tsx +24 -0
  100. package/src/components/mail/RawMessageView.tsx +84 -0
  101. package/src/components/mail/ReadingPaneEmpty.render.test.ts +42 -0
  102. package/src/components/mail/SelectionToolbar.tsx +139 -0
  103. package/src/components/mail/SpamRescue.render.test.ts +35 -0
  104. package/src/components/mail/SpamRescue.tsx +138 -0
  105. package/src/components/mail/SwipeableMessageRow.tsx +148 -0
  106. package/src/components/mail/message-body-error-banner-content.ts +87 -0
  107. package/src/components/mail/organize/OrganizeDialog.render.test.ts +37 -0
  108. package/src/components/mail/organize/OrganizeDialog.tsx +83 -0
  109. package/src/components/mail/organize/OrganizePanel.render.test.ts +102 -0
  110. package/src/components/mail/organize/OrganizePanel.tsx +344 -0
  111. package/src/components/onboarding/OnboardingWizard.tsx +1547 -0
  112. package/src/components/settings/AccountFormPanel.test.ts +72 -0
  113. package/src/components/settings/AccountFormPanel.tsx +942 -0
  114. package/src/components/settings/DangerZone.tsx +30 -0
  115. package/src/components/settings/DeleteAccountDialog.render.test.ts +47 -0
  116. package/src/components/settings/DeleteAccountDialog.tsx +224 -0
  117. package/src/components/settings/FiltersList.render.test.ts +71 -0
  118. package/src/components/settings/FiltersList.tsx +93 -0
  119. package/src/components/settings/account-form-helpers.test.ts +172 -0
  120. package/src/components/settings/account-form-helpers.ts +105 -0
  121. package/src/components/ui/AppVersion.tsx +50 -0
  122. package/src/components/ui/BugReportButton.tsx +45 -0
  123. package/src/components/ui/ConfirmDialog.tsx +125 -0
  124. package/src/components/ui/DropdownMenu.tsx +105 -0
  125. package/src/components/ui/EmptyState.tsx +11 -0
  126. package/src/components/ui/ErrorBanner.tsx +88 -0
  127. package/src/components/ui/ErrorBannerProvider.tsx +77 -0
  128. package/src/components/ui/ErrorBannerStack.tsx +34 -0
  129. package/src/components/ui/ErrorState.tsx +80 -0
  130. package/src/components/ui/FatalErrorOverlay.render.test.ts +66 -0
  131. package/src/components/ui/FatalErrorOverlay.tsx +151 -0
  132. package/src/components/ui/KeyboardShortcutsModal.tsx +120 -0
  133. package/src/components/ui/SlidePanel.tsx +72 -0
  134. package/src/components/ui/error-banners.test.ts +207 -0
  135. package/src/components/ui/error-banners.ts +111 -0
  136. package/src/hooks/queries/keys.ts +38 -0
  137. package/src/hooks/useArchiveMailbox.ts +104 -0
  138. package/src/hooks/useAutoMovedBadge.ts +77 -0
  139. package/src/hooks/useCurrentMailboxName.ts +99 -0
  140. package/src/hooks/useDebouncedValue.ts +12 -0
  141. package/src/hooks/useDeleteMessages.test.ts +103 -0
  142. package/src/hooks/useDeleteMessages.ts +226 -0
  143. package/src/hooks/useFilters.ts +112 -0
  144. package/src/hooks/useIntelligenceData.test.ts +269 -0
  145. package/src/hooks/useIntelligenceData.ts +284 -0
  146. package/src/hooks/useIsDark.ts +27 -0
  147. package/src/hooks/useKeyboardNavigation.ts +192 -0
  148. package/src/hooks/useLayoutTier.test.ts +47 -0
  149. package/src/hooks/useLayoutTier.ts +44 -0
  150. package/src/hooks/useLongPress.test.ts +291 -0
  151. package/src/hooks/useLongPress.ts +87 -0
  152. package/src/hooks/useMailboxAccount.ts +62 -0
  153. package/src/hooks/useMailboxNameIndex.ts +32 -0
  154. package/src/hooks/useMarkAsRead.test.ts +165 -0
  155. package/src/hooks/useMarkAsRead.ts +319 -0
  156. package/src/hooks/useMediaQuery.ts +39 -0
  157. package/src/hooks/useMessageBodyContent.test.ts +370 -0
  158. package/src/hooks/useMessageBodyContent.ts +380 -0
  159. package/src/hooks/useMoveMessages.test.ts +63 -0
  160. package/src/hooks/useMoveMessages.ts +221 -0
  161. package/src/hooks/useOrganizeJob.ts +90 -0
  162. package/src/hooks/useOrganizePreview.ts +40 -0
  163. package/src/hooks/useRescueCandidates.test.ts +217 -0
  164. package/src/hooks/useRescueCandidates.ts +48 -0
  165. package/src/hooks/useSaveDraft.ts +118 -0
  166. package/src/hooks/useSelection.test.ts +75 -0
  167. package/src/hooks/useSelection.ts +211 -0
  168. package/src/hooks/useSemanticSearch.ts +94 -0
  169. package/src/hooks/useSignature.ts +69 -0
  170. package/src/hooks/useStaleAccountSync.test.ts +211 -0
  171. package/src/hooks/useStaleAccountSync.ts +246 -0
  172. package/src/hooks/useSwipeNavigation.test.ts +35 -0
  173. package/src/hooks/useSwipeNavigation.ts +99 -0
  174. package/src/hooks/useToggleStar.ts +187 -0
  175. package/src/hooks/useToggleTrusted.test.ts +102 -0
  176. package/src/hooks/useToggleTrusted.ts +161 -0
  177. package/src/hooks/useTriageKeyboard.ts +103 -0
  178. package/src/hooks/useTriggerSync.test.ts +24 -0
  179. package/src/hooks/useTriggerSync.ts +58 -0
  180. package/src/hooks/useUpdateAddressFlags.ts +125 -0
  181. package/src/hooks/useVisualViewport.test.ts +127 -0
  182. package/src/hooks/useVisualViewport.ts +51 -0
  183. package/src/index.css +19 -0
  184. package/src/lib/account-order.test.ts +84 -0
  185. package/src/lib/account-order.ts +13 -0
  186. package/src/lib/adjacent-message.test.ts +43 -0
  187. package/src/lib/adjacent-message.ts +20 -0
  188. package/src/lib/api.ts +82 -0
  189. package/src/lib/app-info.ts +15 -0
  190. package/src/lib/auto-moved.test.ts +140 -0
  191. package/src/lib/auto-moved.ts +68 -0
  192. package/src/lib/autodiscovery.test.ts +94 -0
  193. package/src/lib/autodiscovery.ts +354 -0
  194. package/src/lib/brief.test.ts +366 -0
  195. package/src/lib/brief.ts +180 -0
  196. package/src/lib/bug-report.test.ts +213 -0
  197. package/src/lib/bug-report.ts +176 -0
  198. package/src/lib/client.ts +36 -0
  199. package/src/lib/console-errors.test.ts +64 -0
  200. package/src/lib/console-errors.ts +92 -0
  201. package/src/lib/conversation-target.test.ts +68 -0
  202. package/src/lib/conversation-target.ts +59 -0
  203. package/src/lib/display-category.ts +20 -0
  204. package/src/lib/drafts.test.ts +241 -0
  205. package/src/lib/drafts.ts +121 -0
  206. package/src/lib/error-classifier.test.ts +133 -0
  207. package/src/lib/error-classifier.ts +96 -0
  208. package/src/lib/fatal-error.test.ts +97 -0
  209. package/src/lib/fatal-error.ts +165 -0
  210. package/src/lib/folder-roles.test.ts +113 -0
  211. package/src/lib/folder-roles.ts +112 -0
  212. package/src/lib/format.test.ts +115 -0
  213. package/src/lib/format.ts +198 -0
  214. package/src/lib/i18n.ts +36 -0
  215. package/src/lib/intelligence-pref.test.ts +57 -0
  216. package/src/lib/intelligence-pref.ts +25 -0
  217. package/src/lib/keymap-dispatch.test.ts +178 -0
  218. package/src/lib/keymap-dispatch.ts +187 -0
  219. package/src/lib/keymap.test.ts +49 -0
  220. package/src/lib/keymap.ts +178 -0
  221. package/src/lib/mail-context.ts +64 -0
  222. package/src/lib/mail-route.test.ts +80 -0
  223. package/src/lib/mail-route.ts +44 -0
  224. package/src/lib/message-body-source.test.ts +98 -0
  225. package/src/lib/message-body-source.ts +48 -0
  226. package/src/lib/move-targets.test.ts +195 -0
  227. package/src/lib/move-targets.ts +74 -0
  228. package/src/lib/onboarding-completion.test.ts +64 -0
  229. package/src/lib/onboarding-completion.ts +23 -0
  230. package/src/lib/organize/filter-status.test.ts +99 -0
  231. package/src/lib/organize/filter-status.ts +86 -0
  232. package/src/lib/organize/organize-copy.test.ts +93 -0
  233. package/src/lib/organize/organize-copy.ts +61 -0
  234. package/src/lib/organize/organize-model.test.ts +104 -0
  235. package/src/lib/organize/organize-model.ts +105 -0
  236. package/src/lib/organize/organize-poll.test.ts +37 -0
  237. package/src/lib/organize/organize-poll.ts +28 -0
  238. package/src/lib/outbox-status.test.ts +64 -0
  239. package/src/lib/outbox-status.ts +75 -0
  240. package/src/lib/plate-serializer.ts +164 -0
  241. package/src/lib/provider-presets.test.ts +96 -0
  242. package/src/lib/provider-presets.ts +81 -0
  243. package/src/lib/query-error-handler.test.ts +144 -0
  244. package/src/lib/query-error-handler.ts +34 -0
  245. package/src/lib/query-escalation.integration.test.ts +138 -0
  246. package/src/lib/recent-searches.test.ts +53 -0
  247. package/src/lib/recent-searches.ts +34 -0
  248. package/src/lib/rescue-candidates.test.ts +94 -0
  249. package/src/lib/rescue-candidates.ts +35 -0
  250. package/src/lib/rescue-telemetry.test.ts +75 -0
  251. package/src/lib/rescue-telemetry.ts +55 -0
  252. package/src/lib/rum-adapter.test.ts +299 -0
  253. package/src/lib/rum-adapter.ts +107 -0
  254. package/src/lib/saved-searches.test.ts +80 -0
  255. package/src/lib/saved-searches.ts +52 -0
  256. package/src/lib/search-pending.test.ts +61 -0
  257. package/src/lib/search-pending.ts +24 -0
  258. package/src/lib/search-query.test.ts +35 -0
  259. package/src/lib/search-query.ts +11 -0
  260. package/src/lib/search-result.test.ts +160 -0
  261. package/src/lib/search-result.ts +102 -0
  262. package/src/lib/search-schemas.ts +34 -0
  263. package/src/lib/search-token-index.test.ts +112 -0
  264. package/src/lib/search-token-index.ts +56 -0
  265. package/src/lib/search-tokens.test.ts +218 -0
  266. package/src/lib/search-tokens.ts +133 -0
  267. package/src/lib/telemetry-context.tsx +9 -0
  268. package/src/lib/telemetry.ts +17 -0
  269. package/src/lib/theme-preference.ts +46 -0
  270. package/src/lib/theme.ts +33 -0
  271. package/src/lib/utils.ts +4 -0
  272. package/src/main.tsx +10 -0
  273. package/src/routeTree.gen.ts +392 -0
  274. package/src/router.test.ts +81 -0
  275. package/src/router.tsx +31 -0
  276. package/src/routes/__root.tsx +69 -0
  277. package/src/routes/index.tsx +7 -0
  278. package/src/routes/mail/$mailboxId.tsx +27 -0
  279. package/src/routes/mail/flagged.tsx +37 -0
  280. package/src/routes/mail/index.tsx +41 -0
  281. package/src/routes/mail/outbox.tsx +13 -0
  282. package/src/routes/mail.tsx +413 -0
  283. package/src/routes/onboarding.tsx +35 -0
  284. package/src/routes/settings/-accounts.test.ts +65 -0
  285. package/src/routes/settings/accounts.tsx +542 -0
  286. package/src/routes/settings/advanced.tsx +55 -0
  287. package/src/routes/settings/appearance.tsx +140 -0
  288. package/src/routes/settings/filters.tsx +141 -0
  289. package/src/routes/settings/folders.tsx +216 -0
  290. package/src/routes/settings/index.tsx +5 -0
  291. package/src/routes/settings/senders.tsx +466 -0
  292. package/src/routes/settings/suggested-vips.tsx +10 -0
  293. package/src/routes/settings.tsx +66 -0
  294. package/src/runtime-config.ts +75 -0
  295. package/src/shell/index.tsx +98 -0
  296. package/src/types/index.ts +73 -0
  297. package/src/vite-env.d.ts +4 -0
  298. package/vite.base.ts +43 -0
@@ -0,0 +1,289 @@
1
+ /**
2
+ * BriefPane — compound component for the daily-brief view (/mail route).
3
+ *
4
+ * Usage in mail.tsx:
5
+ *
6
+ * <BriefPane selectedMessageId={...}>
7
+ * <AppShellSlotted
8
+ * list={<BriefPane.List />}
9
+ * reading={<BriefPane.Reading />}
10
+ * />
11
+ * </BriefPane>
12
+ *
13
+ * On phone, use `<BriefPane.Phone />` instead.
14
+ */
15
+ import { unifiedThreadOperationsListAllThreadsOptions } from "@remit/api-http-client/@tanstack/react-query.gen.ts";
16
+ import type { RemitImapThreadMessageResponse } from "@remit/api-http-client/types.gen.ts";
17
+ import { ReadingPaneEmpty, type SearchResult } from "@remit/ui";
18
+ import { useQuery } from "@tanstack/react-query";
19
+ import { useNavigate, useSearch } from "@tanstack/react-router";
20
+ import {
21
+ createContext,
22
+ type ReactNode,
23
+ useCallback,
24
+ useContext,
25
+ useMemo,
26
+ } from "react";
27
+ import { Drawer } from "@/components/layout/Drawer";
28
+ import { ConversationView } from "@/components/mail/ConversationView";
29
+ import { DailyBrief } from "@/components/mail/DailyBrief";
30
+ import { IntelligencePane } from "@/components/mail/IntelligencePane";
31
+ import { MessageToolbar } from "@/components/mail/MessageToolbar";
32
+ import {
33
+ buildConversationTarget,
34
+ type ConversationTarget,
35
+ } from "@/lib/conversation-target";
36
+ import { useMailContext } from "@/lib/mail-context";
37
+
38
+ /* ------------------------------------------------------------------ */
39
+ /* Context */
40
+ /* ------------------------------------------------------------------ */
41
+
42
+ interface BriefPaneContextValue {
43
+ selectedMessageId: string | undefined;
44
+ selectedThread: RemitImapThreadMessageResponse | undefined;
45
+ /** The conversation to open — the loaded thread, or a tapped "Related" hit. */
46
+ conversation: ConversationTarget | undefined;
47
+ onSelectMessage: (id: string) => void;
48
+ onSelectSearchResult: (result: SearchResult) => void;
49
+ onCloseThread: () => void;
50
+ }
51
+
52
+ const BriefPaneCtx = createContext<BriefPaneContextValue | null>(null);
53
+
54
+ function useBriefPane(): BriefPaneContextValue {
55
+ const ctx = useContext(BriefPaneCtx);
56
+ if (!ctx) throw new Error("BriefPane.* must be used inside <BriefPane>");
57
+ return ctx;
58
+ }
59
+
60
+ /* ------------------------------------------------------------------ */
61
+ /* Provider */
62
+ /* ------------------------------------------------------------------ */
63
+
64
+ interface BriefPaneProps {
65
+ selectedMessageId: string | undefined;
66
+ children: ReactNode;
67
+ }
68
+
69
+ function BriefPaneProvider({ selectedMessageId, children }: BriefPaneProps) {
70
+ const navigate = useNavigate();
71
+ const { searchInput } = useMailContext();
72
+ const { selectedThreadId, selectedMailboxId } = useSearch({
73
+ strict: false,
74
+ }) as { selectedThreadId?: string; selectedMailboxId?: string };
75
+
76
+ const { data: threadsData } = useQuery({
77
+ ...unifiedThreadOperationsListAllThreadsOptions(),
78
+ staleTime: 60_000,
79
+ });
80
+
81
+ const selectedThread = useMemo(() => {
82
+ if (!selectedMessageId) return undefined;
83
+ return threadsData?.items.find((t) => t.messageId === selectedMessageId);
84
+ }, [threadsData, selectedMessageId]);
85
+
86
+ // A literal hit resolves to a loaded thread; a semantic "Related" hit may not
87
+ // be in the capped brief list, so fall back to the thread + mailbox the hit
88
+ // carried through the URL.
89
+ const conversation = useMemo(
90
+ () =>
91
+ buildConversationTarget(selectedThread, {
92
+ messageId: selectedMessageId,
93
+ threadId: selectedThreadId,
94
+ mailboxId: selectedMailboxId,
95
+ }),
96
+ [selectedThread, selectedMessageId, selectedThreadId, selectedMailboxId],
97
+ );
98
+
99
+ const handleSelectMessage = useCallback(
100
+ (id: string) => {
101
+ navigate({
102
+ to: "/mail",
103
+ search: (prev) => ({
104
+ ...prev,
105
+ selectedMessageId: id,
106
+ selectedThreadId: undefined,
107
+ selectedMailboxId: undefined,
108
+ }),
109
+ });
110
+ },
111
+ [navigate],
112
+ );
113
+
114
+ const handleSelectSearchResult = useCallback(
115
+ (result: SearchResult) => {
116
+ navigate({
117
+ to: "/mail",
118
+ search: (prev) => ({
119
+ ...prev,
120
+ // Commit the active query with the selection so the debounced
121
+ // q-mirror (mail.tsx) — which strips the selection when the query
122
+ // goes active — is already satisfied and leaves the opened result
123
+ // alone. Use the *live* `searchInput`: the row can be tapped before
124
+ // the debounce settles, when the committed query is still empty.
125
+ q: searchInput || undefined,
126
+ selectedMessageId: result.id,
127
+ selectedThreadId: result.threadId,
128
+ selectedMailboxId: result.mailboxId,
129
+ }),
130
+ });
131
+ },
132
+ [navigate, searchInput],
133
+ );
134
+
135
+ const handleCloseThread = useCallback(() => {
136
+ navigate({
137
+ to: "/mail",
138
+ search: (prev) => ({
139
+ ...prev,
140
+ selectedMessageId: undefined,
141
+ selectedThreadId: undefined,
142
+ selectedMailboxId: undefined,
143
+ }),
144
+ });
145
+ }, [navigate]);
146
+
147
+ const ctx: BriefPaneContextValue = {
148
+ selectedMessageId,
149
+ selectedThread,
150
+ conversation,
151
+ onSelectMessage: handleSelectMessage,
152
+ onSelectSearchResult: handleSelectSearchResult,
153
+ onCloseThread: handleCloseThread,
154
+ };
155
+
156
+ return <BriefPaneCtx.Provider value={ctx}>{children}</BriefPaneCtx.Provider>;
157
+ }
158
+
159
+ /* ------------------------------------------------------------------ */
160
+ /* Sub-views */
161
+ /* ------------------------------------------------------------------ */
162
+
163
+ /**
164
+ * Daily brief list. Mount in the `list` slot of `AppShellSlotted`.
165
+ */
166
+ function BriefList() {
167
+ const { selectedMessageId, onSelectMessage, onSelectSearchResult } =
168
+ useBriefPane();
169
+ const { accounts } = useMailContext();
170
+
171
+ return (
172
+ <DailyBrief
173
+ accounts={accounts}
174
+ selectedMessageId={selectedMessageId}
175
+ onSelectMessage={onSelectMessage}
176
+ onSelectSearchResult={onSelectSearchResult}
177
+ />
178
+ );
179
+ }
180
+
181
+ /**
182
+ * Brief reading pane: toolbar + ConversationView.
183
+ * Mount in the `reading` slot of `AppShellSlotted`. Only rendered ≥ 1024px.
184
+ */
185
+ function BriefReading() {
186
+ const { conversation } = useBriefPane();
187
+ const {
188
+ onToggleIntelligence,
189
+ searchInput,
190
+ onSearchChange,
191
+ onSearchClear,
192
+ onSearchClearQuery,
193
+ } = useMailContext();
194
+
195
+ return (
196
+ <section className="flex h-full w-full min-w-0 flex-col bg-canvas">
197
+ <MessageToolbar
198
+ hasThread={Boolean(conversation)}
199
+ onCompose={() => undefined}
200
+ intelligenceOpen={false}
201
+ showIntelligenceToggle={false}
202
+ onToggleIntelligence={onToggleIntelligence}
203
+ searchValue={searchInput}
204
+ onSearchChange={onSearchChange}
205
+ onSearchClear={onSearchClear}
206
+ onSearchClearQuery={onSearchClearQuery}
207
+ />
208
+ <div className="min-h-0 flex-1 overflow-hidden">
209
+ {conversation ? (
210
+ <ConversationView
211
+ threadId={conversation.threadId}
212
+ mailboxId={conversation.mailboxId}
213
+ subject={conversation.subject}
214
+ selectedMessageId={conversation.messageId}
215
+ authenticity={conversation.authenticity}
216
+ />
217
+ ) : (
218
+ <ReadingPaneEmpty />
219
+ )}
220
+ </div>
221
+ </section>
222
+ );
223
+ }
224
+
225
+ /**
226
+ * Phone view: ConversationView when thread is open, or the DailyBrief list.
227
+ */
228
+ function BriefPhone() {
229
+ const {
230
+ selectedThread,
231
+ conversation,
232
+ selectedMessageId,
233
+ onSelectMessage,
234
+ onSelectSearchResult,
235
+ onCloseThread,
236
+ } = useBriefPane();
237
+ const { accounts, intelligenceOpen, onToggleIntelligence } = useMailContext();
238
+
239
+ if (conversation) {
240
+ return (
241
+ <>
242
+ <ConversationView
243
+ threadId={conversation.threadId}
244
+ mailboxId={conversation.mailboxId}
245
+ subject={conversation.subject}
246
+ selectedMessageId={conversation.messageId}
247
+ authenticity={conversation.authenticity}
248
+ onBack={onCloseThread}
249
+ onOpenIntelligence={onToggleIntelligence}
250
+ />
251
+ <Drawer
252
+ isOpen={intelligenceOpen}
253
+ onClose={onToggleIntelligence}
254
+ ariaLabel="Message details"
255
+ side="right"
256
+ >
257
+ <IntelligencePane
258
+ onClose={onToggleIntelligence}
259
+ thread={selectedThread}
260
+ hideCloseButton
261
+ />
262
+ </Drawer>
263
+ </>
264
+ );
265
+ }
266
+
267
+ return (
268
+ <div className="h-full">
269
+ <DailyBrief
270
+ accounts={accounts}
271
+ selectedMessageId={selectedMessageId}
272
+ onSelectMessage={onSelectMessage}
273
+ onSelectSearchResult={onSelectSearchResult}
274
+ />
275
+ </div>
276
+ );
277
+ }
278
+
279
+ /* ------------------------------------------------------------------ */
280
+ /* Compound component assembly */
281
+ /* ------------------------------------------------------------------ */
282
+
283
+ const BriefPane = Object.assign(BriefPaneProvider, {
284
+ List: BriefList,
285
+ Reading: BriefReading,
286
+ Phone: BriefPhone,
287
+ });
288
+
289
+ export { BriefPane };