@shipfox/client-auth 1.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +44 -0
  3. package/dist/feature.d.ts +0 -4
  4. package/dist/feature.d.ts.map +1 -1
  5. package/dist/feature.js +0 -5
  6. package/dist/feature.js.map +1 -1
  7. package/dist/hooks/api/signup-auth.d.ts +4 -0
  8. package/dist/hooks/api/signup-auth.d.ts.map +1 -1
  9. package/dist/hooks/api/verify-email-auth.d.ts +4 -1
  10. package/dist/hooks/api/verify-email-auth.d.ts.map +1 -1
  11. package/dist/index.d.ts +0 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +0 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/pages/email-verification-resend-model.d.ts +0 -1
  16. package/dist/pages/email-verification-resend-model.d.ts.map +1 -1
  17. package/dist/pages/email-verification-resend-model.js +0 -4
  18. package/dist/pages/email-verification-resend-model.js.map +1 -1
  19. package/dist/pages/form-utils.js +1 -1
  20. package/dist/pages/form-utils.js.map +1 -1
  21. package/dist/pages/signup-page.d.ts.map +1 -1
  22. package/dist/pages/signup-page.js +90 -36
  23. package/dist/pages/signup-page.js.map +1 -1
  24. package/dist/tsconfig.test.tsbuildinfo +1 -1
  25. package/package.json +9 -9
  26. package/src/feature.ts +0 -1
  27. package/src/index.ts +0 -1
  28. package/src/pages/email-verification-resend-model.test.ts +0 -10
  29. package/src/pages/email-verification-resend-model.ts +0 -6
  30. package/src/pages/form-errors.test.ts +1 -1
  31. package/src/pages/form-utils.test.ts +1 -4
  32. package/src/pages/form-utils.ts +1 -1
  33. package/src/pages/signup-page.test.tsx +60 -6
  34. package/src/pages/signup-page.tsx +87 -36
  35. package/test/pages.tsx +0 -7
  36. package/tsconfig.build.tsbuildinfo +1 -1
  37. package/dist/pages/verify-email-page.d.ts +0 -2
  38. package/dist/pages/verify-email-page.d.ts.map +0 -1
  39. package/dist/pages/verify-email-page.js +0 -57
  40. package/dist/pages/verify-email-page.js.map +0 -1
  41. package/dist/routes/verify-email.d.ts +0 -5
  42. package/dist/routes/verify-email.d.ts.map +0 -1
  43. package/dist/routes/verify-email.js +0 -11
  44. package/dist/routes/verify-email.js.map +0 -1
  45. package/src/pages/verify-email-page.test.tsx +0 -82
  46. package/src/pages/verify-email-page.tsx +0 -48
  47. package/src/routes/verify-email.tsx +0 -11
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 38 files with swc (145.79ms)
2
+ Successfully compiled: 36 files with swc (473.63ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,49 @@
1
1
  # @shipfox/client-auth
2
2
 
3
+ ## 3.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - ffc7fc9: Republishes the affected release set after recovering package publication.
8
+ - Updated dependencies [ffc7fc9]
9
+ - @shipfox/client-shell@3.0.1
10
+ - @shipfox/client-ui@3.0.1
11
+ - @shipfox/react-ui@0.3.5
12
+
13
+ ## 3.0.0
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [cb58afe]
18
+ - Updated dependencies [d735fe3]
19
+ - Updated dependencies [5b06cd5]
20
+ - @shipfox/react-ui@0.3.4
21
+ - @shipfox/client-shell@3.0.0
22
+ - @shipfox/client-ui@3.0.0
23
+
24
+ ## 2.0.0
25
+
26
+ ### Major Changes
27
+
28
+ - ba2e3dc: Migrates password email verification from magic links to shared eight-digit email challenges.
29
+
30
+ ### Patch Changes
31
+
32
+ - Updated dependencies [e6eba5b]
33
+ - Updated dependencies [ba2e3dc]
34
+ - Updated dependencies [1820feb]
35
+ - Updated dependencies [7ac43a4]
36
+ - Updated dependencies [1b79cda]
37
+ - Updated dependencies [c2db8c3]
38
+ - Updated dependencies [112c0fa]
39
+ - Updated dependencies [326f4c0]
40
+ - Updated dependencies [4a91956]
41
+ - @shipfox/api-auth-dto@6.0.0
42
+ - @shipfox/react-ui@0.3.3
43
+ - @shipfox/client-shell@2.0.0
44
+ - @shipfox/api-workspaces-dto@6.0.0
45
+ - @shipfox/client-ui@2.0.0
46
+
3
47
  ## 1.0.0
4
48
 
5
49
  ### Patch Changes
package/dist/feature.d.ts CHANGED
@@ -20,10 +20,6 @@ export declare const authFeature: {
20
20
  readonly path: "/auth/signup";
21
21
  readonly parent: "root";
22
22
  readonly impl: "@shipfox/client-auth/routes/signup";
23
- }, {
24
- readonly path: "/auth/verify-email";
25
- readonly parent: "root";
26
- readonly impl: "@shipfox/client-auth/routes/verify-email";
27
23
  }, {
28
24
  readonly path: "/setup/workspaces/new";
29
25
  readonly parent: "root";
@@ -1 +1 @@
1
- {"version":3,"file":"feature.d.ts","sourceRoot":"","sources":["../src/feature.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAetB,CAAC"}
1
+ {"version":3,"file":"feature.d.ts","sourceRoot":"","sources":["../src/feature.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;CActB,CAAC"}
package/dist/feature.js CHANGED
@@ -27,11 +27,6 @@ export const authFeature = defineClientFeature({
27
27
  parent: 'root',
28
28
  impl: '@shipfox/client-auth/routes/signup'
29
29
  },
30
- {
31
- path: '/auth/verify-email',
32
- parent: 'root',
33
- impl: '@shipfox/client-auth/routes/verify-email'
34
- },
35
30
  {
36
31
  path: '/setup/workspaces/new',
37
32
  parent: 'root',
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/feature.ts"],"sourcesContent":["import {defineClientFeature} from '@shipfox/client-shell';\n\nexport const authFeature = defineClientFeature({\n id: 'shipfox.auth',\n routes: [\n {path: '/', parent: 'root', impl: '@shipfox/client-auth/routes/index'},\n {path: '/auth/login', parent: 'root', impl: '@shipfox/client-auth/routes/login'},\n {path: '/auth/logout', parent: 'root', impl: '@shipfox/client-auth/routes/logout'},\n {path: '/auth/reset', parent: 'root', impl: '@shipfox/client-auth/routes/reset'},\n {path: '/auth/signup', parent: 'root', impl: '@shipfox/client-auth/routes/signup'},\n {path: '/auth/verify-email', parent: 'root', impl: '@shipfox/client-auth/routes/verify-email'},\n {\n path: '/setup/workspaces/new',\n parent: 'root',\n impl: '@shipfox/client-auth/routes/workspace-onboarding',\n },\n ],\n});\n"],"names":["defineClientFeature","authFeature","id","routes","path","parent","impl"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,wBAAwB;AAE1D,OAAO,MAAMC,cAAcD,oBAAoB;IAC7CE,IAAI;IACJC,QAAQ;QACN;YAACC,MAAM;YAAKC,QAAQ;YAAQC,MAAM;QAAmC;QACrE;YAACF,MAAM;YAAeC,QAAQ;YAAQC,MAAM;QAAmC;QAC/E;YAACF,MAAM;YAAgBC,QAAQ;YAAQC,MAAM;QAAoC;QACjF;YAACF,MAAM;YAAeC,QAAQ;YAAQC,MAAM;QAAmC;QAC/E;YAACF,MAAM;YAAgBC,QAAQ;YAAQC,MAAM;QAAoC;QACjF;YAACF,MAAM;YAAsBC,QAAQ;YAAQC,MAAM;QAA0C;QAC7F;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;KACD;AACH,GAAG"}
1
+ {"version":3,"sources":["../src/feature.ts"],"sourcesContent":["import {defineClientFeature} from '@shipfox/client-shell';\n\nexport const authFeature = defineClientFeature({\n id: 'shipfox.auth',\n routes: [\n {path: '/', parent: 'root', impl: '@shipfox/client-auth/routes/index'},\n {path: '/auth/login', parent: 'root', impl: '@shipfox/client-auth/routes/login'},\n {path: '/auth/logout', parent: 'root', impl: '@shipfox/client-auth/routes/logout'},\n {path: '/auth/reset', parent: 'root', impl: '@shipfox/client-auth/routes/reset'},\n {path: '/auth/signup', parent: 'root', impl: '@shipfox/client-auth/routes/signup'},\n {\n path: '/setup/workspaces/new',\n parent: 'root',\n impl: '@shipfox/client-auth/routes/workspace-onboarding',\n },\n ],\n});\n"],"names":["defineClientFeature","authFeature","id","routes","path","parent","impl"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,wBAAwB;AAE1D,OAAO,MAAMC,cAAcD,oBAAoB;IAC7CE,IAAI;IACJC,QAAQ;QACN;YAACC,MAAM;YAAKC,QAAQ;YAAQC,MAAM;QAAmC;QACrE;YAACF,MAAM;YAAeC,QAAQ;YAAQC,MAAM;QAAmC;QAC/E;YAACF,MAAM;YAAgBC,QAAQ;YAAQC,MAAM;QAAoC;QACjF;YAACF,MAAM;YAAeC,QAAQ;YAAQC,MAAM;QAAmC;QAC/E;YAACF,MAAM;YAAgBC,QAAQ;YAAQC,MAAM;QAAoC;QACjF;YACEF,MAAM;YACNC,QAAQ;YACRC,MAAM;QACR;KACD;AACH,GAAG"}
@@ -8,6 +8,10 @@ export declare function useSignupAuth(): import("@tanstack/react-query").UseMuta
8
8
  created_at: string;
9
9
  updated_at: string;
10
10
  };
11
+ email_challenge?: {
12
+ id: string;
13
+ next_resend_available_at: string;
14
+ } | undefined;
11
15
  token?: string | undefined;
12
16
  membership?: {
13
17
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"signup-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/signup-auth.ts"],"names":[],"mappings":"AAQA,wBAAgB,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;YAE5B"}
1
+ {"version":3,"file":"signup-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/signup-auth.ts"],"names":[],"mappings":"AAQA,wBAAgB,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAE5B"}
@@ -2,6 +2,7 @@ export declare function useResendEmailVerificationAuth(): import("@tanstack/reac
2
2
  next_resend_available_at: string;
3
3
  }, Error, {
4
4
  email: string;
5
+ challenge_id: string;
5
6
  }, unknown>;
6
7
  export declare function useVerifyEmailAuth(): import("@tanstack/react-query").UseMutationResult<{
7
8
  token: string;
@@ -15,6 +16,8 @@ export declare function useVerifyEmailAuth(): import("@tanstack/react-query").Us
15
16
  updated_at: string;
16
17
  };
17
18
  }, Error, {
18
- token: string;
19
+ email: string;
20
+ challenge_id: string;
21
+ code: string;
19
22
  }, unknown>;
20
23
  //# sourceMappingURL=verify-email-auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"verify-email-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/verify-email-auth.ts"],"names":[],"mappings":"AA2BA,wBAAgB,8BAA8B;;;;YAE7C;AAED,wBAAgB,kBAAkB;;;;;;;;;;;;;YAuBjC"}
1
+ {"version":3,"file":"verify-email-auth.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/verify-email-auth.ts"],"names":[],"mappings":"AA2BA,wBAAgB,8BAA8B;;;;;YAE7C;AAED,wBAAgB,kBAAkB;;;;;;;;;;;;;;;YAuBjC"}
package/dist/index.d.ts CHANGED
@@ -8,7 +8,6 @@ export * from './pages/login-page.js';
8
8
  export * from './pages/logout-page.js';
9
9
  export * from './pages/password-reset-page.js';
10
10
  export * from './pages/signup-page.js';
11
- export * from './pages/verify-email-page.js';
12
11
  export * from './pages/workspace-onboarding-page.js';
13
12
  export * from './state/auth.js';
14
13
  export { getLastWorkspaceId, lastWorkspaceIdAtom, rememberLastWorkspaceId, } from './state/last-workspace.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAAC,cAAc,EAAE,KAAK,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzF,OAAO,EAAC,iBAAiB,EAAE,KAAK,sBAAsB,EAAC,MAAM,oCAAoC,CAAC;AAClG,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,iBAAiB,CAAC;AAChC,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAAC,cAAc,EAAE,KAAK,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzF,OAAO,EAAC,iBAAiB,EAAE,KAAK,sBAAsB,EAAC,MAAM,oCAAoC,CAAC;AAClG,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,wBAAwB,CAAC;AACvC,cAAc,sCAAsC,CAAC;AACrD,cAAc,iBAAiB,CAAC;AAChC,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -8,7 +8,6 @@ export * from './pages/login-page.js';
8
8
  export * from './pages/logout-page.js';
9
9
  export * from './pages/password-reset-page.js';
10
10
  export * from './pages/signup-page.js';
11
- export * from './pages/verify-email-page.js';
12
11
  export * from './pages/workspace-onboarding-page.js';
13
12
  export * from './state/auth.js';
14
13
  export { getLastWorkspaceId, lastWorkspaceIdAtom, rememberLastWorkspaceId } from './state/last-workspace.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './components/auth-guard.js';\nexport * from './components/auth-provider.js';\nexport * from './components/auth-shell.js';\nexport {WorkspaceCrumb, type WorkspaceCrumbProps} from './components/workspace-crumb.js';\nexport {WorkspaceSwitcher, type WorkspaceSwitcherProps} from './components/workspace-switcher.js';\nexport * from './hooks/index.js';\nexport * from './pages/login-page.js';\nexport * from './pages/logout-page.js';\nexport * from './pages/password-reset-page.js';\nexport * from './pages/signup-page.js';\nexport * from './pages/verify-email-page.js';\nexport * from './pages/workspace-onboarding-page.js';\nexport * from './state/auth.js';\nexport {\n getLastWorkspaceId,\n lastWorkspaceIdAtom,\n rememberLastWorkspaceId,\n} from './state/last-workspace.js';\n"],"names":["WorkspaceCrumb","WorkspaceSwitcher","getLastWorkspaceId","lastWorkspaceIdAtom","rememberLastWorkspaceId"],"mappings":"AAAA,cAAc,6BAA6B;AAC3C,cAAc,gCAAgC;AAC9C,cAAc,6BAA6B;AAC3C,SAAQA,cAAc,QAAiC,kCAAkC;AACzF,SAAQC,iBAAiB,QAAoC,qCAAqC;AAClG,cAAc,mBAAmB;AACjC,cAAc,wBAAwB;AACtC,cAAc,yBAAyB;AACvC,cAAc,iCAAiC;AAC/C,cAAc,yBAAyB;AACvC,cAAc,+BAA+B;AAC7C,cAAc,uCAAuC;AACrD,cAAc,kBAAkB;AAChC,SACEC,kBAAkB,EAClBC,mBAAmB,EACnBC,uBAAuB,QAClB,4BAA4B"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './components/auth-guard.js';\nexport * from './components/auth-provider.js';\nexport * from './components/auth-shell.js';\nexport {WorkspaceCrumb, type WorkspaceCrumbProps} from './components/workspace-crumb.js';\nexport {WorkspaceSwitcher, type WorkspaceSwitcherProps} from './components/workspace-switcher.js';\nexport * from './hooks/index.js';\nexport * from './pages/login-page.js';\nexport * from './pages/logout-page.js';\nexport * from './pages/password-reset-page.js';\nexport * from './pages/signup-page.js';\nexport * from './pages/workspace-onboarding-page.js';\nexport * from './state/auth.js';\nexport {\n getLastWorkspaceId,\n lastWorkspaceIdAtom,\n rememberLastWorkspaceId,\n} from './state/last-workspace.js';\n"],"names":["WorkspaceCrumb","WorkspaceSwitcher","getLastWorkspaceId","lastWorkspaceIdAtom","rememberLastWorkspaceId"],"mappings":"AAAA,cAAc,6BAA6B;AAC3C,cAAc,gCAAgC;AAC9C,cAAc,6BAA6B;AAC3C,SAAQA,cAAc,QAAiC,kCAAkC;AACzF,SAAQC,iBAAiB,QAAoC,qCAAqC;AAClG,cAAc,mBAAmB;AACjC,cAAc,wBAAwB;AACtC,cAAc,yBAAyB;AACvC,cAAc,iCAAiC;AAC/C,cAAc,yBAAyB;AACvC,cAAc,uCAAuC;AACrD,cAAc,kBAAkB;AAChC,SACEC,kBAAkB,EAClBC,mBAAmB,EACnBC,uBAAuB,QAClB,4BAA4B"}
@@ -1,4 +1,3 @@
1
- export declare function getLocalResendAvailableAt(now: number): number;
2
1
  export declare function getResendRemainingSeconds(params: {
3
2
  nextResendAvailableAt: number | undefined;
4
3
  now: number;
@@ -1 +1 @@
1
- {"version":3,"file":"email-verification-resend-model.d.ts","sourceRoot":"","sources":["../../src/pages/email-verification-resend-model.ts"],"names":[],"mappings":"AAEA,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE;IAChD,qBAAqB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,MAAM,CAIT;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK5E"}
1
+ {"version":3,"file":"email-verification-resend-model.d.ts","sourceRoot":"","sources":["../../src/pages/email-verification-resend-model.ts"],"names":[],"mappings":"AAAA,wBAAgB,yBAAyB,CAAC,MAAM,EAAE;IAChD,qBAAqB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,MAAM,CAIT;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK5E"}
@@ -1,7 +1,3 @@
1
- import { EMAIL_VERIFICATION_RESEND_COOLDOWN_SECONDS } from '@shipfox/api-auth-dto';
2
- export function getLocalResendAvailableAt(now) {
3
- return now + EMAIL_VERIFICATION_RESEND_COOLDOWN_SECONDS * 1000;
4
- }
5
1
  export function getResendRemainingSeconds(params) {
6
2
  if (!params.nextResendAvailableAt) return 0;
7
3
  return Math.max(0, Math.ceil((params.nextResendAvailableAt - params.now) / 1000));
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pages/email-verification-resend-model.ts"],"sourcesContent":["import {EMAIL_VERIFICATION_RESEND_COOLDOWN_SECONDS} from '@shipfox/api-auth-dto';\n\nexport function getLocalResendAvailableAt(now: number): number {\n return now + EMAIL_VERIFICATION_RESEND_COOLDOWN_SECONDS * 1000;\n}\n\nexport function getResendRemainingSeconds(params: {\n nextResendAvailableAt: number | undefined;\n now: number;\n}): number {\n if (!params.nextResendAvailableAt) return 0;\n\n return Math.max(0, Math.ceil((params.nextResendAvailableAt - params.now) / 1000));\n}\n\nexport function parseNextResendAvailableAt(value: string): number | undefined {\n const nextAvailableAt = Date.parse(value);\n if (!Number.isFinite(nextAvailableAt)) return undefined;\n\n return nextAvailableAt;\n}\n"],"names":["EMAIL_VERIFICATION_RESEND_COOLDOWN_SECONDS","getLocalResendAvailableAt","now","getResendRemainingSeconds","params","nextResendAvailableAt","Math","max","ceil","parseNextResendAvailableAt","value","nextAvailableAt","Date","parse","Number","isFinite","undefined"],"mappings":"AAAA,SAAQA,0CAA0C,QAAO,wBAAwB;AAEjF,OAAO,SAASC,0BAA0BC,GAAW;IACnD,OAAOA,MAAMF,6CAA6C;AAC5D;AAEA,OAAO,SAASG,0BAA0BC,MAGzC;IACC,IAAI,CAACA,OAAOC,qBAAqB,EAAE,OAAO;IAE1C,OAAOC,KAAKC,GAAG,CAAC,GAAGD,KAAKE,IAAI,CAAC,AAACJ,CAAAA,OAAOC,qBAAqB,GAAGD,OAAOF,GAAG,AAAD,IAAK;AAC7E;AAEA,OAAO,SAASO,2BAA2BC,KAAa;IACtD,MAAMC,kBAAkBC,KAAKC,KAAK,CAACH;IACnC,IAAI,CAACI,OAAOC,QAAQ,CAACJ,kBAAkB,OAAOK;IAE9C,OAAOL;AACT"}
1
+ {"version":3,"sources":["../../src/pages/email-verification-resend-model.ts"],"sourcesContent":["export function getResendRemainingSeconds(params: {\n nextResendAvailableAt: number | undefined;\n now: number;\n}): number {\n if (!params.nextResendAvailableAt) return 0;\n\n return Math.max(0, Math.ceil((params.nextResendAvailableAt - params.now) / 1000));\n}\n\nexport function parseNextResendAvailableAt(value: string): number | undefined {\n const nextAvailableAt = Date.parse(value);\n if (!Number.isFinite(nextAvailableAt)) return undefined;\n\n return nextAvailableAt;\n}\n"],"names":["getResendRemainingSeconds","params","nextResendAvailableAt","Math","max","ceil","now","parseNextResendAvailableAt","value","nextAvailableAt","Date","parse","Number","isFinite","undefined"],"mappings":"AAAA,OAAO,SAASA,0BAA0BC,MAGzC;IACC,IAAI,CAACA,OAAOC,qBAAqB,EAAE,OAAO;IAE1C,OAAOC,KAAKC,GAAG,CAAC,GAAGD,KAAKE,IAAI,CAAC,AAACJ,CAAAA,OAAOC,qBAAqB,GAAGD,OAAOK,GAAG,AAAD,IAAK;AAC7E;AAEA,OAAO,SAASC,2BAA2BC,KAAa;IACtD,MAAMC,kBAAkBC,KAAKC,KAAK,CAACH;IACnC,IAAI,CAACI,OAAOC,QAAQ,CAACJ,kBAAkB,OAAOK;IAE9C,OAAOL;AACT"}
@@ -17,7 +17,7 @@ export function authErrorMessage(error) {
17
17
  return 'Too many attempts. Wait a bit and try again.';
18
18
  }
19
19
  if (error.code === 'auth-rate-limit-unavailable') {
20
- return 'Sign-in protection is temporarily unavailable. Try again soon.';
20
+ return 'Sign-in is temporarily unavailable. Try again soon.';
21
21
  }
22
22
  if (error.code === 'network-error') {
23
23
  return 'We could not reach the API. Check your connection and try again.';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pages/form-utils.ts"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\n\nexport function authErrorMessage(error: unknown): string {\n if (!(error instanceof ApiError)) return 'Something went wrong. Try again.';\n\n if (error.code === 'invalid-credentials') {\n return 'Email or password is incorrect.';\n }\n if (error.code === 'email-not-verified') {\n return 'Verify your email before signing in.';\n }\n if (error.code === 'email-taken') {\n return 'An account already exists for this email.';\n }\n if (error.code === 'token-invalid') {\n return 'This link is invalid or expired.';\n }\n if (error.code === 'rate-limited') {\n return 'Too many attempts. Wait a bit and try again.';\n }\n if (error.code === 'auth-rate-limit-unavailable') {\n return 'Sign-in protection is temporarily unavailable. Try again soon.';\n }\n if (error.code === 'network-error') {\n return 'We could not reach the API. Check your connection and try again.';\n }\n\n return error.message || 'Something went wrong. Try again.';\n}\n"],"names":["ApiError","authErrorMessage","error","code","message"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,sBAAsB;AAE7C,OAAO,SAASC,iBAAiBC,KAAc;IAC7C,IAAI,CAAEA,CAAAA,iBAAiBF,QAAO,GAAI,OAAO;IAEzC,IAAIE,MAAMC,IAAI,KAAK,uBAAuB;QACxC,OAAO;IACT;IACA,IAAID,MAAMC,IAAI,KAAK,sBAAsB;QACvC,OAAO;IACT;IACA,IAAID,MAAMC,IAAI,KAAK,eAAe;QAChC,OAAO;IACT;IACA,IAAID,MAAMC,IAAI,KAAK,iBAAiB;QAClC,OAAO;IACT;IACA,IAAID,MAAMC,IAAI,KAAK,gBAAgB;QACjC,OAAO;IACT;IACA,IAAID,MAAMC,IAAI,KAAK,+BAA+B;QAChD,OAAO;IACT;IACA,IAAID,MAAMC,IAAI,KAAK,iBAAiB;QAClC,OAAO;IACT;IAEA,OAAOD,MAAME,OAAO,IAAI;AAC1B"}
1
+ {"version":3,"sources":["../../src/pages/form-utils.ts"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\n\nexport function authErrorMessage(error: unknown): string {\n if (!(error instanceof ApiError)) return 'Something went wrong. Try again.';\n\n if (error.code === 'invalid-credentials') {\n return 'Email or password is incorrect.';\n }\n if (error.code === 'email-not-verified') {\n return 'Verify your email before signing in.';\n }\n if (error.code === 'email-taken') {\n return 'An account already exists for this email.';\n }\n if (error.code === 'token-invalid') {\n return 'This link is invalid or expired.';\n }\n if (error.code === 'rate-limited') {\n return 'Too many attempts. Wait a bit and try again.';\n }\n if (error.code === 'auth-rate-limit-unavailable') {\n return 'Sign-in is temporarily unavailable. Try again soon.';\n }\n if (error.code === 'network-error') {\n return 'We could not reach the API. Check your connection and try again.';\n }\n\n return error.message || 'Something went wrong. Try again.';\n}\n"],"names":["ApiError","authErrorMessage","error","code","message"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,sBAAsB;AAE7C,OAAO,SAASC,iBAAiBC,KAAc;IAC7C,IAAI,CAAEA,CAAAA,iBAAiBF,QAAO,GAAI,OAAO;IAEzC,IAAIE,MAAMC,IAAI,KAAK,uBAAuB;QACxC,OAAO;IACT;IACA,IAAID,MAAMC,IAAI,KAAK,sBAAsB;QACvC,OAAO;IACT;IACA,IAAID,MAAMC,IAAI,KAAK,eAAe;QAChC,OAAO;IACT;IACA,IAAID,MAAMC,IAAI,KAAK,iBAAiB;QAClC,OAAO;IACT;IACA,IAAID,MAAMC,IAAI,KAAK,gBAAgB;QACjC,OAAO;IACT;IACA,IAAID,MAAMC,IAAI,KAAK,+BAA+B;QAChD,OAAO;IACT;IACA,IAAID,MAAMC,IAAI,KAAK,iBAAiB;QAClC,OAAO;IACT;IAEA,OAAOD,MAAME,OAAO,IAAI;AAC1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"signup-page.d.ts","sourceRoot":"","sources":["../../src/pages/signup-page.tsx"],"names":[],"mappings":"AA8BA,wBAAgB,UAAU,gCAmUzB"}
1
+ {"version":3,"file":"signup-page.d.ts","sourceRoot":"","sources":["../../src/pages/signup-page.tsx"],"names":[],"mappings":"AA6BA,wBAAgB,UAAU,gCAuXzB"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { signupBodySchema } from '@shipfox/api-auth-dto';
2
+ import { signupBodySchema, verifyEmailConfirmBodySchema } from '@shipfox/api-auth-dto';
3
3
  import { displayNameFieldError } from '@shipfox/client-ui';
4
4
  import { Button, ButtonLink } from '@shipfox/react-ui/button';
5
5
  import { Callout } from '@shipfox/react-ui/callout';
@@ -14,14 +14,15 @@ import { useEffect, useRef, useState } from 'react';
14
14
  import { AuthShell } from '#/components/auth-shell.js';
15
15
  import { useRefreshAuth } from '#hooks/api/refresh-auth.js';
16
16
  import { useSignupAuth } from '#hooks/api/signup-auth.js';
17
- import { useResendEmailVerificationAuth } from '#hooks/api/verify-email-auth.js';
17
+ import { useResendEmailVerificationAuth, useVerifyEmailAuth } from '#hooks/api/verify-email-auth.js';
18
18
  import { authFormDraftAtom, initialAuthFormDraft } from '#state/auth.js';
19
- import { getLocalResendAvailableAt, getResendRemainingSeconds, parseNextResendAvailableAt } from './email-verification-resend-model.js';
19
+ import { getResendRemainingSeconds, parseNextResendAvailableAt } from './email-verification-resend-model.js';
20
20
  import { signupErrorToFormError } from './form-errors.js';
21
21
  import { authErrorMessage } from './form-utils.js';
22
22
  import { extractInvitationToken, pendingInvitation, useInvitationContext } from './invitation-context.js';
23
23
  export function SignupPage() {
24
24
  const signup = useSignupAuth();
25
+ const verifyEmail = useVerifyEmailAuth();
25
26
  const resendEmailVerification = useResendEmailVerificationAuth();
26
27
  const refreshAuth = useRefreshAuth();
27
28
  const navigate = useNavigate();
@@ -32,7 +33,7 @@ export function SignupPage() {
32
33
  const invitationPreview = useInvitationContext(invitationToken);
33
34
  const invitationPending = pendingInvitation(invitationPreview.data);
34
35
  const [authFormDraft, setAuthFormDraft] = useAtom(authFormDraftAtom);
35
- const [submittedEmail, setSubmittedEmail] = useState();
36
+ const [emailChallenge, setEmailChallenge] = useState();
36
37
  const [now, setNow] = useState(()=>Date.now());
37
38
  const [nextResendAvailableAt, setNextResendAvailableAt] = useState();
38
39
  const [formError, setFormError] = useState();
@@ -93,9 +94,17 @@ export function SignupPage() {
93
94
  });
94
95
  return;
95
96
  }
96
- setSubmittedEmail(result.user.email);
97
+ if (!result.email_challenge) {
98
+ throw new Error('Signup did not return an email verification challenge');
99
+ }
100
+ setEmailChallenge({
101
+ email: result.user.email,
102
+ id: result.email_challenge.id
103
+ });
104
+ verificationForm.reset();
97
105
  setResendError(undefined);
98
- restartLocalCooldown();
106
+ setNow(Date.now());
107
+ setNextResendAvailableAt(parseNextResendAvailableAt(result.email_challenge.next_resend_available_at));
99
108
  } catch (error) {
100
109
  const mapped = signupErrorToFormError(error);
101
110
  if (mapped.kind === 'field') {
@@ -112,8 +121,32 @@ export function SignupPage() {
112
121
  }
113
122
  }
114
123
  });
124
+ const verificationForm = useForm({
125
+ defaultValues: {
126
+ code: ''
127
+ },
128
+ onSubmit: async ({ value })=>{
129
+ if (!emailChallenge || verifyEmail.isPending) return;
130
+ setResendError(undefined);
131
+ try {
132
+ await verifyEmail.mutateAsync({
133
+ email: emailChallenge.email,
134
+ challenge_id: emailChallenge.id,
135
+ code: value.code
136
+ });
137
+ await refreshAuth();
138
+ toast.success('Your email is verified. You are now logged in.');
139
+ await navigate({
140
+ to: '/',
141
+ replace: true
142
+ });
143
+ } catch (error) {
144
+ setResendError(authErrorMessage(error));
145
+ }
146
+ }
147
+ });
115
148
  useEffect(()=>{
116
- if (!submittedEmail || !nextResendAvailableAt) {
149
+ if (!emailChallenge || !nextResendAvailableAt) {
117
150
  return;
118
151
  }
119
152
  const current = Date.now();
@@ -130,14 +163,9 @@ export function SignupPage() {
130
163
  }, 1000);
131
164
  return ()=>window.clearInterval(handle);
132
165
  }, [
133
- nextResendAvailableAt,
134
- submittedEmail
166
+ emailChallenge,
167
+ nextResendAvailableAt
135
168
  ]);
136
- function restartLocalCooldown() {
137
- const current = Date.now();
138
- setNow(current);
139
- setNextResendAvailableAt(getLocalResendAvailableAt(current));
140
- }
141
169
  // When arriving from an invitation link, prefill the email and lock it.
142
170
  useEffect(()=>{
143
171
  if (invitationPending && form.state.values.email !== invitationPending.email) {
@@ -171,42 +199,68 @@ export function SignupPage() {
171
199
  setAuthFormDraft
172
200
  ]);
173
201
  async function onResendVerificationEmail() {
174
- if (!submittedEmail || isResendCoolingDown || resendEmailVerification.isPending) return;
202
+ if (!emailChallenge || isResendCoolingDown || resendEmailVerification.isPending) return;
175
203
  setResendError(undefined);
176
204
  try {
177
205
  const result = await resendEmailVerification.mutateAsync({
178
- email: submittedEmail
206
+ email: emailChallenge.email,
207
+ challenge_id: emailChallenge.id
179
208
  });
180
209
  const nextAvailableAt = parseNextResendAvailableAt(result.next_resend_available_at);
181
210
  setNow(Date.now());
182
211
  if (nextAvailableAt !== undefined) {
183
212
  setNextResendAvailableAt(nextAvailableAt);
184
- } else {
185
- restartLocalCooldown();
186
213
  }
187
214
  toast.success('If another verification email can be sent, it will arrive shortly.');
188
215
  } catch (error) {
189
216
  setResendError(authErrorMessage(error));
190
217
  }
191
218
  }
192
- if (submittedEmail) {
219
+ if (emailChallenge) {
193
220
  return /*#__PURE__*/ _jsxs(AuthShell, {
194
221
  title: "Check your email",
195
- description: `We sent a verification link to ${submittedEmail}.`,
222
+ description: `We sent an eight-digit verification code to ${emailChallenge.email}.`,
196
223
  children: [
197
224
  resendError ? /*#__PURE__*/ _jsx(Callout, {
198
225
  role: "alert",
199
226
  type: "error",
200
227
  children: resendError
201
228
  }) : null,
202
- /*#__PURE__*/ _jsx(Callout, {
203
- role: "alert",
204
- type: "success",
205
- children: "Click the verification link to activate your account, then come back to log in."
206
- }),
207
- /*#__PURE__*/ _jsxs("div", {
229
+ /*#__PURE__*/ _jsxs("form", {
208
230
  className: "flex flex-col gap-8",
231
+ noValidate: true,
232
+ onSubmit: (event)=>{
233
+ event.preventDefault();
234
+ void verificationForm.handleSubmit();
235
+ },
209
236
  children: [
237
+ /*#__PURE__*/ _jsx(verificationForm.Field, {
238
+ name: "code",
239
+ validators: {
240
+ onBlur: verifyEmailConfirmBodySchema.shape.code,
241
+ onSubmit: verifyEmailConfirmBodySchema.shape.code
242
+ },
243
+ children: (field)=>/*#__PURE__*/ _jsx(FormField, {
244
+ label: "Verification code",
245
+ id: "verification-code",
246
+ error: fieldError(field),
247
+ children: /*#__PURE__*/ _jsx(FormFieldInput, {
248
+ autoComplete: "one-time-code",
249
+ inputMode: "numeric",
250
+ maxLength: 8,
251
+ pattern: "[0-9]{8}",
252
+ value: field.state.value,
253
+ onChange: (event)=>field.handleChange(event.target.value.replace(/\D/gu, '')),
254
+ onBlur: field.handleBlur
255
+ })
256
+ })
257
+ }),
258
+ /*#__PURE__*/ _jsx(Button, {
259
+ className: "w-full",
260
+ type: "submit",
261
+ isLoading: verifyEmail.isPending,
262
+ children: "Verify email"
263
+ }),
210
264
  /*#__PURE__*/ _jsx(Button, {
211
265
  "aria-disabled": isResendCoolingDown ? true : undefined,
212
266
  className: "w-full aria-disabled:cursor-not-allowed aria-disabled:opacity-70",
@@ -215,19 +269,19 @@ export function SignupPage() {
215
269
  isLoading: resendEmailVerification.isPending,
216
270
  onClick: onResendVerificationEmail,
217
271
  children: resendEmailVerification.isPending ? 'Sending email...' : isResendCoolingDown ? `Resend in ${resendRemainingSeconds}s` : 'Resend verification email'
218
- }),
219
- /*#__PURE__*/ _jsx(Button, {
220
- className: "w-full",
221
- variant: "transparent",
222
- type: "button",
223
- onClick: ()=>{
224
- setSubmittedEmail(undefined);
225
- setResendError(undefined);
226
- },
227
- children: "Use another email"
228
272
  })
229
273
  ]
230
274
  }),
275
+ /*#__PURE__*/ _jsx(Button, {
276
+ className: "w-full",
277
+ variant: "transparent",
278
+ type: "button",
279
+ onClick: ()=>{
280
+ setEmailChallenge(undefined);
281
+ setResendError(undefined);
282
+ },
283
+ children: "Use another email"
284
+ }),
231
285
  /*#__PURE__*/ _jsxs(Text, {
232
286
  size: "sm",
233
287
  className: "text-center text-foreground-neutral-subtle",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pages/signup-page.tsx"],"sourcesContent":["import {signupBodySchema} from '@shipfox/api-auth-dto';\nimport {displayNameFieldError} from '@shipfox/client-ui';\nimport {Button, ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\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 {Link, useNavigate, useSearch} from '@tanstack/react-router';\nimport {useAtom} from 'jotai';\nimport {useEffect, useRef, useState} from 'react';\nimport {AuthShell} from '#/components/auth-shell.js';\nimport {useRefreshAuth} from '#hooks/api/refresh-auth.js';\nimport {useSignupAuth} from '#hooks/api/signup-auth.js';\nimport {useResendEmailVerificationAuth} from '#hooks/api/verify-email-auth.js';\nimport {authFormDraftAtom, initialAuthFormDraft} from '#state/auth.js';\nimport {\n getLocalResendAvailableAt,\n getResendRemainingSeconds,\n parseNextResendAvailableAt,\n} from './email-verification-resend-model.js';\nimport {signupErrorToFormError} from './form-errors.js';\nimport {authErrorMessage} from './form-utils.js';\nimport {\n extractInvitationToken,\n pendingInvitation,\n useInvitationContext,\n} from './invitation-context.js';\n\nexport function SignupPage() {\n const signup = useSignupAuth();\n const resendEmailVerification = useResendEmailVerificationAuth();\n const refreshAuth = useRefreshAuth();\n const navigate = useNavigate();\n const search = useSearch({strict: false}) as {redirect?: unknown};\n const invitationToken = extractInvitationToken(search.redirect);\n const invitationPreview = useInvitationContext(invitationToken);\n const invitationPending = pendingInvitation(invitationPreview.data);\n const [authFormDraft, setAuthFormDraft] = useAtom(authFormDraftAtom);\n const [submittedEmail, setSubmittedEmail] = useState<string | undefined>();\n const [now, setNow] = useState(() => Date.now());\n const [nextResendAvailableAt, setNextResendAvailableAt] = useState<number | undefined>();\n const [formError, setFormError] = useState<string | undefined>();\n const [resendError, setResendError] = useState<string | undefined>();\n const draftRef = useRef(authFormDraft);\n draftRef.current = authFormDraft;\n // Set just before clearing the draft on success so the unmount cleanup\n // below does not repersist the just-submitted credentials.\n const skipDraftPersistRef = useRef(false);\n const resendRemainingSeconds = getResendRemainingSeconds({nextResendAvailableAt, now});\n const isResendCoolingDown = resendRemainingSeconds > 0;\n\n const form = useForm({\n defaultValues: {email: authFormDraft.email, password: authFormDraft.password, name: ''},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n const body = signupBodySchema.parse({\n email: value.email,\n password: value.password,\n name: value.name,\n ...(invitationToken ? {invitation_token: invitationToken} : {}),\n });\n const result = await signup.mutateAsync(body);\n skipDraftPersistRef.current = true;\n setAuthFormDraft(initialAuthFormDraft);\n\n if (invitationToken && result.membership && invitationPending) {\n try {\n await refreshAuth();\n } catch {\n // Refresh failures don't block the success message — the next API\n // call's 401 handling will re-route the user.\n }\n toast.success(`You joined ${invitationPending.workspace_name}.`);\n await navigate({\n to: '/workspaces/$wid',\n params: {wid: result.membership.workspace_id},\n });\n return;\n }\n\n if (invitationToken && result.accept_error) {\n toast.error(result.accept_error.message);\n await navigate({\n to: '/invitations/accept',\n search: {token: invitationToken},\n });\n return;\n }\n\n setSubmittedEmail(result.user.email);\n setResendError(undefined);\n restartLocalCooldown();\n } catch (error) {\n const mapped = signupErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n useEffect(() => {\n if (!submittedEmail || !nextResendAvailableAt) {\n return;\n }\n\n const current = Date.now();\n setNow(current);\n if (nextResendAvailableAt <= current) {\n return;\n }\n\n const handle = window.setInterval(() => {\n const tickNow = Date.now();\n setNow(tickNow);\n if (nextResendAvailableAt <= tickNow) {\n window.clearInterval(handle);\n }\n }, 1000);\n return () => window.clearInterval(handle);\n }, [nextResendAvailableAt, submittedEmail]);\n\n function restartLocalCooldown() {\n const current = Date.now();\n setNow(current);\n setNextResendAvailableAt(getLocalResendAvailableAt(current));\n }\n\n // When arriving from an invitation link, prefill the email and lock it.\n useEffect(() => {\n if (invitationPending && form.state.values.email !== invitationPending.email) {\n form.setFieldValue('email', invitationPending.email);\n setAuthFormDraft((current) => ({...current, email: invitationPending.email}));\n }\n }, [invitationPending, form, setAuthFormDraft]);\n\n // Sync form values back to the Jotai draft on unmount (only email + password\n // — name is intentionally not persisted across navigation). Skipped after a\n // successful signup because we just intentionally cleared the draft.\n useEffect(() => {\n return () => {\n if (skipDraftPersistRef.current) return;\n const {email, password} = form.state.values;\n if (email !== draftRef.current.email || password !== draftRef.current.password) {\n setAuthFormDraft({email, password});\n }\n };\n }, [form, setAuthFormDraft]);\n\n async function onResendVerificationEmail() {\n if (!submittedEmail || isResendCoolingDown || resendEmailVerification.isPending) return;\n\n setResendError(undefined);\n try {\n const result = await resendEmailVerification.mutateAsync({email: submittedEmail});\n const nextAvailableAt = parseNextResendAvailableAt(result.next_resend_available_at);\n setNow(Date.now());\n if (nextAvailableAt !== undefined) {\n setNextResendAvailableAt(nextAvailableAt);\n } else {\n restartLocalCooldown();\n }\n toast.success('If another verification email can be sent, it will arrive shortly.');\n } catch (error) {\n setResendError(authErrorMessage(error));\n }\n }\n\n if (submittedEmail) {\n return (\n <AuthShell\n title=\"Check your email\"\n description={`We sent a verification link to ${submittedEmail}.`}\n >\n {resendError ? (\n <Callout role=\"alert\" type=\"error\">\n {resendError}\n </Callout>\n ) : null}\n <Callout role=\"alert\" type=\"success\">\n Click the verification link to activate your account, then come back to log in.\n </Callout>\n <div className=\"flex flex-col gap-8\">\n <Button\n aria-disabled={isResendCoolingDown ? true : undefined}\n className=\"w-full aria-disabled:cursor-not-allowed aria-disabled:opacity-70\"\n variant=\"secondary\"\n type=\"button\"\n isLoading={resendEmailVerification.isPending}\n onClick={onResendVerificationEmail}\n >\n {resendEmailVerification.isPending\n ? 'Sending email...'\n : isResendCoolingDown\n ? `Resend in ${resendRemainingSeconds}s`\n : 'Resend verification email'}\n </Button>\n <Button\n className=\"w-full\"\n variant=\"transparent\"\n type=\"button\"\n onClick={() => {\n setSubmittedEmail(undefined);\n setResendError(undefined);\n }}\n >\n Use another email\n </Button>\n </div>\n <Text size=\"sm\" className=\"text-center text-foreground-neutral-subtle\">\n Already verified?{' '}\n <ButtonLink asChild variant=\"interactive\" underline>\n <Link to=\"/auth/login\">Log in</Link>\n </ButtonLink>\n </Text>\n </AuthShell>\n );\n }\n\n const headerTitle = invitationPending\n ? `Join ${invitationPending.workspace_name}`\n : 'Create your Shipfox account';\n const headerDescription = invitationPending\n ? `Create an account to accept your invitation.`\n : 'Start with your email and a password.';\n const isInvitationEmailLocked = Boolean(invitationPending);\n const invitationRedirect = invitationToken\n ? `/invitations/accept?token=${encodeURIComponent(invitationToken)}`\n : undefined;\n\n function persistDraft() {\n const {email, password} = form.state.values;\n setAuthFormDraft({email, password});\n }\n\n return (\n <AuthShell title={headerTitle} description={headerDescription}>\n <form\n className=\"flex flex-col gap-18\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n {formError}\n </Callout>\n ) : null}\n <form.Field\n name=\"name\"\n validators={{\n onBlur: ({value}) => displayNameFieldError(value, 'Name', signupBodySchema.shape.name),\n onSubmit: ({value}) =>\n displayNameFieldError(value, 'Name', signupBodySchema.shape.name),\n }}\n >\n {(field) => (\n <FormField label=\"Name\" id=\"name\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"name\"\n name=\"name\"\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 <form.Field\n name=\"email\"\n validators={{\n onBlur: signupBodySchema.shape.email,\n onSubmit: signupBodySchema.shape.email,\n }}\n >\n {(field) => (\n <FormField label=\"Email\" id=\"email\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"email\"\n name=\"email\"\n type=\"email\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={() => {\n field.handleBlur();\n persistDraft();\n }}\n readOnly={isInvitationEmailLocked}\n iconRight={\n isInvitationEmailLocked ? (\n <Icon\n aria-hidden=\"true\"\n className=\"size-16 text-foreground-neutral-disabled\"\n name=\"lockLine\"\n />\n ) : undefined\n }\n />\n </FormField>\n )}\n </form.Field>\n <form.Field\n name=\"password\"\n validators={{\n onBlur: signupBodySchema.shape.password,\n onSubmit: signupBodySchema.shape.password,\n }}\n >\n {(field) => (\n <FormField label=\"Password\" id=\"password\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"new-password\"\n name=\"password\"\n type=\"password\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={() => {\n field.handleBlur();\n persistDraft();\n }}\n />\n </FormField>\n )}\n </form.Field>\n <Button className=\"w-full\" isLoading={signup.isPending} type=\"submit\">\n {signup.isPending ? 'Creating account...' : 'Create account'}\n </Button>\n </form>\n <Text size=\"sm\" className=\"text-center text-foreground-neutral-subtle\">\n Already have an account?{' '}\n <ButtonLink asChild variant=\"interactive\" underline>\n <Link\n to=\"/auth/login\"\n search={invitationRedirect ? {redirect: invitationRedirect} : undefined}\n >\n Log in\n </Link>\n </ButtonLink>\n </Text>\n </AuthShell>\n );\n}\n"],"names":["signupBodySchema","displayNameFieldError","Button","ButtonLink","Callout","FormField","FormFieldInput","fieldError","Icon","toast","Text","useForm","Link","useNavigate","useSearch","useAtom","useEffect","useRef","useState","AuthShell","useRefreshAuth","useSignupAuth","useResendEmailVerificationAuth","authFormDraftAtom","initialAuthFormDraft","getLocalResendAvailableAt","getResendRemainingSeconds","parseNextResendAvailableAt","signupErrorToFormError","authErrorMessage","extractInvitationToken","pendingInvitation","useInvitationContext","SignupPage","signup","resendEmailVerification","refreshAuth","navigate","search","strict","invitationToken","redirect","invitationPreview","invitationPending","data","authFormDraft","setAuthFormDraft","submittedEmail","setSubmittedEmail","now","setNow","Date","nextResendAvailableAt","setNextResendAvailableAt","formError","setFormError","resendError","setResendError","draftRef","current","skipDraftPersistRef","resendRemainingSeconds","isResendCoolingDown","form","defaultValues","email","password","name","onSubmit","value","undefined","body","parse","invitation_token","result","mutateAsync","membership","success","workspace_name","to","params","wid","workspace_id","accept_error","error","message","token","user","restartLocalCooldown","mapped","kind","setFieldMeta","field","prev","errorMap","onServer","handle","window","setInterval","tickNow","clearInterval","state","values","setFieldValue","onResendVerificationEmail","isPending","nextAvailableAt","next_resend_available_at","title","description","role","type","div","className","aria-disabled","variant","isLoading","onClick","size","asChild","underline","headerTitle","headerDescription","isInvitationEmailLocked","Boolean","invitationRedirect","encodeURIComponent","persistDraft","noValidate","event","preventDefault","stopPropagation","handleSubmit","Field","validators","onBlur","shape","label","id","autoComplete","onChange","handleChange","target","handleBlur","readOnly","iconRight","aria-hidden"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/pages/signup-page.tsx"],"sourcesContent":["import {signupBodySchema, verifyEmailConfirmBodySchema} from '@shipfox/api-auth-dto';\nimport {displayNameFieldError} from '@shipfox/client-ui';\nimport {Button, ButtonLink} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\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 {Link, useNavigate, useSearch} from '@tanstack/react-router';\nimport {useAtom} from 'jotai';\nimport {useEffect, useRef, useState} from 'react';\nimport {AuthShell} from '#/components/auth-shell.js';\nimport {useRefreshAuth} from '#hooks/api/refresh-auth.js';\nimport {useSignupAuth} from '#hooks/api/signup-auth.js';\nimport {useResendEmailVerificationAuth, useVerifyEmailAuth} from '#hooks/api/verify-email-auth.js';\nimport {authFormDraftAtom, initialAuthFormDraft} from '#state/auth.js';\nimport {\n getResendRemainingSeconds,\n parseNextResendAvailableAt,\n} from './email-verification-resend-model.js';\nimport {signupErrorToFormError} from './form-errors.js';\nimport {authErrorMessage} from './form-utils.js';\nimport {\n extractInvitationToken,\n pendingInvitation,\n useInvitationContext,\n} from './invitation-context.js';\n\nexport function SignupPage() {\n const signup = useSignupAuth();\n const verifyEmail = useVerifyEmailAuth();\n const resendEmailVerification = useResendEmailVerificationAuth();\n const refreshAuth = useRefreshAuth();\n const navigate = useNavigate();\n const search = useSearch({strict: false}) as {redirect?: unknown};\n const invitationToken = extractInvitationToken(search.redirect);\n const invitationPreview = useInvitationContext(invitationToken);\n const invitationPending = pendingInvitation(invitationPreview.data);\n const [authFormDraft, setAuthFormDraft] = useAtom(authFormDraftAtom);\n const [emailChallenge, setEmailChallenge] = useState<{email: string; id: string} | undefined>();\n const [now, setNow] = useState(() => Date.now());\n const [nextResendAvailableAt, setNextResendAvailableAt] = useState<number | undefined>();\n const [formError, setFormError] = useState<string | undefined>();\n const [resendError, setResendError] = useState<string | undefined>();\n const draftRef = useRef(authFormDraft);\n draftRef.current = authFormDraft;\n // Set just before clearing the draft on success so the unmount cleanup\n // below does not repersist the just-submitted credentials.\n const skipDraftPersistRef = useRef(false);\n const resendRemainingSeconds = getResendRemainingSeconds({nextResendAvailableAt, now});\n const isResendCoolingDown = resendRemainingSeconds > 0;\n\n const form = useForm({\n defaultValues: {email: authFormDraft.email, password: authFormDraft.password, name: ''},\n onSubmit: async ({value}) => {\n setFormError(undefined);\n try {\n const body = signupBodySchema.parse({\n email: value.email,\n password: value.password,\n name: value.name,\n ...(invitationToken ? {invitation_token: invitationToken} : {}),\n });\n const result = await signup.mutateAsync(body);\n skipDraftPersistRef.current = true;\n setAuthFormDraft(initialAuthFormDraft);\n\n if (invitationToken && result.membership && invitationPending) {\n try {\n await refreshAuth();\n } catch {\n // Refresh failures don't block the success message — the next API\n // call's 401 handling will re-route the user.\n }\n toast.success(`You joined ${invitationPending.workspace_name}.`);\n await navigate({\n to: '/workspaces/$wid',\n params: {wid: result.membership.workspace_id},\n });\n return;\n }\n\n if (invitationToken && result.accept_error) {\n toast.error(result.accept_error.message);\n await navigate({\n to: '/invitations/accept',\n search: {token: invitationToken},\n });\n return;\n }\n\n if (!result.email_challenge) {\n throw new Error('Signup did not return an email verification challenge');\n }\n setEmailChallenge({email: result.user.email, id: result.email_challenge.id});\n verificationForm.reset();\n setResendError(undefined);\n setNow(Date.now());\n setNextResendAvailableAt(\n parseNextResendAvailableAt(result.email_challenge.next_resend_available_at),\n );\n } catch (error) {\n const mapped = signupErrorToFormError(error);\n if (mapped.kind === 'field') {\n form.setFieldMeta(mapped.field, (prev) => ({\n ...prev,\n errorMap: {...prev.errorMap, onServer: mapped.message},\n }));\n } else {\n setFormError(mapped.message);\n }\n }\n },\n });\n\n const verificationForm = useForm({\n defaultValues: {code: ''},\n onSubmit: async ({value}) => {\n if (!emailChallenge || verifyEmail.isPending) return;\n\n setResendError(undefined);\n try {\n await verifyEmail.mutateAsync({\n email: emailChallenge.email,\n challenge_id: emailChallenge.id,\n code: value.code,\n });\n await refreshAuth();\n toast.success('Your email is verified. You are now logged in.');\n await navigate({to: '/', replace: true});\n } catch (error) {\n setResendError(authErrorMessage(error));\n }\n },\n });\n\n useEffect(() => {\n if (!emailChallenge || !nextResendAvailableAt) {\n return;\n }\n\n const current = Date.now();\n setNow(current);\n if (nextResendAvailableAt <= current) {\n return;\n }\n\n const handle = window.setInterval(() => {\n const tickNow = Date.now();\n setNow(tickNow);\n if (nextResendAvailableAt <= tickNow) {\n window.clearInterval(handle);\n }\n }, 1000);\n return () => window.clearInterval(handle);\n }, [emailChallenge, nextResendAvailableAt]);\n\n // When arriving from an invitation link, prefill the email and lock it.\n useEffect(() => {\n if (invitationPending && form.state.values.email !== invitationPending.email) {\n form.setFieldValue('email', invitationPending.email);\n setAuthFormDraft((current) => ({...current, email: invitationPending.email}));\n }\n }, [invitationPending, form, setAuthFormDraft]);\n\n // Sync form values back to the Jotai draft on unmount (only email + password\n // — name is intentionally not persisted across navigation). Skipped after a\n // successful signup because we just intentionally cleared the draft.\n useEffect(() => {\n return () => {\n if (skipDraftPersistRef.current) return;\n const {email, password} = form.state.values;\n if (email !== draftRef.current.email || password !== draftRef.current.password) {\n setAuthFormDraft({email, password});\n }\n };\n }, [form, setAuthFormDraft]);\n\n async function onResendVerificationEmail() {\n if (!emailChallenge || isResendCoolingDown || resendEmailVerification.isPending) return;\n\n setResendError(undefined);\n try {\n const result = await resendEmailVerification.mutateAsync({\n email: emailChallenge.email,\n challenge_id: emailChallenge.id,\n });\n const nextAvailableAt = parseNextResendAvailableAt(result.next_resend_available_at);\n setNow(Date.now());\n if (nextAvailableAt !== undefined) {\n setNextResendAvailableAt(nextAvailableAt);\n }\n toast.success('If another verification email can be sent, it will arrive shortly.');\n } catch (error) {\n setResendError(authErrorMessage(error));\n }\n }\n\n if (emailChallenge) {\n return (\n <AuthShell\n title=\"Check your email\"\n description={`We sent an eight-digit verification code to ${emailChallenge.email}.`}\n >\n {resendError ? (\n <Callout role=\"alert\" type=\"error\">\n {resendError}\n </Callout>\n ) : null}\n <form\n className=\"flex flex-col gap-8\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n void verificationForm.handleSubmit();\n }}\n >\n <verificationForm.Field\n name=\"code\"\n validators={{\n onBlur: verifyEmailConfirmBodySchema.shape.code,\n onSubmit: verifyEmailConfirmBodySchema.shape.code,\n }}\n >\n {(field) => (\n <FormField label=\"Verification code\" id=\"verification-code\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"one-time-code\"\n inputMode=\"numeric\"\n maxLength={8}\n pattern=\"[0-9]{8}\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value.replace(/\\D/gu, ''))}\n onBlur={field.handleBlur}\n />\n </FormField>\n )}\n </verificationForm.Field>\n <Button className=\"w-full\" type=\"submit\" isLoading={verifyEmail.isPending}>\n Verify email\n </Button>\n <Button\n aria-disabled={isResendCoolingDown ? true : undefined}\n className=\"w-full aria-disabled:cursor-not-allowed aria-disabled:opacity-70\"\n variant=\"secondary\"\n type=\"button\"\n isLoading={resendEmailVerification.isPending}\n onClick={onResendVerificationEmail}\n >\n {resendEmailVerification.isPending\n ? 'Sending email...'\n : isResendCoolingDown\n ? `Resend in ${resendRemainingSeconds}s`\n : 'Resend verification email'}\n </Button>\n </form>\n <Button\n className=\"w-full\"\n variant=\"transparent\"\n type=\"button\"\n onClick={() => {\n setEmailChallenge(undefined);\n setResendError(undefined);\n }}\n >\n Use another email\n </Button>\n <Text size=\"sm\" className=\"text-center text-foreground-neutral-subtle\">\n Already verified?{' '}\n <ButtonLink asChild variant=\"interactive\" underline>\n <Link to=\"/auth/login\">Log in</Link>\n </ButtonLink>\n </Text>\n </AuthShell>\n );\n }\n\n const headerTitle = invitationPending\n ? `Join ${invitationPending.workspace_name}`\n : 'Create your Shipfox account';\n const headerDescription = invitationPending\n ? `Create an account to accept your invitation.`\n : 'Start with your email and a password.';\n const isInvitationEmailLocked = Boolean(invitationPending);\n const invitationRedirect = invitationToken\n ? `/invitations/accept?token=${encodeURIComponent(invitationToken)}`\n : undefined;\n\n function persistDraft() {\n const {email, password} = form.state.values;\n setAuthFormDraft({email, password});\n }\n\n return (\n <AuthShell title={headerTitle} description={headerDescription}>\n <form\n className=\"flex flex-col gap-18\"\n noValidate\n onSubmit={(event) => {\n event.preventDefault();\n event.stopPropagation();\n void form.handleSubmit();\n }}\n >\n {formError ? (\n <Callout role=\"alert\" type=\"error\">\n {formError}\n </Callout>\n ) : null}\n <form.Field\n name=\"name\"\n validators={{\n onBlur: ({value}) => displayNameFieldError(value, 'Name', signupBodySchema.shape.name),\n onSubmit: ({value}) =>\n displayNameFieldError(value, 'Name', signupBodySchema.shape.name),\n }}\n >\n {(field) => (\n <FormField label=\"Name\" id=\"name\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"name\"\n name=\"name\"\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 <form.Field\n name=\"email\"\n validators={{\n onBlur: signupBodySchema.shape.email,\n onSubmit: signupBodySchema.shape.email,\n }}\n >\n {(field) => (\n <FormField label=\"Email\" id=\"email\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"email\"\n name=\"email\"\n type=\"email\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={() => {\n field.handleBlur();\n persistDraft();\n }}\n readOnly={isInvitationEmailLocked}\n iconRight={\n isInvitationEmailLocked ? (\n <Icon\n aria-hidden=\"true\"\n className=\"size-16 text-foreground-neutral-disabled\"\n name=\"lockLine\"\n />\n ) : undefined\n }\n />\n </FormField>\n )}\n </form.Field>\n <form.Field\n name=\"password\"\n validators={{\n onBlur: signupBodySchema.shape.password,\n onSubmit: signupBodySchema.shape.password,\n }}\n >\n {(field) => (\n <FormField label=\"Password\" id=\"password\" error={fieldError(field)}>\n <FormFieldInput\n autoComplete=\"new-password\"\n name=\"password\"\n type=\"password\"\n value={field.state.value}\n onChange={(event) => field.handleChange(event.target.value)}\n onBlur={() => {\n field.handleBlur();\n persistDraft();\n }}\n />\n </FormField>\n )}\n </form.Field>\n <Button className=\"w-full\" isLoading={signup.isPending} type=\"submit\">\n {signup.isPending ? 'Creating account...' : 'Create account'}\n </Button>\n </form>\n <Text size=\"sm\" className=\"text-center text-foreground-neutral-subtle\">\n Already have an account?{' '}\n <ButtonLink asChild variant=\"interactive\" underline>\n <Link\n to=\"/auth/login\"\n search={invitationRedirect ? {redirect: invitationRedirect} : undefined}\n >\n Log in\n </Link>\n </ButtonLink>\n </Text>\n </AuthShell>\n );\n}\n"],"names":["signupBodySchema","verifyEmailConfirmBodySchema","displayNameFieldError","Button","ButtonLink","Callout","FormField","FormFieldInput","fieldError","Icon","toast","Text","useForm","Link","useNavigate","useSearch","useAtom","useEffect","useRef","useState","AuthShell","useRefreshAuth","useSignupAuth","useResendEmailVerificationAuth","useVerifyEmailAuth","authFormDraftAtom","initialAuthFormDraft","getResendRemainingSeconds","parseNextResendAvailableAt","signupErrorToFormError","authErrorMessage","extractInvitationToken","pendingInvitation","useInvitationContext","SignupPage","signup","verifyEmail","resendEmailVerification","refreshAuth","navigate","search","strict","invitationToken","redirect","invitationPreview","invitationPending","data","authFormDraft","setAuthFormDraft","emailChallenge","setEmailChallenge","now","setNow","Date","nextResendAvailableAt","setNextResendAvailableAt","formError","setFormError","resendError","setResendError","draftRef","current","skipDraftPersistRef","resendRemainingSeconds","isResendCoolingDown","form","defaultValues","email","password","name","onSubmit","value","undefined","body","parse","invitation_token","result","mutateAsync","membership","success","workspace_name","to","params","wid","workspace_id","accept_error","error","message","token","email_challenge","Error","user","id","verificationForm","reset","next_resend_available_at","mapped","kind","setFieldMeta","field","prev","errorMap","onServer","code","isPending","challenge_id","replace","handle","window","setInterval","tickNow","clearInterval","state","values","setFieldValue","onResendVerificationEmail","nextAvailableAt","title","description","role","type","className","noValidate","event","preventDefault","handleSubmit","Field","validators","onBlur","shape","label","autoComplete","inputMode","maxLength","pattern","onChange","handleChange","target","handleBlur","isLoading","aria-disabled","variant","onClick","size","asChild","underline","headerTitle","headerDescription","isInvitationEmailLocked","Boolean","invitationRedirect","encodeURIComponent","persistDraft","stopPropagation","readOnly","iconRight","aria-hidden"],"mappings":"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"}