@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.
- package/.storybook/main.ts +1 -0
- package/.storybook/preview.css +7 -0
- package/.storybook/preview.tsx +56 -0
- package/.turbo/turbo-build.log +2 -0
- package/.turbo/turbo-type$colon$emit.log +1 -0
- package/.turbo/turbo-type.log +1 -0
- package/CHANGELOG.md +111 -0
- package/LICENSE +21 -0
- package/dist/components/auth-guard.d.ts +5 -0
- package/dist/components/auth-guard.d.ts.map +1 -0
- package/dist/components/auth-guard.js +61 -0
- package/dist/components/auth-guard.js.map +1 -0
- package/dist/components/auth-provider.d.ts +11 -0
- package/dist/components/auth-provider.d.ts.map +1 -0
- package/dist/components/auth-provider.js +21 -0
- package/dist/components/auth-provider.js.map +1 -0
- package/dist/components/auth-shell.d.ts +11 -0
- package/dist/components/auth-shell.d.ts.map +1 -0
- package/dist/components/auth-shell.js +63 -0
- package/dist/components/auth-shell.js.map +1 -0
- package/dist/components/redirect-target.d.ts +2 -0
- package/dist/components/redirect-target.d.ts.map +1 -0
- package/dist/components/redirect-target.js +22 -0
- package/dist/components/redirect-target.js.map +1 -0
- package/dist/components/workspace-crumb.d.ts +3 -0
- package/dist/components/workspace-crumb.d.ts.map +1 -0
- package/dist/components/workspace-crumb.js +3 -0
- package/dist/components/workspace-crumb.js.map +1 -0
- package/dist/components/workspace-switcher.d.ts +6 -0
- package/dist/components/workspace-switcher.d.ts.map +1 -0
- package/dist/components/workspace-switcher.js +91 -0
- package/dist/components/workspace-switcher.js.map +1 -0
- package/dist/components/workspace-switcher.stories.d.ts +26 -0
- package/dist/components/workspace-switcher.stories.d.ts.map +1 -0
- package/dist/components/workspace-switcher.stories.js +168 -0
- package/dist/components/workspace-switcher.stories.js.map +1 -0
- package/dist/feature.d.ts +33 -0
- package/dist/feature.d.ts.map +1 -0
- package/dist/feature.js +43 -0
- package/dist/feature.js.map +1 -0
- package/dist/hooks/api/login-auth.d.ts +29 -0
- package/dist/hooks/api/login-auth.d.ts.map +1 -0
- package/dist/hooks/api/login-auth.js +42 -0
- package/dist/hooks/api/login-auth.js.map +1 -0
- package/dist/hooks/api/logout-auth.d.ts +2 -0
- package/dist/hooks/api/logout-auth.d.ts.map +1 -0
- package/dist/hooks/api/logout-auth.js +32 -0
- package/dist/hooks/api/logout-auth.js.map +1 -0
- package/dist/hooks/api/password-reset-auth.d.ts +33 -0
- package/dist/hooks/api/password-reset-auth.d.ts.map +1 -0
- package/dist/hooks/api/password-reset-auth.js +48 -0
- package/dist/hooks/api/password-reset-auth.js.map +1 -0
- package/dist/hooks/api/refresh-auth.d.ts +2 -0
- package/dist/hooks/api/refresh-auth.d.ts.map +1 -0
- package/dist/hooks/api/refresh-auth.js +3 -0
- package/dist/hooks/api/refresh-auth.js.map +1 -0
- package/dist/hooks/api/signup-auth.d.ts +27 -0
- package/dist/hooks/api/signup-auth.d.ts.map +1 -0
- package/dist/hooks/api/signup-auth.js +15 -0
- package/dist/hooks/api/signup-auth.js.map +1 -0
- package/dist/hooks/api/verify-email-auth.d.ts +20 -0
- package/dist/hooks/api/verify-email-auth.d.ts.map +1 -0
- package/dist/hooks/api/verify-email-auth.js +48 -0
- package/dist/hooks/api/verify-email-auth.js.map +1 -0
- package/dist/hooks/api/workspace-auth.d.ts +22 -0
- package/dist/hooks/api/workspace-auth.d.ts.map +1 -0
- package/dist/hooks/api/workspace-auth.js +25 -0
- package/dist/hooks/api/workspace-auth.js.map +1 -0
- package/dist/hooks/index.d.ts +11 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +11 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/use-active-workspace.d.ts +2 -0
- package/dist/hooks/use-active-workspace.d.ts.map +1 -0
- package/dist/hooks/use-active-workspace.js +3 -0
- package/dist/hooks/use-active-workspace.js.map +1 -0
- package/dist/hooks/use-auth-state.d.ts +2 -0
- package/dist/hooks/use-auth-state.d.ts.map +1 -0
- package/dist/hooks/use-auth-state.js +3 -0
- package/dist/hooks/use-auth-state.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/pages/email-verification-resend-model.d.ts +7 -0
- package/dist/pages/email-verification-resend-model.d.ts.map +1 -0
- package/dist/pages/email-verification-resend-model.js +15 -0
- package/dist/pages/email-verification-resend-model.js.map +1 -0
- package/dist/pages/form-errors.d.ts +19 -0
- package/dist/pages/form-errors.d.ts.map +1 -0
- package/dist/pages/form-errors.js +51 -0
- package/dist/pages/form-errors.js.map +1 -0
- package/dist/pages/form-utils.d.ts +2 -0
- package/dist/pages/form-utils.d.ts.map +1 -0
- package/dist/pages/form-utils.js +28 -0
- package/dist/pages/form-utils.js.map +1 -0
- package/dist/pages/invitation-context.d.ts +31 -0
- package/dist/pages/invitation-context.d.ts.map +1 -0
- package/dist/pages/invitation-context.js +50 -0
- package/dist/pages/invitation-context.js.map +1 -0
- package/dist/pages/login-page.d.ts +2 -0
- package/dist/pages/login-page.d.ts.map +1 -0
- package/dist/pages/login-page.js +214 -0
- package/dist/pages/login-page.js.map +1 -0
- package/dist/pages/logout-page.d.ts +2 -0
- package/dist/pages/logout-page.d.ts.map +1 -0
- package/dist/pages/logout-page.js +45 -0
- package/dist/pages/logout-page.js.map +1 -0
- package/dist/pages/password-reset-page.d.ts +2 -0
- package/dist/pages/password-reset-page.d.ts.map +1 -0
- package/dist/pages/password-reset-page.js +265 -0
- package/dist/pages/password-reset-page.js.map +1 -0
- package/dist/pages/signup-page.d.ts +2 -0
- package/dist/pages/signup-page.d.ts.map +1 -0
- package/dist/pages/signup-page.js +384 -0
- package/dist/pages/signup-page.js.map +1 -0
- package/dist/pages/verify-email-page.d.ts +2 -0
- package/dist/pages/verify-email-page.d.ts.map +1 -0
- package/dist/pages/verify-email-page.js +57 -0
- package/dist/pages/verify-email-page.js.map +1 -0
- package/dist/pages/workspace-onboarding-page.d.ts +2 -0
- package/dist/pages/workspace-onboarding-page.d.ts.map +1 -0
- package/dist/pages/workspace-onboarding-page.js +294 -0
- package/dist/pages/workspace-onboarding-page.js.map +1 -0
- package/dist/routes/index.d.ts +10 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +29 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/routes/login.d.ts +5 -0
- package/dist/routes/login.d.ts.map +1 -0
- package/dist/routes/login.js +11 -0
- package/dist/routes/login.js.map +1 -0
- package/dist/routes/logout.d.ts +6 -0
- package/dist/routes/logout.d.ts.map +1 -0
- package/dist/routes/logout.js +7 -0
- package/dist/routes/logout.js.map +1 -0
- package/dist/routes/reset.d.ts +5 -0
- package/dist/routes/reset.d.ts.map +1 -0
- package/dist/routes/reset.js +11 -0
- package/dist/routes/reset.js.map +1 -0
- package/dist/routes/signup.d.ts +5 -0
- package/dist/routes/signup.d.ts.map +1 -0
- package/dist/routes/signup.js +11 -0
- package/dist/routes/signup.js.map +1 -0
- package/dist/routes/verify-email.d.ts +5 -0
- package/dist/routes/verify-email.d.ts.map +1 -0
- package/dist/routes/verify-email.js +11 -0
- package/dist/routes/verify-email.js.map +1 -0
- package/dist/routes/workspace-onboarding.d.ts +13 -0
- package/dist/routes/workspace-onboarding.d.ts.map +1 -0
- package/dist/routes/workspace-onboarding.js +18 -0
- package/dist/routes/workspace-onboarding.js.map +1 -0
- package/dist/state/auth.d.ts +10 -0
- package/dist/state/auth.d.ts.map +1 -0
- package/dist/state/auth.js +9 -0
- package/dist/state/auth.js.map +1 -0
- package/dist/state/last-workspace.d.ts +2 -0
- package/dist/state/last-workspace.d.ts.map +1 -0
- package/dist/state/last-workspace.js +3 -0
- package/dist/state/last-workspace.js.map +1 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -0
- package/package.json +116 -0
- package/src/components/auth-guard.tsx +58 -0
- package/src/components/auth-provider.test.tsx +164 -0
- package/src/components/auth-provider.tsx +24 -0
- package/src/components/auth-shell.tsx +53 -0
- package/src/components/redirect-target.test.ts +60 -0
- package/src/components/redirect-target.ts +21 -0
- package/src/components/workspace-crumb.tsx +2 -0
- package/src/components/workspace-switcher.stories.tsx +169 -0
- package/src/components/workspace-switcher.tsx +76 -0
- package/src/feature.ts +18 -0
- package/src/hooks/api/login-auth.test.ts +45 -0
- package/src/hooks/api/login-auth.ts +41 -0
- package/src/hooks/api/logout-auth.ts +26 -0
- package/src/hooks/api/password-reset-auth.test.ts +68 -0
- package/src/hooks/api/password-reset-auth.ts +51 -0
- package/src/hooks/api/refresh-auth.test.ts +37 -0
- package/src/hooks/api/refresh-auth.ts +5 -0
- package/src/hooks/api/signup-auth.ts +11 -0
- package/src/hooks/api/verify-email-auth.ts +55 -0
- package/src/hooks/api/workspace-auth.test.ts +40 -0
- package/src/hooks/api/workspace-auth.ts +25 -0
- package/src/hooks/index.ts +13 -0
- package/src/hooks/use-active-workspace.ts +1 -0
- package/src/hooks/use-auth-state.ts +1 -0
- package/src/index.ts +18 -0
- package/src/pages/email-verification-resend-model.test.ts +52 -0
- package/src/pages/email-verification-resend-model.ts +21 -0
- package/src/pages/form-errors.test.ts +114 -0
- package/src/pages/form-errors.ts +45 -0
- package/src/pages/form-utils.test.ts +37 -0
- package/src/pages/form-utils.ts +29 -0
- package/src/pages/invitation-context.ts +57 -0
- package/src/pages/login-page.test.tsx +128 -0
- package/src/pages/login-page.tsx +184 -0
- package/src/pages/logout-page.tsx +33 -0
- package/src/pages/password-reset-page.test.tsx +109 -0
- package/src/pages/password-reset-page.tsx +222 -0
- package/src/pages/signup-page.test.tsx +289 -0
- package/src/pages/signup-page.tsx +354 -0
- package/src/pages/verify-email-page.test.tsx +82 -0
- package/src/pages/verify-email-page.tsx +48 -0
- package/src/pages/workspace-onboarding-page.test.tsx +161 -0
- package/src/pages/workspace-onboarding-page.tsx +213 -0
- package/src/routes/index.tsx +18 -0
- package/src/routes/login.tsx +11 -0
- package/src/routes/logout.tsx +4 -0
- package/src/routes/reset.tsx +11 -0
- package/src/routes/signup.tsx +11 -0
- package/src/routes/verify-email.tsx +11 -0
- package/src/routes/workspace-onboarding.tsx +14 -0
- package/src/state/auth.ts +18 -0
- package/src/state/last-workspace.test.ts +63 -0
- package/src/state/last-workspace.ts +5 -0
- package/test/factories/user.ts +17 -0
- package/test/pages.tsx +83 -0
- package/test/setup.ts +3 -0
- package/test/utils.ts +11 -0
- package/tsconfig.build.json +10 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +3 -0
- package/tsconfig.test.json +8 -0
- package/vercel.json +8 -0
- 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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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"}
|