@shipfox/client-auth 0.2.0

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 (225) hide show
  1. package/.storybook/main.ts +1 -0
  2. package/.storybook/preview.css +7 -0
  3. package/.storybook/preview.tsx +56 -0
  4. package/.turbo/turbo-build.log +2 -0
  5. package/.turbo/turbo-type$colon$emit.log +1 -0
  6. package/.turbo/turbo-type.log +1 -0
  7. package/CHANGELOG.md +111 -0
  8. package/LICENSE +21 -0
  9. package/dist/components/auth-guard.d.ts +5 -0
  10. package/dist/components/auth-guard.d.ts.map +1 -0
  11. package/dist/components/auth-guard.js +61 -0
  12. package/dist/components/auth-guard.js.map +1 -0
  13. package/dist/components/auth-provider.d.ts +11 -0
  14. package/dist/components/auth-provider.d.ts.map +1 -0
  15. package/dist/components/auth-provider.js +21 -0
  16. package/dist/components/auth-provider.js.map +1 -0
  17. package/dist/components/auth-shell.d.ts +11 -0
  18. package/dist/components/auth-shell.d.ts.map +1 -0
  19. package/dist/components/auth-shell.js +63 -0
  20. package/dist/components/auth-shell.js.map +1 -0
  21. package/dist/components/redirect-target.d.ts +2 -0
  22. package/dist/components/redirect-target.d.ts.map +1 -0
  23. package/dist/components/redirect-target.js +22 -0
  24. package/dist/components/redirect-target.js.map +1 -0
  25. package/dist/components/workspace-crumb.d.ts +3 -0
  26. package/dist/components/workspace-crumb.d.ts.map +1 -0
  27. package/dist/components/workspace-crumb.js +3 -0
  28. package/dist/components/workspace-crumb.js.map +1 -0
  29. package/dist/components/workspace-switcher.d.ts +6 -0
  30. package/dist/components/workspace-switcher.d.ts.map +1 -0
  31. package/dist/components/workspace-switcher.js +91 -0
  32. package/dist/components/workspace-switcher.js.map +1 -0
  33. package/dist/components/workspace-switcher.stories.d.ts +26 -0
  34. package/dist/components/workspace-switcher.stories.d.ts.map +1 -0
  35. package/dist/components/workspace-switcher.stories.js +168 -0
  36. package/dist/components/workspace-switcher.stories.js.map +1 -0
  37. package/dist/feature.d.ts +33 -0
  38. package/dist/feature.d.ts.map +1 -0
  39. package/dist/feature.js +43 -0
  40. package/dist/feature.js.map +1 -0
  41. package/dist/hooks/api/login-auth.d.ts +29 -0
  42. package/dist/hooks/api/login-auth.d.ts.map +1 -0
  43. package/dist/hooks/api/login-auth.js +42 -0
  44. package/dist/hooks/api/login-auth.js.map +1 -0
  45. package/dist/hooks/api/logout-auth.d.ts +2 -0
  46. package/dist/hooks/api/logout-auth.d.ts.map +1 -0
  47. package/dist/hooks/api/logout-auth.js +32 -0
  48. package/dist/hooks/api/logout-auth.js.map +1 -0
  49. package/dist/hooks/api/password-reset-auth.d.ts +33 -0
  50. package/dist/hooks/api/password-reset-auth.d.ts.map +1 -0
  51. package/dist/hooks/api/password-reset-auth.js +48 -0
  52. package/dist/hooks/api/password-reset-auth.js.map +1 -0
  53. package/dist/hooks/api/refresh-auth.d.ts +2 -0
  54. package/dist/hooks/api/refresh-auth.d.ts.map +1 -0
  55. package/dist/hooks/api/refresh-auth.js +3 -0
  56. package/dist/hooks/api/refresh-auth.js.map +1 -0
  57. package/dist/hooks/api/signup-auth.d.ts +27 -0
  58. package/dist/hooks/api/signup-auth.d.ts.map +1 -0
  59. package/dist/hooks/api/signup-auth.js +15 -0
  60. package/dist/hooks/api/signup-auth.js.map +1 -0
  61. package/dist/hooks/api/verify-email-auth.d.ts +20 -0
  62. package/dist/hooks/api/verify-email-auth.d.ts.map +1 -0
  63. package/dist/hooks/api/verify-email-auth.js +48 -0
  64. package/dist/hooks/api/verify-email-auth.js.map +1 -0
  65. package/dist/hooks/api/workspace-auth.d.ts +22 -0
  66. package/dist/hooks/api/workspace-auth.d.ts.map +1 -0
  67. package/dist/hooks/api/workspace-auth.js +25 -0
  68. package/dist/hooks/api/workspace-auth.js.map +1 -0
  69. package/dist/hooks/index.d.ts +11 -0
  70. package/dist/hooks/index.d.ts.map +1 -0
  71. package/dist/hooks/index.js +11 -0
  72. package/dist/hooks/index.js.map +1 -0
  73. package/dist/hooks/use-active-workspace.d.ts +2 -0
  74. package/dist/hooks/use-active-workspace.d.ts.map +1 -0
  75. package/dist/hooks/use-active-workspace.js +3 -0
  76. package/dist/hooks/use-active-workspace.js.map +1 -0
  77. package/dist/hooks/use-auth-state.d.ts +2 -0
  78. package/dist/hooks/use-auth-state.d.ts.map +1 -0
  79. package/dist/hooks/use-auth-state.js +3 -0
  80. package/dist/hooks/use-auth-state.js.map +1 -0
  81. package/dist/index.d.ts +15 -0
  82. package/dist/index.d.ts.map +1 -0
  83. package/dist/index.js +16 -0
  84. package/dist/index.js.map +1 -0
  85. package/dist/pages/email-verification-resend-model.d.ts +7 -0
  86. package/dist/pages/email-verification-resend-model.d.ts.map +1 -0
  87. package/dist/pages/email-verification-resend-model.js +15 -0
  88. package/dist/pages/email-verification-resend-model.js.map +1 -0
  89. package/dist/pages/form-errors.d.ts +19 -0
  90. package/dist/pages/form-errors.d.ts.map +1 -0
  91. package/dist/pages/form-errors.js +51 -0
  92. package/dist/pages/form-errors.js.map +1 -0
  93. package/dist/pages/form-utils.d.ts +2 -0
  94. package/dist/pages/form-utils.d.ts.map +1 -0
  95. package/dist/pages/form-utils.js +28 -0
  96. package/dist/pages/form-utils.js.map +1 -0
  97. package/dist/pages/invitation-context.d.ts +31 -0
  98. package/dist/pages/invitation-context.d.ts.map +1 -0
  99. package/dist/pages/invitation-context.js +50 -0
  100. package/dist/pages/invitation-context.js.map +1 -0
  101. package/dist/pages/login-page.d.ts +2 -0
  102. package/dist/pages/login-page.d.ts.map +1 -0
  103. package/dist/pages/login-page.js +214 -0
  104. package/dist/pages/login-page.js.map +1 -0
  105. package/dist/pages/logout-page.d.ts +2 -0
  106. package/dist/pages/logout-page.d.ts.map +1 -0
  107. package/dist/pages/logout-page.js +45 -0
  108. package/dist/pages/logout-page.js.map +1 -0
  109. package/dist/pages/password-reset-page.d.ts +2 -0
  110. package/dist/pages/password-reset-page.d.ts.map +1 -0
  111. package/dist/pages/password-reset-page.js +265 -0
  112. package/dist/pages/password-reset-page.js.map +1 -0
  113. package/dist/pages/signup-page.d.ts +2 -0
  114. package/dist/pages/signup-page.d.ts.map +1 -0
  115. package/dist/pages/signup-page.js +384 -0
  116. package/dist/pages/signup-page.js.map +1 -0
  117. package/dist/pages/verify-email-page.d.ts +2 -0
  118. package/dist/pages/verify-email-page.d.ts.map +1 -0
  119. package/dist/pages/verify-email-page.js +57 -0
  120. package/dist/pages/verify-email-page.js.map +1 -0
  121. package/dist/pages/workspace-onboarding-page.d.ts +2 -0
  122. package/dist/pages/workspace-onboarding-page.d.ts.map +1 -0
  123. package/dist/pages/workspace-onboarding-page.js +294 -0
  124. package/dist/pages/workspace-onboarding-page.js.map +1 -0
  125. package/dist/routes/index.d.ts +10 -0
  126. package/dist/routes/index.d.ts.map +1 -0
  127. package/dist/routes/index.js +29 -0
  128. package/dist/routes/index.js.map +1 -0
  129. package/dist/routes/login.d.ts +5 -0
  130. package/dist/routes/login.d.ts.map +1 -0
  131. package/dist/routes/login.js +11 -0
  132. package/dist/routes/login.js.map +1 -0
  133. package/dist/routes/logout.d.ts +6 -0
  134. package/dist/routes/logout.d.ts.map +1 -0
  135. package/dist/routes/logout.js +7 -0
  136. package/dist/routes/logout.js.map +1 -0
  137. package/dist/routes/reset.d.ts +5 -0
  138. package/dist/routes/reset.d.ts.map +1 -0
  139. package/dist/routes/reset.js +11 -0
  140. package/dist/routes/reset.js.map +1 -0
  141. package/dist/routes/signup.d.ts +5 -0
  142. package/dist/routes/signup.d.ts.map +1 -0
  143. package/dist/routes/signup.js +11 -0
  144. package/dist/routes/signup.js.map +1 -0
  145. package/dist/routes/verify-email.d.ts +5 -0
  146. package/dist/routes/verify-email.d.ts.map +1 -0
  147. package/dist/routes/verify-email.js +11 -0
  148. package/dist/routes/verify-email.js.map +1 -0
  149. package/dist/routes/workspace-onboarding.d.ts +13 -0
  150. package/dist/routes/workspace-onboarding.d.ts.map +1 -0
  151. package/dist/routes/workspace-onboarding.js +18 -0
  152. package/dist/routes/workspace-onboarding.js.map +1 -0
  153. package/dist/state/auth.d.ts +10 -0
  154. package/dist/state/auth.d.ts.map +1 -0
  155. package/dist/state/auth.js +9 -0
  156. package/dist/state/auth.js.map +1 -0
  157. package/dist/state/last-workspace.d.ts +2 -0
  158. package/dist/state/last-workspace.d.ts.map +1 -0
  159. package/dist/state/last-workspace.js +3 -0
  160. package/dist/state/last-workspace.js.map +1 -0
  161. package/dist/tsconfig.test.tsbuildinfo +1 -0
  162. package/package.json +116 -0
  163. package/src/components/auth-guard.tsx +58 -0
  164. package/src/components/auth-provider.test.tsx +164 -0
  165. package/src/components/auth-provider.tsx +24 -0
  166. package/src/components/auth-shell.tsx +53 -0
  167. package/src/components/redirect-target.test.ts +60 -0
  168. package/src/components/redirect-target.ts +21 -0
  169. package/src/components/workspace-crumb.tsx +2 -0
  170. package/src/components/workspace-switcher.stories.tsx +169 -0
  171. package/src/components/workspace-switcher.tsx +76 -0
  172. package/src/feature.ts +18 -0
  173. package/src/hooks/api/login-auth.test.ts +45 -0
  174. package/src/hooks/api/login-auth.ts +41 -0
  175. package/src/hooks/api/logout-auth.ts +26 -0
  176. package/src/hooks/api/password-reset-auth.test.ts +68 -0
  177. package/src/hooks/api/password-reset-auth.ts +51 -0
  178. package/src/hooks/api/refresh-auth.test.ts +37 -0
  179. package/src/hooks/api/refresh-auth.ts +5 -0
  180. package/src/hooks/api/signup-auth.ts +11 -0
  181. package/src/hooks/api/verify-email-auth.ts +55 -0
  182. package/src/hooks/api/workspace-auth.test.ts +40 -0
  183. package/src/hooks/api/workspace-auth.ts +25 -0
  184. package/src/hooks/index.ts +13 -0
  185. package/src/hooks/use-active-workspace.ts +1 -0
  186. package/src/hooks/use-auth-state.ts +1 -0
  187. package/src/index.ts +18 -0
  188. package/src/pages/email-verification-resend-model.test.ts +52 -0
  189. package/src/pages/email-verification-resend-model.ts +21 -0
  190. package/src/pages/form-errors.test.ts +114 -0
  191. package/src/pages/form-errors.ts +45 -0
  192. package/src/pages/form-utils.test.ts +37 -0
  193. package/src/pages/form-utils.ts +29 -0
  194. package/src/pages/invitation-context.ts +57 -0
  195. package/src/pages/login-page.test.tsx +128 -0
  196. package/src/pages/login-page.tsx +184 -0
  197. package/src/pages/logout-page.tsx +33 -0
  198. package/src/pages/password-reset-page.test.tsx +109 -0
  199. package/src/pages/password-reset-page.tsx +222 -0
  200. package/src/pages/signup-page.test.tsx +289 -0
  201. package/src/pages/signup-page.tsx +354 -0
  202. package/src/pages/verify-email-page.test.tsx +82 -0
  203. package/src/pages/verify-email-page.tsx +48 -0
  204. package/src/pages/workspace-onboarding-page.test.tsx +161 -0
  205. package/src/pages/workspace-onboarding-page.tsx +213 -0
  206. package/src/routes/index.tsx +18 -0
  207. package/src/routes/login.tsx +11 -0
  208. package/src/routes/logout.tsx +4 -0
  209. package/src/routes/reset.tsx +11 -0
  210. package/src/routes/signup.tsx +11 -0
  211. package/src/routes/verify-email.tsx +11 -0
  212. package/src/routes/workspace-onboarding.tsx +14 -0
  213. package/src/state/auth.ts +18 -0
  214. package/src/state/last-workspace.test.ts +63 -0
  215. package/src/state/last-workspace.ts +5 -0
  216. package/test/factories/user.ts +17 -0
  217. package/test/pages.tsx +83 -0
  218. package/test/setup.ts +3 -0
  219. package/test/utils.ts +11 -0
  220. package/tsconfig.build.json +10 -0
  221. package/tsconfig.build.tsbuildinfo +1 -0
  222. package/tsconfig.json +3 -0
  223. package/tsconfig.test.json +8 -0
  224. package/vercel.json +8 -0
  225. package/vitest.config.ts +71 -0
