@remit/web-client 0.0.238 → 0.0.239
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.
- package/package.json +1 -1
- package/src/components/settings/CalendarFeedCard.render.test.ts +154 -0
- package/src/components/settings/CalendarFeedCard.stories.tsx +134 -0
- package/src/components/settings/CalendarFeedCard.tsx +282 -0
- package/src/components/settings/CalendarFeedPanel.tsx +34 -0
- package/src/components/settings/calendar-feed-flow.render.test.ts +449 -0
- package/src/hooks/calendar/useCalendarFeed.ts +163 -0
- package/src/lib/calendar-feed-copy.ts +29 -0
- package/src/lib/calendar-feed-url.ts +14 -0
- package/src/routeTree.gen.ts +21 -0
- package/src/routes/settings/calendars.tsx +73 -0
- package/src/routes/settings.tsx +15 -1
package/src/routeTree.gen.ts
CHANGED
|
@@ -25,6 +25,7 @@ import { Route as SettingsIndexRouteImport } from './routes/settings/index'
|
|
|
25
25
|
import { Route as SettingsAccountsRouteImport } from './routes/settings/accounts'
|
|
26
26
|
import { Route as SettingsAdvancedRouteImport } from './routes/settings/advanced'
|
|
27
27
|
import { Route as SettingsAppearanceRouteImport } from './routes/settings/appearance'
|
|
28
|
+
import { Route as SettingsCalendarsRouteImport } from './routes/settings/calendars'
|
|
28
29
|
import { Route as SettingsFiltersRouteImport } from './routes/settings/filters'
|
|
29
30
|
import { Route as SettingsFoldersRouteImport } from './routes/settings/folders'
|
|
30
31
|
import { Route as SettingsLabelsRouteImport } from './routes/settings/labels'
|
|
@@ -138,6 +139,11 @@ const SettingsAppearanceRoute = SettingsAppearanceRouteImport.update({
|
|
|
138
139
|
path: '/appearance',
|
|
139
140
|
getParentRoute: () => SettingsRoute,
|
|
140
141
|
} as any)
|
|
142
|
+
const SettingsCalendarsRoute = SettingsCalendarsRouteImport.update({
|
|
143
|
+
id: '/calendars',
|
|
144
|
+
path: '/calendars',
|
|
145
|
+
getParentRoute: () => SettingsRoute,
|
|
146
|
+
} as any)
|
|
141
147
|
const SettingsFiltersRoute = SettingsFiltersRouteImport.update({
|
|
142
148
|
id: '/filters',
|
|
143
149
|
path: '/filters',
|
|
@@ -335,6 +341,7 @@ export interface FileRoutesByFullPath {
|
|
|
335
341
|
'/settings/accounts': typeof SettingsAccountsRoute
|
|
336
342
|
'/settings/advanced': typeof SettingsAdvancedRoute
|
|
337
343
|
'/settings/appearance': typeof SettingsAppearanceRoute
|
|
344
|
+
'/settings/calendars': typeof SettingsCalendarsRoute
|
|
338
345
|
'/settings/filters': typeof SettingsFiltersRoute
|
|
339
346
|
'/settings/folders': typeof SettingsFoldersRoute
|
|
340
347
|
'/settings/labels': typeof SettingsLabelsRoute
|
|
@@ -378,6 +385,7 @@ export interface FileRoutesByTo {
|
|
|
378
385
|
'/settings/accounts': typeof SettingsAccountsRoute
|
|
379
386
|
'/settings/advanced': typeof SettingsAdvancedRoute
|
|
380
387
|
'/settings/appearance': typeof SettingsAppearanceRoute
|
|
388
|
+
'/settings/calendars': typeof SettingsCalendarsRoute
|
|
381
389
|
'/settings/filters': typeof SettingsFiltersRoute
|
|
382
390
|
'/settings/folders': typeof SettingsFoldersRoute
|
|
383
391
|
'/settings/labels': typeof SettingsLabelsRoute
|
|
@@ -424,6 +432,7 @@ export interface FileRoutesById {
|
|
|
424
432
|
'/settings/accounts': typeof SettingsAccountsRoute
|
|
425
433
|
'/settings/advanced': typeof SettingsAdvancedRoute
|
|
426
434
|
'/settings/appearance': typeof SettingsAppearanceRoute
|
|
435
|
+
'/settings/calendars': typeof SettingsCalendarsRoute
|
|
427
436
|
'/settings/filters': typeof SettingsFiltersRoute
|
|
428
437
|
'/settings/folders': typeof SettingsFoldersRoute
|
|
429
438
|
'/settings/labels': typeof SettingsLabelsRoute
|
|
@@ -476,6 +485,7 @@ export interface FileRouteTypes {
|
|
|
476
485
|
| '/settings/accounts'
|
|
477
486
|
| '/settings/advanced'
|
|
478
487
|
| '/settings/appearance'
|
|
488
|
+
| '/settings/calendars'
|
|
479
489
|
| '/settings/filters'
|
|
480
490
|
| '/settings/folders'
|
|
481
491
|
| '/settings/labels'
|
|
@@ -519,6 +529,7 @@ export interface FileRouteTypes {
|
|
|
519
529
|
| '/settings/accounts'
|
|
520
530
|
| '/settings/advanced'
|
|
521
531
|
| '/settings/appearance'
|
|
532
|
+
| '/settings/calendars'
|
|
522
533
|
| '/settings/filters'
|
|
523
534
|
| '/settings/folders'
|
|
524
535
|
| '/settings/labels'
|
|
@@ -564,6 +575,7 @@ export interface FileRouteTypes {
|
|
|
564
575
|
| '/settings/accounts'
|
|
565
576
|
| '/settings/advanced'
|
|
566
577
|
| '/settings/appearance'
|
|
578
|
+
| '/settings/calendars'
|
|
567
579
|
| '/settings/filters'
|
|
568
580
|
| '/settings/folders'
|
|
569
581
|
| '/settings/labels'
|
|
@@ -724,6 +736,13 @@ declare module '@tanstack/react-router' {
|
|
|
724
736
|
preLoaderRoute: typeof SettingsAppearanceRouteImport
|
|
725
737
|
parentRoute: typeof SettingsRoute
|
|
726
738
|
}
|
|
739
|
+
'/settings/calendars': {
|
|
740
|
+
id: '/settings/calendars'
|
|
741
|
+
path: '/calendars'
|
|
742
|
+
fullPath: '/settings/calendars'
|
|
743
|
+
preLoaderRoute: typeof SettingsCalendarsRouteImport
|
|
744
|
+
parentRoute: typeof SettingsRoute
|
|
745
|
+
}
|
|
727
746
|
'/settings/filters': {
|
|
728
747
|
id: '/settings/filters'
|
|
729
748
|
path: '/filters'
|
|
@@ -1177,6 +1196,7 @@ interface SettingsRouteChildren {
|
|
|
1177
1196
|
SettingsAccountsRoute: typeof SettingsAccountsRoute
|
|
1178
1197
|
SettingsAdvancedRoute: typeof SettingsAdvancedRoute
|
|
1179
1198
|
SettingsAppearanceRoute: typeof SettingsAppearanceRoute
|
|
1199
|
+
SettingsCalendarsRoute: typeof SettingsCalendarsRoute
|
|
1180
1200
|
SettingsFiltersRoute: typeof SettingsFiltersRoute
|
|
1181
1201
|
SettingsFoldersRoute: typeof SettingsFoldersRoute
|
|
1182
1202
|
SettingsLabelsRoute: typeof SettingsLabelsRoute
|
|
@@ -1189,6 +1209,7 @@ const SettingsRouteChildren: SettingsRouteChildren = {
|
|
|
1189
1209
|
SettingsAccountsRoute: SettingsAccountsRoute,
|
|
1190
1210
|
SettingsAdvancedRoute: SettingsAdvancedRoute,
|
|
1191
1211
|
SettingsAppearanceRoute: SettingsAppearanceRoute,
|
|
1212
|
+
SettingsCalendarsRoute: SettingsCalendarsRoute,
|
|
1192
1213
|
SettingsFiltersRoute: SettingsFiltersRoute,
|
|
1193
1214
|
SettingsFoldersRoute: SettingsFoldersRoute,
|
|
1194
1215
|
SettingsLabelsRoute: SettingsLabelsRoute,
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { SettingsShell } from "@remit/ui";
|
|
2
|
+
import { createFileRoute, useNavigate } from "@tanstack/react-router";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { CalendarFeedPanel } from "@/components/settings/CalendarFeedPanel";
|
|
5
|
+
import { useCalendars } from "@/hooks/calendar/useCalendars";
|
|
6
|
+
import { SETTINGS_ID_TO_PATH, SETTINGS_NAV_ITEMS } from "@/routes/settings";
|
|
7
|
+
|
|
8
|
+
export const Route = createFileRoute("/settings/calendars")({
|
|
9
|
+
component: CalendarsSettings,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const calendarsHelp = (
|
|
13
|
+
<div className="space-y-3">
|
|
14
|
+
<p>
|
|
15
|
+
A subscription address lets Apple Calendar, Google Calendar, Outlook and
|
|
16
|
+
Thunderbird show a calendar from here, read-only and kept up to date.
|
|
17
|
+
</p>
|
|
18
|
+
<p>
|
|
19
|
+
Those clients never sign in, so the address itself is the credential.
|
|
20
|
+
Anyone who has it can read the calendar; nobody who has it can change
|
|
21
|
+
anything.
|
|
22
|
+
</p>
|
|
23
|
+
<p>
|
|
24
|
+
Only a hash of the address is stored, so it is shown once and cannot be
|
|
25
|
+
looked up later. Replacing it breaks every subscription built on the old
|
|
26
|
+
one, which is how a shared address is taken back.
|
|
27
|
+
</p>
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
function CalendarsSettings() {
|
|
32
|
+
const navigate = useNavigate();
|
|
33
|
+
const [helpOpen, setHelpOpen] = useState(true);
|
|
34
|
+
const { calendars, isLoading } = useCalendars();
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<SettingsShell
|
|
38
|
+
items={SETTINGS_NAV_ITEMS}
|
|
39
|
+
activeId="calendars"
|
|
40
|
+
title="Calendars"
|
|
41
|
+
description="Share a calendar with any client that can subscribe to a URL."
|
|
42
|
+
help={calendarsHelp}
|
|
43
|
+
helpOpen={helpOpen}
|
|
44
|
+
onToggleHelp={() => setHelpOpen((open) => !open)}
|
|
45
|
+
onSelect={(id) => {
|
|
46
|
+
const path = SETTINGS_ID_TO_PATH[id];
|
|
47
|
+
if (path) void navigate({ to: path });
|
|
48
|
+
}}
|
|
49
|
+
onBackToMail={() => void navigate({ to: "/mail" })}
|
|
50
|
+
>
|
|
51
|
+
{isLoading ? (
|
|
52
|
+
// biome-ignore lint/a11y/useAriaPropsSupportedByRole: aria-label on a loading skeleton is what assistive tech has to go on
|
|
53
|
+
<div
|
|
54
|
+
className="h-24 animate-pulse rounded-sm border border-line bg-surface"
|
|
55
|
+
aria-busy="true"
|
|
56
|
+
aria-label="Loading calendars"
|
|
57
|
+
/>
|
|
58
|
+
) : calendars.length === 0 ? (
|
|
59
|
+
<p className="py-12 text-sm text-fg-muted">No calendars yet.</p>
|
|
60
|
+
) : (
|
|
61
|
+
<div className="space-y-4">
|
|
62
|
+
{calendars.map((calendar) => (
|
|
63
|
+
<CalendarFeedPanel
|
|
64
|
+
key={calendar.id}
|
|
65
|
+
calendarId={calendar.id}
|
|
66
|
+
calendarName={calendar.name}
|
|
67
|
+
/>
|
|
68
|
+
))}
|
|
69
|
+
</div>
|
|
70
|
+
)}
|
|
71
|
+
</SettingsShell>
|
|
72
|
+
);
|
|
73
|
+
}
|
package/src/routes/settings.tsx
CHANGED
|
@@ -10,7 +10,15 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { SettingsNavItem } from "@remit/ui";
|
|
12
12
|
import { createFileRoute, Outlet } from "@tanstack/react-router";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
CalendarDays,
|
|
15
|
+
Filter,
|
|
16
|
+
FolderTree,
|
|
17
|
+
Inbox,
|
|
18
|
+
Palette,
|
|
19
|
+
Tag,
|
|
20
|
+
Users,
|
|
21
|
+
} from "lucide-react";
|
|
14
22
|
import { AdvancedNavIcon } from "@/components/settings/AdvancedNavIcon";
|
|
15
23
|
|
|
16
24
|
/* ------------------------------------------------------------------ */
|
|
@@ -39,6 +47,11 @@ export const SETTINGS_NAV_ITEMS: SettingsNavItem[] = [
|
|
|
39
47
|
label: "Labels",
|
|
40
48
|
icon: <Tag className="size-4" />,
|
|
41
49
|
},
|
|
50
|
+
{
|
|
51
|
+
id: "calendars",
|
|
52
|
+
label: "Calendars",
|
|
53
|
+
icon: <CalendarDays className="size-4" />,
|
|
54
|
+
},
|
|
42
55
|
{
|
|
43
56
|
id: "appearance",
|
|
44
57
|
label: "Appearance",
|
|
@@ -53,6 +66,7 @@ export const SETTINGS_ID_TO_PATH: Record<string, string> = {
|
|
|
53
66
|
folders: "/settings/folders",
|
|
54
67
|
filters: "/settings/filters",
|
|
55
68
|
labels: "/settings/labels",
|
|
69
|
+
calendars: "/settings/calendars",
|
|
56
70
|
appearance: "/settings/appearance",
|
|
57
71
|
advanced: "/settings/advanced",
|
|
58
72
|
};
|