@shipfox/client-invitations 13.0.0 → 14.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.
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 12 files with swc (265.2ms)
2
+ Successfully compiled: 12 files with swc (293.44ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @shipfox/client-invitations
2
2
 
3
+ ## 14.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 88bf8e8: Migrates the shell, auth, secrets, logs, workspace-settings, config, and invitations
8
+ surfaces to semantic spacing roles and brings them under the `no-raw-spacing` Biome
9
+ plugin. Adds shared menu-surface and edge-specific panel roles for existing spacing
10
+ contracts.
11
+ - Updated dependencies [88bf8e8]
12
+ - Updated dependencies [6aa6c7a]
13
+ - Updated dependencies [5c56ba6]
14
+ - @shipfox/react-ui@1.0.0
15
+ - @shipfox/client-shell@14.0.1
16
+ - @shipfox/client-ui@14.0.1
17
+
18
+ ## 14.0.0
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies [baa7594]
23
+ - Updated dependencies [f8a98cb]
24
+ - Updated dependencies [1267eb3]
25
+ - Updated dependencies [b2d4550]
26
+ - @shipfox/react-ui@0.5.0
27
+ - @shipfox/client-ui@14.0.0
28
+ - @shipfox/client-shell@14.0.0
29
+
3
30
  ## 13.0.0
4
31
 
5
32
  ### Major Changes
@@ -255,7 +255,7 @@ export function InvitationAcceptPage() {
255
255
  description: inviterLine,
256
256
  children: [
257
257
  /*#__PURE__*/ _jsxs("div", {
258
- className: "flex flex-col gap-16",
258
+ className: "flex flex-col gap-group",
259
259
  children: [
260
260
  /*#__PURE__*/ _jsx(Button, {
261
261
  asChild: true,
@@ -309,7 +309,7 @@ export function InvitationAcceptPage() {
309
309
  ]
310
310
  }),
311
311
  /*#__PURE__*/ _jsxs("div", {
312
- className: "flex flex-col gap-16",
312
+ className: "flex flex-col gap-group",
313
313
  children: [
314
314
  /*#__PURE__*/ _jsx(Button, {
315
315
  asChild: true,
@@ -401,7 +401,7 @@ export function InvitationAcceptPage() {
401
401
  title: data.workspaceName,
402
402
  description: inviterLine,
403
403
  children: /*#__PURE__*/ _jsxs("div", {
404
- className: "flex flex-col items-center gap-12",
404
+ className: "flex flex-col items-center gap-cluster",
405
405
  "aria-live": "polite",
406
406
  children: [
407
407
  /*#__PURE__*/ _jsx(ShipfoxLoader, {}),
@@ -420,7 +420,7 @@ export function InvitationAcceptPage() {
420
420
  }
421
421
  function CenteredLoader() {
422
422
  return /*#__PURE__*/ _jsx("div", {
423
- className: "flex justify-center py-16",
423
+ className: "flex justify-center py-row",
424
424
  "aria-busy": "true",
425
425
  children: /*#__PURE__*/ _jsx(ShipfoxLoader, {})
426
426
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pages/invitation-accept-page.tsx"],"sourcesContent":["import {\n AuthShell,\n useAuthState,\n useRefreshAuth,\n useRouteSearch,\n} from '@shipfox/client-shell/runtime';\nimport {createSingleFlight} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {ShipfoxLoader} from '@shipfox/react-ui/loader';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {formatDate} from '@shipfox/react-ui/utils';\nimport {Link, useNavigate} from '@tanstack/react-router';\nimport {useCallback, useEffect, useRef, useState} from 'react';\nimport {completeInvitationAcceptance} from '#complete-acceptance.js';\nimport {useAcceptInvitation} from '#hooks/api/accept-invitation.js';\nimport {usePreviewInvitation} from '#hooks/api/preview-invitation.js';\nimport {validateInvitationAcceptSearch} from '../routes/inputs.js';\n\nconst invitationAccepts = createSingleFlight<string, void>();\nconst toastedTerminals = new Set<string>();\nconst TOASTED_TERMINALS_MAX = 32;\n\nexport function InvitationAcceptPage() {\n const {token} = useRouteSearch(validateInvitationAcceptSearch);\n const navigate = useNavigate();\n const auth = useAuthState();\n const refreshAuth = useRefreshAuth();\n const preview = usePreviewInvitation(token);\n const accept = useAcceptInvitation();\n const hasKickedAccept = useRef(false);\n const hasRetriedWorkspaceHydration = useRef(false);\n const [authRefreshFailed, setAuthRefreshFailed] = useState(false);\n const [pendingWorkspaceId, setPendingWorkspaceId] = useState<string>();\n\n useEffect(() => {\n if (!pendingWorkspaceId || auth.isLoading || !auth.isAuthenticated) return;\n if (!auth.workspaces.some(({id}) => id === pendingWorkspaceId)) {\n if (hasRetriedWorkspaceHydration.current) {\n setPendingWorkspaceId(undefined);\n setAuthRefreshFailed(true);\n return;\n }\n hasRetriedWorkspaceHydration.current = true;\n void refreshAuth().catch(() => {\n setPendingWorkspaceId(undefined);\n setAuthRefreshFailed(true);\n });\n return;\n }\n\n setPendingWorkspaceId(undefined);\n void navigate({to: '/', replace: true});\n }, [\n auth.isAuthenticated,\n auth.isLoading,\n auth.workspaces,\n navigate,\n pendingWorkspaceId,\n refreshAuth,\n ]);\n\n useEffect(() => {\n hasKickedAccept.current = false;\n hasRetriedWorkspaceHydration.current = false;\n setAuthRefreshFailed(false);\n setPendingWorkspaceId(undefined);\n if (!token) {\n toast.error('This invitation link is missing a token.');\n const timeout = window.setTimeout(() => {\n navigate({to: '/', replace: true});\n }, 2000);\n return () => window.clearTimeout(timeout);\n }\n return undefined;\n }, [navigate, token]);\n\n const completeAccept = useCallback(\n async (workspaceId: string, workspaceName: string) => {\n const userId = auth.user?.id;\n if (!userId) throw new Error('Cannot complete invitation without an authenticated user.');\n const refreshed = await completeInvitationAcceptance({\n userId,\n workspaceId,\n workspaceName,\n refreshAuth,\n // Wait for the refreshed workspace list to reach the router context\n // before resolving the root route.\n navigate: () => setPendingWorkspaceId(workspaceId),\n });\n if (!refreshed) setAuthRefreshFailed(true);\n },\n [auth.user?.id, refreshAuth],\n );\n\n const runAccept = useCallback(\n async (params: {token: string; workspaceName: string}) => {\n const result = await accept.mutateAsync({token: params.token});\n await completeAccept(result.membership.workspaceId, params.workspaceName);\n },\n [accept, completeAccept],\n );\n\n // Auto-accept when authenticated and emails match (also handles already_used\n // for the canonical authenticated path: backend returns already_member=true).\n useEffect(() => {\n if (!token) return;\n if (auth.isLoading) return;\n if (hasKickedAccept.current) return;\n const data = preview.data;\n if (!data) return;\n if (data.status !== 'pending') return;\n if (!auth.isAuthenticated) return;\n\n const authedEmail = auth.user?.email?.toLowerCase();\n if (authedEmail !== data.email.toLowerCase()) return;\n\n hasKickedAccept.current = true;\n invitationAccepts\n .run(token, async () => await runAccept({token, workspaceName: data.workspaceName}))\n .catch(() => {\n // The mutation surfaces its error via accept.error; the UI re-renders\n // into the auth-match-error state below.\n });\n }, [auth.isAuthenticated, auth.isLoading, auth.user?.email, preview.data, runAccept, token]);\n\n if (!token) {\n return (\n <AuthShell title=\"Invalid link\" description=\"This invitation link is incomplete.\">\n <Callout role=\"alert\" type=\"error\">\n This invitation link is missing a token. Ask your administrator to resend it.\n </Callout>\n <Text size=\"sm\" className=\"text-center text-foreground-neutral-muted\" aria-live=\"polite\">\n Redirecting to the dashboard…\n </Text>\n </AuthShell>\n );\n }\n\n if (preview.isLoading) {\n return (\n <AuthShell title=\"Loading invitation\" description=\"One moment please.\">\n <CenteredLoader />\n </AuthShell>\n );\n }\n\n if (preview.isError) {\n return (\n <AuthShell title=\"Couldn't load invitation\" description=\"Try again in a moment.\">\n <Callout role=\"alert\" type=\"error\">\n We couldn't reach the server. Check your connection and retry.\n </Callout>\n <Button className=\"w-full\" onClick={() => preview.refetch()}>\n Try again\n </Button>\n </AuthShell>\n );\n }\n\n const data = preview.data;\n if (!data) {\n return null;\n }\n\n if (data.status === 'invalid') {\n notifyOnce(`invalid:${token}`, () => toast.error('This invitation link is no longer valid.'));\n return (\n <AuthShell title=\"Invalid invitation\" description=\"The link you used didn't work.\">\n <Callout role=\"alert\" type=\"error\">\n This invitation link is not valid. Ask your administrator to send a new one.\n </Callout>\n <GoHomeButton navigate={navigate} />\n </AuthShell>\n );\n }\n\n if (data.status === 'expired') {\n notifyOnce(`expired:${token}`, () => toast.error('This invitation has expired.'));\n return (\n <AuthShell title=\"Invitation expired\" description=\"The link is no longer accepting joins.\">\n <Callout role=\"alert\" type=\"error\">\n This invitation expired on {formatDate(data.expiresAt)}. Ask your administrator to send a\n new one.\n </Callout>\n <GoHomeButton navigate={navigate} />\n </AuthShell>\n );\n }\n\n if (data.status === 'already_used') {\n notifyOnce(`already-used:${token}`, () =>\n toast.info(`This invitation has already been accepted.`),\n );\n return (\n <AuthShell title=\"Invitation already used\" description={data.workspaceName}>\n <Callout role=\"alert\" type=\"info\">\n This invitation has already been accepted.{' '}\n {auth.isAuthenticated\n ? `Open your dashboard to access ${data.workspaceName} if your account is a member.`\n : `Log in to access ${data.workspaceName}.`}\n </Callout>\n {auth.isAuthenticated ? null : (\n <Button asChild className=\"w-full\">\n <Link to=\"/auth/login\">Log in</Link>\n </Button>\n )}\n <GoHomeButton navigate={navigate} secondary />\n </AuthShell>\n );\n }\n\n const inviterLine =\n data.invitedByDisplay != null\n ? `Invited by ${data.invitedByDisplay} to join as ${data.email}.`\n : `Invited to join as ${data.email}.`;\n\n if (!auth.isAuthenticated) {\n const redirect = `/invitations/accept?token=${encodeURIComponent(token)}`;\n const signupHref = `/auth/signup?redirect=${encodeURIComponent(redirect)}`;\n const loginHref = `/auth/login?redirect=${encodeURIComponent(redirect)}`;\n return (\n <AuthShell title={data.workspaceName} description={inviterLine}>\n <div className=\"flex flex-col gap-16\">\n <Button asChild className=\"w-full\">\n <Link to={signupHref}>Create account</Link>\n </Button>\n <Button asChild className=\"w-full\" variant=\"secondary\">\n <Link to={loginHref}>I already have an account</Link>\n </Button>\n </div>\n <Text size=\"xs\" className=\"text-center text-foreground-neutral-muted\">\n Not {data.email}? Contact your administrator.\n </Text>\n </AuthShell>\n );\n }\n\n const viewerEmail = auth.user?.email?.toLowerCase();\n const inviteeEmail = data.email.toLowerCase();\n if (viewerEmail !== inviteeEmail) {\n const redirect = `/invitations/accept?token=${encodeURIComponent(token)}`;\n const logoutHref = `/auth/logout?redirect=${encodeURIComponent(redirect)}`;\n return (\n <AuthShell title={data.workspaceName} description={inviterLine}>\n <Callout role=\"alert\" type=\"warning\">\n You're signed in as {auth.user?.email}, but this invitation is for {data.email}.\n </Callout>\n <div className=\"flex flex-col gap-16\">\n <Button asChild className=\"w-full\">\n <Link to={logoutHref}>Log out and continue</Link>\n </Button>\n <Button\n className=\"w-full\"\n variant=\"secondary\"\n onClick={() => navigate({to: '/', replace: true})}\n >\n Cancel\n </Button>\n </div>\n </AuthShell>\n );\n }\n\n if (authRefreshFailed) {\n return (\n <AuthShell title={data.workspaceName} description={inviterLine}>\n <Callout role=\"alert\" type=\"error\">\n You joined {data.workspaceName}, but we couldn't refresh your session. Retry to continue\n to the workspace.\n </Callout>\n <Button\n className=\"w-full\"\n onClick={async () => {\n try {\n await refreshAuth();\n setAuthRefreshFailed(false);\n hasRetriedWorkspaceHydration.current = false;\n setPendingWorkspaceId(data.workspaceId);\n } catch {\n setAuthRefreshFailed(true);\n }\n }}\n >\n Retry\n </Button>\n </AuthShell>\n );\n }\n\n // Authenticated + matches — auto-accept is in flight or about to render its\n // result. Show either the pending state or the error state.\n if (accept.isError) {\n return (\n <AuthShell title={data.workspaceName} description={inviterLine}>\n <Callout role=\"alert\" type=\"error\">\n We couldn't add you to {data.workspaceName}. Try again in a moment.\n </Callout>\n <Button\n className=\"w-full\"\n isLoading={accept.isPending}\n onClick={() => {\n runAccept({token, workspaceName: data.workspaceName}).catch(() => {\n // The mutation state drives the rendered error; avoid an\n // unhandled rejection from the click handler.\n });\n }}\n >\n Try again\n </Button>\n </AuthShell>\n );\n }\n\n return (\n <AuthShell title={data.workspaceName} description={inviterLine}>\n <div className=\"flex flex-col items-center gap-12\" aria-live=\"polite\">\n <ShipfoxLoader />\n <Text size=\"sm\" className=\"text-foreground-neutral-subtle\">\n Adding you to {data.workspaceName}…\n </Text>\n </div>\n </AuthShell>\n );\n}\n\nfunction CenteredLoader() {\n return (\n <div className=\"flex justify-center py-16\" aria-busy=\"true\">\n <ShipfoxLoader />\n </div>\n );\n}\n\nfunction GoHomeButton({\n navigate,\n secondary,\n}: {\n navigate: ReturnType<typeof useNavigate>;\n secondary?: boolean;\n}) {\n return (\n <Button\n className=\"w-full\"\n variant={secondary ? 'secondary' : 'primary'}\n onClick={() => navigate({to: '/', replace: true})}\n >\n Go to dashboard\n </Button>\n );\n}\n\nfunction notifyOnce(key: string, fn: () => void): void {\n if (toastedTerminals.has(key)) return;\n if (toastedTerminals.size >= TOASTED_TERMINALS_MAX) {\n const oldest = toastedTerminals.values().next().value;\n if (oldest !== undefined) toastedTerminals.delete(oldest);\n }\n toastedTerminals.add(key);\n fn();\n}\n"],"names":["AuthShell","useAuthState","useRefreshAuth","useRouteSearch","createSingleFlight","Button","Callout","ShipfoxLoader","toast","Text","formatDate","Link","useNavigate","useCallback","useEffect","useRef","useState","completeInvitationAcceptance","useAcceptInvitation","usePreviewInvitation","validateInvitationAcceptSearch","invitationAccepts","toastedTerminals","Set","TOASTED_TERMINALS_MAX","InvitationAcceptPage","token","navigate","auth","refreshAuth","preview","accept","hasKickedAccept","hasRetriedWorkspaceHydration","authRefreshFailed","setAuthRefreshFailed","pendingWorkspaceId","setPendingWorkspaceId","isLoading","isAuthenticated","workspaces","some","id","current","undefined","catch","to","replace","error","timeout","window","setTimeout","clearTimeout","completeAccept","workspaceId","workspaceName","userId","user","Error","refreshed","runAccept","params","result","mutateAsync","membership","data","status","authedEmail","email","toLowerCase","run","title","description","role","type","size","className","aria-live","CenteredLoader","isError","onClick","refetch","notifyOnce","GoHomeButton","expiresAt","info","asChild","secondary","inviterLine","invitedByDisplay","redirect","encodeURIComponent","signupHref","loginHref","div","variant","viewerEmail","inviteeEmail","logoutHref","isPending","aria-busy","key","fn","has","oldest","values","next","value","delete","add"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/pages/invitation-accept-page.tsx"],"sourcesContent":["import {\n AuthShell,\n useAuthState,\n useRefreshAuth,\n useRouteSearch,\n} from '@shipfox/client-shell/runtime';\nimport {createSingleFlight} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {ShipfoxLoader} from '@shipfox/react-ui/loader';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {formatDate} from '@shipfox/react-ui/utils';\nimport {Link, useNavigate} from '@tanstack/react-router';\nimport {useCallback, useEffect, useRef, useState} from 'react';\nimport {completeInvitationAcceptance} from '#complete-acceptance.js';\nimport {useAcceptInvitation} from '#hooks/api/accept-invitation.js';\nimport {usePreviewInvitation} from '#hooks/api/preview-invitation.js';\nimport {validateInvitationAcceptSearch} from '../routes/inputs.js';\n\nconst invitationAccepts = createSingleFlight<string, void>();\nconst toastedTerminals = new Set<string>();\nconst TOASTED_TERMINALS_MAX = 32;\n\nexport function InvitationAcceptPage() {\n const {token} = useRouteSearch(validateInvitationAcceptSearch);\n const navigate = useNavigate();\n const auth = useAuthState();\n const refreshAuth = useRefreshAuth();\n const preview = usePreviewInvitation(token);\n const accept = useAcceptInvitation();\n const hasKickedAccept = useRef(false);\n const hasRetriedWorkspaceHydration = useRef(false);\n const [authRefreshFailed, setAuthRefreshFailed] = useState(false);\n const [pendingWorkspaceId, setPendingWorkspaceId] = useState<string>();\n\n useEffect(() => {\n if (!pendingWorkspaceId || auth.isLoading || !auth.isAuthenticated) return;\n if (!auth.workspaces.some(({id}) => id === pendingWorkspaceId)) {\n if (hasRetriedWorkspaceHydration.current) {\n setPendingWorkspaceId(undefined);\n setAuthRefreshFailed(true);\n return;\n }\n hasRetriedWorkspaceHydration.current = true;\n void refreshAuth().catch(() => {\n setPendingWorkspaceId(undefined);\n setAuthRefreshFailed(true);\n });\n return;\n }\n\n setPendingWorkspaceId(undefined);\n void navigate({to: '/', replace: true});\n }, [\n auth.isAuthenticated,\n auth.isLoading,\n auth.workspaces,\n navigate,\n pendingWorkspaceId,\n refreshAuth,\n ]);\n\n useEffect(() => {\n hasKickedAccept.current = false;\n hasRetriedWorkspaceHydration.current = false;\n setAuthRefreshFailed(false);\n setPendingWorkspaceId(undefined);\n if (!token) {\n toast.error('This invitation link is missing a token.');\n const timeout = window.setTimeout(() => {\n navigate({to: '/', replace: true});\n }, 2000);\n return () => window.clearTimeout(timeout);\n }\n return undefined;\n }, [navigate, token]);\n\n const completeAccept = useCallback(\n async (workspaceId: string, workspaceName: string) => {\n const userId = auth.user?.id;\n if (!userId) throw new Error('Cannot complete invitation without an authenticated user.');\n const refreshed = await completeInvitationAcceptance({\n userId,\n workspaceId,\n workspaceName,\n refreshAuth,\n // Wait for the refreshed workspace list to reach the router context\n // before resolving the root route.\n navigate: () => setPendingWorkspaceId(workspaceId),\n });\n if (!refreshed) setAuthRefreshFailed(true);\n },\n [auth.user?.id, refreshAuth],\n );\n\n const runAccept = useCallback(\n async (params: {token: string; workspaceName: string}) => {\n const result = await accept.mutateAsync({token: params.token});\n await completeAccept(result.membership.workspaceId, params.workspaceName);\n },\n [accept, completeAccept],\n );\n\n // Auto-accept when authenticated and emails match (also handles already_used\n // for the canonical authenticated path: backend returns already_member=true).\n useEffect(() => {\n if (!token) return;\n if (auth.isLoading) return;\n if (hasKickedAccept.current) return;\n const data = preview.data;\n if (!data) return;\n if (data.status !== 'pending') return;\n if (!auth.isAuthenticated) return;\n\n const authedEmail = auth.user?.email?.toLowerCase();\n if (authedEmail !== data.email.toLowerCase()) return;\n\n hasKickedAccept.current = true;\n invitationAccepts\n .run(token, async () => await runAccept({token, workspaceName: data.workspaceName}))\n .catch(() => {\n // The mutation surfaces its error via accept.error; the UI re-renders\n // into the auth-match-error state below.\n });\n }, [auth.isAuthenticated, auth.isLoading, auth.user?.email, preview.data, runAccept, token]);\n\n if (!token) {\n return (\n <AuthShell title=\"Invalid link\" description=\"This invitation link is incomplete.\">\n <Callout role=\"alert\" type=\"error\">\n This invitation link is missing a token. Ask your administrator to resend it.\n </Callout>\n <Text size=\"sm\" className=\"text-center text-foreground-neutral-muted\" aria-live=\"polite\">\n Redirecting to the dashboard…\n </Text>\n </AuthShell>\n );\n }\n\n if (preview.isLoading) {\n return (\n <AuthShell title=\"Loading invitation\" description=\"One moment please.\">\n <CenteredLoader />\n </AuthShell>\n );\n }\n\n if (preview.isError) {\n return (\n <AuthShell title=\"Couldn't load invitation\" description=\"Try again in a moment.\">\n <Callout role=\"alert\" type=\"error\">\n We couldn't reach the server. Check your connection and retry.\n </Callout>\n <Button className=\"w-full\" onClick={() => preview.refetch()}>\n Try again\n </Button>\n </AuthShell>\n );\n }\n\n const data = preview.data;\n if (!data) {\n return null;\n }\n\n if (data.status === 'invalid') {\n notifyOnce(`invalid:${token}`, () => toast.error('This invitation link is no longer valid.'));\n return (\n <AuthShell title=\"Invalid invitation\" description=\"The link you used didn't work.\">\n <Callout role=\"alert\" type=\"error\">\n This invitation link is not valid. Ask your administrator to send a new one.\n </Callout>\n <GoHomeButton navigate={navigate} />\n </AuthShell>\n );\n }\n\n if (data.status === 'expired') {\n notifyOnce(`expired:${token}`, () => toast.error('This invitation has expired.'));\n return (\n <AuthShell title=\"Invitation expired\" description=\"The link is no longer accepting joins.\">\n <Callout role=\"alert\" type=\"error\">\n This invitation expired on {formatDate(data.expiresAt)}. Ask your administrator to send a\n new one.\n </Callout>\n <GoHomeButton navigate={navigate} />\n </AuthShell>\n );\n }\n\n if (data.status === 'already_used') {\n notifyOnce(`already-used:${token}`, () =>\n toast.info(`This invitation has already been accepted.`),\n );\n return (\n <AuthShell title=\"Invitation already used\" description={data.workspaceName}>\n <Callout role=\"alert\" type=\"info\">\n This invitation has already been accepted.{' '}\n {auth.isAuthenticated\n ? `Open your dashboard to access ${data.workspaceName} if your account is a member.`\n : `Log in to access ${data.workspaceName}.`}\n </Callout>\n {auth.isAuthenticated ? null : (\n <Button asChild className=\"w-full\">\n <Link to=\"/auth/login\">Log in</Link>\n </Button>\n )}\n <GoHomeButton navigate={navigate} secondary />\n </AuthShell>\n );\n }\n\n const inviterLine =\n data.invitedByDisplay != null\n ? `Invited by ${data.invitedByDisplay} to join as ${data.email}.`\n : `Invited to join as ${data.email}.`;\n\n if (!auth.isAuthenticated) {\n const redirect = `/invitations/accept?token=${encodeURIComponent(token)}`;\n const signupHref = `/auth/signup?redirect=${encodeURIComponent(redirect)}`;\n const loginHref = `/auth/login?redirect=${encodeURIComponent(redirect)}`;\n return (\n <AuthShell title={data.workspaceName} description={inviterLine}>\n <div className=\"flex flex-col gap-group\">\n <Button asChild className=\"w-full\">\n <Link to={signupHref}>Create account</Link>\n </Button>\n <Button asChild className=\"w-full\" variant=\"secondary\">\n <Link to={loginHref}>I already have an account</Link>\n </Button>\n </div>\n <Text size=\"xs\" className=\"text-center text-foreground-neutral-muted\">\n Not {data.email}? Contact your administrator.\n </Text>\n </AuthShell>\n );\n }\n\n const viewerEmail = auth.user?.email?.toLowerCase();\n const inviteeEmail = data.email.toLowerCase();\n if (viewerEmail !== inviteeEmail) {\n const redirect = `/invitations/accept?token=${encodeURIComponent(token)}`;\n const logoutHref = `/auth/logout?redirect=${encodeURIComponent(redirect)}`;\n return (\n <AuthShell title={data.workspaceName} description={inviterLine}>\n <Callout role=\"alert\" type=\"warning\">\n You're signed in as {auth.user?.email}, but this invitation is for {data.email}.\n </Callout>\n <div className=\"flex flex-col gap-group\">\n <Button asChild className=\"w-full\">\n <Link to={logoutHref}>Log out and continue</Link>\n </Button>\n <Button\n className=\"w-full\"\n variant=\"secondary\"\n onClick={() => navigate({to: '/', replace: true})}\n >\n Cancel\n </Button>\n </div>\n </AuthShell>\n );\n }\n\n if (authRefreshFailed) {\n return (\n <AuthShell title={data.workspaceName} description={inviterLine}>\n <Callout role=\"alert\" type=\"error\">\n You joined {data.workspaceName}, but we couldn't refresh your session. Retry to continue\n to the workspace.\n </Callout>\n <Button\n className=\"w-full\"\n onClick={async () => {\n try {\n await refreshAuth();\n setAuthRefreshFailed(false);\n hasRetriedWorkspaceHydration.current = false;\n setPendingWorkspaceId(data.workspaceId);\n } catch {\n setAuthRefreshFailed(true);\n }\n }}\n >\n Retry\n </Button>\n </AuthShell>\n );\n }\n\n // Authenticated + matches — auto-accept is in flight or about to render its\n // result. Show either the pending state or the error state.\n if (accept.isError) {\n return (\n <AuthShell title={data.workspaceName} description={inviterLine}>\n <Callout role=\"alert\" type=\"error\">\n We couldn't add you to {data.workspaceName}. Try again in a moment.\n </Callout>\n <Button\n className=\"w-full\"\n isLoading={accept.isPending}\n onClick={() => {\n runAccept({token, workspaceName: data.workspaceName}).catch(() => {\n // The mutation state drives the rendered error; avoid an\n // unhandled rejection from the click handler.\n });\n }}\n >\n Try again\n </Button>\n </AuthShell>\n );\n }\n\n return (\n <AuthShell title={data.workspaceName} description={inviterLine}>\n <div className=\"flex flex-col items-center gap-cluster\" aria-live=\"polite\">\n <ShipfoxLoader />\n <Text size=\"sm\" className=\"text-foreground-neutral-subtle\">\n Adding you to {data.workspaceName}…\n </Text>\n </div>\n </AuthShell>\n );\n}\n\nfunction CenteredLoader() {\n return (\n <div className=\"flex justify-center py-row\" aria-busy=\"true\">\n <ShipfoxLoader />\n </div>\n );\n}\n\nfunction GoHomeButton({\n navigate,\n secondary,\n}: {\n navigate: ReturnType<typeof useNavigate>;\n secondary?: boolean;\n}) {\n return (\n <Button\n className=\"w-full\"\n variant={secondary ? 'secondary' : 'primary'}\n onClick={() => navigate({to: '/', replace: true})}\n >\n Go to dashboard\n </Button>\n );\n}\n\nfunction notifyOnce(key: string, fn: () => void): void {\n if (toastedTerminals.has(key)) return;\n if (toastedTerminals.size >= TOASTED_TERMINALS_MAX) {\n const oldest = toastedTerminals.values().next().value;\n if (oldest !== undefined) toastedTerminals.delete(oldest);\n }\n toastedTerminals.add(key);\n fn();\n}\n"],"names":["AuthShell","useAuthState","useRefreshAuth","useRouteSearch","createSingleFlight","Button","Callout","ShipfoxLoader","toast","Text","formatDate","Link","useNavigate","useCallback","useEffect","useRef","useState","completeInvitationAcceptance","useAcceptInvitation","usePreviewInvitation","validateInvitationAcceptSearch","invitationAccepts","toastedTerminals","Set","TOASTED_TERMINALS_MAX","InvitationAcceptPage","token","navigate","auth","refreshAuth","preview","accept","hasKickedAccept","hasRetriedWorkspaceHydration","authRefreshFailed","setAuthRefreshFailed","pendingWorkspaceId","setPendingWorkspaceId","isLoading","isAuthenticated","workspaces","some","id","current","undefined","catch","to","replace","error","timeout","window","setTimeout","clearTimeout","completeAccept","workspaceId","workspaceName","userId","user","Error","refreshed","runAccept","params","result","mutateAsync","membership","data","status","authedEmail","email","toLowerCase","run","title","description","role","type","size","className","aria-live","CenteredLoader","isError","onClick","refetch","notifyOnce","GoHomeButton","expiresAt","info","asChild","secondary","inviterLine","invitedByDisplay","redirect","encodeURIComponent","signupHref","loginHref","div","variant","viewerEmail","inviteeEmail","logoutHref","isPending","aria-busy","key","fn","has","oldest","values","next","value","delete","add"],"mappings":"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"}