@@ -0,0 +1,294 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createWorkspaceBodySchema } from '@shipfox/api-workspaces-dto';
3
+ import { displayNameFieldError } from '@shipfox/client-ui';
4
+ import { Button } from '@shipfox/react-ui/button';
5
+ import { Callout } from '@shipfox/react-ui/callout';
6
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@shipfox/react-ui/card';
7
+ import { FormField, FormFieldInput, fieldError } from '@shipfox/react-ui/form-field';
8
+ import { Icon } from '@shipfox/react-ui/icon';
9
+ import { toast } from '@shipfox/react-ui/toast';
10
+ import { Text } from '@shipfox/react-ui/typography';
11
+ import { useForm } from '@tanstack/react-form';
12
+ import { useNavigate } from '@tanstack/react-router';
13
+ import { useSetAtom } from 'jotai';
14
+ import { useState } from 'react';
15
+ import { useCreateWorkspaceAuth } from '#hooks/api/workspace-auth.js';
16
+ import { lastWorkspaceIdAtom } from '#state/last-workspace.js';
17
+ import { workspaceOnboardingErrorToFormError } from './form-errors.js';
18
+ const previewMetrics = [
19
+ {
20
+ label: 'Runs',
21
+ value: '--'
22
+ },
23
+ {
24
+ label: 'Passed',
25
+ value: '--'
26
+ },
27
+ {
28
+ label: 'Failed',
29
+ value: '--'
30
+ },
31
+ {
32
+ label: 'Duration',
33
+ value: '--'
34
+ }
35
+ ];
36
+ const previewBars = [
37
+ {
38
+ id: 'runs-start',
39
+ height: 32
40
+ },
41
+ {
42
+ id: 'runs-mid-low',
43
+ height: 48
44
+ },
45
+ {
46
+ id: 'runs-dip',
47
+ height: 28
48
+ },
49
+ {
50
+ id: 'runs-mid-high',
51
+ height: 66
52
+ },
53
+ {
54
+ id: 'runs-mid',
55
+ height: 54
56
+ },
57
+ {
58
+ id: 'runs-peak',
59
+ height: 82
60
+ },
61
+ {
62
+ id: 'runs-late-low',
63
+ height: 44
64
+ },
65
+ {
66
+ id: 'runs-late-high',
67
+ height: 74
68
+ }
69
+ ];
70
+ export function WorkspaceOnboardingPage() {
71
+ const createWorkspace = useCreateWorkspaceAuth();
72
+ const navigate = useNavigate();
73
+ const setLastWorkspaceId = useSetAtom(lastWorkspaceIdAtom);
74
+ const [formError, setFormError] = useState();
75
+ const form = useForm({
76
+ defaultValues: {
77
+ name: ''
78
+ },
79
+ onSubmit: async ({ value })=>{
80
+ setFormError(undefined);
81
+ try {
82
+ const body = createWorkspaceBodySchema.parse({
83
+ name: value.name
84
+ });
85
+ const created = await createWorkspace.mutateAsync(body);
86
+ toast.success('Workspace created.');
87
+ // Pin the new workspace as the last-active one so a page refresh and
88
+ // future visits to `/` land on it.
89
+ try {
90
+ setLastWorkspaceId(created.id);
91
+ } catch {
92
+ // localStorage may throw in private browsing or quota-exceeded.
93
+ }
94
+ await navigate({
95
+ to: '/workspaces/$wid',
96
+ params: {
97
+ wid: created.id
98
+ }
99
+ });
100
+ } catch (error) {
101
+ const mapped = workspaceOnboardingErrorToFormError(error);
102
+ setFormError(mapped.message);
103
+ }
104
+ }
105
+ });
106
+ return /*#__PURE__*/ _jsx("main", {
107
+ className: "min-h-screen bg-background-subtle-base px-24 py-32 max-[520px]:px-16",
108
+ children: /*#__PURE__*/ _jsxs("div", {
109
+ className: "mx-auto flex min-h-[calc(100vh-64px)] w-full max-w-[1120px] flex-col gap-24",
110
+ children: [
111
+ /*#__PURE__*/ _jsx("header", {
112
+ className: "flex items-center justify-between",
113
+ children: /*#__PURE__*/ _jsxs("div", {
114
+ className: "flex items-center gap-10",
115
+ children: [
116
+ /*#__PURE__*/ _jsx("div", {
117
+ className: "flex size-36 items-center justify-center rounded-8 border border-border-neutral-base bg-background-neutral-base shadow-button-neutral",
118
+ children: /*#__PURE__*/ _jsx(Icon, {
119
+ name: "shipfox",
120
+ className: "size-24 text-background-highlight-interactive"
121
+ })
122
+ }),
123
+ /*#__PURE__*/ _jsx(Text, {
124
+ size: "md",
125
+ bold: true,
126
+ children: "Shipfox"
127
+ })
128
+ ]
129
+ })
130
+ }),
131
+ /*#__PURE__*/ _jsxs("section", {
132
+ className: "grid flex-1 items-center gap-32 lg:grid-cols-[minmax(0,440px)_minmax(0,1fr)]",
133
+ children: [
134
+ /*#__PURE__*/ _jsx("form", {
135
+ className: "relative z-10 w-full",
136
+ noValidate: true,
137
+ "aria-labelledby": "workspace-onboarding-title",
138
+ onSubmit: (event)=>{
139
+ event.preventDefault();
140
+ event.stopPropagation();
141
+ void form.handleSubmit();
142
+ },
143
+ children: /*#__PURE__*/ _jsxs(Card, {
144
+ className: "gap-20 p-24 shadow-button-neutral",
145
+ children: [
146
+ /*#__PURE__*/ _jsxs(CardHeader, {
147
+ className: "gap-8",
148
+ children: [
149
+ /*#__PURE__*/ _jsx(CardTitle, {
150
+ id: "workspace-onboarding-title",
151
+ variant: "h1",
152
+ children: "Create your workspace"
153
+ }),
154
+ /*#__PURE__*/ _jsx(CardDescription, {
155
+ children: "Give your team a place to collaborate."
156
+ })
157
+ ]
158
+ }),
159
+ formError ? /*#__PURE__*/ _jsx(Callout, {
160
+ role: "alert",
161
+ type: "error",
162
+ children: formError
163
+ }) : null,
164
+ /*#__PURE__*/ _jsx(CardContent, {
165
+ className: "flex flex-col gap-8",
166
+ children: /*#__PURE__*/ _jsx(form.Field, {
167
+ name: "name",
168
+ validators: {
169
+ onBlur: ({ value })=>displayNameFieldError(value, 'Workspace name', createWorkspaceBodySchema.shape.name),
170
+ onSubmit: ({ value })=>displayNameFieldError(value, 'Workspace name', createWorkspaceBodySchema.shape.name)
171
+ },
172
+ children: (field)=>/*#__PURE__*/ _jsx(FormField, {
173
+ label: "Workspace name",
174
+ id: "workspace-name",
175
+ error: fieldError(field),
176
+ children: /*#__PURE__*/ _jsx(FormFieldInput, {
177
+ autoComplete: "organization",
178
+ name: "name",
179
+ placeholder: "Acme",
180
+ type: "text",
181
+ value: field.state.value,
182
+ onChange: (event)=>field.handleChange(event.target.value),
183
+ onBlur: field.handleBlur
184
+ })
185
+ })
186
+ })
187
+ }),
188
+ /*#__PURE__*/ _jsx(Button, {
189
+ className: "w-full",
190
+ iconRight: "chevronRight",
191
+ isLoading: createWorkspace.isPending,
192
+ type: "submit",
193
+ children: createWorkspace.isPending ? 'Creating workspace...' : 'Create workspace'
194
+ })
195
+ ]
196
+ })
197
+ }),
198
+ /*#__PURE__*/ _jsxs("div", {
199
+ className: "hidden flex-col gap-18 lg:flex",
200
+ "aria-hidden": "true",
201
+ children: [
202
+ /*#__PURE__*/ _jsx("div", {
203
+ className: "grid grid-cols-4 gap-12",
204
+ children: previewMetrics.map((metric)=>/*#__PURE__*/ _jsxs("div", {
205
+ className: "rounded-8 border border-border-neutral-base bg-background-neutral-base p-14 shadow-button-neutral",
206
+ children: [
207
+ /*#__PURE__*/ _jsx(Text, {
208
+ size: "xs",
209
+ className: "text-foreground-neutral-muted",
210
+ children: metric.label
211
+ }),
212
+ /*#__PURE__*/ _jsx(Text, {
213
+ size: "xl",
214
+ bold: true,
215
+ children: metric.value
216
+ })
217
+ ]
218
+ }, metric.label))
219
+ }),
220
+ /*#__PURE__*/ _jsxs("div", {
221
+ className: "grid grid-cols-2 gap-18",
222
+ children: [
223
+ /*#__PURE__*/ _jsx(PreviewPanel, {
224
+ title: "Performance over time"
225
+ }),
226
+ /*#__PURE__*/ _jsx(PreviewPanel, {
227
+ title: "Duration distribution",
228
+ bars: true
229
+ })
230
+ ]
231
+ }),
232
+ /*#__PURE__*/ _jsxs("div", {
233
+ className: "rounded-8 border border-border-neutral-base bg-background-neutral-base p-16 shadow-button-neutral",
234
+ children: [
235
+ /*#__PURE__*/ _jsx(Text, {
236
+ size: "sm",
237
+ bold: true,
238
+ children: "Jobs breakdown"
239
+ }),
240
+ /*#__PURE__*/ _jsx("div", {
241
+ className: "mt-14 flex flex-col gap-10",
242
+ children: [
243
+ 0,
244
+ 1,
245
+ 2,
246
+ 3
247
+ ].map((row)=>/*#__PURE__*/ _jsxs("div", {
248
+ className: "grid grid-cols-[1fr_80px_80px] gap-12 border-t border-border-neutral-base pt-10",
249
+ children: [
250
+ /*#__PURE__*/ _jsx("div", {
251
+ className: "h-12 rounded-full bg-background-neutral-disabled"
252
+ }),
253
+ /*#__PURE__*/ _jsx("div", {
254
+ className: "h-12 rounded-full bg-background-neutral-disabled"
255
+ }),
256
+ /*#__PURE__*/ _jsx("div", {
257
+ className: "h-12 rounded-full bg-background-neutral-disabled"
258
+ })
259
+ ]
260
+ }, row))
261
+ })
262
+ ]
263
+ })
264
+ ]
265
+ })
266
+ ]
267
+ })
268
+ ]
269
+ })
270
+ });
271
+ }
272
+ function PreviewPanel({ title, bars = false }) {
273
+ return /*#__PURE__*/ _jsxs("div", {
274
+ className: "rounded-8 border border-border-neutral-base bg-background-neutral-base p-16 shadow-button-neutral",
275
+ children: [
276
+ /*#__PURE__*/ _jsx(Text, {
277
+ size: "sm",
278
+ bold: true,
279
+ children: title
280
+ }),
281
+ /*#__PURE__*/ _jsx("div", {
282
+ className: "mt-16 flex h-[220px] items-end gap-8 border-b border-l border-border-neutral-base px-12 pb-10",
283
+ children: previewBars.map((bar)=>/*#__PURE__*/ _jsx("div", {
284
+ className: bars ? 'w-full rounded-t-4 bg-background-neutral-disabled' : 'w-full rounded-full bg-background-neutral-disabled',
285
+ style: {
286
+ height: `${bar.height}%`
287
+ }
288
+ }, `${title}-${bar.id}`))
289
+ })
290
+ ]
291
+ });
292
+ }
293
+
294
+ //# sourceMappingURL=workspace-onboarding-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/pages/workspace-onboarding-page.tsx"],"sourcesContent":["import {createWorkspaceBodySchema} from '@shipfox/api-workspaces-dto';\nimport {displayNameFieldError} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {Card, CardContent, CardDescription, CardHeader, CardTitle} from '@shipfox/react-ui/card';\nimport {FormField, FormFieldInput, fieldError} from '@shipfox/react-ui/form-field';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {useForm} from '@tanstack/react-form';\nimport {useNavigate} from '@tanstack/react-router';\nimport {useSetAtom} from 'jotai';\nimport {useState} from 'react';\nimport {useCreateWorkspaceAuth} from '#hooks/api/workspace-auth.js';\nimport {lastWorkspaceIdAtom} from '#state/last-workspace.js';\nimport {workspaceOnboardingErrorToFormError} from './form-errors.js';\n\nconst previewMetrics = [\n {label: 'Runs', value: '--'},\n {label: 'Passed', value: '--'},\n {label: 'Failed', value: '--'},\n {label: 'Duration', value: '--'},\n];\nconst previewBars = [\n {id: 'runs-start', height: 32},\n {id: 'runs-mid-low', height: 48},\n {id: 'runs-dip', height: 28},\n {id: 'runs-mid-high', height: 66},\n {id: 'runs-mid', height: 54},\n {id: 'runs-peak', height: 82},\n {id: 'runs-late-low', height: 44},\n {id: 'runs-late-high', height: 74},\n];\n\nexport function WorkspaceOnboardingPage() {\n const createWorkspace = useCreateWorkspaceAuth();\n const navigate = useNavigate();\n const setLastWorkspaceId = useSetAtom(lastWorkspaceIdAtom);\n const [formError, setFormError] = useState<string | undefined>();\n\n const form = useForm({\n defaultValues: {name: ''},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n const body = createWorkspaceBodySchema.parse({name: value.name});\n const created = await createWorkspace.mutateAsync(body);\n toast.success('Workspace created.');\n // Pin the new workspace as the last-active one so a page refresh and\n // future visits to `/` land on it.\n try {\n setLastWorkspaceId(created.id);\n } catch {\n // localStorage may throw in private browsing or quota-exceeded.\n }\n await navigate({to: '/workspaces/$wid', params: {wid: created.id}});\n } catch (error) {\n const mapped = workspaceOnboardingErrorToFormError(error);\n setFormError(mapped.message);\n }\n },\n });\n\n return (\n <main className=\"min-h-screen bg-background-subtle-base px-24 py-32 max-[520px]:px-16\">\n <div className=\"mx-auto flex min-h-[calc(100vh-64px)] w-full max-w-[1120px] flex-col gap-24\">\n <header className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-10\">\n <div className=\"flex size-36 items-center justify-center rounded-8 border border-border-neutral-base bg-background-neutral-base shadow-button-neutral\">\n <Icon name=\"shipfox\" className=\"size-24 text-background-highlight-interactive\" />\n </div>\n <Text size=\"md\" bold>\n Shipfox\n </Text>\n </div>\n </header>\n\n <section className=\"grid flex-1 items-center gap-32 lg:grid-cols-[minmax(0,440px)_minmax(0,1fr)]\">\n <form\n className=\"relative z-10 w-full\"\n noValidate\n aria-labelledby=\"workspace-onboarding-title\"\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n <Card className=\"gap-20 p-24 shadow-button-neutral\">\n <CardHeader className=\"gap-8\">\n <CardTitle id=\"workspace-onboarding-title\" variant=\"h1\">\n Create your workspace\n </CardTitle>\n <CardDescription>Give your team a place to collaborate.</CardDescription>\n </CardHeader>\n\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n {formError}\n </Callout>\n ) : null}\n\n <CardContent className=\"flex flex-col gap-8\">\n <form.Field\n name=\"name\"\n validators={{\n onBlur: ({value}) =>\n displayNameFieldError(\n value,\n 'Workspace name',\n createWorkspaceBodySchema.shape.name,\n ),\n onSubmit: ({value}) =>\n displayNameFieldError(\n value,\n 'Workspace name',\n createWorkspaceBodySchema.shape.name,\n ),\n }}\n >\n {(field) => (\n <FormField label=\"Workspace name\" id=\"workspace-name\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"organization\"\n name=\"name\"\n placeholder=\"Acme\"\n type=\"text\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={field.handleBlur}\n />\n </FormField>\n )}\n </form.Field>\n </CardContent>\n\n <Button\n className=\"w-full\"\n iconRight=\"chevronRight\"\n isLoading={createWorkspace.isPending}\n type=\"submit\"\n >\n {createWorkspace.isPending ? 'Creating workspace...' : 'Create workspace'}\n </Button>\n </Card>\n </form>\n\n <div className=\"hidden flex-col gap-18 lg:flex\" aria-hidden=\"true\">\n <div className=\"grid grid-cols-4 gap-12\">\n {previewMetrics.map((metric) => (\n <div\n className=\"rounded-8 border border-border-neutral-base bg-background-neutral-base p-14 shadow-button-neutral\"\n key={metric.label}\n >\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n {metric.label}\n </Text>\n <Text size=\"xl\" bold>\n {metric.value}\n </Text>\n </div>\n ))}\n </div>\n <div className=\"grid grid-cols-2 gap-18\">\n <PreviewPanel title=\"Performance over time\" />\n <PreviewPanel title=\"Duration distribution\" bars />\n </div>\n <div className=\"rounded-8 border border-border-neutral-base bg-background-neutral-base p-16 shadow-button-neutral\">\n <Text size=\"sm\" bold>\n Jobs breakdown\n </Text>\n <div className=\"mt-14 flex flex-col gap-10\">\n {[0, 1, 2, 3].map((row) => (\n <div\n className=\"grid grid-cols-[1fr_80px_80px] gap-12 border-t border-border-neutral-base pt-10\"\n key={row}\n >\n <div className=\"h-12 rounded-full bg-background-neutral-disabled\" />\n <div className=\"h-12 rounded-full bg-background-neutral-disabled\" />\n <div className=\"h-12 rounded-full bg-background-neutral-disabled\" />\n </div>\n ))}\n </div>\n </div>\n </div>\n </section>\n </div>\n </main>\n );\n}\n\nfunction PreviewPanel({title, bars = false}: {title: string; bars?: boolean}) {\n return (\n <div className=\"rounded-8 border border-border-neutral-base bg-background-neutral-base p-16 shadow-button-neutral\">\n <Text size=\"sm\" bold>\n {title}\n </Text>\n <div className=\"mt-16 flex h-[220px] items-end gap-8 border-b border-l border-border-neutral-base px-12 pb-10\">\n {previewBars.map((bar) => (\n <div\n className={\n bars\n ? 'w-full rounded-t-4 bg-background-neutral-disabled'\n : 'w-full rounded-full bg-background-neutral-disabled'\n }\n key={`${title}-${bar.id}`}\n style={{height: `${bar.height}%`}}\n />\n ))}\n </div>\n </div>\n );\n}\n"],"names":["createWorkspaceBodySchema","displayNameFieldError","Button","Callout","Card","CardContent","CardDescription","CardHeader","CardTitle","FormField","FormFieldInput","fieldError","Icon","toast","Text","useForm","useNavigate","useSetAtom","useState","useCreateWorkspaceAuth","lastWorkspaceIdAtom","workspaceOnboardingErrorToFormError","previewMetrics","label","value","previewBars","id","height","WorkspaceOnboardingPage","createWorkspace","navigate","setLastWorkspaceId","formError","setFormError","form","defaultValues","name","onSubmit","undefined","body","parse","created","mutateAsync","success","to","params","wid","error","mapped","message","main","className","div","header","size","bold","section","noValidate","aria-labelledby","event","preventDefault","stopPropagation","handleSubmit","variant","role","type","Field","validators","onBlur","shape","field","autoComplete","placeholder","state","onChange","handleChange","target","handleBlur","iconRight","isLoading","isPending","aria-hidden","map","metric","PreviewPanel","title","bars","row","bar","style"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { RouterContext } from '@shipfox/client-shell/runtime';
2
+ import { FullPageLoader } from '@shipfox/react-ui/loader';
3
+ declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
4
+ readonly beforeLoad: ({ context }: {
5
+ context: RouterContext;
6
+ }) => void;
7
+ readonly component: typeof FullPageLoader;
8
+ }>;
9
+ export default _default;
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routes/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,+BAA+B,CAAC;AAEjE,OAAO,EAAC,cAAc,EAAC,MAAM,0BAA0B,CAAC;;uCAI9B;QAAC,OAAO,EAAE,aAAa,CAAA;KAAC;;;AADlD,wBAYG"}
@@ -0,0 +1,29 @@
1
+ import { defineRoute, getLastWorkspaceId } from '@shipfox/client-shell/runtime';
2
+ import { FullPageLoader } from '@shipfox/react-ui/loader';
3
+ import { redirect } from '@tanstack/react-router';
4
+ export default defineRoute({
5
+ beforeLoad: ({ context })=>{
6
+ const auth = context.auth;
7
+ if (!auth || auth.isLoading) return;
8
+ if (!auth.isAuthenticated) throw redirect({
9
+ to: '/auth/login'
10
+ });
11
+ const [first, ...rest] = auth.workspaces;
12
+ if (!first) throw redirect({
13
+ to: '/setup/workspaces/new'
14
+ });
15
+ const target = [
16
+ first,
17
+ ...rest
18
+ ].find((workspace)=>workspace.id === getLastWorkspaceId()) ?? first;
19
+ throw redirect({
20
+ to: '/workspaces/$wid',
21
+ params: {
22
+ wid: target.id
23
+ }
24
+ });
25
+ },
26
+ component: FullPageLoader
27
+ });
28
+
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/routes/index.tsx"],"sourcesContent":["import type {RouterContext} from '@shipfox/client-shell/runtime';\nimport {defineRoute, getLastWorkspaceId} from '@shipfox/client-shell/runtime';\nimport {FullPageLoader} from '@shipfox/react-ui/loader';\nimport {redirect} from '@tanstack/react-router';\n\nexport default defineRoute({\n beforeLoad: ({context}: {context: RouterContext}) => {\n const auth = context.auth;\n if (!auth || auth.isLoading) return;\n if (!auth.isAuthenticated) throw redirect({to: '/auth/login'});\n const [first, ...rest] = auth.workspaces;\n if (!first) throw redirect({to: '/setup/workspaces/new'});\n const target =\n [first, ...rest].find((workspace) => workspace.id === getLastWorkspaceId()) ?? first;\n throw redirect({to: '/workspaces/$wid', params: {wid: target.id}});\n },\n component: FullPageLoader,\n});\n"],"names":["defineRoute","getLastWorkspaceId","FullPageLoader","redirect","beforeLoad","context","auth","isLoading","isAuthenticated","to","first","rest","workspaces","target","find","workspace","id","params","wid","component"],"mappings":"AACA,SAAQA,WAAW,EAAEC,kBAAkB,QAAO,gCAAgC;AAC9E,SAAQC,cAAc,QAAO,2BAA2B;AACxD,SAAQC,QAAQ,QAAO,yBAAyB;AAEhD,eAAeH,YAAY;IACzBI,YAAY,CAAC,EAACC,OAAO,EAA2B;QAC9C,MAAMC,OAAOD,QAAQC,IAAI;QACzB,IAAI,CAACA,QAAQA,KAAKC,SAAS,EAAE;QAC7B,IAAI,CAACD,KAAKE,eAAe,EAAE,MAAML,SAAS;YAACM,IAAI;QAAa;QAC5D,MAAM,CAACC,OAAO,GAAGC,KAAK,GAAGL,KAAKM,UAAU;QACxC,IAAI,CAACF,OAAO,MAAMP,SAAS;YAACM,IAAI;QAAuB;QACvD,MAAMI,SACJ;YAACH;eAAUC;SAAK,CAACG,IAAI,CAAC,CAACC,YAAcA,UAAUC,EAAE,KAAKf,yBAAyBS;QACjF,MAAMP,SAAS;YAACM,IAAI;YAAoBQ,QAAQ;gBAACC,KAAKL,OAAOG,EAAE;YAAA;QAAC;IAClE;IACAG,WAAWjB;AACb,GAAG"}
@@ -0,0 +1,5 @@
1
+ declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
2
+ readonly component: () => import("react").JSX.Element;
3
+ }>;
4
+ export default _default;
5
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/routes/login.tsx"],"names":[],"mappings":";;;AAIA,wBAMG"}
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { defineRoute } from '@shipfox/client-shell/runtime';
3
+ import { GuestGuard } from '#components/auth-guard.js';
4
+ import { LoginPage } from '#pages/login-page.js';
5
+ export default defineRoute({
6
+ component: ()=>/*#__PURE__*/ _jsx(GuestGuard, {
7
+ children: /*#__PURE__*/ _jsx(LoginPage, {})
8
+ })
9
+ });
10
+
11
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/routes/login.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {GuestGuard} from '#components/auth-guard.js';\nimport {LoginPage} from '#pages/login-page.js';\n\nexport default defineRoute({\n component: () => (\n <GuestGuard>\n <LoginPage />\n </GuestGuard>\n ),\n});\n"],"names":["defineRoute","GuestGuard","LoginPage","component"],"mappings":";AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,UAAU,QAAO,4BAA4B;AACrD,SAAQC,SAAS,QAAO,uBAAuB;AAE/C,eAAeF,YAAY;IACzBG,WAAW,kBACT,KAACF;sBACC,cAAA,KAACC;;AAGP,GAAG"}
@@ -0,0 +1,6 @@
1
+ import { LogoutPage } from '#pages/logout-page.js';
2
+ declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
3
+ readonly component: typeof LogoutPage;
4
+ }>;
5
+ export default _default;
6
+ //# sourceMappingURL=logout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/routes/logout.tsx"],"names":[],"mappings":"AACA,OAAO,EAAC,UAAU,EAAC,MAAM,uBAAuB,CAAC;;;;AAEjD,wBAAoD"}
@@ -0,0 +1,7 @@
1
+ import { defineRoute } from '@shipfox/client-shell/runtime';
2
+ import { LogoutPage } from '#pages/logout-page.js';
3
+ export default defineRoute({
4
+ component: LogoutPage
5
+ });
6
+
7
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/routes/logout.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {LogoutPage} from '#pages/logout-page.js';\n\nexport default defineRoute({component: LogoutPage});\n"],"names":["defineRoute","LogoutPage","component"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,UAAU,QAAO,wBAAwB;AAEjD,eAAeD,YAAY;IAACE,WAAWD;AAAU,GAAG"}
@@ -0,0 +1,5 @@
1
+ declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
2
+ readonly component: () => import("react").JSX.Element;
3
+ }>;
4
+ export default _default;
5
+ //# sourceMappingURL=reset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reset.d.ts","sourceRoot":"","sources":["../../src/routes/reset.tsx"],"names":[],"mappings":";;;AAIA,wBAMG"}
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { defineRoute } from '@shipfox/client-shell/runtime';
3
+ import { GuestGuard } from '#components/auth-guard.js';
4
+ import { PasswordResetPage } from '#pages/password-reset-page.js';
5
+ export default defineRoute({
6
+ component: ()=>/*#__PURE__*/ _jsx(GuestGuard, {
7
+ children: /*#__PURE__*/ _jsx(PasswordResetPage, {})
8
+ })
9
+ });
10
+
11
+ //# sourceMappingURL=reset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/routes/reset.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {GuestGuard} from '#components/auth-guard.js';\nimport {PasswordResetPage} from '#pages/password-reset-page.js';\n\nexport default defineRoute({\n component: () => (\n <GuestGuard>\n <PasswordResetPage />\n </GuestGuard>\n ),\n});\n"],"names":["defineRoute","GuestGuard","PasswordResetPage","component"],"mappings":";AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,UAAU,QAAO,4BAA4B;AACrD,SAAQC,iBAAiB,QAAO,gCAAgC;AAEhE,eAAeF,YAAY;IACzBG,WAAW,kBACT,KAACF;sBACC,cAAA,KAACC;;AAGP,GAAG"}
@@ -0,0 +1,5 @@
1
+ declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
2
+ readonly component: () => import("react").JSX.Element;
3
+ }>;
4
+ export default _default;
5
+ //# sourceMappingURL=signup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signup.d.ts","sourceRoot":"","sources":["../../src/routes/signup.tsx"],"names":[],"mappings":";;;AAIA,wBAMG"}
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { defineRoute } from '@shipfox/client-shell/runtime';
3
+ import { GuestGuard } from '#components/auth-guard.js';
4
+ import { SignupPage } from '#pages/signup-page.js';
5
+ export default defineRoute({
6
+ component: ()=>/*#__PURE__*/ _jsx(GuestGuard, {
7
+ children: /*#__PURE__*/ _jsx(SignupPage, {})
8
+ })
9
+ });
10
+
11
+ //# sourceMappingURL=signup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/routes/signup.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {GuestGuard} from '#components/auth-guard.js';\nimport {SignupPage} from '#pages/signup-page.js';\n\nexport default defineRoute({\n component: () => (\n <GuestGuard>\n <SignupPage />\n </GuestGuard>\n ),\n});\n"],"names":["defineRoute","GuestGuard","SignupPage","component"],"mappings":";AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,UAAU,QAAO,4BAA4B;AACrD,SAAQC,UAAU,QAAO,wBAAwB;AAEjD,eAAeF,YAAY;IACzBG,WAAW,kBACT,KAACF;sBACC,cAAA,KAACC;;AAGP,GAAG"}
@@ -0,0 +1,5 @@
1
+ declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
2
+ readonly component: () => import("react").JSX.Element;
3
+ }>;
4
+ export default _default;
5
+ //# sourceMappingURL=verify-email.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-email.d.ts","sourceRoot":"","sources":["../../src/routes/verify-email.tsx"],"names":[],"mappings":";;;AAIA,wBAMG"}
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { defineRoute } from '@shipfox/client-shell/runtime';
3
+ import { GuestGuard } from '#components/auth-guard.js';
4
+ import { VerifyEmailPage } from '#pages/verify-email-page.js';
5
+ export default defineRoute({
6
+ component: ()=>/*#__PURE__*/ _jsx(GuestGuard, {
7
+ children: /*#__PURE__*/ _jsx(VerifyEmailPage, {})
8
+ })
9
+ });
10
+
11
+ //# sourceMappingURL=verify-email.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/routes/verify-email.tsx"],"sourcesContent":["import {defineRoute} from '@shipfox/client-shell/runtime';\nimport {GuestGuard} from '#components/auth-guard.js';\nimport {VerifyEmailPage} from '#pages/verify-email-page.js';\n\nexport default defineRoute({\n component: () => (\n <GuestGuard>\n <VerifyEmailPage />\n </GuestGuard>\n ),\n});\n"],"names":["defineRoute","GuestGuard","VerifyEmailPage","component"],"mappings":";AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,UAAU,QAAO,4BAA4B;AACrD,SAAQC,eAAe,QAAO,8BAA8B;AAE5D,eAAeF,YAAY;IACzBG,WAAW,kBACT,KAACF;sBACC,cAAA,KAACC;;AAGP,GAAG"}
@@ -0,0 +1,13 @@
1
+ import type { RouterContext } from '@shipfox/client-shell/runtime';
2
+ import { WorkspaceOnboardingPage } from '#pages/workspace-onboarding-page.js';
3
+ declare const _default: import("@shipfox/client-shell/runtime").RouteImpl<{
4
+ readonly beforeLoad: ({ context, location }: {
5
+ context: RouterContext;
6
+ location: {
7
+ href: string;
8
+ };
9
+ }) => void;
10
+ readonly component: typeof WorkspaceOnboardingPage;
11
+ }>;
12
+ export default _default;
13
+ //# sourceMappingURL=workspace-onboarding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-onboarding.d.ts","sourceRoot":"","sources":["../../src/routes/workspace-onboarding.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,+BAA+B,CAAC;AAGjE,OAAO,EAAC,uBAAuB,EAAC,MAAM,qCAAqC,CAAC;;iDAGxC;QAAC,OAAO,EAAE,aAAa,CAAC;QAAC,QAAQ,EAAE;YAAC,IAAI,EAAE,MAAM,CAAA;SAAC,CAAA;KAAC;;;AADtF,wBAQG"}
@@ -0,0 +1,18 @@
1
+ import { defineRoute } from '@shipfox/client-shell/runtime';
2
+ import { redirect } from '@tanstack/react-router';
3
+ import { WorkspaceOnboardingPage } from '#pages/workspace-onboarding-page.js';
4
+ export default defineRoute({
5
+ beforeLoad: ({ context, location })=>{
6
+ const auth = context.auth;
7
+ if (!auth || auth.isLoading) return;
8
+ if (!auth.isAuthenticated) throw redirect({
9
+ to: '/auth/login',
10
+ search: {
11
+ redirect: location.href
12
+ }
13
+ });
14
+ },
15
+ component: WorkspaceOnboardingPage
16
+ });
17
+
18
+ //# sourceMappingURL=workspace-onboarding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/routes/workspace-onboarding.tsx"],"sourcesContent":["import type {RouterContext} from '@shipfox/client-shell/runtime';\nimport {defineRoute} from '@shipfox/client-shell/runtime';\nimport {redirect} from '@tanstack/react-router';\nimport {WorkspaceOnboardingPage} from '#pages/workspace-onboarding-page.js';\n\nexport default defineRoute({\n beforeLoad: ({context, location}: {context: RouterContext; location: {href: string}}) => {\n const auth = context.auth;\n if (!auth || auth.isLoading) return;\n if (!auth.isAuthenticated)\n throw redirect({to: '/auth/login', search: {redirect: location.href}});\n },\n component: WorkspaceOnboardingPage,\n});\n"],"names":["defineRoute","redirect","WorkspaceOnboardingPage","beforeLoad","context","location","auth","isLoading","isAuthenticated","to","search","href","component"],"mappings":"AACA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,QAAQ,QAAO,yBAAyB;AAChD,SAAQC,uBAAuB,QAAO,sCAAsC;AAE5E,eAAeF,YAAY;IACzBG,YAAY,CAAC,EAACC,OAAO,EAAEC,QAAQ,EAAqD;QAClF,MAAMC,OAAOF,QAAQE,IAAI;QACzB,IAAI,CAACA,QAAQA,KAAKC,SAAS,EAAE;QAC7B,IAAI,CAACD,KAAKE,eAAe,EACvB,MAAMP,SAAS;YAACQ,IAAI;YAAeC,QAAQ;gBAACT,UAAUI,SAASM,IAAI;YAAA;QAAC;IACxE;IACAC,WAAWV;AACb,GAAG"}
@@ -0,0 +1,10 @@
1
+ export { type AuthState, type AuthStatus, authStateAtom, initialAuthState, toAuthenticatedState, type Workspace, } from '@shipfox/client-shell/runtime';
2
+ export interface AuthFormDraft {
3
+ email: string;
4
+ password: string;
5
+ }
6
+ export declare const initialAuthFormDraft: AuthFormDraft;
7
+ export declare const authFormDraftAtom: import("jotai").PrimitiveAtom<AuthFormDraft> & {
8
+ init: AuthFormDraft;
9
+ };
10
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/state/auth.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,KAAK,SAAS,GACf,MAAM,+BAA+B,CAAC;AAEvC,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,oBAAoB,EAAE,aAAyC,CAAC;AAC7E,eAAO,MAAM,iBAAiB;;CAA4C,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { atom } from 'jotai';
2
+ export { authStateAtom, initialAuthState, toAuthenticatedState } from '@shipfox/client-shell/runtime';
3
+ export const initialAuthFormDraft = {
4
+ email: '',
5
+ password: ''
6
+ };
7
+ export const authFormDraftAtom = atom(initialAuthFormDraft);
8
+
9
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/state/auth.ts"],"sourcesContent":["import {atom} from 'jotai';\n\nexport {\n type AuthState,\n type AuthStatus,\n authStateAtom,\n initialAuthState,\n toAuthenticatedState,\n type Workspace,\n} from '@shipfox/client-shell/runtime';\n\nexport interface AuthFormDraft {\n email: string;\n password: string;\n}\n\nexport const initialAuthFormDraft: AuthFormDraft = {email: '', password: ''};\nexport const authFormDraftAtom = atom<AuthFormDraft>(initialAuthFormDraft);\n"],"names":["atom","authStateAtom","initialAuthState","toAuthenticatedState","initialAuthFormDraft","email","password","authFormDraftAtom"],"mappings":"AAAA,SAAQA,IAAI,QAAO,QAAQ;AAE3B,SAGEC,aAAa,EACbC,gBAAgB,EAChBC,oBAAoB,QAEf,gCAAgC;AAOvC,OAAO,MAAMC,uBAAsC;IAACC,OAAO;IAAIC,UAAU;AAAE,EAAE;AAC7E,OAAO,MAAMC,oBAAoBP,KAAoBI,sBAAsB"}
@@ -0,0 +1,2 @@
1
+ export { getLastWorkspaceId, lastWorkspaceIdAtom, rememberLastWorkspaceId, } from '@shipfox/client-shell/runtime';
2
+ //# sourceMappingURL=last-workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"last-workspace.d.ts","sourceRoot":"","sources":["../../src/state/last-workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,+BAA+B,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { getLastWorkspaceId, lastWorkspaceIdAtom, rememberLastWorkspaceId } from '@shipfox/client-shell/runtime';
2
+
3
+ //# sourceMappingURL=last-workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/state/last-workspace.ts"],"sourcesContent":["export {\n getLastWorkspaceId,\n lastWorkspaceIdAtom,\n rememberLastWorkspaceId,\n} from '@shipfox/client-shell/runtime';\n"],"names":["getLastWorkspaceId","lastWorkspaceIdAtom","rememberLastWorkspaceId"],"mappings":"AAAA,SACEA,kBAAkB,EAClBC,mBAAmB,EACnBC,uBAAuB,QAClB,gCAAgC"}