@shipfox/client-auth 6.0.1 → 6.0.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.
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 41 files with swc (135.57ms)
2
+ Successfully compiled: 41 files with swc (106.33ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @shipfox/client-auth
2
2
 
3
+ ## 6.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 102c5f4: Isolates private browser state and React Query data across authenticated principal transitions.
8
+ - Updated dependencies [4b85404]
9
+ - Updated dependencies [102c5f4]
10
+ - @shipfox/api-auth-dto@9.0.2
11
+ - @shipfox/api-workspaces-dto@9.0.2
12
+ - @shipfox/react-ui@0.3.7
13
+ - @shipfox/client-ui@6.0.2
14
+ - @shipfox/client-shell@6.0.2
15
+ - @shipfox/client-invitations@6.0.2
16
+
3
17
  ## 6.0.1
4
18
 
5
19
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-switcher.d.ts","sourceRoot":"","sources":["../../src/components/workspace-switcher.tsx"],"names":[],"mappings":"AAeA,MAAM,WAAW,sBAAsB;IACrC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,wBAAgB,iBAAiB,CAAC,EAAC,iBAAiB,EAAE,QAAQ,EAAC,EAAE,sBAAsB,+BAuDtF"}
1
+ {"version":3,"file":"workspace-switcher.d.ts","sourceRoot":"","sources":["../../src/components/workspace-switcher.tsx"],"names":[],"mappings":"AAeA,MAAM,WAAW,sBAAsB;IACrC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,wBAAgB,iBAAiB,CAAC,EAAC,iBAAiB,EAAE,QAAQ,EAAC,EAAE,sBAAsB,+BAwDtF"}
@@ -4,14 +4,15 @@ import { Icon } from '@shipfox/react-ui/icon';
4
4
  import { useNavigate } from '@tanstack/react-router';
5
5
  import { useSetAtom } from 'jotai';
6
6
  import { useAuthState } from '#hooks/use-auth-state.js';
7
- import { lastWorkspaceIdAtom } from '#state/last-workspace.js';
7
+ import { lastWorkspaceIdAtom, rememberLastWorkspaceId } from '#state/last-workspace.js';
8
8
  export function WorkspaceSwitcher({ activeWorkspaceId, onSelect }) {
9
- const { workspaces } = useAuthState();
9
+ const { user, workspaces } = useAuthState();
10
10
  const navigate = useNavigate();
11
11
  const setLastWorkspaceId = useSetAtom(lastWorkspaceIdAtom);
12
12
  const handleSelect = (workspaceId)=>{
13
13
  try {
14
14
  setLastWorkspaceId(workspaceId);
15
+ if (user?.id) rememberLastWorkspaceId(user.id, workspaceId);
15
16
  } catch {
16
17
  // localStorage may throw in private browsing or quota-exceeded; persistence is best-effort.
17
18
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/workspace-switcher.tsx"],"sourcesContent":["import {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n} from '@shipfox/react-ui/command';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {useNavigate} from '@tanstack/react-router';\nimport {useSetAtom} from 'jotai';\nimport {useAuthState} from '#hooks/use-auth-state.js';\nimport {lastWorkspaceIdAtom} from '#state/last-workspace.js';\n\nexport interface WorkspaceSwitcherProps {\n activeWorkspaceId: string | undefined;\n onSelect?: () => void;\n}\n\nexport function WorkspaceSwitcher({activeWorkspaceId, onSelect}: WorkspaceSwitcherProps) {\n const {workspaces} = useAuthState();\n const navigate = useNavigate();\n const setLastWorkspaceId = useSetAtom(lastWorkspaceIdAtom);\n\n const handleSelect = (workspaceId: string) => {\n try {\n setLastWorkspaceId(workspaceId);\n } catch {\n // localStorage may throw in private browsing or quota-exceeded; persistence is best-effort.\n }\n navigate({to: '/workspaces/$wid', params: {wid: workspaceId}});\n onSelect?.();\n };\n\n const handleCreate = () => {\n navigate({to: '/setup/workspaces/new'});\n onSelect?.();\n };\n\n return (\n <Command>\n <CommandInput placeholder=\"Search workspaces...\" />\n <CommandList className=\"max-h-none overflow-visible overflow-y-visible p-0\">\n <div className=\"max-h-300 overflow-y-auto overflow-x-hidden p-4 scrollbar\">\n <CommandEmpty>No workspaces found.</CommandEmpty>\n <CommandGroup heading=\"Workspaces\">\n {workspaces.map((workspace) => (\n <CommandItem\n key={workspace.id}\n value={workspace.id}\n keywords={[workspace.name]}\n onSelect={() => handleSelect(workspace.id)}\n >\n <Icon\n name=\"check\"\n className={`size-16 mr-8 ${\n activeWorkspaceId === workspace.id ? 'opacity-100' : 'opacity-0'\n }`}\n />\n {workspace.name}\n </CommandItem>\n ))}\n </CommandGroup>\n </div>\n <CommandSeparator alwaysRender className=\"mx-0\" />\n <CommandGroup forceMount className=\"p-4\">\n <CommandItem value=\"__create\" onSelect={handleCreate} forceMount>\n <Icon name=\"addLine\" className=\"size-16\" />\n Create workspace\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n );\n}\n"],"names":["Command","CommandEmpty","CommandGroup","CommandInput","CommandItem","CommandList","CommandSeparator","Icon","useNavigate","useSetAtom","useAuthState","lastWorkspaceIdAtom","WorkspaceSwitcher","activeWorkspaceId","onSelect","workspaces","navigate","setLastWorkspaceId","handleSelect","workspaceId","to","params","wid","handleCreate","placeholder","className","div","heading","map","workspace","value","id","keywords","name","alwaysRender","forceMount"],"mappings":";AAAA,SACEA,OAAO,EACPC,YAAY,EACZC,YAAY,EACZC,YAAY,EACZC,WAAW,EACXC,WAAW,EACXC,gBAAgB,QACX,4BAA4B;AACnC,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,WAAW,QAAO,yBAAyB;AACnD,SAAQC,UAAU,QAAO,QAAQ;AACjC,SAAQC,YAAY,QAAO,2BAA2B;AACtD,SAAQC,mBAAmB,QAAO,2BAA2B;AAO7D,OAAO,SAASC,kBAAkB,EAACC,iBAAiB,EAAEC,QAAQ,EAAyB;IACrF,MAAM,EAACC,UAAU,EAAC,GAAGL;IACrB,MAAMM,WAAWR;IACjB,MAAMS,qBAAqBR,WAAWE;IAEtC,MAAMO,eAAe,CAACC;QACpB,IAAI;YACFF,mBAAmBE;QACrB,EAAE,OAAM;QACN,4FAA4F;QAC9F;QACAH,SAAS;YAACI,IAAI;YAAoBC,QAAQ;gBAACC,KAAKH;YAAW;QAAC;QAC5DL;IACF;IAEA,MAAMS,eAAe;QACnBP,SAAS;YAACI,IAAI;QAAuB;QACrCN;IACF;IAEA,qBACE,MAACd;;0BACC,KAACG;gBAAaqB,aAAY;;0BAC1B,MAACnB;gBAAYoB,WAAU;;kCACrB,MAACC;wBAAID,WAAU;;0CACb,KAACxB;0CAAa;;0CACd,KAACC;gCAAayB,SAAQ;0CACnBZ,WAAWa,GAAG,CAAC,CAACC,0BACf,MAACzB;wCAEC0B,OAAOD,UAAUE,EAAE;wCACnBC,UAAU;4CAACH,UAAUI,IAAI;yCAAC;wCAC1BnB,UAAU,IAAMI,aAAaW,UAAUE,EAAE;;0DAEzC,KAACxB;gDACC0B,MAAK;gDACLR,WAAW,CAAC,aAAa,EACvBZ,sBAAsBgB,UAAUE,EAAE,GAAG,gBAAgB,aACrD;;4CAEHF,UAAUI,IAAI;;uCAXVJ,UAAUE,EAAE;;;;kCAgBzB,KAACzB;wBAAiB4B,YAAY;wBAACT,WAAU;;kCACzC,KAACvB;wBAAaiC,UAAU;wBAACV,WAAU;kCACjC,cAAA,MAACrB;4BAAY0B,OAAM;4BAAWhB,UAAUS;4BAAcY,UAAU;;8CAC9D,KAAC5B;oCAAK0B,MAAK;oCAAUR,WAAU;;gCAAY;;;;;;;;AAOvD"}
1
+ {"version":3,"sources":["../../src/components/workspace-switcher.tsx"],"sourcesContent":["import {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n} from '@shipfox/react-ui/command';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {useNavigate} from '@tanstack/react-router';\nimport {useSetAtom} from 'jotai';\nimport {useAuthState} from '#hooks/use-auth-state.js';\nimport {lastWorkspaceIdAtom, rememberLastWorkspaceId} from '#state/last-workspace.js';\n\nexport interface WorkspaceSwitcherProps {\n activeWorkspaceId: string | undefined;\n onSelect?: () => void;\n}\n\nexport function WorkspaceSwitcher({activeWorkspaceId, onSelect}: WorkspaceSwitcherProps) {\n const {user, workspaces} = useAuthState();\n const navigate = useNavigate();\n const setLastWorkspaceId = useSetAtom(lastWorkspaceIdAtom);\n\n const handleSelect = (workspaceId: string) => {\n try {\n setLastWorkspaceId(workspaceId);\n if (user?.id) rememberLastWorkspaceId(user.id, workspaceId);\n } catch {\n // localStorage may throw in private browsing or quota-exceeded; persistence is best-effort.\n }\n navigate({to: '/workspaces/$wid', params: {wid: workspaceId}});\n onSelect?.();\n };\n\n const handleCreate = () => {\n navigate({to: '/setup/workspaces/new'});\n onSelect?.();\n };\n\n return (\n <Command>\n <CommandInput placeholder=\"Search workspaces...\" />\n <CommandList className=\"max-h-none overflow-visible overflow-y-visible p-0\">\n <div className=\"max-h-300 overflow-y-auto overflow-x-hidden p-4 scrollbar\">\n <CommandEmpty>No workspaces found.</CommandEmpty>\n <CommandGroup heading=\"Workspaces\">\n {workspaces.map((workspace) => (\n <CommandItem\n key={workspace.id}\n value={workspace.id}\n keywords={[workspace.name]}\n onSelect={() => handleSelect(workspace.id)}\n >\n <Icon\n name=\"check\"\n className={`size-16 mr-8 ${\n activeWorkspaceId === workspace.id ? 'opacity-100' : 'opacity-0'\n }`}\n />\n {workspace.name}\n </CommandItem>\n ))}\n </CommandGroup>\n </div>\n <CommandSeparator alwaysRender className=\"mx-0\" />\n <CommandGroup forceMount className=\"p-4\">\n <CommandItem value=\"__create\" onSelect={handleCreate} forceMount>\n <Icon name=\"addLine\" className=\"size-16\" />\n Create workspace\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n );\n}\n"],"names":["Command","CommandEmpty","CommandGroup","CommandInput","CommandItem","CommandList","CommandSeparator","Icon","useNavigate","useSetAtom","useAuthState","lastWorkspaceIdAtom","rememberLastWorkspaceId","WorkspaceSwitcher","activeWorkspaceId","onSelect","user","workspaces","navigate","setLastWorkspaceId","handleSelect","workspaceId","id","to","params","wid","handleCreate","placeholder","className","div","heading","map","workspace","value","keywords","name","alwaysRender","forceMount"],"mappings":";AAAA,SACEA,OAAO,EACPC,YAAY,EACZC,YAAY,EACZC,YAAY,EACZC,WAAW,EACXC,WAAW,EACXC,gBAAgB,QACX,4BAA4B;AACnC,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,WAAW,QAAO,yBAAyB;AACnD,SAAQC,UAAU,QAAO,QAAQ;AACjC,SAAQC,YAAY,QAAO,2BAA2B;AACtD,SAAQC,mBAAmB,EAAEC,uBAAuB,QAAO,2BAA2B;AAOtF,OAAO,SAASC,kBAAkB,EAACC,iBAAiB,EAAEC,QAAQ,EAAyB;IACrF,MAAM,EAACC,IAAI,EAAEC,UAAU,EAAC,GAAGP;IAC3B,MAAMQ,WAAWV;IACjB,MAAMW,qBAAqBV,WAAWE;IAEtC,MAAMS,eAAe,CAACC;QACpB,IAAI;YACFF,mBAAmBE;YACnB,IAAIL,MAAMM,IAAIV,wBAAwBI,KAAKM,EAAE,EAAED;QACjD,EAAE,OAAM;QACN,4FAA4F;QAC9F;QACAH,SAAS;YAACK,IAAI;YAAoBC,QAAQ;gBAACC,KAAKJ;YAAW;QAAC;QAC5DN;IACF;IAEA,MAAMW,eAAe;QACnBR,SAAS;YAACK,IAAI;QAAuB;QACrCR;IACF;IAEA,qBACE,MAACf;;0BACC,KAACG;gBAAawB,aAAY;;0BAC1B,MAACtB;gBAAYuB,WAAU;;kCACrB,MAACC;wBAAID,WAAU;;0CACb,KAAC3B;0CAAa;;0CACd,KAACC;gCAAa4B,SAAQ;0CACnBb,WAAWc,GAAG,CAAC,CAACC,0BACf,MAAC5B;wCAEC6B,OAAOD,UAAUV,EAAE;wCACnBY,UAAU;4CAACF,UAAUG,IAAI;yCAAC;wCAC1BpB,UAAU,IAAMK,aAAaY,UAAUV,EAAE;;0DAEzC,KAACf;gDACC4B,MAAK;gDACLP,WAAW,CAAC,aAAa,EACvBd,sBAAsBkB,UAAUV,EAAE,GAAG,gBAAgB,aACrD;;4CAEHU,UAAUG,IAAI;;uCAXVH,UAAUV,EAAE;;;;kCAgBzB,KAAChB;wBAAiB8B,YAAY;wBAACR,WAAU;;kCACzC,KAAC1B;wBAAamC,UAAU;wBAACT,WAAU;kCACjC,cAAA,MAACxB;4BAAY6B,OAAM;4BAAWlB,UAAUW;4BAAcW,UAAU;;8CAC9D,KAAC9B;oCAAK4B,MAAK;oCAAUP,WAAU;;gCAAY;;;;;;;;AAOvD"}
@@ -14,7 +14,7 @@ export function useLoginAuth() {
14
14
  const { enterAuthenticated } = useAuthTransition();
15
15
  return useMutation({
16
16
  mutationFn: loginAuth,
17
- onSuccess: enterAuthenticated
17
+ onSuccess: (session)=>enterAuthenticated(session)
18
18
  });
19
19
  }
20
20
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/api/login-auth.ts"],"sourcesContent":["import {loginResponseSchema} from '@shipfox/api-auth-dto';\nimport {checkedApiRequest} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport type {LoginCommand} from '#core/auth.js';\nimport {useAuthTransition} from '#state/auth.js';\nimport {toAuthenticatedSession} from './auth-mapper.js';\n\nexport async function loginAuth(command: LoginCommand) {\n const response = await checkedApiRequest(loginResponseSchema, '/auth/login', {\n method: 'POST',\n body: command,\n });\n return toAuthenticatedSession(response);\n}\n\nexport function useLoginAuth() {\n const {enterAuthenticated} = useAuthTransition();\n\n return useMutation({\n mutationFn: loginAuth,\n onSuccess: enterAuthenticated,\n });\n}\n"],"names":["loginResponseSchema","checkedApiRequest","useMutation","useAuthTransition","toAuthenticatedSession","loginAuth","command","response","method","body","useLoginAuth","enterAuthenticated","mutationFn","onSuccess"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,wBAAwB;AAC1D,SAAQC,iBAAiB,QAAO,sBAAsB;AACtD,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,iBAAiB,QAAO,iBAAiB;AACjD,SAAQC,sBAAsB,QAAO,mBAAmB;AAExD,OAAO,eAAeC,UAAUC,OAAqB;IACnD,MAAMC,WAAW,MAAMN,kBAAkBD,qBAAqB,eAAe;QAC3EQ,QAAQ;QACRC,MAAMH;IACR;IACA,OAAOF,uBAAuBG;AAChC;AAEA,OAAO,SAASG;IACd,MAAM,EAACC,kBAAkB,EAAC,GAAGR;IAE7B,OAAOD,YAAY;QACjBU,YAAYP;QACZQ,WAAWF;IACb;AACF"}
1
+ {"version":3,"sources":["../../../src/hooks/api/login-auth.ts"],"sourcesContent":["import {loginResponseSchema} from '@shipfox/api-auth-dto';\nimport {checkedApiRequest} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport type {LoginCommand} from '#core/auth.js';\nimport {useAuthTransition} from '#state/auth.js';\nimport {toAuthenticatedSession} from './auth-mapper.js';\n\nexport async function loginAuth(command: LoginCommand) {\n const response = await checkedApiRequest(loginResponseSchema, '/auth/login', {\n method: 'POST',\n body: command,\n });\n return toAuthenticatedSession(response);\n}\n\nexport function useLoginAuth() {\n const {enterAuthenticated} = useAuthTransition();\n\n return useMutation({\n mutationFn: loginAuth,\n onSuccess: (session) => enterAuthenticated(session),\n });\n}\n"],"names":["loginResponseSchema","checkedApiRequest","useMutation","useAuthTransition","toAuthenticatedSession","loginAuth","command","response","method","body","useLoginAuth","enterAuthenticated","mutationFn","onSuccess","session"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,wBAAwB;AAC1D,SAAQC,iBAAiB,QAAO,sBAAsB;AACtD,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,iBAAiB,QAAO,iBAAiB;AACjD,SAAQC,sBAAsB,QAAO,mBAAmB;AAExD,OAAO,eAAeC,UAAUC,OAAqB;IACnD,MAAMC,WAAW,MAAMN,kBAAkBD,qBAAqB,eAAe;QAC3EQ,QAAQ;QACRC,MAAMH;IACR;IACA,OAAOF,uBAAuBG;AAChC;AAEA,OAAO,SAASG;IACd,MAAM,EAACC,kBAAkB,EAAC,GAAGR;IAE7B,OAAOD,YAAY;QACjBU,YAAYP;QACZQ,WAAW,CAACC,UAAYH,mBAAmBG;IAC7C;AACF"}
@@ -15,7 +15,7 @@ export function useLogoutAuth() {
15
15
  const { enterGuest } = useAuthTransition();
16
16
  return useMutation({
17
17
  mutationFn: logoutAuth,
18
- onSettled: enterGuest
18
+ onSettled: ()=>enterGuest()
19
19
  });
20
20
  }
21
21
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/api/logout-auth.ts"],"sourcesContent":["import {checkedApiRequest, emptyResponseSchema} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport {useAuthTransition} from '#state/auth.js';\n\nasync function logoutAuth() {\n try {\n await checkedApiRequest(emptyResponseSchema, '/auth/logout', {method: 'POST', body: {}});\n } catch {\n // Logout is best-effort: local session state must clear even if the API is offline.\n }\n}\n\nexport function useLogoutAuth() {\n const {enterGuest} = useAuthTransition();\n\n return useMutation({\n mutationFn: logoutAuth,\n onSettled: enterGuest,\n });\n}\n"],"names":["checkedApiRequest","emptyResponseSchema","useMutation","useAuthTransition","logoutAuth","method","body","useLogoutAuth","enterGuest","mutationFn","onSettled"],"mappings":"AAAA,SAAQA,iBAAiB,EAAEC,mBAAmB,QAAO,sBAAsB;AAC3E,SAAQC,WAAW,QAAO,wBAAwB;AAClD,SAAQC,iBAAiB,QAAO,iBAAiB;AAEjD,eAAeC;IACb,IAAI;QACF,MAAMJ,kBAAkBC,qBAAqB,gBAAgB;YAACI,QAAQ;YAAQC,MAAM,CAAC;QAAC;IACxF,EAAE,OAAM;IACN,oFAAoF;IACtF;AACF;AAEA,OAAO,SAASC;IACd,MAAM,EAACC,UAAU,EAAC,GAAGL;IAErB,OAAOD,YAAY;QACjBO,YAAYL;QACZM,WAAWF;IACb;AACF"}
1
+ {"version":3,"sources":["../../../src/hooks/api/logout-auth.ts"],"sourcesContent":["import {checkedApiRequest, emptyResponseSchema} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport {useAuthTransition} from '#state/auth.js';\n\nasync function logoutAuth() {\n try {\n await checkedApiRequest(emptyResponseSchema, '/auth/logout', {method: 'POST', body: {}});\n } catch {\n // Logout is best-effort: local session state must clear even if the API is offline.\n }\n}\n\nexport function useLogoutAuth() {\n const {enterGuest} = useAuthTransition();\n\n return useMutation({\n mutationFn: logoutAuth,\n onSettled: () => enterGuest(),\n });\n}\n"],"names":["checkedApiRequest","emptyResponseSchema","useMutation","useAuthTransition","logoutAuth","method","body","useLogoutAuth","enterGuest","mutationFn","onSettled"],"mappings":"AAAA,SAAQA,iBAAiB,EAAEC,mBAAmB,QAAO,sBAAsB;AAC3E,SAAQC,WAAW,QAAO,wBAAwB;AAClD,SAAQC,iBAAiB,QAAO,iBAAiB;AAEjD,eAAeC;IACb,IAAI;QACF,MAAMJ,kBAAkBC,qBAAqB,gBAAgB;YAACI,QAAQ;YAAQC,MAAM,CAAC;QAAC;IACxF,EAAE,OAAM;IACN,oFAAoF;IACtF;AACF;AAEA,OAAO,SAASC;IACd,MAAM,EAACC,UAAU,EAAC,GAAGL;IAErB,OAAOD,YAAY;QACjBO,YAAYL;QACZM,WAAW,IAAMF;IACnB;AACF"}
@@ -28,7 +28,7 @@ export function useConfirmPasswordResetAuth() {
28
28
  const { enterAuthenticated } = useAuthTransition();
29
29
  return useMutation({
30
30
  mutationFn: confirmPasswordReset,
31
- onSuccess: enterAuthenticated
31
+ onSuccess: (session)=>enterAuthenticated(session)
32
32
  });
33
33
  }
34
34
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/api/password-reset-auth.ts"],"sourcesContent":["import {passwordResetConfirmResponseSchema} from '@shipfox/api-auth-dto';\nimport {checkedApiRequest, emptyResponseSchema} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport type {PasswordResetConfirmCommand, PasswordResetRequestCommand} from '#core/auth.js';\nimport {useAuthTransition} from '#state/auth.js';\nimport {toAuthenticatedSession} from './auth-mapper.js';\n\nexport async function requestPasswordReset(command: PasswordResetRequestCommand) {\n await checkedApiRequest(emptyResponseSchema, '/auth/password-reset', {\n method: 'POST',\n body: command,\n });\n}\n\nexport async function confirmPasswordReset(command: PasswordResetConfirmCommand) {\n const response = await checkedApiRequest(\n passwordResetConfirmResponseSchema,\n '/auth/password-reset/confirm',\n {\n method: 'POST',\n body: {token: command.token, new_password: command.newPassword},\n },\n );\n return toAuthenticatedSession(response);\n}\n\nexport function useRequestPasswordResetAuth() {\n return useMutation({mutationFn: requestPasswordReset});\n}\n\nexport function useConfirmPasswordResetAuth() {\n const {enterAuthenticated} = useAuthTransition();\n\n return useMutation({\n mutationFn: confirmPasswordReset,\n onSuccess: enterAuthenticated,\n });\n}\n"],"names":["passwordResetConfirmResponseSchema","checkedApiRequest","emptyResponseSchema","useMutation","useAuthTransition","toAuthenticatedSession","requestPasswordReset","command","method","body","confirmPasswordReset","response","token","new_password","newPassword","useRequestPasswordResetAuth","mutationFn","useConfirmPasswordResetAuth","enterAuthenticated","onSuccess"],"mappings":"AAAA,SAAQA,kCAAkC,QAAO,wBAAwB;AACzE,SAAQC,iBAAiB,EAAEC,mBAAmB,QAAO,sBAAsB;AAC3E,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,iBAAiB,QAAO,iBAAiB;AACjD,SAAQC,sBAAsB,QAAO,mBAAmB;AAExD,OAAO,eAAeC,qBAAqBC,OAAoC;IAC7E,MAAMN,kBAAkBC,qBAAqB,wBAAwB;QACnEM,QAAQ;QACRC,MAAMF;IACR;AACF;AAEA,OAAO,eAAeG,qBAAqBH,OAAoC;IAC7E,MAAMI,WAAW,MAAMV,kBACrBD,oCACA,gCACA;QACEQ,QAAQ;QACRC,MAAM;YAACG,OAAOL,QAAQK,KAAK;YAAEC,cAAcN,QAAQO,WAAW;QAAA;IAChE;IAEF,OAAOT,uBAAuBM;AAChC;AAEA,OAAO,SAASI;IACd,OAAOZ,YAAY;QAACa,YAAYV;IAAoB;AACtD;AAEA,OAAO,SAASW;IACd,MAAM,EAACC,kBAAkB,EAAC,GAAGd;IAE7B,OAAOD,YAAY;QACjBa,YAAYN;QACZS,WAAWD;IACb;AACF"}
1
+ {"version":3,"sources":["../../../src/hooks/api/password-reset-auth.ts"],"sourcesContent":["import {passwordResetConfirmResponseSchema} from '@shipfox/api-auth-dto';\nimport {checkedApiRequest, emptyResponseSchema} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport type {PasswordResetConfirmCommand, PasswordResetRequestCommand} from '#core/auth.js';\nimport {useAuthTransition} from '#state/auth.js';\nimport {toAuthenticatedSession} from './auth-mapper.js';\n\nexport async function requestPasswordReset(command: PasswordResetRequestCommand) {\n await checkedApiRequest(emptyResponseSchema, '/auth/password-reset', {\n method: 'POST',\n body: command,\n });\n}\n\nexport async function confirmPasswordReset(command: PasswordResetConfirmCommand) {\n const response = await checkedApiRequest(\n passwordResetConfirmResponseSchema,\n '/auth/password-reset/confirm',\n {\n method: 'POST',\n body: {token: command.token, new_password: command.newPassword},\n },\n );\n return toAuthenticatedSession(response);\n}\n\nexport function useRequestPasswordResetAuth() {\n return useMutation({mutationFn: requestPasswordReset});\n}\n\nexport function useConfirmPasswordResetAuth() {\n const {enterAuthenticated} = useAuthTransition();\n\n return useMutation({\n mutationFn: confirmPasswordReset,\n onSuccess: (session) => enterAuthenticated(session),\n });\n}\n"],"names":["passwordResetConfirmResponseSchema","checkedApiRequest","emptyResponseSchema","useMutation","useAuthTransition","toAuthenticatedSession","requestPasswordReset","command","method","body","confirmPasswordReset","response","token","new_password","newPassword","useRequestPasswordResetAuth","mutationFn","useConfirmPasswordResetAuth","enterAuthenticated","onSuccess","session"],"mappings":"AAAA,SAAQA,kCAAkC,QAAO,wBAAwB;AACzE,SAAQC,iBAAiB,EAAEC,mBAAmB,QAAO,sBAAsB;AAC3E,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,iBAAiB,QAAO,iBAAiB;AACjD,SAAQC,sBAAsB,QAAO,mBAAmB;AAExD,OAAO,eAAeC,qBAAqBC,OAAoC;IAC7E,MAAMN,kBAAkBC,qBAAqB,wBAAwB;QACnEM,QAAQ;QACRC,MAAMF;IACR;AACF;AAEA,OAAO,eAAeG,qBAAqBH,OAAoC;IAC7E,MAAMI,WAAW,MAAMV,kBACrBD,oCACA,gCACA;QACEQ,QAAQ;QACRC,MAAM;YAACG,OAAOL,QAAQK,KAAK;YAAEC,cAAcN,QAAQO,WAAW;QAAA;IAChE;IAEF,OAAOT,uBAAuBM;AAChC;AAEA,OAAO,SAASI;IACd,OAAOZ,YAAY;QAACa,YAAYV;IAAoB;AACtD;AAEA,OAAO,SAASW;IACd,MAAM,EAACC,kBAAkB,EAAC,GAAGd;IAE7B,OAAOD,YAAY;QACjBa,YAAYN;QACZS,WAAW,CAACC,UAAYF,mBAAmBE;IAC7C;AACF"}
@@ -35,7 +35,7 @@ export function useVerifyEmailAuth() {
35
35
  const { enterAuthenticated } = useAuthTransition();
36
36
  return useMutation({
37
37
  mutationFn: verifyEmailAuth,
38
- onSuccess: enterAuthenticated
38
+ onSuccess: (session)=>enterAuthenticated(session)
39
39
  });
40
40
  }
41
41
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/api/verify-email-auth.ts"],"sourcesContent":["import {\n verifyEmailConfirmResponseSchema,\n verifyEmailResendResponseSchema,\n} from '@shipfox/api-auth-dto';\nimport {checkedApiRequest} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport type {\n EmailVerificationResendResult,\n ResendEmailVerificationCommand,\n VerifyEmailCommand,\n} from '#core/auth.js';\nimport {useAuthTransition} from '#state/auth.js';\nimport {toAuthenticatedSession} from './auth-mapper.js';\n\nasync function verifyEmailAuth(command: VerifyEmailCommand) {\n const response = await checkedApiRequest(\n verifyEmailConfirmResponseSchema,\n '/auth/verify-email/confirm',\n {\n method: 'POST',\n body: {email: command.email, challenge_id: command.challengeId, code: command.code},\n },\n );\n return toAuthenticatedSession(response);\n}\n\nasync function resendEmailVerificationAuth(command: ResendEmailVerificationCommand) {\n const response = await checkedApiRequest(\n verifyEmailResendResponseSchema,\n '/auth/verify-email/resend',\n {\n method: 'POST',\n body: {email: command.email, challenge_id: command.challengeId},\n },\n );\n return {\n nextResendAvailableAt: response.next_resend_available_at,\n } satisfies EmailVerificationResendResult;\n}\n\nexport function useResendEmailVerificationAuth() {\n return useMutation({mutationFn: resendEmailVerificationAuth});\n}\n\nexport function useVerifyEmailAuth() {\n const {enterAuthenticated} = useAuthTransition();\n\n return useMutation({\n mutationFn: verifyEmailAuth,\n onSuccess: enterAuthenticated,\n });\n}\n"],"names":["verifyEmailConfirmResponseSchema","verifyEmailResendResponseSchema","checkedApiRequest","useMutation","useAuthTransition","toAuthenticatedSession","verifyEmailAuth","command","response","method","body","email","challenge_id","challengeId","code","resendEmailVerificationAuth","nextResendAvailableAt","next_resend_available_at","useResendEmailVerificationAuth","mutationFn","useVerifyEmailAuth","enterAuthenticated","onSuccess"],"mappings":"AAAA,SACEA,gCAAgC,EAChCC,+BAA+B,QAC1B,wBAAwB;AAC/B,SAAQC,iBAAiB,QAAO,sBAAsB;AACtD,SAAQC,WAAW,QAAO,wBAAwB;AAMlD,SAAQC,iBAAiB,QAAO,iBAAiB;AACjD,SAAQC,sBAAsB,QAAO,mBAAmB;AAExD,eAAeC,gBAAgBC,OAA2B;IACxD,MAAMC,WAAW,MAAMN,kBACrBF,kCACA,8BACA;QACES,QAAQ;QACRC,MAAM;YAACC,OAAOJ,QAAQI,KAAK;YAAEC,cAAcL,QAAQM,WAAW;YAAEC,MAAMP,QAAQO,IAAI;QAAA;IACpF;IAEF,OAAOT,uBAAuBG;AAChC;AAEA,eAAeO,4BAA4BR,OAAuC;IAChF,MAAMC,WAAW,MAAMN,kBACrBD,iCACA,6BACA;QACEQ,QAAQ;QACRC,MAAM;YAACC,OAAOJ,QAAQI,KAAK;YAAEC,cAAcL,QAAQM,WAAW;QAAA;IAChE;IAEF,OAAO;QACLG,uBAAuBR,SAASS,wBAAwB;IAC1D;AACF;AAEA,OAAO,SAASC;IACd,OAAOf,YAAY;QAACgB,YAAYJ;IAA2B;AAC7D;AAEA,OAAO,SAASK;IACd,MAAM,EAACC,kBAAkB,EAAC,GAAGjB;IAE7B,OAAOD,YAAY;QACjBgB,YAAYb;QACZgB,WAAWD;IACb;AACF"}
1
+ {"version":3,"sources":["../../../src/hooks/api/verify-email-auth.ts"],"sourcesContent":["import {\n verifyEmailConfirmResponseSchema,\n verifyEmailResendResponseSchema,\n} from '@shipfox/api-auth-dto';\nimport {checkedApiRequest} from '@shipfox/client-api';\nimport {useMutation} from '@tanstack/react-query';\nimport type {\n EmailVerificationResendResult,\n ResendEmailVerificationCommand,\n VerifyEmailCommand,\n} from '#core/auth.js';\nimport {useAuthTransition} from '#state/auth.js';\nimport {toAuthenticatedSession} from './auth-mapper.js';\n\nasync function verifyEmailAuth(command: VerifyEmailCommand) {\n const response = await checkedApiRequest(\n verifyEmailConfirmResponseSchema,\n '/auth/verify-email/confirm',\n {\n method: 'POST',\n body: {email: command.email, challenge_id: command.challengeId, code: command.code},\n },\n );\n return toAuthenticatedSession(response);\n}\n\nasync function resendEmailVerificationAuth(command: ResendEmailVerificationCommand) {\n const response = await checkedApiRequest(\n verifyEmailResendResponseSchema,\n '/auth/verify-email/resend',\n {\n method: 'POST',\n body: {email: command.email, challenge_id: command.challengeId},\n },\n );\n return {\n nextResendAvailableAt: response.next_resend_available_at,\n } satisfies EmailVerificationResendResult;\n}\n\nexport function useResendEmailVerificationAuth() {\n return useMutation({mutationFn: resendEmailVerificationAuth});\n}\n\nexport function useVerifyEmailAuth() {\n const {enterAuthenticated} = useAuthTransition();\n\n return useMutation({\n mutationFn: verifyEmailAuth,\n onSuccess: (session) => enterAuthenticated(session),\n });\n}\n"],"names":["verifyEmailConfirmResponseSchema","verifyEmailResendResponseSchema","checkedApiRequest","useMutation","useAuthTransition","toAuthenticatedSession","verifyEmailAuth","command","response","method","body","email","challenge_id","challengeId","code","resendEmailVerificationAuth","nextResendAvailableAt","next_resend_available_at","useResendEmailVerificationAuth","mutationFn","useVerifyEmailAuth","enterAuthenticated","onSuccess","session"],"mappings":"AAAA,SACEA,gCAAgC,EAChCC,+BAA+B,QAC1B,wBAAwB;AAC/B,SAAQC,iBAAiB,QAAO,sBAAsB;AACtD,SAAQC,WAAW,QAAO,wBAAwB;AAMlD,SAAQC,iBAAiB,QAAO,iBAAiB;AACjD,SAAQC,sBAAsB,QAAO,mBAAmB;AAExD,eAAeC,gBAAgBC,OAA2B;IACxD,MAAMC,WAAW,MAAMN,kBACrBF,kCACA,8BACA;QACES,QAAQ;QACRC,MAAM;YAACC,OAAOJ,QAAQI,KAAK;YAAEC,cAAcL,QAAQM,WAAW;YAAEC,MAAMP,QAAQO,IAAI;QAAA;IACpF;IAEF,OAAOT,uBAAuBG;AAChC;AAEA,eAAeO,4BAA4BR,OAAuC;IAChF,MAAMC,WAAW,MAAMN,kBACrBD,iCACA,6BACA;QACEQ,QAAQ;QACRC,MAAM;YAACC,OAAOJ,QAAQI,KAAK;YAAEC,cAAcL,QAAQM,WAAW;QAAA;IAChE;IAEF,OAAO;QACLG,uBAAuBR,SAASS,wBAAwB;IAC1D;AACF;AAEA,OAAO,SAASC;IACd,OAAOf,YAAY;QAACgB,YAAYJ;IAA2B;AAC7D;AAEA,OAAO,SAASK;IACd,MAAM,EAACC,kBAAkB,EAAC,GAAGjB;IAE7B,OAAOD,YAAY;QACjBgB,YAAYb;QACZgB,WAAW,CAACC,UAAYF,mBAAmBE;IAC7C;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-onboarding-page.d.ts","sourceRoot":"","sources":["../../src/pages/workspace-onboarding-page.tsx"],"names":[],"mappings":"AAkCA,wBAAgB,uBAAuB,gCA2JtC"}
1
+ {"version":3,"file":"workspace-onboarding-page.d.ts","sourceRoot":"","sources":["../../src/pages/workspace-onboarding-page.tsx"],"names":[],"mappings":"AAmCA,wBAAgB,uBAAuB,gCA6JtC"}
@@ -13,7 +13,8 @@ import { useNavigate } from '@tanstack/react-router';
13
13
  import { useSetAtom } from 'jotai';
14
14
  import { useState } from 'react';
15
15
  import { useCreateWorkspaceAuth } from '#hooks/api/workspace-auth.js';
16
- import { lastWorkspaceIdAtom } from '#state/last-workspace.js';
16
+ import { useAuthState } from '#hooks/use-auth-state.js';
17
+ import { lastWorkspaceIdAtom, rememberLastWorkspaceId } from '#state/last-workspace.js';
17
18
  import { workspaceOnboardingErrorToFormError } from './form-errors.js';
18
19
  const previewMetrics = [
19
20
  {
@@ -69,6 +70,7 @@ const previewBars = [
69
70
  ];
70
71
  export function WorkspaceOnboardingPage() {
71
72
  const createWorkspace = useCreateWorkspaceAuth();
73
+ const { user } = useAuthState();
72
74
  const navigate = useNavigate();
73
75
  const setLastWorkspaceId = useSetAtom(lastWorkspaceIdAtom);
74
76
  const [formError, setFormError] = useState();
@@ -88,6 +90,7 @@ export function WorkspaceOnboardingPage() {
88
90
  // future visits to `/` land on it.
89
91
  try {
90
92
  setLastWorkspaceId(created.id);
93
+ if (user?.id) rememberLastWorkspaceId(user.id, created.id);
91
94
  } catch {
92
95
  // localStorage may throw in private browsing or quota-exceeded.
93
96
  }
@@ -1 +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 command = createWorkspaceBodySchema.parse({name: value.name});\n const created = await createWorkspace.mutateAsync(command);\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","command","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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"}
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 {useAuthState} from '#hooks/use-auth-state.js';\nimport {lastWorkspaceIdAtom, rememberLastWorkspaceId} 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 {user} = useAuthState();\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 command = createWorkspaceBodySchema.parse({name: value.name});\n const created = await createWorkspace.mutateAsync(command);\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 if (user?.id) rememberLastWorkspaceId(user.id, 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","useAuthState","lastWorkspaceIdAtom","rememberLastWorkspaceId","workspaceOnboardingErrorToFormError","previewMetrics","label","value","previewBars","id","height","WorkspaceOnboardingPage","createWorkspace","user","navigate","setLastWorkspaceId","formError","setFormError","form","defaultValues","name","onSubmit","undefined","command","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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"}
@@ -1 +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"}
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,wBAcG"}
@@ -12,14 +12,15 @@ export default defineRoute({
12
12
  if (!first) throw redirect({
13
13
  to: '/setup/workspaces/new'
14
14
  });
15
- const target = [
15
+ const principalId = auth.user?.id;
16
+ const target = principalId ? [
16
17
  first,
17
18
  ...rest
18
- ].find((workspace)=>workspace.id === getLastWorkspaceId()) ?? first;
19
+ ].find((workspace)=>workspace.id === getLastWorkspaceId(principalId)) : undefined;
19
20
  throw redirect({
20
21
  to: '/workspaces/$wid',
21
22
  params: {
22
- wid: target.id
23
+ wid: (target ?? first).id
23
24
  }
24
25
  });
25
26
  },
@@ -1 +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"}
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 principalId = auth.user?.id;\n const target = principalId\n ? [first, ...rest].find((workspace) => workspace.id === getLastWorkspaceId(principalId))\n : undefined;\n throw redirect({to: '/workspaces/$wid', params: {wid: (target ?? first).id}});\n },\n component: FullPageLoader,\n});\n"],"names":["defineRoute","getLastWorkspaceId","FullPageLoader","redirect","beforeLoad","context","auth","isLoading","isAuthenticated","to","first","rest","workspaces","principalId","user","id","target","find","workspace","undefined","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,cAAcP,KAAKQ,IAAI,EAAEC;QAC/B,MAAMC,SAASH,cACX;YAACH;eAAUC;SAAK,CAACM,IAAI,CAAC,CAACC,YAAcA,UAAUH,EAAE,KAAKd,mBAAmBY,gBACzEM;QACJ,MAAMhB,SAAS;YAACM,IAAI;YAAoBW,QAAQ;gBAACC,KAAK,AAACL,CAAAA,UAAUN,KAAI,EAAGK,EAAE;YAAA;QAAC;IAC7E;IACAO,WAAWpB;AACb,GAAG"}