astryx-dracula 0.5.0 → 0.6.2
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/BRAND.md +3 -3
- package/README.md +7 -4
- package/USAGE.md +49 -49
- package/astryx-dracula.d.ts +2 -2
- package/astryx-dracula.js +25 -9
- package/astryx-dracula.variants.d.ts +2 -2
- package/astryx.integration.mjs +1 -1
- package/icons.mjs +21 -17
- package/icons.tsx +69 -62
- package/package.json +125 -120
- package/shared/auth-chrome-config.ts +6 -6
- package/shared/auth-chrome.tsx +143 -144
- package/shared/auth-copy.ts +14 -14
- package/shared/chaptered-doc-config.ts +48 -51
- package/shared/chaptered-doc.tsx +267 -289
- package/shared/chart-hues.ts +25 -10
- package/shared/chart-labels.tsx +31 -30
- package/shared/chart-legend.tsx +55 -56
- package/shared/chart-panel-style.ts +3 -3
- package/shared/data-bar.tsx +97 -102
- package/shared/format-money.ts +1 -1
- package/shared/gallery-image.ts +6 -6
- package/shared/login-demo.ts +1 -1
- package/shared/metric-card.tsx +101 -105
- package/shared/metric-delta.tsx +28 -27
- package/shared/order-desk.tsx +205 -216
- package/shared/revenue-chart.tsx +145 -165
- package/shared/scene-castle.tsx +206 -291
- package/shared/scene-frame.tsx +33 -32
- package/shared/scene-hues.ts +17 -17
- package/shared/scene-tile.tsx +88 -92
- package/shared/settings-data.ts +119 -125
- package/shared/settings-rows.tsx +122 -159
- package/shared/sparkline.tsx +75 -88
- package/shared/sso-icons.tsx +10 -22
- package/shared/stars.tsx +16 -25
- package/templates/ai-chat-landing.template.mjs +5 -4
- package/templates/ai-chat-landing.tsx +473 -460
- package/templates/ai-chat.template.mjs +5 -4
- package/templates/ai-chat.tsx +543 -612
- package/templates/blank.template.mjs +5 -4
- package/templates/blank.tsx +18 -14
- package/templates/centered-hero.template.mjs +5 -4
- package/templates/centered-hero.tsx +55 -68
- package/templates/classic-gallery.template.mjs +5 -4
- package/templates/classic-gallery.tsx +97 -104
- package/templates/contact-form.template.mjs +5 -4
- package/templates/contact-form.tsx +247 -282
- package/templates/dashboard-portfolio.template.mjs +5 -4
- package/templates/dashboard-portfolio.tsx +717 -548
- package/templates/dashboard.template.mjs +5 -4
- package/templates/dashboard.tsx +596 -567
- package/templates/detail-page.template.mjs +5 -4
- package/templates/detail-page.tsx +546 -603
- package/templates/documentation-design.template.mjs +5 -4
- package/templates/documentation-design.tsx +231 -243
- package/templates/documentation-technical.template.mjs +5 -4
- package/templates/documentation-technical.tsx +236 -239
- package/templates/documentation.template.mjs +5 -4
- package/templates/documentation.tsx +267 -279
- package/templates/editor.template.mjs +5 -4
- package/templates/editor.tsx +844 -877
- package/templates/file-explorer.template.mjs +5 -4
- package/templates/file-explorer.tsx +566 -590
- package/templates/form-two-column.template.mjs +5 -4
- package/templates/form-two-column.tsx +195 -210
- package/templates/gallery-hero.template.mjs +5 -4
- package/templates/gallery-hero.tsx +93 -114
- package/templates/ide.template.mjs +5 -4
- package/templates/ide.tsx +407 -453
- package/templates/incident-console.template.mjs +5 -4
- package/templates/incident-console.tsx +593 -575
- package/templates/kanban-board.template.mjs +5 -4
- package/templates/kanban-board.tsx +665 -683
- package/templates/library.template.mjs +5 -4
- package/templates/library.tsx +409 -430
- package/templates/login-card.template.mjs +5 -4
- package/templates/login-card.tsx +63 -72
- package/templates/login-split.template.mjs +5 -4
- package/templates/login-split.tsx +192 -193
- package/templates/login-sso.template.mjs +5 -4
- package/templates/login-sso.tsx +257 -258
- package/templates/login.template.mjs +5 -4
- package/templates/login.tsx +53 -49
- package/templates/messaging-shell.template.mjs +5 -4
- package/templates/messaging-shell.tsx +556 -574
- package/templates/mixed-gallery.template.mjs +5 -4
- package/templates/mixed-gallery.tsx +60 -58
- package/templates/payment-form.template.mjs +5 -4
- package/templates/payment-form.tsx +882 -991
- package/templates/product-detail.template.mjs +5 -4
- package/templates/product-detail.tsx +261 -272
- package/templates/product-gallery.template.mjs +5 -4
- package/templates/product-gallery.tsx +126 -137
- package/templates/product-tour.template.mjs +5 -4
- package/templates/product-tour.tsx +741 -773
- package/templates/settings-dialog.template.mjs +5 -4
- package/templates/settings-dialog.tsx +688 -717
- package/templates/settings-sidebar.template.mjs +5 -4
- package/templates/settings-sidebar.tsx +762 -807
- package/templates/settings.template.mjs +5 -4
- package/templates/settings.tsx +289 -304
- package/templates/shell-nav.template.mjs +5 -4
- package/templates/shell-nav.tsx +212 -219
- package/templates/shell-side-nav.template.mjs +5 -4
- package/templates/shell-side-nav.tsx +135 -157
- package/templates/shell-top-nav.template.mjs +5 -4
- package/templates/shell-top-nav.tsx +182 -203
- package/templates/side-gallery.template.mjs +5 -4
- package/templates/side-gallery.tsx +85 -90
- package/templates/table-grouped.template.mjs +5 -4
- package/templates/table-grouped.tsx +1000 -1053
- package/templates/table-page-chart.template.mjs +5 -4
- package/templates/table-page-chart.tsx +400 -398
- package/templates/table-page-heatmap-status.template.mjs +5 -4
- package/templates/table-page-heatmap-status.tsx +483 -512
- package/templates/table-page-shoe-store-heatmap.template.mjs +5 -4
- package/templates/table-page-shoe-store-heatmap.tsx +748 -746
- package/templates/table-page.template.mjs +5 -4
- package/templates/table-page.tsx +396 -405
- package/templates/table.template.mjs +5 -4
- package/templates/table.tsx +92 -93
- package/templates/tech-report.template.mjs +5 -4
- package/templates/tech-report.tsx +1316 -1304
- package/templates/theme-showcase.template.mjs +5 -4
- package/templates/theme-showcase.tsx +871 -951
- package/theme.css +35 -77
- package/theme.css.d.ts +9 -0
- package/tokens.css +373 -380
|
@@ -1,57 +1,70 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
// XLE (canonical structure
|
|
3
|
-
//
|
|
2
|
+
// XLE (canonical structure of the tree below; the CLI had no XLE validator
|
|
3
|
+
// after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
|
|
4
|
+
// human drift check — update it with the file, never alone):
|
|
5
|
+
// L[h=auto] > LC[p=0] > Ctr[h=80vh] > B.primary"Open settings"[opens=#settings] ;; Dlg#settings > L[h=fill] > (LP[w=280 divider p=3] > V[g=4] > Tx"Account settings"[t=label] + (UL[density=spacious edge=flush] > LI"Personal information" + LI"Login & security"! + LI*6)) + (LC[p=6] > V[g=6] > DH"Login & security" + SE{Selector}"Settings section" + (V[g=0 mw=680] > (TL[divider] > Tab"Login"! + Tab"Shared access") + (V[g=8] > (V[g=2] > Hd"Login"[level=3] + (H[j=between a=start] > (V[g=1] > Tx"Password"[weight=semibold] + Tx"Not created"[t=body]) + B.secondary"Create")) + (V[g=2] > Hd"Social accounts"[level=3] + (H[j=between a=start] > (V[g=1] > Tx"Google"[weight=semibold] + Tx"Connected"[t=body]) + B.destructive"Disconnect")) + (V[g=2] > Hd"Device history"[level=3] + (H[g=3 a=start] > Ic + (SI[fill] > V[g=1] > (H[g=2 a=center wrap] > Tx"OS X 10.15.7 · Chrome"[weight=semibold] + SD.success) + Tx"March 30, 2026"[t=supporting]))*3) + (V[g=2] > Hd"Account"[level=3] + (H[j=between a=start] > (V[g=1] > Tx"Deactivate your account"[weight=semibold] + Tx"This action cannot be undone"[t=supporting]) + B.destructive"Deactivate")))))
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Settings Dialog — account sections inside one modal. Frame: the trigger page, then a Dialog that sizes to (Frame/responsive/container: see XLE header above.)
|
|
7
9
|
*/
|
|
8
10
|
|
|
9
|
-
import {
|
|
11
|
+
import { Button } from "@astryxdesign/core/Button";
|
|
12
|
+
import { Card } from "@astryxdesign/core/Card";
|
|
13
|
+
import { Center } from "@astryxdesign/core/Center";
|
|
14
|
+
import { Dialog, DialogHeader } from "@astryxdesign/core/Dialog";
|
|
15
|
+
import { useMediaQuery } from "@astryxdesign/core/hooks";
|
|
16
|
+
import { Icon } from "@astryxdesign/core/Icon";
|
|
10
17
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
} from
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
18
|
+
HStack,
|
|
19
|
+
Layout,
|
|
20
|
+
LayoutContent,
|
|
21
|
+
LayoutPanel,
|
|
22
|
+
StackItem,
|
|
23
|
+
VStack,
|
|
24
|
+
} from "@astryxdesign/core/Layout";
|
|
25
|
+
import { Link } from "@astryxdesign/core/Link";
|
|
26
|
+
import { List, ListItem } from "@astryxdesign/core/List";
|
|
27
|
+
import { Selector } from "@astryxdesign/core/Selector";
|
|
28
|
+
import { StatusDot } from "@astryxdesign/core/StatusDot";
|
|
29
|
+
import { Switch } from "@astryxdesign/core/Switch";
|
|
30
|
+
import { Tab, TabList } from "@astryxdesign/core/TabList";
|
|
31
|
+
import { Heading, Text } from "@astryxdesign/core/Text";
|
|
32
|
+
import { TextInput } from "@astryxdesign/core/TextInput";
|
|
33
|
+
import type { DeviceRow, InfoTileData } from "astryx-dracula/shared/settings-data";
|
|
34
|
+
import {
|
|
35
|
+
CURRENCIES,
|
|
36
|
+
DEVICE_ROWS,
|
|
37
|
+
INFO_TILES,
|
|
38
|
+
iconBox,
|
|
39
|
+
LANGUAGES,
|
|
40
|
+
LOGIN_ROWS,
|
|
41
|
+
NAV_ITEMS,
|
|
42
|
+
SOCIAL_ROWS,
|
|
43
|
+
sideNavHeading,
|
|
44
|
+
TIMEZONES,
|
|
45
|
+
} from "astryx-dracula/shared/settings-data";
|
|
46
|
+
import { ExpandableRow, InfoRowItem } from "astryx-dracula/shared/settings-rows";
|
|
47
|
+
import { Lock, Monitor, ShieldCheck } from "lucide-react";
|
|
48
|
+
import { type CSSProperties, useState } from "react";
|
|
36
49
|
|
|
37
50
|
// Sticky dialog header bar — no Astryx prop for sticky/background/z-index.
|
|
38
51
|
// Inline + block padding comes from the parent LayoutContent `padding`.
|
|
39
52
|
const headerSticky: CSSProperties = {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
53
|
+
position: "sticky",
|
|
54
|
+
top: 0,
|
|
55
|
+
backgroundColor: "var(--color-background-surface)",
|
|
56
|
+
zIndex: 1,
|
|
44
57
|
};
|
|
45
58
|
|
|
46
59
|
// Width cap on the content column (VStack `maxWidth`; inline padding comes
|
|
47
60
|
// from the parent LayoutContent `padding`).
|
|
48
61
|
const dialogHeight: CSSProperties = {
|
|
49
|
-
|
|
62
|
+
height: "85vh",
|
|
50
63
|
};
|
|
51
64
|
|
|
52
65
|
// Same-route hash: demo links stay focusable anchors without escaping the
|
|
53
66
|
// template through the hash router (bare "#" would drop back to the home page).
|
|
54
|
-
const SELF_HASH =
|
|
67
|
+
const SELF_HASH = "#/templates/settings-dialog";
|
|
55
68
|
|
|
56
69
|
// InfoTile renders the icon tile plus title/body stacked text. DeviceRowItem
|
|
57
70
|
// renders the session icon, label + current-session badge, timestamp, and
|
|
@@ -59,696 +72,654 @@ const SELF_HASH = '#/templates/settings-dialog';
|
|
|
59
72
|
// because that module already covered InfoRowItem/ExpandableRow at its size
|
|
60
73
|
// limit, and these two are used by this dialog only.
|
|
61
74
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
);
|
|
75
|
+
function InfoTile({ icon, title, body }: InfoTileData) {
|
|
76
|
+
return (
|
|
77
|
+
<HStack gap={3} vAlign="start">
|
|
78
|
+
<Center width={48} height={48} style={iconBox}>
|
|
79
|
+
<Icon icon={icon} />
|
|
80
|
+
</Center>
|
|
81
|
+
<VStack gap={1}>
|
|
82
|
+
<Text type="body" weight="semibold" display="block">
|
|
83
|
+
{title}
|
|
84
|
+
</Text>
|
|
85
|
+
<Text type="body" color="secondary" display="block">
|
|
86
|
+
{body}
|
|
87
|
+
</Text>
|
|
88
|
+
</VStack>
|
|
89
|
+
</HStack>
|
|
90
|
+
);
|
|
79
91
|
}
|
|
80
92
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
{/* wrap: the label plus the session status exceed the compact
|
|
93
|
+
function DeviceRowItem({ label, isCurrent, location, action }: DeviceRow) {
|
|
94
|
+
return (
|
|
95
|
+
<HStack gap={3} vAlign="start">
|
|
96
|
+
<Icon icon={Monitor} />
|
|
97
|
+
<StackItem size="fill">
|
|
98
|
+
<VStack gap={1}>
|
|
99
|
+
{/* wrap: the label plus the session status exceed the compact
|
|
89
100
|
content width (~280px). */}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
{/* Ending a session changes state in place — a Button, not a Link. */}
|
|
113
|
-
{action && <Button label={action} variant="secondary" size="sm" />}
|
|
114
|
-
</HStack>
|
|
115
|
-
);
|
|
101
|
+
<HStack gap={2} vAlign="center" wrap="wrap">
|
|
102
|
+
<Text type="body" weight="semibold">
|
|
103
|
+
{label}
|
|
104
|
+
</Text>
|
|
105
|
+
{isCurrent && (
|
|
106
|
+
<HStack gap={1} vAlign="center">
|
|
107
|
+
<StatusDot variant="success" label="Current session" />
|
|
108
|
+
<Text type="supporting" color="secondary">
|
|
109
|
+
Current session
|
|
110
|
+
</Text>
|
|
111
|
+
</HStack>
|
|
112
|
+
)}
|
|
113
|
+
</HStack>
|
|
114
|
+
<Text type="supporting" color="secondary" display="block" hasTabularNumbers>
|
|
115
|
+
{location}
|
|
116
|
+
</Text>
|
|
117
|
+
</VStack>
|
|
118
|
+
</StackItem>
|
|
119
|
+
{/* Ending a session changes state in place — a Button, not a Link. */}
|
|
120
|
+
{action && <Button label={action} variant="secondary" size="sm" />}
|
|
121
|
+
</HStack>
|
|
122
|
+
);
|
|
116
123
|
}
|
|
117
124
|
|
|
118
125
|
export default function SettingsDialog() {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
126
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
127
|
+
const [activeNav, setActiveNav] = useState("Login & security");
|
|
128
|
+
const [expandedRow, setExpandedRow] = useState<string | null>(null);
|
|
129
|
+
|
|
130
|
+
const [language, setLanguage] = useState("en-CA");
|
|
131
|
+
const [currency, setCurrency] = useState("CAD");
|
|
132
|
+
const [timezone, setTimezone] = useState("ET");
|
|
133
|
+
const [activeTab, setActiveTab] = useState("login");
|
|
134
|
+
|
|
135
|
+
const [legalName, setLegalName] = useState("Vlad Dracul");
|
|
136
|
+
const [preferredName, setPreferredName] = useState("");
|
|
137
|
+
const [email, setEmail] = useState("v***d@castle-dracula.ro");
|
|
138
|
+
const [phone, setPhone] = useState("+1 ***-***-0123");
|
|
139
|
+
const [address, setAddress] = useState("");
|
|
140
|
+
const [mailingAddress, setMailingAddress] = useState("");
|
|
141
|
+
const [emergencyContact, setEmergencyContact] = useState("Provided");
|
|
142
|
+
const [readReceipts, setReadReceipts] = useState(true);
|
|
143
|
+
const [searchEngines, setSearchEngines] = useState(true);
|
|
144
|
+
const [showCity, setShowCity] = useState(true);
|
|
145
|
+
const [showTripType, setShowTripType] = useState(true);
|
|
146
|
+
const [showStayLength, setShowStayLength] = useState(true);
|
|
147
|
+
const [showServices, setShowServices] = useState(true);
|
|
148
|
+
const [aiFeatures, setAiFeatures] = useState(true);
|
|
149
|
+
const [emailNotif, setEmailNotif] = useState(true);
|
|
150
|
+
const [pushNotif, setPushNotif] = useState(false);
|
|
151
|
+
const [workTravel, setWorkTravel] = useState(false);
|
|
152
|
+
|
|
153
|
+
// Below ~640px the 280px section sidebar crushes the content column to
|
|
154
|
+
// ~110px. The sidebar hides and a section picker renders above the content.
|
|
155
|
+
const isCompact = useMediaQuery("(max-width: 640px)");
|
|
156
|
+
|
|
157
|
+
const handleEdit = (row: string) => setExpandedRow(row);
|
|
158
|
+
const handleCancel = () => setExpandedRow(null);
|
|
159
|
+
const handleSave = () => setExpandedRow(null);
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<>
|
|
163
|
+
<Layout
|
|
164
|
+
height="auto"
|
|
165
|
+
content={
|
|
166
|
+
<LayoutContent padding={0}>
|
|
167
|
+
<Center height="80vh">
|
|
168
|
+
<Button label="Open settings" variant="primary" onClick={() => setIsOpen(true)} />
|
|
169
|
+
</Center>
|
|
170
|
+
</LayoutContent>
|
|
171
|
+
}
|
|
172
|
+
/>
|
|
173
|
+
|
|
174
|
+
<Dialog
|
|
175
|
+
isOpen={isOpen}
|
|
176
|
+
onOpenChange={(open) => setIsOpen(open)}
|
|
177
|
+
// One width for every viewport: below 932px the dialog shrinks with the
|
|
178
|
+
// window instead of clipping, so no compact branch is needed.
|
|
179
|
+
width="min(900px, calc(100vw - 32px))"
|
|
180
|
+
maxHeight="85vh"
|
|
181
|
+
padding={0}
|
|
182
|
+
purpose="form"
|
|
183
|
+
style={dialogHeight}
|
|
184
|
+
>
|
|
185
|
+
<Layout
|
|
186
|
+
height="fill"
|
|
187
|
+
start={
|
|
188
|
+
isCompact ? undefined : (
|
|
189
|
+
<LayoutPanel width={280} hasDivider role="navigation" padding={3}>
|
|
190
|
+
<VStack gap={4}>
|
|
191
|
+
<Text type="label" style={sideNavHeading}>
|
|
192
|
+
Account settings
|
|
193
|
+
</Text>
|
|
194
|
+
<List density="spacious" edge="flush">
|
|
195
|
+
{NAV_ITEMS.map((item) => (
|
|
196
|
+
<ListItem
|
|
197
|
+
key={item.label}
|
|
198
|
+
label={item.label}
|
|
199
|
+
startContent={<Icon icon={item.icon} />}
|
|
200
|
+
isSelected={activeNav === item.label}
|
|
201
|
+
onClick={() => {
|
|
202
|
+
setActiveNav(item.label);
|
|
203
|
+
setExpandedRow(null);
|
|
204
|
+
}}
|
|
205
|
+
/>
|
|
206
|
+
))}
|
|
207
|
+
</List>
|
|
208
|
+
</VStack>
|
|
209
|
+
</LayoutPanel>
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
content={
|
|
213
|
+
<LayoutContent isScrollable padding={6}>
|
|
214
|
+
<VStack gap={6}>
|
|
215
|
+
<VStack style={headerSticky}>
|
|
216
|
+
<DialogHeader
|
|
217
|
+
title={activeNav === "Personal information" ? "Personal info" : activeNav}
|
|
218
|
+
onOpenChange={(open) => setIsOpen(open)}
|
|
219
|
+
hasDivider={false}
|
|
220
|
+
/>
|
|
221
|
+
</VStack>
|
|
222
|
+
{isCompact && (
|
|
223
|
+
<Selector
|
|
224
|
+
label="Settings section"
|
|
225
|
+
value={activeNav}
|
|
226
|
+
onChange={(value) => {
|
|
227
|
+
setActiveNav(value);
|
|
228
|
+
setExpandedRow(null);
|
|
229
|
+
}}
|
|
230
|
+
options={NAV_ITEMS.map((item) => ({
|
|
231
|
+
label: item.label,
|
|
232
|
+
value: item.label,
|
|
233
|
+
}))}
|
|
234
|
+
width="100%"
|
|
235
|
+
/>
|
|
236
|
+
)}
|
|
237
|
+
<VStack gap={0} maxWidth={680}>
|
|
238
|
+
{activeNav === "Personal information" && (
|
|
239
|
+
<VStack gap={6}>
|
|
240
|
+
<VStack gap={4}>
|
|
241
|
+
<ExpandableRow
|
|
242
|
+
label="Legal name"
|
|
243
|
+
value={legalName}
|
|
244
|
+
isExpanded={expandedRow === "legalName"}
|
|
245
|
+
onEdit={() => handleEdit("legalName")}
|
|
246
|
+
onCancel={handleCancel}
|
|
247
|
+
onSave={handleSave}
|
|
248
|
+
hasDivider={false}
|
|
249
|
+
>
|
|
250
|
+
<TextInput
|
|
251
|
+
label="Legal name"
|
|
252
|
+
isLabelHidden
|
|
253
|
+
value={legalName}
|
|
254
|
+
onChange={setLegalName}
|
|
255
|
+
/>
|
|
256
|
+
</ExpandableRow>
|
|
257
|
+
<ExpandableRow
|
|
258
|
+
label="Preferred first name"
|
|
259
|
+
value={preferredName || "Not provided"}
|
|
260
|
+
isExpanded={expandedRow === "preferredName"}
|
|
261
|
+
onEdit={() => handleEdit("preferredName")}
|
|
262
|
+
onCancel={handleCancel}
|
|
263
|
+
onSave={handleSave}
|
|
264
|
+
hasDivider={false}
|
|
265
|
+
>
|
|
266
|
+
<TextInput
|
|
267
|
+
label="Preferred first name"
|
|
268
|
+
isLabelHidden
|
|
269
|
+
value={preferredName}
|
|
270
|
+
onChange={setPreferredName}
|
|
271
|
+
/>
|
|
272
|
+
</ExpandableRow>
|
|
273
|
+
<ExpandableRow
|
|
274
|
+
label="Email address"
|
|
275
|
+
value={email}
|
|
276
|
+
isExpanded={expandedRow === "email"}
|
|
277
|
+
onEdit={() => handleEdit("email")}
|
|
278
|
+
onCancel={handleCancel}
|
|
279
|
+
onSave={handleSave}
|
|
280
|
+
hasDivider={false}
|
|
281
|
+
>
|
|
282
|
+
<TextInput
|
|
283
|
+
label="Email address"
|
|
284
|
+
isLabelHidden
|
|
285
|
+
value={email}
|
|
286
|
+
onChange={setEmail}
|
|
287
|
+
/>
|
|
288
|
+
</ExpandableRow>
|
|
289
|
+
<ExpandableRow
|
|
290
|
+
label="Phone number"
|
|
291
|
+
value={phone}
|
|
292
|
+
isExpanded={expandedRow === "phone"}
|
|
293
|
+
onEdit={() => handleEdit("phone")}
|
|
294
|
+
onCancel={handleCancel}
|
|
295
|
+
onSave={handleSave}
|
|
296
|
+
hasDivider={false}
|
|
297
|
+
>
|
|
298
|
+
<TextInput
|
|
299
|
+
label="Phone number"
|
|
300
|
+
isLabelHidden
|
|
301
|
+
value={phone}
|
|
302
|
+
onChange={setPhone}
|
|
303
|
+
/>
|
|
304
|
+
</ExpandableRow>
|
|
305
|
+
<InfoRowItem
|
|
306
|
+
label="Identity verification"
|
|
307
|
+
value="Verified"
|
|
308
|
+
action=""
|
|
309
|
+
hasDivider={false}
|
|
310
|
+
/>
|
|
311
|
+
<ExpandableRow
|
|
312
|
+
label="Residential address"
|
|
313
|
+
value={address || "Not provided"}
|
|
314
|
+
isExpanded={expandedRow === "address"}
|
|
315
|
+
onEdit={() => handleEdit("address")}
|
|
316
|
+
onCancel={handleCancel}
|
|
317
|
+
onSave={handleSave}
|
|
318
|
+
hasDivider={false}
|
|
319
|
+
>
|
|
320
|
+
<TextInput
|
|
321
|
+
label="Residential address"
|
|
322
|
+
isLabelHidden
|
|
323
|
+
value={address}
|
|
324
|
+
onChange={setAddress}
|
|
325
|
+
/>
|
|
326
|
+
</ExpandableRow>
|
|
327
|
+
<ExpandableRow
|
|
328
|
+
label="Mailing address"
|
|
329
|
+
value={mailingAddress || "Not provided"}
|
|
330
|
+
isExpanded={expandedRow === "mailingAddress"}
|
|
331
|
+
onEdit={() => handleEdit("mailingAddress")}
|
|
332
|
+
onCancel={handleCancel}
|
|
333
|
+
onSave={handleSave}
|
|
334
|
+
hasDivider={false}
|
|
335
|
+
>
|
|
336
|
+
<TextInput
|
|
337
|
+
label="Mailing address"
|
|
338
|
+
isLabelHidden
|
|
339
|
+
value={mailingAddress}
|
|
340
|
+
onChange={setMailingAddress}
|
|
341
|
+
/>
|
|
342
|
+
</ExpandableRow>
|
|
343
|
+
<ExpandableRow
|
|
344
|
+
label="Emergency contact"
|
|
345
|
+
value={emergencyContact}
|
|
346
|
+
isExpanded={expandedRow === "emergencyContact"}
|
|
347
|
+
onEdit={() => handleEdit("emergencyContact")}
|
|
348
|
+
onCancel={handleCancel}
|
|
349
|
+
onSave={handleSave}
|
|
350
|
+
hasDivider={false}
|
|
351
|
+
>
|
|
352
|
+
<TextInput
|
|
353
|
+
label="Emergency contact"
|
|
354
|
+
isLabelHidden
|
|
355
|
+
value={emergencyContact}
|
|
356
|
+
onChange={setEmergencyContact}
|
|
357
|
+
/>
|
|
358
|
+
</ExpandableRow>
|
|
359
|
+
</VStack>
|
|
360
|
+
|
|
361
|
+
{/* One divider at most per panel: the tiles are one
|
|
355
362
|
group, so `gap` carries the rhythm. */}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
</TabList>
|
|
375
|
-
|
|
376
|
-
{/* Four genuinely different groups, each with its own
|
|
363
|
+
<Card padding={4}>
|
|
364
|
+
<VStack gap={4}>
|
|
365
|
+
{INFO_TILES.map((tile) => (
|
|
366
|
+
<InfoTile key={tile.title} {...tile} />
|
|
367
|
+
))}
|
|
368
|
+
</VStack>
|
|
369
|
+
</Card>
|
|
370
|
+
</VStack>
|
|
371
|
+
)}
|
|
372
|
+
|
|
373
|
+
{activeNav === "Login & security" && (
|
|
374
|
+
<VStack gap={6}>
|
|
375
|
+
<TabList value={activeTab} onChange={setActiveTab} hasDivider>
|
|
376
|
+
<Tab value="login" label="Login" />
|
|
377
|
+
<Tab value="shared" label="Shared access" />
|
|
378
|
+
</TabList>
|
|
379
|
+
|
|
380
|
+
{/* Four genuinely different groups, each with its own
|
|
377
381
|
heading: `gap` is the boundary, so no rule between
|
|
378
382
|
them and none after the last row. */}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
</Card>
|
|
722
|
-
<Card variant="muted">
|
|
723
|
-
<HStack gap={4} vAlign="start">
|
|
724
|
-
<Center width={48} height={48} style={iconBox}>
|
|
725
|
-
<Icon icon={ShieldCheck} />
|
|
726
|
-
</Center>
|
|
727
|
-
<VStack gap={1}>
|
|
728
|
-
<Text type="body">
|
|
729
|
-
Committed to privacy
|
|
730
|
-
</Text>
|
|
731
|
-
<Text type="body" color="secondary">
|
|
732
|
-
We're committed to keeping your data
|
|
733
|
-
protected. See details in our{' '}
|
|
734
|
-
<Link href={SELF_HASH} hasUnderline>
|
|
735
|
-
Privacy Policy
|
|
736
|
-
</Link>
|
|
737
|
-
.
|
|
738
|
-
</Text>
|
|
739
|
-
</VStack>
|
|
740
|
-
</HStack>
|
|
741
|
-
</Card>
|
|
742
|
-
</VStack>
|
|
743
|
-
</VStack>
|
|
744
|
-
</VStack>
|
|
745
|
-
)}
|
|
746
|
-
</VStack>
|
|
747
|
-
</VStack>
|
|
748
|
-
</LayoutContent>
|
|
749
|
-
}
|
|
750
|
-
/>
|
|
751
|
-
</Dialog>
|
|
752
|
-
</>
|
|
753
|
-
);
|
|
383
|
+
{activeTab === "login" && (
|
|
384
|
+
<VStack gap={8}>
|
|
385
|
+
<VStack gap={2}>
|
|
386
|
+
<Heading level={3}>Login</Heading>
|
|
387
|
+
{LOGIN_ROWS.map((row) => (
|
|
388
|
+
<InfoRowItem key={row.label} {...row} hasDivider={false} />
|
|
389
|
+
))}
|
|
390
|
+
</VStack>
|
|
391
|
+
|
|
392
|
+
<VStack gap={2}>
|
|
393
|
+
<Heading level={3}>Social accounts</Heading>
|
|
394
|
+
{SOCIAL_ROWS.map((row) => (
|
|
395
|
+
<InfoRowItem key={row.label} {...row} hasDivider={false} />
|
|
396
|
+
))}
|
|
397
|
+
</VStack>
|
|
398
|
+
|
|
399
|
+
<VStack gap={2}>
|
|
400
|
+
<Heading level={3}>Device history</Heading>
|
|
401
|
+
{DEVICE_ROWS.map((device) => (
|
|
402
|
+
<DeviceRowItem key={device.location} {...device} />
|
|
403
|
+
))}
|
|
404
|
+
</VStack>
|
|
405
|
+
|
|
406
|
+
<VStack gap={2}>
|
|
407
|
+
<Heading level={3}>Account</Heading>
|
|
408
|
+
<HStack hAlign="between" vAlign="start">
|
|
409
|
+
<VStack gap={1}>
|
|
410
|
+
<Text type="body" weight="semibold" display="block">
|
|
411
|
+
Deactivate your account
|
|
412
|
+
</Text>
|
|
413
|
+
<Text type="supporting" color="secondary" display="block">
|
|
414
|
+
This action cannot be undone
|
|
415
|
+
</Text>
|
|
416
|
+
</VStack>
|
|
417
|
+
{/* Deactivating changes state in place. */}
|
|
418
|
+
<Button label="Deactivate" variant="destructive" size="sm" />
|
|
419
|
+
</HStack>
|
|
420
|
+
</VStack>
|
|
421
|
+
</VStack>
|
|
422
|
+
)}
|
|
423
|
+
|
|
424
|
+
{activeTab === "shared" && (
|
|
425
|
+
<VStack gap={8}>
|
|
426
|
+
<VStack gap={2}>
|
|
427
|
+
<Heading level={3}>Shared access</Heading>
|
|
428
|
+
<Text type="body" color="secondary">
|
|
429
|
+
Review each request carefully before approving access. We'll
|
|
430
|
+
email your kin or coven-mate a 4-digit code that lets them enter your
|
|
431
|
+
crypt from their trusted device.
|
|
432
|
+
</Text>
|
|
433
|
+
</VStack>
|
|
434
|
+
|
|
435
|
+
<Card variant="muted">
|
|
436
|
+
<HStack gap={4} vAlign="start">
|
|
437
|
+
<Center width={48} height={48} style={iconBox}>
|
|
438
|
+
<Icon icon={Lock} />
|
|
439
|
+
</Center>
|
|
440
|
+
<VStack gap={1}>
|
|
441
|
+
<Text type="body">Adding devices for your trusted coven</Text>
|
|
442
|
+
<Text type="body" color="secondary">
|
|
443
|
+
When you approve a request, you grant them full passage through
|
|
444
|
+
your crypt. They'll be able to change bookings and send
|
|
445
|
+
ravens on your behalf.
|
|
446
|
+
</Text>
|
|
447
|
+
</VStack>
|
|
448
|
+
</HStack>
|
|
449
|
+
</Card>
|
|
450
|
+
</VStack>
|
|
451
|
+
)}
|
|
452
|
+
</VStack>
|
|
453
|
+
)}
|
|
454
|
+
|
|
455
|
+
{activeNav === "Languages & currency" && (
|
|
456
|
+
<VStack gap={6}>
|
|
457
|
+
<VStack gap={4}>
|
|
458
|
+
<ExpandableRow
|
|
459
|
+
label="Preferred language"
|
|
460
|
+
value={LANGUAGES.find((l) => l.value === language)?.label ?? language}
|
|
461
|
+
isExpanded={expandedRow === "language"}
|
|
462
|
+
onEdit={() => handleEdit("language")}
|
|
463
|
+
onCancel={handleCancel}
|
|
464
|
+
onSave={handleSave}
|
|
465
|
+
hasDivider={false}
|
|
466
|
+
>
|
|
467
|
+
<Selector
|
|
468
|
+
label="Language"
|
|
469
|
+
isLabelHidden
|
|
470
|
+
size="lg"
|
|
471
|
+
value={language}
|
|
472
|
+
onChange={setLanguage}
|
|
473
|
+
options={LANGUAGES}
|
|
474
|
+
/>
|
|
475
|
+
</ExpandableRow>
|
|
476
|
+
<ExpandableRow
|
|
477
|
+
label="Preferred currency"
|
|
478
|
+
value={CURRENCIES.find((c) => c.value === currency)?.label ?? currency}
|
|
479
|
+
isExpanded={expandedRow === "currency"}
|
|
480
|
+
onEdit={() => handleEdit("currency")}
|
|
481
|
+
onCancel={handleCancel}
|
|
482
|
+
onSave={handleSave}
|
|
483
|
+
hasDivider={false}
|
|
484
|
+
>
|
|
485
|
+
<Selector
|
|
486
|
+
label="Currency"
|
|
487
|
+
isLabelHidden
|
|
488
|
+
size="lg"
|
|
489
|
+
value={currency}
|
|
490
|
+
onChange={setCurrency}
|
|
491
|
+
options={CURRENCIES}
|
|
492
|
+
/>
|
|
493
|
+
</ExpandableRow>
|
|
494
|
+
<ExpandableRow
|
|
495
|
+
label="Time zone"
|
|
496
|
+
value={TIMEZONES.find((t) => t.value === timezone)?.label ?? timezone}
|
|
497
|
+
isExpanded={expandedRow === "timezone"}
|
|
498
|
+
onEdit={() => handleEdit("timezone")}
|
|
499
|
+
onCancel={handleCancel}
|
|
500
|
+
onSave={handleSave}
|
|
501
|
+
hasDivider={false}
|
|
502
|
+
>
|
|
503
|
+
<Selector
|
|
504
|
+
label="Time zone"
|
|
505
|
+
isLabelHidden
|
|
506
|
+
size="lg"
|
|
507
|
+
value={timezone}
|
|
508
|
+
onChange={setTimezone}
|
|
509
|
+
options={TIMEZONES}
|
|
510
|
+
/>
|
|
511
|
+
</ExpandableRow>
|
|
512
|
+
</VStack>
|
|
513
|
+
</VStack>
|
|
514
|
+
)}
|
|
515
|
+
|
|
516
|
+
{activeNav === "Notifications" && (
|
|
517
|
+
<VStack gap={6}>
|
|
518
|
+
<VStack gap={4}>
|
|
519
|
+
<Heading level={3}>Notifications</Heading>
|
|
520
|
+
<Switch
|
|
521
|
+
label="Email notifications"
|
|
522
|
+
description="Booking updates, reminders, and coven decrees."
|
|
523
|
+
value={emailNotif}
|
|
524
|
+
onChange={setEmailNotif}
|
|
525
|
+
labelPosition="start"
|
|
526
|
+
labelSpacing="spread"
|
|
527
|
+
/>
|
|
528
|
+
<Switch
|
|
529
|
+
label="Push notifications"
|
|
530
|
+
description="Time-sensitive alerts, delivered by raven."
|
|
531
|
+
value={pushNotif}
|
|
532
|
+
onChange={setPushNotif}
|
|
533
|
+
labelPosition="start"
|
|
534
|
+
labelSpacing="spread"
|
|
535
|
+
/>
|
|
536
|
+
</VStack>
|
|
537
|
+
</VStack>
|
|
538
|
+
)}
|
|
539
|
+
|
|
540
|
+
{activeNav === "Payments" && (
|
|
541
|
+
<VStack gap={6}>
|
|
542
|
+
<VStack gap={4}>
|
|
543
|
+
<Heading level={3}>Payments</Heading>
|
|
544
|
+
<InfoRowItem
|
|
545
|
+
label="Payout crypt"
|
|
546
|
+
value="Visa ending in 4821"
|
|
547
|
+
action=""
|
|
548
|
+
hasDivider={false}
|
|
549
|
+
/>
|
|
550
|
+
<InfoRowItem
|
|
551
|
+
label="Past payouts"
|
|
552
|
+
value="No tributes yet"
|
|
553
|
+
action=""
|
|
554
|
+
hasDivider={false}
|
|
555
|
+
/>
|
|
556
|
+
</VStack>
|
|
557
|
+
</VStack>
|
|
558
|
+
)}
|
|
559
|
+
|
|
560
|
+
{activeNav === "Taxes" && (
|
|
561
|
+
<VStack gap={6}>
|
|
562
|
+
<VStack gap={4}>
|
|
563
|
+
<Heading level={3}>Taxes</Heading>
|
|
564
|
+
<InfoRowItem
|
|
565
|
+
label="Tax scrolls"
|
|
566
|
+
value="Not submitted"
|
|
567
|
+
action=""
|
|
568
|
+
hasDivider={false}
|
|
569
|
+
/>
|
|
570
|
+
<InfoRowItem
|
|
571
|
+
label="Past scrolls"
|
|
572
|
+
value="Available after your first tribute"
|
|
573
|
+
action=""
|
|
574
|
+
hasDivider={false}
|
|
575
|
+
/>
|
|
576
|
+
</VStack>
|
|
577
|
+
</VStack>
|
|
578
|
+
)}
|
|
579
|
+
|
|
580
|
+
{activeNav === "Travel for work" && (
|
|
581
|
+
<VStack gap={6}>
|
|
582
|
+
<VStack gap={4}>
|
|
583
|
+
<Heading level={3}>Travel for work</Heading>
|
|
584
|
+
<Switch
|
|
585
|
+
label="Show night-errand options at checkout"
|
|
586
|
+
description="Adds a night-errand toggle to your account."
|
|
587
|
+
value={workTravel}
|
|
588
|
+
onChange={setWorkTravel}
|
|
589
|
+
labelPosition="start"
|
|
590
|
+
labelSpacing="spread"
|
|
591
|
+
/>
|
|
592
|
+
</VStack>
|
|
593
|
+
</VStack>
|
|
594
|
+
)}
|
|
595
|
+
|
|
596
|
+
{activeNav === "Privacy" && (
|
|
597
|
+
<VStack gap={6}>
|
|
598
|
+
<VStack gap={8}>
|
|
599
|
+
<VStack gap={4}>
|
|
600
|
+
<Heading level={3}>Messages</Heading>
|
|
601
|
+
<Switch
|
|
602
|
+
label="Show people when I've read their messages."
|
|
603
|
+
value={readReceipts}
|
|
604
|
+
onChange={setReadReceipts}
|
|
605
|
+
labelPosition="start"
|
|
606
|
+
labelSpacing="spread"
|
|
607
|
+
/>
|
|
608
|
+
<HStack hAlign="between" vAlign="center">
|
|
609
|
+
<Text type="body" weight="semibold">
|
|
610
|
+
Blocked people
|
|
611
|
+
</Text>
|
|
612
|
+
<Link href={SELF_HASH}>View</Link>
|
|
613
|
+
</HStack>
|
|
614
|
+
</VStack>
|
|
615
|
+
|
|
616
|
+
<VStack gap={4}>
|
|
617
|
+
<Heading level={3}>Listings</Heading>
|
|
618
|
+
<Switch
|
|
619
|
+
label="List my wares in the scrying mirrors"
|
|
620
|
+
description="Turning this on means scrying engines, like Google, will show your wares to seekers."
|
|
621
|
+
value={searchEngines}
|
|
622
|
+
onChange={setSearchEngines}
|
|
623
|
+
labelPosition="start"
|
|
624
|
+
labelSpacing="spread"
|
|
625
|
+
/>
|
|
626
|
+
</VStack>
|
|
627
|
+
|
|
628
|
+
<VStack gap={4}>
|
|
629
|
+
<Heading level={3}>Reviews</Heading>
|
|
630
|
+
<Text type="body" color="secondary">
|
|
631
|
+
Choose what's shared when you write a review.{" "}
|
|
632
|
+
<Link href={SELF_HASH} hasUnderline>
|
|
633
|
+
Learn more
|
|
634
|
+
</Link>
|
|
635
|
+
</Text>
|
|
636
|
+
<VStack gap={4}>
|
|
637
|
+
<Switch
|
|
638
|
+
label="Show my home haunt and country"
|
|
639
|
+
description="Ex: City and country"
|
|
640
|
+
value={showCity}
|
|
641
|
+
onChange={setShowCity}
|
|
642
|
+
labelPosition="start"
|
|
643
|
+
labelSpacing="spread"
|
|
644
|
+
/>
|
|
645
|
+
<Switch
|
|
646
|
+
label="Show my journey type"
|
|
647
|
+
description="Ex: Rested with kin or familiars"
|
|
648
|
+
value={showTripType}
|
|
649
|
+
onChange={setShowTripType}
|
|
650
|
+
labelPosition="start"
|
|
651
|
+
labelSpacing="spread"
|
|
652
|
+
/>
|
|
653
|
+
<Switch
|
|
654
|
+
label="Show my length of stay"
|
|
655
|
+
description="Ex: A few nights, about a week, etc."
|
|
656
|
+
value={showStayLength}
|
|
657
|
+
onChange={setShowStayLength}
|
|
658
|
+
labelPosition="start"
|
|
659
|
+
labelSpacing="spread"
|
|
660
|
+
/>
|
|
661
|
+
<Switch
|
|
662
|
+
label="Show my booked revels"
|
|
663
|
+
description="Ex: Midnight feasts and tasting rituals"
|
|
664
|
+
value={showServices}
|
|
665
|
+
onChange={setShowServices}
|
|
666
|
+
labelPosition="start"
|
|
667
|
+
labelSpacing="spread"
|
|
668
|
+
/>
|
|
669
|
+
</VStack>
|
|
670
|
+
</VStack>
|
|
671
|
+
|
|
672
|
+
<VStack gap={4}>
|
|
673
|
+
<Heading level={3}>Data privacy</Heading>
|
|
674
|
+
<Card>
|
|
675
|
+
<HStack hAlign="between" vAlign="center">
|
|
676
|
+
<Text type="body">Request my personal data</Text>
|
|
677
|
+
{/* A request is submitted in place, so it acts. */}
|
|
678
|
+
<Button label="Request" variant="secondary" size="sm" />
|
|
679
|
+
</HStack>
|
|
680
|
+
</Card>
|
|
681
|
+
<Switch
|
|
682
|
+
label="Help improve AI-powered features"
|
|
683
|
+
description="When this is on, we use your data to develop and improve AI models."
|
|
684
|
+
value={aiFeatures}
|
|
685
|
+
onChange={setAiFeatures}
|
|
686
|
+
labelPosition="start"
|
|
687
|
+
labelSpacing="spread"
|
|
688
|
+
/>
|
|
689
|
+
<Card>
|
|
690
|
+
<HStack hAlign="between" vAlign="center">
|
|
691
|
+
<Text type="body">Delete my account</Text>
|
|
692
|
+
<Button label="Delete" variant="destructive" size="sm" />
|
|
693
|
+
</HStack>
|
|
694
|
+
</Card>
|
|
695
|
+
<Card variant="muted">
|
|
696
|
+
<HStack gap={4} vAlign="start">
|
|
697
|
+
<Center width={48} height={48} style={iconBox}>
|
|
698
|
+
<Icon icon={ShieldCheck} />
|
|
699
|
+
</Center>
|
|
700
|
+
<VStack gap={1}>
|
|
701
|
+
<Text type="body">Committed to privacy</Text>
|
|
702
|
+
<Text type="body" color="secondary">
|
|
703
|
+
We're committed to keeping your data protected. See details
|
|
704
|
+
in our{" "}
|
|
705
|
+
<Link href={SELF_HASH} hasUnderline>
|
|
706
|
+
Privacy Policy
|
|
707
|
+
</Link>
|
|
708
|
+
.
|
|
709
|
+
</Text>
|
|
710
|
+
</VStack>
|
|
711
|
+
</HStack>
|
|
712
|
+
</Card>
|
|
713
|
+
</VStack>
|
|
714
|
+
</VStack>
|
|
715
|
+
</VStack>
|
|
716
|
+
)}
|
|
717
|
+
</VStack>
|
|
718
|
+
</VStack>
|
|
719
|
+
</LayoutContent>
|
|
720
|
+
}
|
|
721
|
+
/>
|
|
722
|
+
</Dialog>
|
|
723
|
+
</>
|
|
724
|
+
);
|
|
754
725
|
}
|