@stackframe/stack 2.8.54 → 2.8.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/credential-sign-up.js.map +1 -1
- package/dist/components/user-button.js +4 -4
- package/dist/components/user-button.js.map +1 -1
- package/dist/components-page/account-settings/email-and-auth/emails-section.js +4 -3
- package/dist/components-page/account-settings/email-and-auth/emails-section.js.map +1 -1
- package/dist/components-page/onboarding.js +170 -0
- package/dist/components-page/onboarding.js.map +1 -0
- package/dist/components-page/stack-handler-client.js +13 -1
- package/dist/components-page/stack-handler-client.js.map +1 -1
- package/dist/components-page/stack-handler.js.map +1 -1
- package/dist/components-page/team-invitation.js +15 -1
- package/dist/components-page/team-invitation.js.map +1 -1
- package/dist/esm/components/credential-sign-up.js.map +1 -1
- package/dist/esm/components/user-button.js +4 -4
- package/dist/esm/components/user-button.js.map +1 -1
- package/dist/esm/components-page/account-settings/email-and-auth/emails-section.js +4 -3
- package/dist/esm/components-page/account-settings/email-and-auth/emails-section.js.map +1 -1
- package/dist/esm/components-page/onboarding.js +146 -0
- package/dist/esm/components-page/onboarding.js.map +1 -0
- package/dist/esm/components-page/stack-handler-client.js +13 -1
- package/dist/esm/components-page/stack-handler-client.js.map +1 -1
- package/dist/esm/components-page/stack-handler.js.map +1 -1
- package/dist/esm/components-page/team-invitation.js +15 -1
- package/dist/esm/components-page/team-invitation.js.map +1 -1
- package/dist/esm/generated/global-css.js +1 -1
- package/dist/esm/generated/global-css.js.map +1 -1
- package/dist/esm/lib/cookie.js +56 -20
- package/dist/esm/lib/cookie.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js +235 -0
- package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js +154 -31
- package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/common.js +2 -1
- package/dist/esm/lib/stack-app/apps/implementations/common.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js +40 -27
- package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/interfaces/client-app.js.map +1 -1
- package/dist/esm/lib/stack-app/apps/interfaces/server-app.js.map +1 -1
- package/dist/esm/lib/stack-app/common.js.map +1 -1
- package/dist/esm/lib/stack-app/index.js.map +1 -1
- package/dist/esm/lib/stack-app/projects/index.js +4 -0
- package/dist/esm/lib/stack-app/projects/index.js.map +1 -1
- package/dist/esm/lib/stack-app/teams/index.js.map +1 -1
- package/dist/esm/lib/stack-app/users/index.js +13 -12
- package/dist/esm/lib/stack-app/users/index.js.map +1 -1
- package/dist/generated/global-css.js +1 -1
- package/dist/generated/global-css.js.map +1 -1
- package/dist/index.d.mts +269 -16
- package/dist/index.d.ts +269 -16
- package/dist/lib/cookie.js +56 -20
- package/dist/lib/cookie.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/admin-app-impl.js +235 -0
- package/dist/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/client-app-impl.js +151 -28
- package/dist/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/common.js +2 -1
- package/dist/lib/stack-app/apps/implementations/common.js.map +1 -1
- package/dist/lib/stack-app/apps/implementations/server-app-impl.js +38 -25
- package/dist/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
- package/dist/lib/stack-app/apps/interfaces/admin-app.js.map +1 -1
- package/dist/lib/stack-app/apps/interfaces/client-app.js.map +1 -1
- package/dist/lib/stack-app/apps/interfaces/server-app.js.map +1 -1
- package/dist/lib/stack-app/common.js.map +1 -1
- package/dist/lib/stack-app/email/index.js.map +1 -1
- package/dist/lib/stack-app/index.js.map +1 -1
- package/dist/lib/stack-app/project-configs/index.js.map +1 -1
- package/dist/lib/stack-app/projects/index.js +4 -0
- package/dist/lib/stack-app/projects/index.js.map +1 -1
- package/dist/lib/stack-app/teams/index.js.map +1 -1
- package/dist/lib/stack-app/users/index.js +15 -14
- package/dist/lib/stack-app/users/index.js.map +1 -1
- package/package.json +6 -5
- package/CHANGELOG.md +0 -2052
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/credential-sign-up.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { getPasswordError } from \"@stackframe/stack-shared/dist/helpers/password\";\nimport { passwordSchema, strictEmailSchema, yupObject } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport { runAsynchronously, runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Button, Input, Label, PasswordInput } from \"@stackframe/stack-ui\";\nimport { useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport * as yup from \"yup\";\nimport { useStackApp } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { FormWarningText } from \"./elements/form-warning\";\n\nexport function CredentialSignUp(props: { noPasswordRepeat?: boolean }) {\n const { t } = useTranslation();\n\n const schema = yupObject({\n email: strictEmailSchema(t('Please enter a valid email')).defined().nonEmpty(t('Please enter your email')),\n password: passwordSchema.defined().nonEmpty(t('Please enter your password')).test({\n name: 'is-valid-password',\n test: (value, ctx) => {\n const error = getPasswordError(value);\n if (error) {\n return ctx.createError({ message: error.message });\n } else {\n return true;\n }\n }\n }),\n ...(!props.noPasswordRepeat && {\n passwordRepeat: passwordSchema.nullable().oneOf([yup.ref('password'), \"\", null], t('Passwords do not match')).nonEmpty(t('Please repeat your password'))\n })\n });\n\n const { register, handleSubmit, setError, formState: { errors }, clearErrors } = useForm({\n resolver: yupResolver(schema)\n });\n const app = useStackApp();\n const [loading, setLoading] = useState(false);\n\n const onSubmit = async (data: yup.InferType<typeof schema>) => {\n setLoading(true);\n try {\n const { email, password } = data;\n const result = await app.signUpWithCredential({ email, password });\n if (result.status === 'error') {\n setError('email', { type: 'manual', message: result.error.message });\n }\n } finally {\n setLoading(false);\n }\n };\n\n const registerPassword = register('password');\n const registerPasswordRepeat = register('passwordRepeat');\n\n return (\n <form\n className=\"flex flex-col items-stretch stack-scope\"\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <Label htmlFor=\"email\" className=\"mb-1\">{t('Email')}</Label>\n <Input id=\"email\" type=\"email\" autoComplete=\"email\" {...register('email')}/>\n <FormWarningText text={errors.email?.message?.toString()} />\n\n <Label htmlFor=\"password\" className=\"mt-4 mb-1\">{t('Password')}</Label>\n <PasswordInput\n id=\"password\"\n autoComplete=\"new-password\"\n {...registerPassword}\n onChange={(e) => {\n clearErrors('password');\n clearErrors('passwordRepeat');\n runAsynchronously(registerPassword.onChange(e));\n }}\n />\n <FormWarningText text={errors.password?.message?.toString()} />\n {\n !props.noPasswordRepeat && (\n <>\n <Label htmlFor=\"repeat-password\" className=\"mt-4 mb-1\">{t('Repeat Password')}</Label>\n <PasswordInput\n id=\"repeat-password\"\n {...registerPasswordRepeat}\n onChange={(e) => {\n clearErrors('password');\n clearErrors('passwordRepeat');\n runAsynchronously(registerPasswordRepeat.onChange(e));\n }}\n />\n <FormWarningText text={errors.passwordRepeat?.message?.toString()} />\n </>\n )\n }\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n {t('Sign Up')}\n </Button>\n </form>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,iBAA4B;AAC5B,sBAAiC;AACjC,2BAA6D;AAC7D,sBAA8D;AAC9D,sBAAoD;AACpD,
|
|
1
|
+
{"version":3,"sources":["../../src/components/credential-sign-up.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { getPasswordError } from \"@stackframe/stack-shared/dist/helpers/password\";\nimport { passwordSchema, strictEmailSchema, yupObject } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport { runAsynchronously, runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Button, Input, Label, PasswordInput } from \"@stackframe/stack-ui\";\nimport React, { useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport * as yup from \"yup\";\nimport { useStackApp } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { FormWarningText } from \"./elements/form-warning\";\n\nexport function CredentialSignUp(props: { noPasswordRepeat?: boolean }) {\n const { t } = useTranslation();\n\n const schema = yupObject({\n email: strictEmailSchema(t('Please enter a valid email')).defined().nonEmpty(t('Please enter your email')),\n password: passwordSchema.defined().nonEmpty(t('Please enter your password')).test({\n name: 'is-valid-password',\n test: (value, ctx) => {\n const error = getPasswordError(value);\n if (error) {\n return ctx.createError({ message: error.message });\n } else {\n return true;\n }\n }\n }),\n ...(!props.noPasswordRepeat && {\n passwordRepeat: passwordSchema.nullable().oneOf([yup.ref('password'), \"\", null], t('Passwords do not match')).nonEmpty(t('Please repeat your password'))\n })\n });\n\n const { register, handleSubmit, setError, formState: { errors }, clearErrors } = useForm({\n resolver: yupResolver(schema)\n });\n const app = useStackApp();\n const [loading, setLoading] = useState(false);\n\n const onSubmit = async (data: yup.InferType<typeof schema>) => {\n setLoading(true);\n try {\n const { email, password } = data;\n const result = await app.signUpWithCredential({ email, password });\n if (result.status === 'error') {\n setError('email', { type: 'manual', message: result.error.message });\n }\n } finally {\n setLoading(false);\n }\n };\n\n const registerPassword = register('password');\n const registerPasswordRepeat = register('passwordRepeat');\n\n return (\n <form\n className=\"flex flex-col items-stretch stack-scope\"\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <Label htmlFor=\"email\" className=\"mb-1\">{t('Email')}</Label>\n <Input id=\"email\" type=\"email\" autoComplete=\"email\" {...register('email')}/>\n <FormWarningText text={errors.email?.message?.toString()} />\n\n <Label htmlFor=\"password\" className=\"mt-4 mb-1\">{t('Password')}</Label>\n <PasswordInput\n id=\"password\"\n autoComplete=\"new-password\"\n {...registerPassword}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n clearErrors('password');\n clearErrors('passwordRepeat');\n runAsynchronously(registerPassword.onChange(e));\n }}\n />\n <FormWarningText text={errors.password?.message?.toString()} />\n {\n !props.noPasswordRepeat && (\n <>\n <Label htmlFor=\"repeat-password\" className=\"mt-4 mb-1\">{t('Repeat Password')}</Label>\n <PasswordInput\n id=\"repeat-password\"\n {...registerPasswordRepeat}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n clearErrors('password');\n clearErrors('passwordRepeat');\n runAsynchronously(registerPasswordRepeat.onChange(e));\n }}\n />\n <FormWarningText text={errors.passwordRepeat?.message?.toString()} />\n </>\n )\n }\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n {t('Sign Up')}\n </Button>\n </form>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -61,11 +61,11 @@ function UserButtonInnerInner(props) {
|
|
|
61
61
|
const app = (0, import__.useStackApp)();
|
|
62
62
|
const iconProps = { size: 20, className: "h-4 w-4" };
|
|
63
63
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.DropdownMenu, { children: [
|
|
64
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DropdownMenuTrigger, { className: "outline-none stack-scope", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-2 items-center", children: [
|
|
64
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.DropdownMenuTrigger, { className: "outline-none stack-scope rounded-lg hover:bg-muted/50 transition-colors hover:transition-none p-1.5", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-2 items-center", children: [
|
|
65
65
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_user_avatar.UserAvatar, { user }),
|
|
66
|
-
user && props.showUserInfo && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col justify-center text-left", children: [
|
|
67
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "max-w-40 truncate", children: user.displayName }),
|
|
68
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "max-w-40 truncate text-
|
|
66
|
+
user && props.showUserInfo && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col justify-center text-left min-w-0", children: [
|
|
67
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "max-w-40 truncate text-sm font-medium", children: user.displayName }),
|
|
68
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "max-w-40 truncate text-xs text-muted-foreground", children: user.primaryEmail })
|
|
69
69
|
] })
|
|
70
70
|
] }) }),
|
|
71
71
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.DropdownMenuContent, { className: "stack-scope", children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/user-button.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Skeleton, Typography } from \"@stackframe/stack-ui\";\nimport { CircleUser, LogIn, LogOut, SunMoon, UserPlus } from \"lucide-react\";\nimport React, { Suspense } from \"react\";\nimport { CurrentUser, useStackApp, useUser } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { UserAvatar } from \"./elements/user-avatar\";\n\nfunction Item(props: { text: string, icon: React.ReactNode, onClick: () => void | Promise<void> }) {\n return (\n <DropdownMenuItem onClick={() => runAsynchronouslyWithAlert(props.onClick)}>\n <div className=\"flex gap-2 items-center\">\n {props.icon}\n <Typography>{props.text}</Typography>\n </div>\n </DropdownMenuItem>\n );\n}\n\ntype UserButtonProps = {\n showUserInfo?: boolean,\n colorModeToggle?: () => void | Promise<void>,\n extraItems?: {\n text: string,\n icon: React.ReactNode,\n onClick: () => void | Promise<void>,\n }[],\n mockUser?: {\n displayName?: string,\n primaryEmail?: string,\n profileImageUrl?: string,\n },\n};\n\nexport function UserButton(props: UserButtonProps) {\n return (\n <Suspense fallback={<Skeleton className=\"h-[34px] w-[34px] rounded-full stack-scope\" />}>\n <UserButtonInner {...props} />\n </Suspense>\n );\n}\n\nfunction UserButtonInner(props: UserButtonProps) {\n const userFromHook = useUser();\n\n // Use mock user if provided, otherwise use real user\n const user = props.mockUser ? {\n displayName: props.mockUser.displayName || 'Mock User',\n primaryEmail: props.mockUser.primaryEmail || 'mock@example.com',\n profileImageUrl: props.mockUser.profileImageUrl,\n signOut: () => {\n console.log('Mock sign out - no action taken in demo mode');\n return Promise.resolve();\n }\n } as CurrentUser : userFromHook;\n\n return <UserButtonInnerInner {...props} user={user} />;\n}\n\n\nfunction UserButtonInnerInner(props: UserButtonProps & { user: CurrentUser | null }) {\n const { t } = useTranslation();\n const user = props.user;\n const app = useStackApp();\n\n const iconProps = { size: 20, className: 'h-4 w-4' };\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger className=\"outline-none stack-scope\">\n <div className=\"flex gap-2 items-center\">\n <UserAvatar user={user} />\n {user && props.showUserInfo &&\n <div className=\"flex flex-col justify-center text-left\">\n <div className=\"max-w-40 truncate\">{user.displayName}</div>\n <div className=\"max-w-40 truncate text-
|
|
1
|
+
{"version":3,"sources":["../../src/components/user-button.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Skeleton, Typography } from \"@stackframe/stack-ui\";\nimport { CircleUser, LogIn, LogOut, SunMoon, UserPlus } from \"lucide-react\";\nimport React, { Suspense } from \"react\";\nimport { CurrentUser, useStackApp, useUser } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { UserAvatar } from \"./elements/user-avatar\";\n\nfunction Item(props: { text: string, icon: React.ReactNode, onClick: () => void | Promise<void> }) {\n return (\n <DropdownMenuItem onClick={() => runAsynchronouslyWithAlert(props.onClick)}>\n <div className=\"flex gap-2 items-center\">\n {props.icon}\n <Typography>{props.text}</Typography>\n </div>\n </DropdownMenuItem>\n );\n}\n\ntype UserButtonProps = {\n showUserInfo?: boolean,\n colorModeToggle?: () => void | Promise<void>,\n extraItems?: {\n text: string,\n icon: React.ReactNode,\n onClick: () => void | Promise<void>,\n }[],\n mockUser?: {\n displayName?: string,\n primaryEmail?: string,\n profileImageUrl?: string,\n },\n};\n\nexport function UserButton(props: UserButtonProps) {\n return (\n <Suspense fallback={<Skeleton className=\"h-[34px] w-[34px] rounded-full stack-scope\" />}>\n <UserButtonInner {...props} />\n </Suspense>\n );\n}\n\nfunction UserButtonInner(props: UserButtonProps) {\n const userFromHook = useUser();\n\n // Use mock user if provided, otherwise use real user\n const user = props.mockUser ? {\n displayName: props.mockUser.displayName || 'Mock User',\n primaryEmail: props.mockUser.primaryEmail || 'mock@example.com',\n profileImageUrl: props.mockUser.profileImageUrl,\n signOut: () => {\n console.log('Mock sign out - no action taken in demo mode');\n return Promise.resolve();\n }\n } as CurrentUser : userFromHook;\n\n return <UserButtonInnerInner {...props} user={user} />;\n}\n\n\nfunction UserButtonInnerInner(props: UserButtonProps & { user: CurrentUser | null }) {\n const { t } = useTranslation();\n const user = props.user;\n const app = useStackApp();\n\n const iconProps = { size: 20, className: 'h-4 w-4' };\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger className=\"outline-none stack-scope rounded-lg hover:bg-muted/50 transition-colors hover:transition-none p-1.5\">\n <div className=\"flex gap-2 items-center\">\n <UserAvatar user={user} />\n {user && props.showUserInfo &&\n <div className=\"flex flex-col justify-center text-left min-w-0\">\n <div className=\"max-w-40 truncate text-sm font-medium\">{user.displayName}</div>\n <div className=\"max-w-40 truncate text-xs text-muted-foreground\">{user.primaryEmail}</div>\n </div>\n }\n </div>\n </DropdownMenuTrigger>\n <DropdownMenuContent className=\"stack-scope\">\n <DropdownMenuLabel>\n <div className=\"flex gap-2 items-center\">\n <UserAvatar user={user} />\n <div>\n {user && <Typography className=\"max-w-40 truncate\">{user.displayName}</Typography>}\n {user && <Typography className=\"max-w-40 truncate\" variant=\"secondary\" type='label'>{user.primaryEmail}</Typography>}\n {!user && <Typography>{t('Not signed in')}</Typography>}\n </div>\n </div>\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n {user && <Item\n text={t('Account settings')}\n onClick={async () => {\n if (props.mockUser) {\n console.log('Mock account settings - no navigation in demo mode');\n } else {\n await app.redirectToAccountSettings();\n }\n }}\n icon={<CircleUser {...iconProps} />}\n />}\n {!user && <Item\n text={t('Sign in')}\n onClick={async () => {\n if (props.mockUser) {\n console.log('Mock sign in - no navigation in demo mode');\n } else {\n await app.redirectToSignIn();\n }\n }}\n icon={<LogIn {...iconProps} />}\n />}\n {!user && <Item\n text={t('Sign up')}\n onClick={async () => {\n if (props.mockUser) {\n console.log('Mock sign up - no navigation in demo mode');\n } else {\n await app.redirectToSignUp();\n }\n }}\n icon={<UserPlus {...iconProps}/> }\n />}\n {user && props.extraItems && props.extraItems.map((item, index) => (\n <Item key={index} {...item} />\n ))}\n {props.colorModeToggle && (\n <Item\n text={t('Toggle theme')}\n onClick={props.colorModeToggle}\n icon={<SunMoon {...iconProps} />}\n />\n )}\n {user && <Item\n text={t('Sign out')}\n onClick={async () => {\n if (props.mockUser) {\n console.log('Mock sign out - no action taken in demo mode');\n } else {\n await user.signOut();\n }\n }}\n icon={<LogOut {...iconProps} />}\n />}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -50,7 +50,7 @@ function EmailsSection(props) {
|
|
|
50
50
|
const [addingEmail, setAddingEmail] = (0, import_react.useState)(contactChannels.length === 0);
|
|
51
51
|
const [addingEmailLoading, setAddingEmailLoading] = (0, import_react.useState)(false);
|
|
52
52
|
const [addedEmail, setAddedEmail] = (0, import_react.useState)(null);
|
|
53
|
-
const
|
|
53
|
+
const isLastEmailUsedForAuth = contactChannels.filter((x) => x.usedForAuth && x.type === "email").length === 1;
|
|
54
54
|
(0, import_react.useEffect)(() => {
|
|
55
55
|
if (addedEmail) {
|
|
56
56
|
(0, import_promises.runAsynchronously)(async () => {
|
|
@@ -161,7 +161,7 @@ function EmailsSection(props) {
|
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
}] : [],
|
|
164
|
-
...x.usedForAuth && !
|
|
164
|
+
...x.usedForAuth && !isLastEmailUsedForAuth ? [{
|
|
165
165
|
item: t("Stop using for sign-in"),
|
|
166
166
|
onClick: async () => {
|
|
167
167
|
await x.update({ usedForAuth: false });
|
|
@@ -173,7 +173,8 @@ function EmailsSection(props) {
|
|
|
173
173
|
disabled: true,
|
|
174
174
|
disabledTooltip: t("You can not remove your last sign-in email")
|
|
175
175
|
}] : [],
|
|
176
|
-
|
|
176
|
+
// Determine if this email can be removed
|
|
177
|
+
...!isLastEmailUsedForAuth || !x.usedForAuth ? [{
|
|
177
178
|
item: t("Remove"),
|
|
178
179
|
onClick: async () => {
|
|
179
180
|
await x.delete();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components-page/account-settings/email-and-auth/emails-section.tsx"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { KnownErrors } from \"@stackframe/stack-shared/dist/known-errors\";\nimport { strictEmailSchema, yupObject } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport { runAsynchronously } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { ActionCell, Badge, Button, Input, Table, TableBody, TableCell, TableRow, Typography } from \"@stackframe/stack-ui\";\nimport { useEffect, useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport * as yup from \"yup\";\nimport { FormWarningText } from \"../../../components/elements/form-warning\";\nimport { useUser } from \"../../../lib/hooks\";\nimport { useTranslation } from \"../../../lib/translations\";\n\nexport function EmailsSection(props?: {\n mockMode?: boolean,\n}) {\n const { t } = useTranslation();\n const user = useUser({ or: props?.mockMode ? 'return-null' : 'redirect' });\n\n // In mock mode, show a placeholder message\n if (props?.mockMode && !user) {\n return (\n <div>\n <div className='flex flex-col md:flex-row justify-between mb-4 gap-4'>\n <Typography className='font-medium'>{t(\"Emails\")}</Typography>\n </div>\n <Typography variant='secondary'>{t(\"Email management is not available in demo mode.\")}</Typography>\n </div>\n );\n }\n\n if (!user) {\n return null; // This shouldn't happen in non-mock mode due to redirect\n }\n\n const contactChannels = user.useContactChannels();\n const [addingEmail, setAddingEmail] = useState(contactChannels.length === 0);\n const [addingEmailLoading, setAddingEmailLoading] = useState(false);\n const [addedEmail, setAddedEmail] = useState<string | null>(null);\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const isLastEmail = contactChannels.filter(x => x.usedForAuth && x.type === 'email').length === 1;\n\n useEffect(() => {\n if (addedEmail) {\n runAsynchronously(async () => {\n const cc = contactChannels.find(x => x.value === addedEmail);\n if (cc && !cc.isVerified) {\n await cc.sendVerificationEmail();\n }\n setAddedEmail(null);\n });\n }\n }, [contactChannels, addedEmail]);\n\n const emailSchema = yupObject({\n email: strictEmailSchema(t('Please enter a valid email address'))\n .notOneOf(contactChannels.map(x => x.value), t('Email already exists'))\n .defined()\n .nonEmpty(t('Email is required')),\n });\n\n const { register, handleSubmit, formState: { errors }, reset } = useForm({\n resolver: yupResolver(emailSchema)\n });\n\n const onSubmit = async (data: yup.InferType<typeof emailSchema>) => {\n setAddingEmailLoading(true);\n try {\n await user.createContactChannel({ type: 'email', value: data.email, usedForAuth: false });\n setAddedEmail(data.email);\n } finally {\n setAddingEmailLoading(false);\n }\n setAddingEmail(false);\n reset();\n };\n\n return (\n <div>\n <div className='flex flex-col md:flex-row justify-between mb-4 gap-4'>\n <Typography className='font-medium'>{t(\"Emails\")}</Typography>\n {addingEmail ? (\n <form\n onSubmit={(e) => {\n e.preventDefault();\n runAsynchronously(handleSubmit(onSubmit));\n }}\n className='flex flex-col'\n >\n <div className='flex gap-2'>\n <Input\n {...register(\"email\")}\n placeholder={t(\"Enter email\")}\n />\n <Button type=\"submit\" loading={addingEmailLoading}>\n {t(\"Add\")}\n </Button>\n <Button\n variant='secondary'\n onClick={() => {\n setAddingEmail(false);\n reset();\n }}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n {errors.email && <FormWarningText text={errors.email.message} />}\n </form>\n ) : (\n <div className='flex md:justify-end'>\n <Button variant='secondary' onClick={() => setAddingEmail(true)}>{t(\"Add an email\")}</Button>\n </div>\n )}\n </div>\n\n {contactChannels.length > 0 ? (\n <div className='border rounded-md'>\n <Table>\n <TableBody>\n {/*eslint-disable-next-line @typescript-eslint/no-unnecessary-condition*/}\n {contactChannels.filter(x => x.type === 'email')\n .sort((a, b) => {\n if (a.isPrimary !== b.isPrimary) return a.isPrimary ? -1 : 1;\n if (a.isVerified !== b.isVerified) return a.isVerified ? -1 : 1;\n return 0;\n })\n .map(x => (\n <TableRow key={x.id}>\n <TableCell>\n <div className='flex flex-col md:flex-row gap-2 md:gap-4'>\n {x.value}\n <div className='flex gap-2'>\n {x.isPrimary ? <Badge>{t(\"Primary\")}</Badge> : null}\n {!x.isVerified ? <Badge variant='destructive'>{t(\"Unverified\")}</Badge> : null}\n {x.usedForAuth ? <Badge variant='outline'>{t(\"Used for sign-in\")}</Badge> : null}\n </div>\n </div>\n </TableCell>\n <TableCell className=\"flex justify-end\">\n <ActionCell items={[\n ...(!x.isVerified ? [{\n item: t(\"Send verification email\"),\n onClick: async () => { await x.sendVerificationEmail(); },\n }] : []),\n ...(!x.isPrimary && x.isVerified ? [{\n item: t(\"Set as primary\"),\n onClick: async () => { await x.update({ isPrimary: true }); },\n }] :\n !x.isPrimary ? [{\n item: t(\"Set as primary\"),\n onClick: async () => {},\n disabled: true,\n disabledTooltip: t(\"Please verify your email first\"),\n }] : []),\n ...(!x.usedForAuth && x.isVerified ? [{\n item: t(\"Use for sign-in\"),\n onClick: async () => {\n try {\n await x.update({ usedForAuth: true });\n } catch (e) {\n if (KnownErrors.ContactChannelAlreadyUsedForAuthBySomeoneElse.isInstance(e)) {\n alert(t(\"This email is already used for sign-in by another user.\"));\n }\n }\n }\n }] : []),\n ...(x.usedForAuth && !isLastEmail ? [{\n item: t(\"Stop using for sign-in\"),\n onClick: async () => { await x.update({ usedForAuth: false }); },\n }] : x.usedForAuth ? [{\n item: t(\"Stop using for sign-in\"),\n onClick: async () => {},\n disabled: true,\n disabledTooltip: t(\"You can not remove your last sign-in email\"),\n }] : []),\n ...(!isLastEmail || !x.usedForAuth ? [{\n item: t(\"Remove\"),\n onClick: async () => { await x.delete(); },\n danger: true,\n }] : [{\n item: t(\"Remove\"),\n onClick: async () => {},\n disabled: true,\n disabledTooltip: t(\"You can not remove your last sign-in email\"),\n }]),\n ]}/>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/components-page/account-settings/email-and-auth/emails-section.tsx"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { KnownErrors } from \"@stackframe/stack-shared/dist/known-errors\";\nimport { strictEmailSchema, yupObject } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport { runAsynchronously } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { ActionCell, Badge, Button, Input, Table, TableBody, TableCell, TableRow, Typography } from \"@stackframe/stack-ui\";\nimport { useEffect, useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport * as yup from \"yup\";\nimport { FormWarningText } from \"../../../components/elements/form-warning\";\nimport { useUser } from \"../../../lib/hooks\";\nimport { useTranslation } from \"../../../lib/translations\";\n\nexport function EmailsSection(props?: {\n mockMode?: boolean,\n}) {\n const { t } = useTranslation();\n const user = useUser({ or: props?.mockMode ? 'return-null' : 'redirect' });\n\n // In mock mode, show a placeholder message\n if (props?.mockMode && !user) {\n return (\n <div>\n <div className='flex flex-col md:flex-row justify-between mb-4 gap-4'>\n <Typography className='font-medium'>{t(\"Emails\")}</Typography>\n </div>\n <Typography variant='secondary'>{t(\"Email management is not available in demo mode.\")}</Typography>\n </div>\n );\n }\n\n if (!user) {\n return null; // This shouldn't happen in non-mock mode due to redirect\n }\n\n const contactChannels = user.useContactChannels();\n const [addingEmail, setAddingEmail] = useState(contactChannels.length === 0);\n const [addingEmailLoading, setAddingEmailLoading] = useState(false);\n const [addedEmail, setAddedEmail] = useState<string | null>(null);\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const isLastEmailUsedForAuth = contactChannels.filter(x => x.usedForAuth && x.type === 'email').length === 1;\n\n useEffect(() => {\n if (addedEmail) {\n runAsynchronously(async () => {\n const cc = contactChannels.find(x => x.value === addedEmail);\n if (cc && !cc.isVerified) {\n await cc.sendVerificationEmail();\n }\n setAddedEmail(null);\n });\n }\n }, [contactChannels, addedEmail]);\n\n const emailSchema = yupObject({\n email: strictEmailSchema(t('Please enter a valid email address'))\n .notOneOf(contactChannels.map(x => x.value), t('Email already exists'))\n .defined()\n .nonEmpty(t('Email is required')),\n });\n\n const { register, handleSubmit, formState: { errors }, reset } = useForm({\n resolver: yupResolver(emailSchema)\n });\n\n const onSubmit = async (data: yup.InferType<typeof emailSchema>) => {\n setAddingEmailLoading(true);\n try {\n await user.createContactChannel({ type: 'email', value: data.email, usedForAuth: false });\n setAddedEmail(data.email);\n } finally {\n setAddingEmailLoading(false);\n }\n setAddingEmail(false);\n reset();\n };\n\n return (\n <div>\n <div className='flex flex-col md:flex-row justify-between mb-4 gap-4'>\n <Typography className='font-medium'>{t(\"Emails\")}</Typography>\n {addingEmail ? (\n <form\n onSubmit={(e) => {\n e.preventDefault();\n runAsynchronously(handleSubmit(onSubmit));\n }}\n className='flex flex-col'\n >\n <div className='flex gap-2'>\n <Input\n {...register(\"email\")}\n placeholder={t(\"Enter email\")}\n />\n <Button type=\"submit\" loading={addingEmailLoading}>\n {t(\"Add\")}\n </Button>\n <Button\n variant='secondary'\n onClick={() => {\n setAddingEmail(false);\n reset();\n }}\n >\n {t(\"Cancel\")}\n </Button>\n </div>\n {errors.email && <FormWarningText text={errors.email.message} />}\n </form>\n ) : (\n <div className='flex md:justify-end'>\n <Button variant='secondary' onClick={() => setAddingEmail(true)}>{t(\"Add an email\")}</Button>\n </div>\n )}\n </div>\n\n {contactChannels.length > 0 ? (\n <div className='border rounded-md'>\n <Table>\n <TableBody>\n {/*eslint-disable-next-line @typescript-eslint/no-unnecessary-condition*/}\n {contactChannels.filter(x => x.type === 'email')\n .sort((a, b) => {\n if (a.isPrimary !== b.isPrimary) return a.isPrimary ? -1 : 1;\n if (a.isVerified !== b.isVerified) return a.isVerified ? -1 : 1;\n return 0;\n })\n .map(x => (\n <TableRow key={x.id}>\n <TableCell>\n <div className='flex flex-col md:flex-row gap-2 md:gap-4'>\n {x.value}\n <div className='flex gap-2'>\n {x.isPrimary ? <Badge>{t(\"Primary\")}</Badge> : null}\n {!x.isVerified ? <Badge variant='destructive'>{t(\"Unverified\")}</Badge> : null}\n {x.usedForAuth ? <Badge variant='outline'>{t(\"Used for sign-in\")}</Badge> : null}\n </div>\n </div>\n </TableCell>\n <TableCell className=\"flex justify-end\">\n <ActionCell items={[\n ...(!x.isVerified ? [{\n item: t(\"Send verification email\"),\n onClick: async () => { await x.sendVerificationEmail(); },\n }] : []),\n ...(!x.isPrimary && x.isVerified ? [{\n item: t(\"Set as primary\"),\n onClick: async () => { await x.update({ isPrimary: true }); },\n }] :\n !x.isPrimary ? [{\n item: t(\"Set as primary\"),\n onClick: async () => {},\n disabled: true,\n disabledTooltip: t(\"Please verify your email first\"),\n }] : []),\n ...(!x.usedForAuth && x.isVerified ? [{\n item: t(\"Use for sign-in\"),\n onClick: async () => {\n try {\n await x.update({ usedForAuth: true });\n } catch (e) {\n if (KnownErrors.ContactChannelAlreadyUsedForAuthBySomeoneElse.isInstance(e)) {\n alert(t(\"This email is already used for sign-in by another user.\"));\n }\n }\n }\n }] : []),\n ...(x.usedForAuth && !isLastEmailUsedForAuth ? [{\n item: t(\"Stop using for sign-in\"),\n onClick: async () => { await x.update({ usedForAuth: false }); },\n }] : x.usedForAuth ? [{\n item: t(\"Stop using for sign-in\"),\n onClick: async () => {},\n disabled: true,\n disabledTooltip: t(\"You can not remove your last sign-in email\"),\n }] : []),\n // Determine if this email can be removed\n ...(!isLastEmailUsedForAuth || !x.usedForAuth ? [{\n item: t(\"Remove\"),\n onClick: async () => { await x.delete(); },\n danger: true,\n }] : [{\n item: t(\"Remove\"),\n onClick: async () => {},\n disabled: true,\n disabledTooltip: t(\"You can not remove your last sign-in email\"),\n }]),\n ]}/>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
"use client";
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
// src/components-page/onboarding.tsx
|
|
23
|
+
var onboarding_exports = {};
|
|
24
|
+
__export(onboarding_exports, {
|
|
25
|
+
Onboarding: () => Onboarding
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(onboarding_exports);
|
|
28
|
+
var import_yup = require("@hookform/resolvers/yup");
|
|
29
|
+
var import_schema_fields = require("@stackframe/stack-shared/dist/schema-fields");
|
|
30
|
+
var import_promises = require("@stackframe/stack-shared/dist/utils/promises");
|
|
31
|
+
var import_stack_ui = require("@stackframe/stack-ui");
|
|
32
|
+
var import_react = require("react");
|
|
33
|
+
var import_react_hook_form = require("react-hook-form");
|
|
34
|
+
var import__ = require("../index.js");
|
|
35
|
+
var import_form_warning = require("../components/elements/form-warning.js");
|
|
36
|
+
var import_message_card = require("../components/message-cards/message-card.js");
|
|
37
|
+
var import_translations = require("../lib/translations.js");
|
|
38
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
39
|
+
function Onboarding(props) {
|
|
40
|
+
const { t } = (0, import_translations.useTranslation)();
|
|
41
|
+
const stackApp = (0, import__.useStackApp)();
|
|
42
|
+
const user = (0, import__.useUser)({ or: "return-null", includeRestricted: true });
|
|
43
|
+
if (user && !user.isRestricted) {
|
|
44
|
+
(0, import_promises.runAsynchronously)(stackApp.redirectToAfterSignIn());
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
if (!user || user.isAnonymous) {
|
|
48
|
+
(0, import_promises.runAsynchronously)(stackApp.redirectToSignIn());
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const restrictedReason = user.restrictedReason;
|
|
52
|
+
if (restrictedReason?.type === "email_not_verified") {
|
|
53
|
+
const hasPrimaryEmail = !!user.primaryEmail;
|
|
54
|
+
if (!hasPrimaryEmail) {
|
|
55
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AddEmailForm, { fullPage: props.fullPage });
|
|
56
|
+
}
|
|
57
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VerifyEmailScreen, { user, email: user.primaryEmail, fullPage: props.fullPage });
|
|
58
|
+
}
|
|
59
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
60
|
+
import_message_card.MessageCard,
|
|
61
|
+
{
|
|
62
|
+
title: t("Complete your account setup"),
|
|
63
|
+
fullPage: !!props.fullPage,
|
|
64
|
+
secondaryButtonText: t("Sign out"),
|
|
65
|
+
secondaryAction: async () => {
|
|
66
|
+
await user.signOut();
|
|
67
|
+
},
|
|
68
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: t("Please complete your account setup to continue.") })
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
function AddEmailForm(props) {
|
|
73
|
+
const { t } = (0, import_translations.useTranslation)();
|
|
74
|
+
const user = (0, import__.useUser)({ or: "throw", includeRestricted: true });
|
|
75
|
+
const stackApp = (0, import__.useStackApp)();
|
|
76
|
+
const [loading, setLoading] = (0, import_react.useState)(false);
|
|
77
|
+
const emailSchema = (0, import_schema_fields.yupObject)({
|
|
78
|
+
email: (0, import_schema_fields.strictEmailSchema)(t("Please enter a valid email address")).defined().nonEmpty(t("Email is required"))
|
|
79
|
+
});
|
|
80
|
+
const { register, handleSubmit, formState: { errors } } = (0, import_react_hook_form.useForm)({
|
|
81
|
+
resolver: (0, import_yup.yupResolver)(emailSchema)
|
|
82
|
+
});
|
|
83
|
+
const onSubmit = async (data) => {
|
|
84
|
+
setLoading(true);
|
|
85
|
+
try {
|
|
86
|
+
await user.update({ primaryEmail: data.email });
|
|
87
|
+
props.onEmailAdded?.();
|
|
88
|
+
} finally {
|
|
89
|
+
setLoading(false);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
93
|
+
import_message_card.MessageCard,
|
|
94
|
+
{
|
|
95
|
+
title: t("Add your email address"),
|
|
96
|
+
fullPage: !!props.fullPage,
|
|
97
|
+
secondaryButtonText: t("Sign out"),
|
|
98
|
+
secondaryAction: async () => {
|
|
99
|
+
await user.signOut();
|
|
100
|
+
},
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { className: "mb-4", children: t("Please add an email address to complete your account setup. We'll send you a verification email.") }),
|
|
103
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
104
|
+
"form",
|
|
105
|
+
{
|
|
106
|
+
onSubmit: (e) => (0, import_promises.runAsynchronouslyWithAlert)(handleSubmit(onSubmit)(e)),
|
|
107
|
+
noValidate: true,
|
|
108
|
+
className: "flex flex-col gap-2",
|
|
109
|
+
children: [
|
|
110
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
111
|
+
import_stack_ui.Input,
|
|
112
|
+
{
|
|
113
|
+
...register("email"),
|
|
114
|
+
placeholder: t("Enter your email"),
|
|
115
|
+
type: "email"
|
|
116
|
+
}
|
|
117
|
+
),
|
|
118
|
+
errors.email && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_form_warning.FormWarningText, { text: errors.email.message }),
|
|
119
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Button, { type: "submit", loading, className: "w-full", children: t("Continue") })
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
)
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
function VerifyEmailScreen(props) {
|
|
128
|
+
const { t } = (0, import_translations.useTranslation)();
|
|
129
|
+
const { user, email } = props;
|
|
130
|
+
const [changingEmail, setChangingEmail] = (0, import_react.useState)(false);
|
|
131
|
+
if (changingEmail) {
|
|
132
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AddEmailForm, { fullPage: props.fullPage, onEmailAdded: () => setChangingEmail(false) });
|
|
133
|
+
}
|
|
134
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
135
|
+
import_message_card.MessageCard,
|
|
136
|
+
{
|
|
137
|
+
title: t("Please check your email inbox"),
|
|
138
|
+
fullPage: !!props.fullPage,
|
|
139
|
+
primaryButtonText: t("Resend verification email"),
|
|
140
|
+
primaryAction: async () => {
|
|
141
|
+
await user.sendVerificationEmail();
|
|
142
|
+
},
|
|
143
|
+
secondaryButtonText: t("Sign out"),
|
|
144
|
+
secondaryAction: async () => {
|
|
145
|
+
await user.signOut();
|
|
146
|
+
},
|
|
147
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_stack_ui.Typography, { children: [
|
|
148
|
+
t("Please verify your email address "),
|
|
149
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-semibold", children: email }),
|
|
150
|
+
" (",
|
|
151
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
152
|
+
"button",
|
|
153
|
+
{
|
|
154
|
+
type: "button",
|
|
155
|
+
className: "text-primary hover:underline",
|
|
156
|
+
onClick: () => setChangingEmail(true),
|
|
157
|
+
children: t("change")
|
|
158
|
+
}
|
|
159
|
+
),
|
|
160
|
+
"). ",
|
|
161
|
+
t("Click the button below to resend the verification link.")
|
|
162
|
+
] })
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
167
|
+
0 && (module.exports = {
|
|
168
|
+
Onboarding
|
|
169
|
+
});
|
|
170
|
+
//# sourceMappingURL=onboarding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components-page/onboarding.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { strictEmailSchema, yupObject } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport { runAsynchronously, runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Button, Input, Typography } from \"@stackframe/stack-ui\";\nimport { useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport * as yup from \"yup\";\nimport { useStackApp, useUser } from \"..\";\nimport { FormWarningText } from \"../components/elements/form-warning\";\nimport { MessageCard } from \"../components/message-cards/message-card\";\nimport { useTranslation } from \"../lib/translations\";\n\nexport function Onboarding(props: {\n fullPage?: boolean,\n}) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const user = useUser({ or: \"return-null\", includeRestricted: true });\n\n // If user is not restricted anymore, redirect to the intended destination\n // redirectToAfterSignIn automatically checks for after_auth_return_to in the URL\n if (user && !user.isRestricted) {\n runAsynchronously(stackApp.redirectToAfterSignIn());\n // TODO: This should return a loading indicator, not just null\n return null;\n }\n\n // If user is anonymous or not logged in, redirect to sign-in\n if (!user || user.isAnonymous) {\n runAsynchronously(stackApp.redirectToSignIn());\n // TODO: This should return a loading indicator, not just null\n return null;\n }\n\n // User is restricted - show appropriate onboarding step based on restricted reason\n const restrictedReason = user.restrictedReason;\n\n if (restrictedReason?.type === \"email_not_verified\") {\n // Check if user has a primary email\n const hasPrimaryEmail = !!user.primaryEmail;\n\n if (!hasPrimaryEmail) {\n // User needs to add an email first\n return <AddEmailForm fullPage={props.fullPage} />;\n }\n\n // User has email but it's not verified\n return <VerifyEmailScreen user={user} email={user.primaryEmail} fullPage={props.fullPage} />;\n }\n\n // Unknown restricted reason - show generic message\n return (\n <MessageCard\n title={t(\"Complete your account setup\")}\n fullPage={!!props.fullPage}\n secondaryButtonText={t(\"Sign out\")}\n secondaryAction={async () => {\n await user.signOut();\n }}\n >\n <p>{t(\"Please complete your account setup to continue.\")}</p>\n </MessageCard>\n );\n}\n\nfunction AddEmailForm(props: {\n fullPage?: boolean,\n onEmailAdded?: () => void,\n}) {\n const { t } = useTranslation();\n const user = useUser({ or: \"throw\", includeRestricted: true });\n const stackApp = useStackApp();\n const [loading, setLoading] = useState(false);\n\n const emailSchema = yupObject({\n email: strictEmailSchema(t('Please enter a valid email address'))\n .defined()\n .nonEmpty(t('Email is required')),\n });\n\n const { register, handleSubmit, formState: { errors } } = useForm({\n resolver: yupResolver(emailSchema)\n });\n\n const onSubmit = async (data: yup.InferType<typeof emailSchema>) => {\n setLoading(true);\n try {\n await user.update({ primaryEmail: data.email });\n props.onEmailAdded?.();\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <MessageCard\n title={t(\"Add your email address\")}\n fullPage={!!props.fullPage}\n secondaryButtonText={t(\"Sign out\")}\n secondaryAction={async () => {\n await user.signOut();\n }}\n >\n <Typography className=\"mb-4\">\n {t(\"Please add an email address to complete your account setup. We'll send you a verification email.\")}\n </Typography>\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n className='flex flex-col gap-2'\n >\n <Input\n {...register(\"email\")}\n placeholder={t(\"Enter your email\")}\n type=\"email\"\n />\n {errors.email && <FormWarningText text={errors.email.message} />}\n <Button type=\"submit\" loading={loading} className=\"w-full\">\n {t(\"Continue\")}\n </Button>\n </form>\n </MessageCard>\n );\n}\n\nfunction VerifyEmailScreen(props: {\n user: NonNullable<ReturnType<typeof useUser>>,\n email: string,\n fullPage?: boolean,\n}) {\n const { t } = useTranslation();\n const { user, email } = props;\n const [changingEmail, setChangingEmail] = useState(false);\n\n if (changingEmail) {\n return <AddEmailForm fullPage={props.fullPage} onEmailAdded={() => setChangingEmail(false)} />;\n }\n\n return (\n <MessageCard\n title={t(\"Please check your email inbox\")}\n fullPage={!!props.fullPage}\n primaryButtonText={t(\"Resend verification email\")}\n primaryAction={async () => {\n await user.sendVerificationEmail();\n }}\n secondaryButtonText={t(\"Sign out\")}\n secondaryAction={async () => {\n await user.signOut();\n }}\n >\n <Typography>\n {t(\"Please verify your email address \")}\n <span className=\"font-semibold\">{email}</span>\n {\" (\"}\n <button\n type=\"button\"\n className=\"text-primary hover:underline\"\n onClick={() => setChangingEmail(true)}\n >\n {t(\"change\")}\n </button>\n {\"). \"}\n {t(\"Click the button below to resend the verification link.\")}\n </Typography>\n </MessageCard>\n );\n}\n\n"],"mappings":"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","names":[]}
|
|
@@ -40,6 +40,7 @@ var import_forgot_password = require("./forgot-password.js");
|
|
|
40
40
|
var import_magic_link_callback = require("./magic-link-callback.js");
|
|
41
41
|
var import_mfa = require("./mfa.js");
|
|
42
42
|
var import_oauth_callback = require("./oauth-callback.js");
|
|
43
|
+
var import_onboarding = require("./onboarding.js");
|
|
43
44
|
var import_password_reset = require("./password-reset.js");
|
|
44
45
|
var import_sign_out = require("./sign-out.js");
|
|
45
46
|
var import_team_invitation = require("./team-invitation.js");
|
|
@@ -57,7 +58,8 @@ var availablePaths = {
|
|
|
57
58
|
accountSettings: "account-settings",
|
|
58
59
|
cliAuthConfirm: "cli-auth-confirm",
|
|
59
60
|
mfa: "mfa",
|
|
60
|
-
error: "error"
|
|
61
|
+
error: "error",
|
|
62
|
+
onboarding: "onboarding"
|
|
61
63
|
};
|
|
62
64
|
var pathAliases = {
|
|
63
65
|
// also includes the uppercase and non-dashed versions
|
|
@@ -202,6 +204,16 @@ function renderComponent(props) {
|
|
|
202
204
|
}
|
|
203
205
|
);
|
|
204
206
|
}
|
|
207
|
+
case availablePaths.onboarding: {
|
|
208
|
+
redirectIfNotHandler?.("onboarding");
|
|
209
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
210
|
+
import_onboarding.Onboarding,
|
|
211
|
+
{
|
|
212
|
+
fullPage,
|
|
213
|
+
...filterUndefinedINU(componentProps?.Onboarding)
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
}
|
|
205
217
|
default: {
|
|
206
218
|
if (Object.values(availablePaths).includes(path)) {
|
|
207
219
|
throw new import_errors.StackAssertionError(`Path alias ${path} not included in switch statement, but in availablePaths?`, { availablePaths });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components-page/stack-handler-client.tsx"],"sourcesContent":["\"use client\";\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { StackAssertionError } from \"@stackframe/stack-shared/dist/utils/errors\";\nimport { FilterUndefined, filterUndefined } from \"@stackframe/stack-shared/dist/utils/objects\";\nimport { getRelativePart } from \"@stackframe/stack-shared/dist/utils/urls\";\nimport { notFound, redirect, RedirectType, usePathname, useSearchParams } from 'next/navigation'; // THIS_LINE_PLATFORM next\nimport { useMemo } from 'react';\nimport { SignIn, SignUp, StackServerApp } from \"..\";\nimport { useStackApp } from \"../lib/hooks\";\nimport { HandlerUrls, StackClientApp } from \"../lib/stack-app\";\nimport { AccountSettings } from \"./account-settings\";\nimport { CliAuthConfirmation } from \"./cli-auth-confirm\";\nimport { EmailVerification } from \"./email-verification\";\nimport { ErrorPage } from \"./error-page\";\nimport { ForgotPassword } from \"./forgot-password\";\nimport { MagicLinkCallback } from \"./magic-link-callback\";\nimport { MFA } from \"./mfa\";\nimport { OAuthCallback } from \"./oauth-callback\";\nimport { PasswordReset } from \"./password-reset\";\nimport { SignOut } from \"./sign-out\";\nimport { TeamInvitation } from \"./team-invitation\";\n\n\ntype Components = {\n SignIn: typeof SignIn,\n SignUp: typeof SignUp,\n EmailVerification: typeof EmailVerification,\n PasswordReset: typeof PasswordReset,\n ForgotPassword: typeof ForgotPassword,\n SignOut: typeof SignOut,\n OAuthCallback: typeof OAuthCallback,\n MagicLinkCallback: typeof MagicLinkCallback,\n TeamInvitation: typeof TeamInvitation,\n ErrorPage: typeof ErrorPage,\n AccountSettings: typeof AccountSettings,\n CliAuthConfirmation: typeof CliAuthConfirmation,\n MFA: typeof MFA,\n};\n\ntype RouteProps = {\n params: Promise<{ stack?: string[] }> | { stack?: string[] },\n searchParams: Promise<Record<string, string>> | Record<string, string>,\n};\n\nconst availablePaths = {\n signIn: 'sign-in',\n signUp: 'sign-up',\n emailVerification: 'email-verification',\n passwordReset: 'password-reset',\n forgotPassword: 'forgot-password',\n signOut: 'sign-out',\n oauthCallback: 'oauth-callback',\n magicLinkCallback: 'magic-link-callback',\n teamInvitation: 'team-invitation',\n accountSettings: 'account-settings',\n cliAuthConfirm: 'cli-auth-confirm',\n mfa: 'mfa',\n error: 'error',\n} as const;\n\nconst pathAliases = {\n // also includes the uppercase and non-dashed versions\n ...Object.fromEntries(Object.entries(availablePaths).map(([key, value]) => [value, value])),\n \"log-in\": availablePaths.signIn,\n \"register\": availablePaths.signUp,\n} as const;\n\nexport type BaseHandlerProps = {\n fullPage: boolean,\n componentProps?: {\n [K in keyof Components]?: Parameters<Components[K]>[0];\n },\n};\n\nfunction renderComponent(props: {\n path: string,\n searchParams: Record<string, string>,\n fullPage: boolean,\n componentProps?: BaseHandlerProps['componentProps'],\n redirectIfNotHandler?: (name: keyof HandlerUrls) => void,\n onNotFound: () => any,\n app: StackClientApp<any> | StackServerApp<any>,\n}) {\n const { path, searchParams, fullPage, componentProps, redirectIfNotHandler, onNotFound, app } = props;\n\n switch (path) {\n case availablePaths.signIn: {\n redirectIfNotHandler?.('signIn');\n return <SignIn\n fullPage={fullPage}\n automaticRedirect\n {...filterUndefinedINU(componentProps?.SignIn)}\n />;\n }\n case availablePaths.signUp: {\n redirectIfNotHandler?.('signUp');\n return <SignUp\n fullPage={fullPage}\n automaticRedirect\n {...filterUndefinedINU(componentProps?.SignUp)}\n />;\n }\n case availablePaths.emailVerification: {\n redirectIfNotHandler?.('emailVerification');\n return <EmailVerification\n searchParams={searchParams}\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.EmailVerification)}\n />;\n }\n case availablePaths.passwordReset: {\n redirectIfNotHandler?.('passwordReset');\n return <PasswordReset\n searchParams={searchParams}\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.PasswordReset)}\n />;\n }\n case availablePaths.forgotPassword: {\n redirectIfNotHandler?.('forgotPassword');\n return <ForgotPassword\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.ForgotPassword)}\n />;\n }\n case availablePaths.signOut: {\n redirectIfNotHandler?.('signOut');\n return <SignOut\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.SignOut)}\n />;\n }\n case availablePaths.oauthCallback: {\n redirectIfNotHandler?.('oauthCallback');\n return <OAuthCallback\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.OAuthCallback)}\n />;\n }\n case availablePaths.magicLinkCallback: {\n redirectIfNotHandler?.('magicLinkCallback');\n return <MagicLinkCallback\n searchParams={searchParams}\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.MagicLinkCallback)}\n />;\n }\n case availablePaths.teamInvitation: {\n redirectIfNotHandler?.('teamInvitation');\n return <TeamInvitation\n searchParams={searchParams}\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.TeamInvitation)}\n />;\n }\n case availablePaths.accountSettings: {\n return <AccountSettings\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.AccountSettings)}\n />;\n }\n case availablePaths.error: {\n return <ErrorPage\n searchParams={searchParams}\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.ErrorPage)}\n />;\n }\n case availablePaths.cliAuthConfirm: {\n return <CliAuthConfirmation\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.CliAuthConfirmation)}\n />;\n }\n case availablePaths.mfa: {\n redirectIfNotHandler?.('mfa');\n return <MFA\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.MFA)}\n />;\n }\n default: {\n if (Object.values(availablePaths).includes(path as any)) {\n throw new StackAssertionError(`Path alias ${path} not included in switch statement, but in availablePaths?`, { availablePaths });\n }\n for (const [key, value] of Object.entries(pathAliases)) {\n if (path.toLowerCase().replaceAll('-', '') === key.toLowerCase().replaceAll('-', '')) {\n const redirectUrl = `${app.urls.handler}/${value}?${new URLSearchParams(searchParams).toString()}`;\n return { redirect: redirectUrl };\n }\n }\n return onNotFound();\n }\n }\n}\n\nexport function StackHandlerClient(props: BaseHandlerProps & Partial<RouteProps> & { location?: string }) {\n // Use hooks to get app\n const stackApp = useStackApp();\n\n const pathname = usePathname();\n const searchParamsFromHook = useSearchParams();\n const currentLocation = pathname;\n const searchParamsSource = searchParamsFromHook;\n\n const { path, searchParams } = useMemo(() => {\n const handlerPath = new URL(stackApp.urls.handler, 'http://example.com').pathname;\n const relativePath = currentLocation.startsWith(handlerPath)\n ? currentLocation.slice(handlerPath.length).replace(/^\\/+/, '')\n : currentLocation.replace(/^\\/+/, '');\n\n return {\n path: relativePath,\n searchParams: Object.fromEntries(searchParamsSource.entries())\n };\n }, [currentLocation, searchParamsSource, stackApp.urls.handler]);\n\n const redirectIfNotHandler = (name: keyof HandlerUrls) => {\n const url = stackApp.urls[name];\n const handlerUrl = stackApp.urls.handler;\n\n if (url !== handlerUrl && url.startsWith(handlerUrl + \"/\")) {\n return;\n }\n\n const urlObj = new URL(url, 'http://example.com');\n for (const [key, value] of Object.entries(searchParams)) {\n urlObj.searchParams.set(key, value);\n }\n\n redirect(getRelativePart(urlObj), RedirectType.replace);\n };\n\n const result = renderComponent({\n path,\n searchParams,\n fullPage: props.fullPage,\n componentProps: props.componentProps,\n redirectIfNotHandler,\n onNotFound: () =>\n notFound()\n ,\n app: stackApp,\n });\n\n if (result && 'redirect' in result) {\n redirect(result.redirect, RedirectType.replace);\n }\n\n return result;\n}\n\n// filter undefined values in object. if object itself is undefined, return undefined\nfunction filterUndefinedINU<T extends {}>(value: T | undefined): FilterUndefined<T> | undefined {\n return value === undefined ? value : filterUndefined(value);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components-page/stack-handler-client.tsx"],"sourcesContent":["\"use client\";\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { StackAssertionError } from \"@stackframe/stack-shared/dist/utils/errors\";\nimport { FilterUndefined, filterUndefined } from \"@stackframe/stack-shared/dist/utils/objects\";\nimport { getRelativePart } from \"@stackframe/stack-shared/dist/utils/urls\";\nimport { notFound, redirect, RedirectType, usePathname, useSearchParams } from 'next/navigation'; // THIS_LINE_PLATFORM next\nimport { useMemo } from 'react';\nimport { SignIn, SignUp, StackServerApp } from \"..\";\nimport { useStackApp } from \"../lib/hooks\";\nimport { HandlerUrls, StackClientApp } from \"../lib/stack-app\";\nimport { AccountSettings } from \"./account-settings\";\nimport { CliAuthConfirmation } from \"./cli-auth-confirm\";\nimport { EmailVerification } from \"./email-verification\";\nimport { ErrorPage } from \"./error-page\";\nimport { ForgotPassword } from \"./forgot-password\";\nimport { MagicLinkCallback } from \"./magic-link-callback\";\nimport { MFA } from \"./mfa\";\nimport { OAuthCallback } from \"./oauth-callback\";\nimport { Onboarding } from \"./onboarding\";\nimport { PasswordReset } from \"./password-reset\";\nimport { SignOut } from \"./sign-out\";\nimport { TeamInvitation } from \"./team-invitation\";\n\n\ntype Components = {\n SignIn: typeof SignIn,\n SignUp: typeof SignUp,\n EmailVerification: typeof EmailVerification,\n PasswordReset: typeof PasswordReset,\n ForgotPassword: typeof ForgotPassword,\n SignOut: typeof SignOut,\n OAuthCallback: typeof OAuthCallback,\n MagicLinkCallback: typeof MagicLinkCallback,\n TeamInvitation: typeof TeamInvitation,\n ErrorPage: typeof ErrorPage,\n AccountSettings: typeof AccountSettings,\n CliAuthConfirmation: typeof CliAuthConfirmation,\n MFA: typeof MFA,\n Onboarding: typeof Onboarding,\n};\n\ntype RouteProps = {\n params: Promise<{ stack?: string[] }> | { stack?: string[] },\n searchParams: Promise<Record<string, string>> | Record<string, string>,\n};\n\nconst availablePaths = {\n signIn: 'sign-in',\n signUp: 'sign-up',\n emailVerification: 'email-verification',\n passwordReset: 'password-reset',\n forgotPassword: 'forgot-password',\n signOut: 'sign-out',\n oauthCallback: 'oauth-callback',\n magicLinkCallback: 'magic-link-callback',\n teamInvitation: 'team-invitation',\n accountSettings: 'account-settings',\n cliAuthConfirm: 'cli-auth-confirm',\n mfa: 'mfa',\n error: 'error',\n onboarding: 'onboarding',\n} as const;\n\nconst pathAliases = {\n // also includes the uppercase and non-dashed versions\n ...Object.fromEntries(Object.entries(availablePaths).map(([key, value]) => [value, value])),\n \"log-in\": availablePaths.signIn,\n \"register\": availablePaths.signUp,\n} as const;\n\nexport type BaseHandlerProps = {\n fullPage: boolean,\n componentProps?: {\n [K in keyof Components]?: Parameters<Components[K]>[0];\n },\n};\n\nfunction renderComponent(props: {\n path: string,\n searchParams: Record<string, string>,\n fullPage: boolean,\n componentProps?: BaseHandlerProps['componentProps'],\n redirectIfNotHandler?: (name: keyof HandlerUrls) => void,\n onNotFound: () => any,\n app: StackClientApp<any> | StackServerApp<any>,\n}) {\n const { path, searchParams, fullPage, componentProps, redirectIfNotHandler, onNotFound, app } = props;\n\n switch (path) {\n case availablePaths.signIn: {\n redirectIfNotHandler?.('signIn');\n return <SignIn\n fullPage={fullPage}\n automaticRedirect\n {...filterUndefinedINU(componentProps?.SignIn)}\n />;\n }\n case availablePaths.signUp: {\n redirectIfNotHandler?.('signUp');\n return <SignUp\n fullPage={fullPage}\n automaticRedirect\n {...filterUndefinedINU(componentProps?.SignUp)}\n />;\n }\n case availablePaths.emailVerification: {\n redirectIfNotHandler?.('emailVerification');\n return <EmailVerification\n searchParams={searchParams}\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.EmailVerification)}\n />;\n }\n case availablePaths.passwordReset: {\n redirectIfNotHandler?.('passwordReset');\n return <PasswordReset\n searchParams={searchParams}\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.PasswordReset)}\n />;\n }\n case availablePaths.forgotPassword: {\n redirectIfNotHandler?.('forgotPassword');\n return <ForgotPassword\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.ForgotPassword)}\n />;\n }\n case availablePaths.signOut: {\n redirectIfNotHandler?.('signOut');\n return <SignOut\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.SignOut)}\n />;\n }\n case availablePaths.oauthCallback: {\n redirectIfNotHandler?.('oauthCallback');\n return <OAuthCallback\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.OAuthCallback)}\n />;\n }\n case availablePaths.magicLinkCallback: {\n redirectIfNotHandler?.('magicLinkCallback');\n return <MagicLinkCallback\n searchParams={searchParams}\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.MagicLinkCallback)}\n />;\n }\n case availablePaths.teamInvitation: {\n redirectIfNotHandler?.('teamInvitation');\n return <TeamInvitation\n searchParams={searchParams}\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.TeamInvitation)}\n />;\n }\n case availablePaths.accountSettings: {\n return <AccountSettings\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.AccountSettings)}\n />;\n }\n case availablePaths.error: {\n return <ErrorPage\n searchParams={searchParams}\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.ErrorPage)}\n />;\n }\n case availablePaths.cliAuthConfirm: {\n return <CliAuthConfirmation\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.CliAuthConfirmation)}\n />;\n }\n case availablePaths.mfa: {\n redirectIfNotHandler?.('mfa');\n return <MFA\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.MFA)}\n />;\n }\n case availablePaths.onboarding: {\n redirectIfNotHandler?.('onboarding');\n return <Onboarding\n fullPage={fullPage}\n {...filterUndefinedINU(componentProps?.Onboarding)}\n />;\n }\n default: {\n if (Object.values(availablePaths).includes(path as any)) {\n throw new StackAssertionError(`Path alias ${path} not included in switch statement, but in availablePaths?`, { availablePaths });\n }\n for (const [key, value] of Object.entries(pathAliases)) {\n if (path.toLowerCase().replaceAll('-', '') === key.toLowerCase().replaceAll('-', '')) {\n const redirectUrl = `${app.urls.handler}/${value}?${new URLSearchParams(searchParams).toString()}`;\n return { redirect: redirectUrl };\n }\n }\n return onNotFound();\n }\n }\n}\n\nexport function StackHandlerClient(props: BaseHandlerProps & Partial<RouteProps> & { location?: string }) {\n // Use hooks to get app\n const stackApp = useStackApp();\n\n const pathname = usePathname();\n const searchParamsFromHook = useSearchParams();\n const currentLocation = pathname;\n const searchParamsSource = searchParamsFromHook;\n\n const { path, searchParams } = useMemo(() => {\n const handlerPath = new URL(stackApp.urls.handler, 'http://example.com').pathname;\n const relativePath = currentLocation.startsWith(handlerPath)\n ? currentLocation.slice(handlerPath.length).replace(/^\\/+/, '')\n : currentLocation.replace(/^\\/+/, '');\n\n return {\n path: relativePath,\n searchParams: Object.fromEntries(searchParamsSource.entries())\n };\n }, [currentLocation, searchParamsSource, stackApp.urls.handler]);\n\n const redirectIfNotHandler = (name: keyof HandlerUrls) => {\n const url = stackApp.urls[name];\n const handlerUrl = stackApp.urls.handler;\n\n if (url !== handlerUrl && url.startsWith(handlerUrl + \"/\")) {\n return;\n }\n\n const urlObj = new URL(url, 'http://example.com');\n for (const [key, value] of Object.entries(searchParams)) {\n urlObj.searchParams.set(key, value);\n }\n\n redirect(getRelativePart(urlObj), RedirectType.replace);\n };\n\n const result = renderComponent({\n path,\n searchParams,\n fullPage: props.fullPage,\n componentProps: props.componentProps,\n redirectIfNotHandler,\n onNotFound: () =>\n notFound()\n ,\n app: stackApp,\n });\n\n if (result && 'redirect' in result) {\n redirect(result.redirect, RedirectType.replace);\n }\n\n return result;\n}\n\n// filter undefined values in object. if object itself is undefined, return undefined\nfunction filterUndefinedINU<T extends {}>(value: T | undefined): FilterUndefined<T> | undefined {\n return value === undefined ? value : filterUndefined(value);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,oBAAoC;AACpC,qBAAiD;AACjD,kBAAgC;AAChC,wBAA+E;AAC/E,mBAAwB;AACxB,eAA+C;AAC/C,mBAA4B;AAE5B,8BAAgC;AAChC,8BAAoC;AACpC,gCAAkC;AAClC,wBAA0B;AAC1B,6BAA+B;AAC/B,iCAAkC;AAClC,iBAAoB;AACpB,4BAA8B;AAC9B,wBAA2B;AAC3B,4BAA8B;AAC9B,sBAAwB;AACxB,6BAA+B;AAsElB;AA7Cb,IAAM,iBAAiB;AAAA,EACrB,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,mBAAmB;AAAA,EACnB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,SAAS;AAAA,EACT,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,KAAK;AAAA,EACL,OAAO;AAAA,EACP,YAAY;AACd;AAEA,IAAM,cAAc;AAAA;AAAA,EAElB,GAAG,OAAO,YAAY,OAAO,QAAQ,cAAc,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,OAAO,KAAK,CAAC,CAAC;AAAA,EAC1F,UAAU,eAAe;AAAA,EACzB,YAAY,eAAe;AAC7B;AASA,SAAS,gBAAgB,OAQtB;AACD,QAAM,EAAE,MAAM,cAAc,UAAU,gBAAgB,sBAAsB,YAAY,IAAI,IAAI;AAEhG,UAAQ,MAAM;AAAA,IACZ,KAAK,eAAe,QAAQ;AAC1B,6BAAuB,QAAQ;AAC/B,aAAO;AAAA,QAAC;AAAA;AAAA,UACN;AAAA,UACA,mBAAiB;AAAA,UAChB,GAAG,mBAAmB,gBAAgB,MAAM;AAAA;AAAA,MAC/C;AAAA,IACF;AAAA,IACA,KAAK,eAAe,QAAQ;AAC1B,6BAAuB,QAAQ;AAC/B,aAAO;AAAA,QAAC;AAAA;AAAA,UACN;AAAA,UACA,mBAAiB;AAAA,UAChB,GAAG,mBAAmB,gBAAgB,MAAM;AAAA;AAAA,MAC/C;AAAA,IACF;AAAA,IACA,KAAK,eAAe,mBAAmB;AACrC,6BAAuB,mBAAmB;AAC1C,aAAO;AAAA,QAAC;AAAA;AAAA,UACN;AAAA,UACA;AAAA,UACC,GAAG,mBAAmB,gBAAgB,iBAAiB;AAAA;AAAA,MAC1D;AAAA,IACF;AAAA,IACA,KAAK,eAAe,eAAe;AACjC,6BAAuB,eAAe;AACtC,aAAO;AAAA,QAAC;AAAA;AAAA,UACN;AAAA,UACA;AAAA,UACC,GAAG,mBAAmB,gBAAgB,aAAa;AAAA;AAAA,MACtD;AAAA,IACF;AAAA,IACA,KAAK,eAAe,gBAAgB;AAClC,6BAAuB,gBAAgB;AACvC,aAAO;AAAA,QAAC;AAAA;AAAA,UACN;AAAA,UACC,GAAG,mBAAmB,gBAAgB,cAAc;AAAA;AAAA,MACvD;AAAA,IACF;AAAA,IACA,KAAK,eAAe,SAAS;AAC3B,6BAAuB,SAAS;AAChC,aAAO;AAAA,QAAC;AAAA;AAAA,UACN;AAAA,UACC,GAAG,mBAAmB,gBAAgB,OAAO;AAAA;AAAA,MAChD;AAAA,IACF;AAAA,IACA,KAAK,eAAe,eAAe;AACjC,6BAAuB,eAAe;AACtC,aAAO;AAAA,QAAC;AAAA;AAAA,UACN;AAAA,UACC,GAAG,mBAAmB,gBAAgB,aAAa;AAAA;AAAA,MACtD;AAAA,IACF;AAAA,IACA,KAAK,eAAe,mBAAmB;AACrC,6BAAuB,mBAAmB;AAC1C,aAAO;AAAA,QAAC;AAAA;AAAA,UACN;AAAA,UACA;AAAA,UACC,GAAG,mBAAmB,gBAAgB,iBAAiB;AAAA;AAAA,MAC1D;AAAA,IACF;AAAA,IACA,KAAK,eAAe,gBAAgB;AAClC,6BAAuB,gBAAgB;AACvC,aAAO;AAAA,QAAC;AAAA;AAAA,UACN;AAAA,UACA;AAAA,UACC,GAAG,mBAAmB,gBAAgB,cAAc;AAAA;AAAA,MACvD;AAAA,IACF;AAAA,IACA,KAAK,eAAe,iBAAiB;AACnC,aAAO;AAAA,QAAC;AAAA;AAAA,UACN;AAAA,UACC,GAAG,mBAAmB,gBAAgB,eAAe;AAAA;AAAA,MACxD;AAAA,IACF;AAAA,IACA,KAAK,eAAe,OAAO;AACzB,aAAO;AAAA,QAAC;AAAA;AAAA,UACN;AAAA,UACA;AAAA,UACC,GAAG,mBAAmB,gBAAgB,SAAS;AAAA;AAAA,MAClD;AAAA,IACF;AAAA,IACA,KAAK,eAAe,gBAAgB;AAClC,aAAO;AAAA,QAAC;AAAA;AAAA,UACN;AAAA,UACC,GAAG,mBAAmB,gBAAgB,mBAAmB;AAAA;AAAA,MAC5D;AAAA,IACF;AAAA,IACA,KAAK,eAAe,KAAK;AACvB,6BAAuB,KAAK;AAC5B,aAAO;AAAA,QAAC;AAAA;AAAA,UACN;AAAA,UACC,GAAG,mBAAmB,gBAAgB,GAAG;AAAA;AAAA,MAC5C;AAAA,IACF;AAAA,IACA,KAAK,eAAe,YAAY;AAC9B,6BAAuB,YAAY;AACnC,aAAO;AAAA,QAAC;AAAA;AAAA,UACN;AAAA,UACC,GAAG,mBAAmB,gBAAgB,UAAU;AAAA;AAAA,MACnD;AAAA,IACF;AAAA,IACA,SAAS;AACP,UAAI,OAAO,OAAO,cAAc,EAAE,SAAS,IAAW,GAAG;AACvD,cAAM,IAAI,kCAAoB,cAAc,IAAI,6DAA6D,EAAE,eAAe,CAAC;AAAA,MACjI;AACA,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,WAAW,GAAG;AACtD,YAAI,KAAK,YAAY,EAAE,WAAW,KAAK,EAAE,MAAM,IAAI,YAAY,EAAE,WAAW,KAAK,EAAE,GAAG;AACpF,gBAAM,cAAc,GAAG,IAAI,KAAK,OAAO,IAAI,KAAK,IAAI,IAAI,gBAAgB,YAAY,EAAE,SAAS,CAAC;AAChG,iBAAO,EAAE,UAAU,YAAY;AAAA,QACjC;AAAA,MACF;AACA,aAAO,WAAW;AAAA,IACpB;AAAA,EACF;AACF;AAEO,SAAS,mBAAmB,OAAuE;AAExG,QAAM,eAAW,0BAAY;AAE7B,QAAM,eAAW,+BAAY;AAC7B,QAAM,2BAAuB,mCAAgB;AAC7C,QAAM,kBAAkB;AACxB,QAAM,qBAAqB;AAE3B,QAAM,EAAE,MAAM,aAAa,QAAI,sBAAQ,MAAM;AAC3C,UAAM,cAAc,IAAI,IAAI,SAAS,KAAK,SAAS,oBAAoB,EAAE;AACzE,UAAM,eAAe,gBAAgB,WAAW,WAAW,IACvD,gBAAgB,MAAM,YAAY,MAAM,EAAE,QAAQ,QAAQ,EAAE,IAC5D,gBAAgB,QAAQ,QAAQ,EAAE;AAEtC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,cAAc,OAAO,YAAY,mBAAmB,QAAQ,CAAC;AAAA,IAC/D;AAAA,EACF,GAAG,CAAC,iBAAiB,oBAAoB,SAAS,KAAK,OAAO,CAAC;AAE/D,QAAM,uBAAuB,CAAC,SAA4B;AACxD,UAAM,MAAM,SAAS,KAAK,IAAI;AAC9B,UAAM,aAAa,SAAS,KAAK;AAEjC,QAAI,QAAQ,cAAc,IAAI,WAAW,aAAa,GAAG,GAAG;AAC1D;AAAA,IACF;AAEA,UAAM,SAAS,IAAI,IAAI,KAAK,oBAAoB;AAChD,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,YAAY,GAAG;AACvD,aAAO,aAAa,IAAI,KAAK,KAAK;AAAA,IACpC;AAEA,wCAAS,6BAAgB,MAAM,GAAG,+BAAa,OAAO;AAAA,EACxD;AAEA,QAAM,SAAS,gBAAgB;AAAA,IAC7B;AAAA,IACA;AAAA,IACA,UAAU,MAAM;AAAA,IAChB,gBAAgB,MAAM;AAAA,IACtB;AAAA,IACA,YAAY,UACV,4BAAS;AAAA,IAEX,KAAK;AAAA,EACP,CAAC;AAED,MAAI,UAAU,cAAc,QAAQ;AAClC,oCAAS,OAAO,UAAU,+BAAa,OAAO;AAAA,EAChD;AAEA,SAAO;AACT;AAGA,SAAS,mBAAiC,OAAsD;AAC9F,SAAO,UAAU,SAAY,YAAQ,gCAAgB,KAAK;AAC5D;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components-page/stack-handler.tsx"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n// This file exists solely so the following old, deprecated code from when StackHandler used to still take props:\n// <StackHandler app={stackServerApp} routeProps={props} />\n// does not throw the following error:\n// Only plain objects, and a few built-ins, can be passed to Client Components from Server Components. Classes or null prototypes are not supported.\n// This file exists as a component that can be both client and server, ignores
|
|
1
|
+
{"version":3,"sources":["../../src/components-page/stack-handler.tsx"],"sourcesContent":["\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n// This file exists solely so the following old, deprecated code from when StackHandler used to still take props:\n// <StackHandler app={stackServerApp} routeProps={props} />\n// does not throw the following error:\n// Only plain objects, and a few built-ins, can be passed to Client Components from Server Components. Classes or null prototypes are not supported.\n// This file exists as a component that can be both client and server, ignores the non-serializable props, and returns <StackHandlerClient />\n\nimport { BaseHandlerProps, StackHandlerClient } from \"./stack-handler-client\";\n\nexport default function StackHandler({ app, routeProps, params, searchParams, ...props }: BaseHandlerProps & { location?: string } & {\n /**\n * @deprecated The app parameter is no longer necessary. You can safely remove it.\n */\n app?: any,\n\n /**\n * @deprecated The routeProps parameter is no longer necessary. You can safely remove it.\n */\n routeProps?: any,\n\n /**\n * @deprecated The params parameter is no longer necessary. You can safely remove it.\n */\n params?: any,\n\n /**\n * @deprecated The searchParams parameter is no longer necessary. You can safely remove it.\n */\n searchParams?: any,\n}) {\n return <StackHandlerClient {...props} />;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA,kCAAqD;AAuB5C;AArBM,SAAR,aAA8B,EAAE,KAAK,YAAY,QAAQ,cAAc,GAAG,MAAM,GAoBpF;AACD,SAAO,4CAAC,kDAAoB,GAAG,OAAO;AACxC;","names":[]}
|
|
@@ -100,7 +100,7 @@ function TeamInvitationInner(props) {
|
|
|
100
100
|
}
|
|
101
101
|
function TeamInvitation({ fullPage = false, searchParams }) {
|
|
102
102
|
const { t } = (0, import_translations.useTranslation)();
|
|
103
|
-
const user = (0, import__.useUser)();
|
|
103
|
+
const user = (0, import__.useUser)({ includeRestricted: true });
|
|
104
104
|
const stackApp = (0, import__.useStackApp)();
|
|
105
105
|
const invalidJsx = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import__.MessageCard, { title: t("Invalid Team Invitation Link"), fullPage, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: t("Please double check if you have the correct team invitation link.") }) });
|
|
106
106
|
const expiredJsx = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import__.MessageCard, { title: t("Expired Team Invitation Link"), fullPage, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: t("Your team invitation link has expired. Please request a new team invitation link ") }) });
|
|
@@ -123,6 +123,20 @@ function TeamInvitation({ fullPage = false, searchParams }) {
|
|
|
123
123
|
}
|
|
124
124
|
);
|
|
125
125
|
}
|
|
126
|
+
if (user.isRestricted) {
|
|
127
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
128
|
+
import__.MessageCard,
|
|
129
|
+
{
|
|
130
|
+
title: t("Complete your account setup"),
|
|
131
|
+
fullPage,
|
|
132
|
+
primaryButtonText: t("Complete setup"),
|
|
133
|
+
primaryAction: () => stackApp.redirectToOnboarding(),
|
|
134
|
+
secondaryButtonText: t("Cancel"),
|
|
135
|
+
secondaryAction: () => stackApp.redirectToHome(),
|
|
136
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: t("Please complete your account setup before joining teams.") })
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
}
|
|
126
140
|
const verificationResult = (0, import_react.use)(cachedVerifyInvitation(stackApp, searchParams.code || ""));
|
|
127
141
|
if (verificationResult.status === "error") {
|
|
128
142
|
const error = verificationResult.error;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components-page/team-invitation.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { KnownErrors } from \"@stackframe/stack-shared\";\nimport { cacheFunction } from \"@stackframe/stack-shared/dist/utils/caches\";\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { use } from \"@stackframe/stack-shared/dist/utils/react\";\nimport { Typography } from \"@stackframe/stack-ui\";\nimport React from \"react\";\nimport { MessageCard, StackClientApp, useStackApp, useUser } from \"..\";\nimport { PredefinedMessageCard } from \"../components/message-cards/predefined-message-card\";\nimport { useTranslation } from \"../lib/translations\";\n\nconst cachedVerifyInvitation = cacheFunction(async (stackApp: StackClientApp<true>, code: string) => {\n return await stackApp.verifyTeamInvitationCode(code);\n});\n\nconst cachedGetInvitationDetails = cacheFunction(async (stackApp: StackClientApp<true>, code: string) => {\n return await stackApp.getTeamInvitationDetails(code);\n});\n\nfunction TeamInvitationInner(props: { fullPage?: boolean, searchParams: Record<string, string> }) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const [success, setSuccess] = React.useState(false);\n const [errorMessage, setErrorMessage] = React.useState<string | null>(null);\n const details = use(cachedGetInvitationDetails(stackApp, props.searchParams.code || ''));\n\n if (errorMessage || details.status === 'error') {\n return (\n <PredefinedMessageCard type=\"unknownError\" fullPage={props.fullPage} />\n );\n }\n\n if (success) {\n return (\n <MessageCard\n title={t('Team invitation')}\n fullPage={props.fullPage}\n primaryButtonText=\"Go home\"\n primaryAction={() => stackApp.redirectToHome()}\n >\n <Typography>You have successfully joined {details.data.teamDisplayName}</Typography>\n </MessageCard>\n );\n }\n\n\n return (\n <MessageCard\n title={t('Team invitation')}\n fullPage={props.fullPage}\n primaryButtonText={t('Join')}\n primaryAction={() => runAsynchronouslyWithAlert(async () => {\n const result = await stackApp.acceptTeamInvitation(props.searchParams.code || '');\n if (result.status === 'error') {\n setErrorMessage(result.error.message);\n } else {\n setSuccess(true);\n }\n })}\n secondaryButtonText={t('Ignore')}\n secondaryAction={() => stackApp.redirectToHome()}\n >\n <Typography>You are invited to join {details.data.teamDisplayName}</Typography>\n </MessageCard>\n );\n}\n\nexport function TeamInvitation({ fullPage=false, searchParams }: { fullPage?: boolean, searchParams: Record<string, string> }) {\n const { t } = useTranslation();\n const user = useUser();\n const stackApp = useStackApp();\n\n const invalidJsx = (\n <MessageCard title={t('Invalid Team Invitation Link')} fullPage={fullPage}>\n <Typography>{t('Please double check if you have the correct team invitation link.')}</Typography>\n </MessageCard>\n );\n\n const expiredJsx = (\n <MessageCard title={t('Expired Team Invitation Link')} fullPage={fullPage}>\n <Typography>{t('Your team invitation link has expired. Please request a new team invitation link ')}</Typography>\n </MessageCard>\n );\n\n const usedJsx = (\n <MessageCard title={t('Used Team Invitation Link')} fullPage={fullPage}>\n <Typography>{t('This team invitation link has already been used.')}</Typography>\n </MessageCard>\n );\n\n const code = searchParams.code;\n if (!code) {\n return invalidJsx;\n }\n\n if (!user) {\n return (\n <MessageCard\n title={t('Team invitation')}\n fullPage={fullPage}\n primaryButtonText={t('Sign in')}\n primaryAction={() => stackApp.redirectToSignIn()}\n secondaryButtonText={t('Cancel')}\n secondaryAction={() => stackApp.redirectToHome()}\n >\n <Typography>{t('Sign in or create an account to join the team.')}</Typography>\n </MessageCard>\n );\n }\n\n const verificationResult = use(cachedVerifyInvitation(stackApp, searchParams.code || ''));\n\n if (verificationResult.status === 'error') {\n const error = verificationResult.error;\n if (KnownErrors.VerificationCodeNotFound.isInstance(error)) {\n return invalidJsx;\n } else if (KnownErrors.VerificationCodeExpired.isInstance(error)) {\n return expiredJsx;\n } else if (KnownErrors.VerificationCodeAlreadyUsed.isInstance(error)) {\n return usedJsx;\n } else {\n throw error;\n }\n }\n\n return <TeamInvitationInner fullPage={fullPage} searchParams={searchParams} />;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,0BAA4B;AAC5B,oBAA8B;AAC9B,sBAA2C;AAC3C,mBAAoB;AACpB,sBAA2B;AAC3B,IAAAA,gBAAkB;AAClB,eAAkE;AAClE,qCAAsC;AACtC,0BAA+B;AAmBzB;AAjBN,IAAM,6BAAyB,6BAAc,OAAO,UAAgC,SAAiB;AACnG,SAAO,MAAM,SAAS,yBAAyB,IAAI;AACrD,CAAC;AAED,IAAM,iCAA6B,6BAAc,OAAO,UAAgC,SAAiB;AACvG,SAAO,MAAM,SAAS,yBAAyB,IAAI;AACrD,CAAC;AAED,SAAS,oBAAoB,OAAqE;AAChG,QAAM,EAAE,EAAE,QAAI,oCAAe;AAC7B,QAAM,eAAW,sBAAY;AAC7B,QAAM,CAAC,SAAS,UAAU,IAAI,cAAAC,QAAM,SAAS,KAAK;AAClD,QAAM,CAAC,cAAc,eAAe,IAAI,cAAAA,QAAM,SAAwB,IAAI;AAC1E,QAAM,cAAU,kBAAI,2BAA2B,UAAU,MAAM,aAAa,QAAQ,EAAE,CAAC;AAEvF,MAAI,gBAAgB,QAAQ,WAAW,SAAS;AAC9C,WACE,4CAAC,wDAAsB,MAAK,gBAAe,UAAU,MAAM,UAAU;AAAA,EAEzE;AAEA,MAAI,SAAS;AACX,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,iBAAiB;AAAA,QAC1B,UAAU,MAAM;AAAA,QAChB,mBAAkB;AAAA,QAClB,eAAe,MAAM,SAAS,eAAe;AAAA,QAE7C,uDAAC,8BAAW;AAAA;AAAA,UAA8B,QAAQ,KAAK;AAAA,WAAgB;AAAA;AAAA,IACzE;AAAA,EAEJ;AAGA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,EAAE,iBAAiB;AAAA,MAC1B,UAAU,MAAM;AAAA,MAChB,mBAAmB,EAAE,MAAM;AAAA,MAC3B,eAAe,UAAM,4CAA2B,YAAY;AAC1D,cAAM,SAAS,MAAM,SAAS,qBAAqB,MAAM,aAAa,QAAQ,EAAE;AAChF,YAAI,OAAO,WAAW,SAAS;AAC/B,0BAAgB,OAAO,MAAM,OAAO;AAAA,QACpC,OAAO;AACP,qBAAW,IAAI;AAAA,QACf;AAAA,MACF,CAAC;AAAA,MACD,qBAAqB,EAAE,QAAQ;AAAA,MAC/B,iBAAiB,MAAM,SAAS,eAAe;AAAA,MAE/C,uDAAC,8BAAW;AAAA;AAAA,QAAyB,QAAQ,KAAK;AAAA,SAAgB;AAAA;AAAA,EACpE;AAEJ;AAEO,SAAS,eAAe,EAAE,WAAS,OAAO,aAAa,GAAiE;AAC7H,QAAM,EAAE,EAAE,QAAI,oCAAe;
|
|
1
|
+
{"version":3,"sources":["../../src/components-page/team-invitation.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY\n//===========================================\n\nimport { KnownErrors } from \"@stackframe/stack-shared\";\nimport { cacheFunction } from \"@stackframe/stack-shared/dist/utils/caches\";\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { use } from \"@stackframe/stack-shared/dist/utils/react\";\nimport { Typography } from \"@stackframe/stack-ui\";\nimport React from \"react\";\nimport { MessageCard, StackClientApp, useStackApp, useUser } from \"..\";\nimport { PredefinedMessageCard } from \"../components/message-cards/predefined-message-card\";\nimport { useTranslation } from \"../lib/translations\";\n\nconst cachedVerifyInvitation = cacheFunction(async (stackApp: StackClientApp<true>, code: string) => {\n return await stackApp.verifyTeamInvitationCode(code);\n});\n\nconst cachedGetInvitationDetails = cacheFunction(async (stackApp: StackClientApp<true>, code: string) => {\n return await stackApp.getTeamInvitationDetails(code);\n});\n\nfunction TeamInvitationInner(props: { fullPage?: boolean, searchParams: Record<string, string> }) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const [success, setSuccess] = React.useState(false);\n const [errorMessage, setErrorMessage] = React.useState<string | null>(null);\n const details = use(cachedGetInvitationDetails(stackApp, props.searchParams.code || ''));\n\n if (errorMessage || details.status === 'error') {\n return (\n <PredefinedMessageCard type=\"unknownError\" fullPage={props.fullPage} />\n );\n }\n\n if (success) {\n return (\n <MessageCard\n title={t('Team invitation')}\n fullPage={props.fullPage}\n primaryButtonText=\"Go home\"\n primaryAction={() => stackApp.redirectToHome()}\n >\n <Typography>You have successfully joined {details.data.teamDisplayName}</Typography>\n </MessageCard>\n );\n }\n\n\n return (\n <MessageCard\n title={t('Team invitation')}\n fullPage={props.fullPage}\n primaryButtonText={t('Join')}\n primaryAction={() => runAsynchronouslyWithAlert(async () => {\n const result = await stackApp.acceptTeamInvitation(props.searchParams.code || '');\n if (result.status === 'error') {\n setErrorMessage(result.error.message);\n } else {\n setSuccess(true);\n }\n })}\n secondaryButtonText={t('Ignore')}\n secondaryAction={() => stackApp.redirectToHome()}\n >\n <Typography>You are invited to join {details.data.teamDisplayName}</Typography>\n </MessageCard>\n );\n}\n\nexport function TeamInvitation({ fullPage=false, searchParams }: { fullPage?: boolean, searchParams: Record<string, string> }) {\n const { t } = useTranslation();\n // Include restricted users to detect if user needs to complete onboarding\n const user = useUser({ includeRestricted: true });\n const stackApp = useStackApp();\n\n const invalidJsx = (\n <MessageCard title={t('Invalid Team Invitation Link')} fullPage={fullPage}>\n <Typography>{t('Please double check if you have the correct team invitation link.')}</Typography>\n </MessageCard>\n );\n\n const expiredJsx = (\n <MessageCard title={t('Expired Team Invitation Link')} fullPage={fullPage}>\n <Typography>{t('Your team invitation link has expired. Please request a new team invitation link ')}</Typography>\n </MessageCard>\n );\n\n const usedJsx = (\n <MessageCard title={t('Used Team Invitation Link')} fullPage={fullPage}>\n <Typography>{t('This team invitation link has already been used.')}</Typography>\n </MessageCard>\n );\n\n const code = searchParams.code;\n if (!code) {\n return invalidJsx;\n }\n\n if (!user) {\n return (\n <MessageCard\n title={t('Team invitation')}\n fullPage={fullPage}\n primaryButtonText={t('Sign in')}\n primaryAction={() => stackApp.redirectToSignIn()}\n secondaryButtonText={t('Cancel')}\n secondaryAction={() => stackApp.redirectToHome()}\n >\n <Typography>{t('Sign in or create an account to join the team.')}</Typography>\n </MessageCard>\n );\n }\n\n // User is restricted (needs to complete onboarding) - redirect to onboarding\n if (user.isRestricted) {\n return (\n <MessageCard\n title={t('Complete your account setup')}\n fullPage={fullPage}\n primaryButtonText={t('Complete setup')}\n primaryAction={() => stackApp.redirectToOnboarding()}\n secondaryButtonText={t('Cancel')}\n secondaryAction={() => stackApp.redirectToHome()}\n >\n <Typography>{t('Please complete your account setup before joining teams.')}</Typography>\n </MessageCard>\n );\n }\n\n const verificationResult = use(cachedVerifyInvitation(stackApp, searchParams.code || ''));\n\n if (verificationResult.status === 'error') {\n const error = verificationResult.error;\n if (KnownErrors.VerificationCodeNotFound.isInstance(error)) {\n return invalidJsx;\n } else if (KnownErrors.VerificationCodeExpired.isInstance(error)) {\n return expiredJsx;\n } else if (KnownErrors.VerificationCodeAlreadyUsed.isInstance(error)) {\n return usedJsx;\n } else {\n throw error;\n }\n }\n\n return <TeamInvitationInner fullPage={fullPage} searchParams={searchParams} />;\n};\n"],"mappings":"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","names":["import_react","React"]}
|