@stackframe/stack 2.5.21 → 2.5.23
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/CHANGELOG.md +20 -0
- package/dist/components-page/account-settings.js +3 -2
- package/dist/components-page/account-settings.js.map +1 -1
- package/dist/esm/components-page/account-settings.js +3 -2
- package/dist/esm/components-page/account-settings.js.map +1 -1
- package/dist/esm/lib/stack-app.js +6 -1
- package/dist/esm/lib/stack-app.js.map +1 -1
- package/dist/lib/stack-app.d.mts +3 -0
- package/dist/lib/stack-app.d.ts +3 -0
- package/dist/lib/stack-app.js +6 -1
- package/dist/lib/stack-app.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @stackframe/stack
|
|
2
2
|
|
|
3
|
+
## 2.5.23
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Various bugfixes and performance improvements
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @stackframe/stack-ui@2.5.23
|
|
10
|
+
- @stackframe/stack-sc@2.5.23
|
|
11
|
+
- @stackframe/stack-shared@2.5.23
|
|
12
|
+
|
|
13
|
+
## 2.5.22
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Team metadata
|
|
18
|
+
- Updated dependencies
|
|
19
|
+
- @stackframe/stack-shared@2.5.22
|
|
20
|
+
- @stackframe/stack-ui@2.5.22
|
|
21
|
+
- @stackframe/stack-sc@2.5.22
|
|
22
|
+
|
|
3
23
|
## 2.5.21
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
|
@@ -408,8 +408,9 @@ var invitationSchema = (0, import_schema_fields.yupObject)({
|
|
|
408
408
|
email: (0, import_schema_fields.yupString)().email().required("Please enter an email address")
|
|
409
409
|
});
|
|
410
410
|
function MemberInvitation(props) {
|
|
411
|
-
const
|
|
412
|
-
|
|
411
|
+
const user = (0, import__.useUser)({ or: "redirect" });
|
|
412
|
+
const inviteMemberPermission = user.usePermission(props.team, "$invite_members");
|
|
413
|
+
if (!inviteMemberPermission) {
|
|
413
414
|
return null;
|
|
414
415
|
}
|
|
415
416
|
const { register, handleSubmit, formState: { errors }, watch } = (0, import_react_hook_form.useForm)({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components-page/account-settings.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { getPasswordError } from '@stackframe/stack-shared/dist/helpers/password';\nimport { useAsyncCallback } from '@stackframe/stack-shared/dist/hooks/use-async-callback';\nimport { yupObject, yupString } from '@stackframe/stack-shared/dist/schema-fields';\nimport { generateRandomValues } from '@stackframe/stack-shared/dist/utils/crypto';\nimport { throwErr } from '@stackframe/stack-shared/dist/utils/errors';\nimport { runAsynchronously, runAsynchronouslyWithAlert } from '@stackframe/stack-shared/dist/utils/promises';\nimport { Button, EditableText, Input, Label, PasswordInput, SimpleTooltip, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Typography } from '@stackframe/stack-ui';\nimport { CirclePlus, Contact, LogOut, ShieldCheck } from 'lucide-react';\nimport { TOTPController, createTOTPKeyURI } from \"oslo/otp\";\nimport * as QRCode from 'qrcode';\nimport { useEffect, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport * as yup from \"yup\";\nimport { CurrentUser, MessageCard, Project, Team, useStackApp, useUser } from '..';\nimport { FormWarningText } from '../components/elements/form-warning';\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { SidebarLayout } from '../components/elements/sidebar-layout';\nimport { UserAvatar } from '../components/elements/user-avatar';\nimport { TeamIcon } from '../components/team-icon';\n\n\nexport function AccountSettings({ fullPage=false }: { fullPage?: boolean }) {\n const user = useUser({ or: 'redirect' });\n const teams = user.useTeams();\n const project = useStackApp().useProject();\n\n return (\n <SidebarLayout\n items={([\n {\n title: 'My Profile',\n type: 'item',\n subpath: '/profile',\n icon: Contact,\n content: <ProfileSection/>,\n },\n {\n title: 'Security',\n type: 'item',\n icon: ShieldCheck,\n subpath: '/security',\n content: (\n <div className='flex flex-col gap-8'>\n <EmailVerificationSection />\n <PasswordSection />\n <MfaSection />\n </div>\n ),\n },\n {\n title: 'Sign Out',\n subpath: '/sign-out',\n type: 'item',\n icon: LogOut,\n content: <SignOutSection />,\n },\n ...(teams.length > 0 || project.config.clientTeamCreationEnabled) ? [{\n title: 'Teams',\n type: 'divider',\n }] as const : [],\n ...teams.map(team => ({\n title: <div className='flex gap-2 items-center'>\n <TeamIcon team={team}/>\n {team.displayName}\n </div>,\n type: 'item',\n subpath: `/teams/${team.id}`,\n content: (\n <div className=\"flex flex-col gap-8\">\n <ProfileSettings team={team}/>\n <ManagementSettings team={team}/>\n <MemberInvitation team={team}/>\n <MembersSettings team={team}/>\n <UserSettings team={team}/>\n </div>\n ),\n } as const)),\n ...project.config.clientTeamCreationEnabled ? [{\n title: 'Create a team',\n icon: CirclePlus,\n type: 'item',\n subpath: '/team-creation',\n content: <TeamCreation />,\n }] as const : [],\n ] as const).filter((p) => p.type === 'divider' || (p as any).content )}\n title='Account Settings'\n basePath='/handler/account-settings'\n />\n );\n}\n\nfunction ProfileSection() {\n const user = useUser({ or: 'redirect' });\n\n return (\n <div>\n <div>\n <Label>Display name</Label>\n <EditableText value={user.displayName || ''} onSave={async (newDisplayName) => {\n await user.update({ displayName: newDisplayName });\n }}/>\n </div>\n </div>\n );\n}\n\nfunction EmailVerificationSection() {\n const user = useUser({ or: 'redirect' });\n const [emailSent, setEmailSent] = useState(false);\n\n if (!user.primaryEmail) {\n return null;\n }\n\n return (\n <>\n <div>\n <Label>Email Verification</Label>\n {user.primaryEmailVerified ? (\n <Typography variant='success'>Your email has been verified.</Typography>\n ) : (\n <>\n <Typography variant='destructive'>Your email has not been verified.</Typography>\n <div className='flex mt-4'>\n <Button\n disabled={emailSent}\n onClick={async () => {\n await user.sendVerificationEmail();\n setEmailSent(true);\n }}\n >\n {emailSent ? 'Email sent!' : 'Send Verification Email'}\n </Button>\n </div>\n </>\n )}\n\n </div>\n </>\n );\n}\n\nconst passwordSchema = yupObject({\n oldPassword: yupString().required('Please enter your old password'),\n newPassword: yupString().required('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 newPasswordRepeat: yupString().nullable().oneOf([yup.ref('newPassword'), \"\", null], 'Passwords do not match').required('Please repeat your password')\n});\n\nfunction PasswordSection() {\n const user = useUser({ or: \"throw\" });\n const [changingPassword, setChangingPassword] = useState(false);\n const { register, handleSubmit, setError, formState: { errors }, clearErrors, reset } = useForm({\n resolver: yupResolver(passwordSchema)\n });\n const [alreadyReset, setAlreadyReset] = useState(false);\n const [loading, setLoading] = useState(false);\n\n const onSubmit = async (data: yup.InferType<typeof passwordSchema>) => {\n setLoading(true);\n try {\n const { oldPassword, newPassword } = data;\n const error = await user.updatePassword({ oldPassword, newPassword });\n if (error) {\n setError('oldPassword', { type: 'manual', message: 'Incorrect password' });\n } else {\n reset();\n setAlreadyReset(true);\n }\n } finally {\n setLoading(false);\n }\n };\n\n const registerPassword = register('newPassword');\n const registerPasswordRepeat = register('newPasswordRepeat');\n\n if (!user.hasPassword) {\n return null;\n }\n\n return (\n <div>\n <Label>Change password</Label>\n <div>\n {\n alreadyReset ?\n <Typography variant='success'>Password changed successfully!</Typography> :\n !changingPassword ?\n <Button\n variant='secondary'\n onClick={async () => {\n setChangingPassword(true);\n }}\n >\n Change Password\n </Button> :\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <Label htmlFor=\"old-password\" className=\"mb-1\">Old password</Label>\n <Input\n id=\"old-password\"\n type=\"password\"\n {...register('oldPassword')}\n />\n <FormWarningText text={errors.oldPassword?.message?.toString()} />\n\n <Label htmlFor=\"new-password\" className=\"mt-4 mb-1\">Password</Label>\n <PasswordInput\n id=\"new-password\"\n {...registerPassword}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPassword.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPassword?.message?.toString()} />\n\n <Label htmlFor=\"repeat-password\" className=\"mt-4 mb-1\">Repeat password</Label>\n <PasswordInput\n id=\"repeat-password\"\n {...registerPasswordRepeat}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPasswordRepeat.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPasswordRepeat?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n Change Password\n </Button>\n </form>\n }\n </div>\n </div>\n );\n}\n\nfunction MfaSection() {\n const project = useStackApp().useProject();\n const user = useUser({ or: \"throw\" });\n const [generatedSecret, setGeneratedSecret] = useState<Uint8Array | null>(null);\n const [qrCodeUrl, setQrCodeUrl] = useState<string | null>(null);\n const [mfaCode, setMfaCode] = useState<string>(\"\");\n const [isMaybeWrong, setIsMaybeWrong] = useState(false);\n const isEnabled = user.isMultiFactorRequired;\n\n const [handleSubmit, isLoading] = useAsyncCallback(async () => {\n await user.update({\n totpMultiFactorSecret: generatedSecret,\n });\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }, [generatedSecret, user]);\n\n useEffect(() => {\n setIsMaybeWrong(false);\n runAsynchronouslyWithAlert(async () => {\n if (generatedSecret && await new TOTPController().verify(mfaCode, generatedSecret)) {\n await handleSubmit();\n }\n setIsMaybeWrong(true);\n });\n }, [mfaCode, generatedSecret, handleSubmit]);\n\n return (\n <div>\n <div>\n <Label>Multi-factor Authentication</Label>\n\n <div>\n {isEnabled ? (\n <Typography variant=\"success\">Multi-factor authentication is currently enabled.</Typography>\n ) : (\n generatedSecret ? (\n <div className='flex flex-col gap-4 items-center'>\n <Typography>Scan this QR code with your authenticator app:</Typography>\n <img width={200} height={200} src={qrCodeUrl ?? throwErr(\"TOTP QR code failed to generate\")} alt=\"TOTP multi-factor authentication QR code\" />\n <Typography>Then, enter your six-digit MFA code:</Typography>\n <Input\n value={mfaCode}\n onChange={(e) => {\n setIsMaybeWrong(false);\n setMfaCode(e.target.value);\n }}\n placeholder=\"123456\"\n maxLength={6}\n disabled={isLoading}\n />\n {isMaybeWrong && mfaCode.length === 6 && (\n <Typography variant=\"destructive\">Incorrect code. Please try again.</Typography>\n )}\n </div>\n ) : (\n <Typography variant=\"destructive\">Multi-factor authentication is currently disabled.</Typography>\n )\n )}\n\n <Button\n className=\"mt-4\"\n variant={isEnabled ? 'secondary' : 'default'}\n onClick={async () => {\n if (isEnabled) {\n await user.update({\n totpMultiFactorSecret: null,\n });\n } else if (!generatedSecret) {\n const secret = generateRandomValues(new Uint8Array(20));\n setQrCodeUrl(await generateTotpQrCode(project, user, secret));\n setGeneratedSecret(secret);\n } else {\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }\n }}\n >\n {isEnabled ? 'Disable' : (generatedSecret ? 'Cancel' : 'Enable')}\n </Button>\n </div>\n </div>\n </div>\n );\n}\n\nasync function generateTotpQrCode(project: Project, user: CurrentUser, secret: Uint8Array) {\n const uri = createTOTPKeyURI(project.displayName, user.primaryEmail ?? user.id, secret);\n return await QRCode.toDataURL(uri) as any;\n}\n\nfunction SignOutSection() {\n const user = useUser({ or: \"throw\" });\n return (\n <div className='flex flex-col gap-2'>\n <div>\n <Button\n variant='secondary'\n onClick={() => user.signOut()}\n >\n Sign Out\n </Button>\n </div>\n </div>\n );\n}\n\nfunction UserSettings(props: { team: Team }) {\n const app = useStackApp();\n const user = useUser({ or: 'redirect' });\n const [leaving, setLeaving] = useState(false);\n\n return (\n <div className='flex flex-col gap-2'>\n <div>\n { !leaving ?\n <Button\n variant='secondary'\n onClick={async () => setLeaving(true)}\n >\n Leave team\n </Button> :\n <div className=''>\n <Typography variant='destructive'>Are you sure you want to leave the team?</Typography>\n <div className='flex gap-2'>\n <Button variant='destructive' onClick={async () => {\n await user.leaveTeam(props.team);\n window.location.reload();\n }}>\n Leave\n </Button>\n <Button variant='secondary' onClick={() => setLeaving(false)}>\n Cancel\n </Button>\n </div>\n </div>}\n </div>\n </div>\n );\n}\n\nfunction ManagementSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const updateTeamPermission = user.usePermission(props.team, '$update_team');\n\n if (!updateTeamPermission) {\n return null;\n }\n\n return (\n <>\n <div>\n <Label>Team display name</Label>\n <EditableText\n value={props.team.displayName}\n onSave={async (newDisplayName) => await props.team.update({ displayName: newDisplayName })}\n />\n </div>\n </>\n );\n}\n\nfunction ProfileSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const profile = user.useTeamProfile(props.team);\n\n return (\n <div className=\"flex flex-col\">\n <div className=\"flex flex-col\">\n <Label className=\"flex gap-2\">User display name <SimpleTooltip tooltip=\"This overwrites your user display name in the account setting\" type='info'/></Label>\n <EditableText\n value={profile.displayName || ''}\n onSave={async (newDisplayName) => {\n await profile.update({ displayName: newDisplayName });\n }}/>\n </div>\n </div>\n );\n}\n\nconst invitationSchema = yupObject({\n email: yupString().email().required('Please enter an email address'),\n});\n\nfunction MemberInvitation(props: { team: Team }) {\n const project = useStackApp().useProject();\n\n if (!project.config.clientTeamCreationEnabled) {\n return null;\n }\n\n const { register, handleSubmit, formState: { errors }, watch } = useForm({\n resolver: yupResolver(invitationSchema)\n });\n const [loading, setLoading] = useState(false);\n const [invitedEmail, setInvitedEmail] = useState<string | null>(null);\n\n const onSubmit = async (data: yup.InferType<typeof invitationSchema>) => {\n setLoading(true);\n\n try {\n await props.team.inviteUser({ email: data.email });\n setInvitedEmail(data.email);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n setInvitedEmail(null);\n }, [watch('email')]);\n\n return (\n <div>\n <Label>Invite a user to team</Label>\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <div className=\"flex flex-col gap-4 md:flex-row\">\n <div>\n <Input\n placeholder=\"Email\"\n {...register('email')}\n />\n </div>\n <Button type=\"submit\" loading={loading}>\n Invite User\n </Button>\n </div>\n <FormWarningText text={errors.email?.message?.toString()} />\n {invitedEmail && <Typography type='label' variant='secondary'>Invited {invitedEmail}</Typography>}\n </form>\n </div>\n );\n}\n\n\nfunction MembersSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const readMemberPermission = user.usePermission(props.team, '$read_members');\n const inviteMemberPermission = user.usePermission(props.team, '$invite_members');\n\n if (!readMemberPermission && !inviteMemberPermission) {\n return null;\n }\n\n const users = props.team.useUsers();\n\n if (!readMemberPermission) {\n return null;\n }\n\n return (\n <div>\n <Label>Members</Label>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[100px]\">User</TableHead>\n <TableHead className=\"w-[200px]\">Name</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {users.map(({ id, teamProfile }, i) => (\n <TableRow key={id}>\n <TableCell>\n <UserAvatar user={teamProfile}/>\n </TableCell>\n <TableCell>\n <Typography>{teamProfile.displayName}</Typography>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n );\n}\n\nconst teamCreationSchema = yupObject({\n displayName: yupString().required('Please enter a team name'),\n});\n\nexport function TeamCreation() {\n const { register, handleSubmit, formState: { errors } } = useForm({\n resolver: yupResolver(teamCreationSchema)\n });\n const app = useStackApp();\n const project = app.useProject();\n const user = useUser({ or: 'redirect' });\n const [loading, setLoading] = useState(false);\n\n if (!project.config.clientTeamCreationEnabled) {\n return <MessageCard title='Team creation is not enabled' />;\n }\n\n const onSubmit = async (data: yup.InferType<typeof teamCreationSchema>) => {\n setLoading(true);\n\n try {\n const team = await user.createTeam({ displayName: data.displayName });\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <div className='stack-scope flex flex-col items-stretch'>\n <div className=\"mb-6\">\n <form\n className=\"flex flex-col items-stretch stack-scope\"\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <div className=\"flex items-end gap-4\">\n <div>\n <Label htmlFor=\"email\" className=\"mb-1\">Display name</Label>\n <Input\n id=\"email\"\n type=\"email\"\n {...register('displayName')}\n />\n </div>\n <FormWarningText text={errors.displayName?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n Create\n </Button>\n </div>\n </form>\n </div>\n </div>\n );\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components-page/account-settings.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { getPasswordError } from '@stackframe/stack-shared/dist/helpers/password';\nimport { useAsyncCallback } from '@stackframe/stack-shared/dist/hooks/use-async-callback';\nimport { yupObject, yupString } from '@stackframe/stack-shared/dist/schema-fields';\nimport { generateRandomValues } from '@stackframe/stack-shared/dist/utils/crypto';\nimport { throwErr } from '@stackframe/stack-shared/dist/utils/errors';\nimport { runAsynchronously, runAsynchronouslyWithAlert } from '@stackframe/stack-shared/dist/utils/promises';\nimport { Button, EditableText, Input, Label, PasswordInput, SimpleTooltip, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Typography } from '@stackframe/stack-ui';\nimport { CirclePlus, Contact, LogOut, ShieldCheck } from 'lucide-react';\nimport { TOTPController, createTOTPKeyURI } from \"oslo/otp\";\nimport * as QRCode from 'qrcode';\nimport { useEffect, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport * as yup from \"yup\";\nimport { CurrentUser, MessageCard, Project, Team, useStackApp, useUser } from '..';\nimport { FormWarningText } from '../components/elements/form-warning';\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { SidebarLayout } from '../components/elements/sidebar-layout';\nimport { UserAvatar } from '../components/elements/user-avatar';\nimport { TeamIcon } from '../components/team-icon';\n\n\nexport function AccountSettings({ fullPage=false }: { fullPage?: boolean }) {\n const user = useUser({ or: 'redirect' });\n const teams = user.useTeams();\n const project = useStackApp().useProject();\n\n return (\n <SidebarLayout\n items={([\n {\n title: 'My Profile',\n type: 'item',\n subpath: '/profile',\n icon: Contact,\n content: <ProfileSection/>,\n },\n {\n title: 'Security',\n type: 'item',\n icon: ShieldCheck,\n subpath: '/security',\n content: (\n <div className='flex flex-col gap-8'>\n <EmailVerificationSection />\n <PasswordSection />\n <MfaSection />\n </div>\n ),\n },\n {\n title: 'Sign Out',\n subpath: '/sign-out',\n type: 'item',\n icon: LogOut,\n content: <SignOutSection />,\n },\n ...(teams.length > 0 || project.config.clientTeamCreationEnabled) ? [{\n title: 'Teams',\n type: 'divider',\n }] as const : [],\n ...teams.map(team => ({\n title: <div className='flex gap-2 items-center'>\n <TeamIcon team={team}/>\n {team.displayName}\n </div>,\n type: 'item',\n subpath: `/teams/${team.id}`,\n content: (\n <div className=\"flex flex-col gap-8\">\n <ProfileSettings team={team}/>\n <ManagementSettings team={team}/>\n <MemberInvitation team={team}/>\n <MembersSettings team={team}/>\n <UserSettings team={team}/>\n </div>\n ),\n } as const)),\n ...project.config.clientTeamCreationEnabled ? [{\n title: 'Create a team',\n icon: CirclePlus,\n type: 'item',\n subpath: '/team-creation',\n content: <TeamCreation />,\n }] as const : [],\n ] as const).filter((p) => p.type === 'divider' || (p as any).content )}\n title='Account Settings'\n basePath='/handler/account-settings'\n />\n );\n}\n\nfunction ProfileSection() {\n const user = useUser({ or: 'redirect' });\n\n return (\n <div>\n <div>\n <Label>Display name</Label>\n <EditableText value={user.displayName || ''} onSave={async (newDisplayName) => {\n await user.update({ displayName: newDisplayName });\n }}/>\n </div>\n </div>\n );\n}\n\nfunction EmailVerificationSection() {\n const user = useUser({ or: 'redirect' });\n const [emailSent, setEmailSent] = useState(false);\n\n if (!user.primaryEmail) {\n return null;\n }\n\n return (\n <>\n <div>\n <Label>Email Verification</Label>\n {user.primaryEmailVerified ? (\n <Typography variant='success'>Your email has been verified.</Typography>\n ) : (\n <>\n <Typography variant='destructive'>Your email has not been verified.</Typography>\n <div className='flex mt-4'>\n <Button\n disabled={emailSent}\n onClick={async () => {\n await user.sendVerificationEmail();\n setEmailSent(true);\n }}\n >\n {emailSent ? 'Email sent!' : 'Send Verification Email'}\n </Button>\n </div>\n </>\n )}\n\n </div>\n </>\n );\n}\n\nconst passwordSchema = yupObject({\n oldPassword: yupString().required('Please enter your old password'),\n newPassword: yupString().required('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 newPasswordRepeat: yupString().nullable().oneOf([yup.ref('newPassword'), \"\", null], 'Passwords do not match').required('Please repeat your password')\n});\n\nfunction PasswordSection() {\n const user = useUser({ or: \"throw\" });\n const [changingPassword, setChangingPassword] = useState(false);\n const { register, handleSubmit, setError, formState: { errors }, clearErrors, reset } = useForm({\n resolver: yupResolver(passwordSchema)\n });\n const [alreadyReset, setAlreadyReset] = useState(false);\n const [loading, setLoading] = useState(false);\n\n const onSubmit = async (data: yup.InferType<typeof passwordSchema>) => {\n setLoading(true);\n try {\n const { oldPassword, newPassword } = data;\n const error = await user.updatePassword({ oldPassword, newPassword });\n if (error) {\n setError('oldPassword', { type: 'manual', message: 'Incorrect password' });\n } else {\n reset();\n setAlreadyReset(true);\n }\n } finally {\n setLoading(false);\n }\n };\n\n const registerPassword = register('newPassword');\n const registerPasswordRepeat = register('newPasswordRepeat');\n\n if (!user.hasPassword) {\n return null;\n }\n\n return (\n <div>\n <Label>Change password</Label>\n <div>\n {\n alreadyReset ?\n <Typography variant='success'>Password changed successfully!</Typography> :\n !changingPassword ?\n <Button\n variant='secondary'\n onClick={async () => {\n setChangingPassword(true);\n }}\n >\n Change Password\n </Button> :\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <Label htmlFor=\"old-password\" className=\"mb-1\">Old password</Label>\n <Input\n id=\"old-password\"\n type=\"password\"\n {...register('oldPassword')}\n />\n <FormWarningText text={errors.oldPassword?.message?.toString()} />\n\n <Label htmlFor=\"new-password\" className=\"mt-4 mb-1\">Password</Label>\n <PasswordInput\n id=\"new-password\"\n {...registerPassword}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPassword.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPassword?.message?.toString()} />\n\n <Label htmlFor=\"repeat-password\" className=\"mt-4 mb-1\">Repeat password</Label>\n <PasswordInput\n id=\"repeat-password\"\n {...registerPasswordRepeat}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPasswordRepeat.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPasswordRepeat?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n Change Password\n </Button>\n </form>\n }\n </div>\n </div>\n );\n}\n\nfunction MfaSection() {\n const project = useStackApp().useProject();\n const user = useUser({ or: \"throw\" });\n const [generatedSecret, setGeneratedSecret] = useState<Uint8Array | null>(null);\n const [qrCodeUrl, setQrCodeUrl] = useState<string | null>(null);\n const [mfaCode, setMfaCode] = useState<string>(\"\");\n const [isMaybeWrong, setIsMaybeWrong] = useState(false);\n const isEnabled = user.isMultiFactorRequired;\n\n const [handleSubmit, isLoading] = useAsyncCallback(async () => {\n await user.update({\n totpMultiFactorSecret: generatedSecret,\n });\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }, [generatedSecret, user]);\n\n useEffect(() => {\n setIsMaybeWrong(false);\n runAsynchronouslyWithAlert(async () => {\n if (generatedSecret && await new TOTPController().verify(mfaCode, generatedSecret)) {\n await handleSubmit();\n }\n setIsMaybeWrong(true);\n });\n }, [mfaCode, generatedSecret, handleSubmit]);\n\n return (\n <div>\n <div>\n <Label>Multi-factor Authentication</Label>\n\n <div>\n {isEnabled ? (\n <Typography variant=\"success\">Multi-factor authentication is currently enabled.</Typography>\n ) : (\n generatedSecret ? (\n <div className='flex flex-col gap-4 items-center'>\n <Typography>Scan this QR code with your authenticator app:</Typography>\n <img width={200} height={200} src={qrCodeUrl ?? throwErr(\"TOTP QR code failed to generate\")} alt=\"TOTP multi-factor authentication QR code\" />\n <Typography>Then, enter your six-digit MFA code:</Typography>\n <Input\n value={mfaCode}\n onChange={(e) => {\n setIsMaybeWrong(false);\n setMfaCode(e.target.value);\n }}\n placeholder=\"123456\"\n maxLength={6}\n disabled={isLoading}\n />\n {isMaybeWrong && mfaCode.length === 6 && (\n <Typography variant=\"destructive\">Incorrect code. Please try again.</Typography>\n )}\n </div>\n ) : (\n <Typography variant=\"destructive\">Multi-factor authentication is currently disabled.</Typography>\n )\n )}\n\n <Button\n className=\"mt-4\"\n variant={isEnabled ? 'secondary' : 'default'}\n onClick={async () => {\n if (isEnabled) {\n await user.update({\n totpMultiFactorSecret: null,\n });\n } else if (!generatedSecret) {\n const secret = generateRandomValues(new Uint8Array(20));\n setQrCodeUrl(await generateTotpQrCode(project, user, secret));\n setGeneratedSecret(secret);\n } else {\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }\n }}\n >\n {isEnabled ? 'Disable' : (generatedSecret ? 'Cancel' : 'Enable')}\n </Button>\n </div>\n </div>\n </div>\n );\n}\n\nasync function generateTotpQrCode(project: Project, user: CurrentUser, secret: Uint8Array) {\n const uri = createTOTPKeyURI(project.displayName, user.primaryEmail ?? user.id, secret);\n return await QRCode.toDataURL(uri) as any;\n}\n\nfunction SignOutSection() {\n const user = useUser({ or: \"throw\" });\n return (\n <div className='flex flex-col gap-2'>\n <div>\n <Button\n variant='secondary'\n onClick={() => user.signOut()}\n >\n Sign Out\n </Button>\n </div>\n </div>\n );\n}\n\nfunction UserSettings(props: { team: Team }) {\n const app = useStackApp();\n const user = useUser({ or: 'redirect' });\n const [leaving, setLeaving] = useState(false);\n\n return (\n <div className='flex flex-col gap-2'>\n <div>\n { !leaving ?\n <Button\n variant='secondary'\n onClick={async () => setLeaving(true)}\n >\n Leave team\n </Button> :\n <div className=''>\n <Typography variant='destructive'>Are you sure you want to leave the team?</Typography>\n <div className='flex gap-2'>\n <Button variant='destructive' onClick={async () => {\n await user.leaveTeam(props.team);\n window.location.reload();\n }}>\n Leave\n </Button>\n <Button variant='secondary' onClick={() => setLeaving(false)}>\n Cancel\n </Button>\n </div>\n </div>}\n </div>\n </div>\n );\n}\n\nfunction ManagementSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const updateTeamPermission = user.usePermission(props.team, '$update_team');\n\n if (!updateTeamPermission) {\n return null;\n }\n\n return (\n <>\n <div>\n <Label>Team display name</Label>\n <EditableText\n value={props.team.displayName}\n onSave={async (newDisplayName) => await props.team.update({ displayName: newDisplayName })}\n />\n </div>\n </>\n );\n}\n\nfunction ProfileSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const profile = user.useTeamProfile(props.team);\n\n return (\n <div className=\"flex flex-col\">\n <div className=\"flex flex-col\">\n <Label className=\"flex gap-2\">User display name <SimpleTooltip tooltip=\"This overwrites your user display name in the account setting\" type='info'/></Label>\n <EditableText\n value={profile.displayName || ''}\n onSave={async (newDisplayName) => {\n await profile.update({ displayName: newDisplayName });\n }}/>\n </div>\n </div>\n );\n}\n\nconst invitationSchema = yupObject({\n email: yupString().email().required('Please enter an email address'),\n});\n\nfunction MemberInvitation(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const inviteMemberPermission = user.usePermission(props.team, '$invite_members');\n\n if (!inviteMemberPermission) {\n return null;\n }\n\n const { register, handleSubmit, formState: { errors }, watch } = useForm({\n resolver: yupResolver(invitationSchema)\n });\n const [loading, setLoading] = useState(false);\n const [invitedEmail, setInvitedEmail] = useState<string | null>(null);\n\n const onSubmit = async (data: yup.InferType<typeof invitationSchema>) => {\n setLoading(true);\n\n try {\n await props.team.inviteUser({ email: data.email });\n setInvitedEmail(data.email);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n setInvitedEmail(null);\n }, [watch('email')]);\n\n return (\n <div>\n <Label>Invite a user to team</Label>\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <div className=\"flex flex-col gap-4 md:flex-row\">\n <div>\n <Input\n placeholder=\"Email\"\n {...register('email')}\n />\n </div>\n <Button type=\"submit\" loading={loading}>\n Invite User\n </Button>\n </div>\n <FormWarningText text={errors.email?.message?.toString()} />\n {invitedEmail && <Typography type='label' variant='secondary'>Invited {invitedEmail}</Typography>}\n </form>\n </div>\n );\n}\n\n\nfunction MembersSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const readMemberPermission = user.usePermission(props.team, '$read_members');\n const inviteMemberPermission = user.usePermission(props.team, '$invite_members');\n\n if (!readMemberPermission && !inviteMemberPermission) {\n return null;\n }\n\n const users = props.team.useUsers();\n\n if (!readMemberPermission) {\n return null;\n }\n\n return (\n <div>\n <Label>Members</Label>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[100px]\">User</TableHead>\n <TableHead className=\"w-[200px]\">Name</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {users.map(({ id, teamProfile }, i) => (\n <TableRow key={id}>\n <TableCell>\n <UserAvatar user={teamProfile}/>\n </TableCell>\n <TableCell>\n <Typography>{teamProfile.displayName}</Typography>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n );\n}\n\nconst teamCreationSchema = yupObject({\n displayName: yupString().required('Please enter a team name'),\n});\n\nexport function TeamCreation() {\n const { register, handleSubmit, formState: { errors } } = useForm({\n resolver: yupResolver(teamCreationSchema)\n });\n const app = useStackApp();\n const project = app.useProject();\n const user = useUser({ or: 'redirect' });\n const [loading, setLoading] = useState(false);\n\n if (!project.config.clientTeamCreationEnabled) {\n return <MessageCard title='Team creation is not enabled' />;\n }\n\n const onSubmit = async (data: yup.InferType<typeof teamCreationSchema>) => {\n setLoading(true);\n\n try {\n const team = await user.createTeam({ displayName: data.displayName });\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <div className='stack-scope flex flex-col items-stretch'>\n <div className=\"mb-6\">\n <form\n className=\"flex flex-col items-stretch stack-scope\"\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <div className=\"flex items-end gap-4\">\n <div>\n <Label htmlFor=\"email\" className=\"mb-1\">Display name</Label>\n <Input\n id=\"email\"\n type=\"email\"\n {...register('displayName')}\n />\n </div>\n <FormWarningText text={errors.displayName?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n Create\n </Button>\n </div>\n </form>\n </div>\n </div>\n );\n}"],"mappings":"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","names":[]}
|
|
@@ -374,8 +374,9 @@ var invitationSchema = yupObject({
|
|
|
374
374
|
email: yupString().email().required("Please enter an email address")
|
|
375
375
|
});
|
|
376
376
|
function MemberInvitation(props) {
|
|
377
|
-
const
|
|
378
|
-
|
|
377
|
+
const user = useUser({ or: "redirect" });
|
|
378
|
+
const inviteMemberPermission = user.usePermission(props.team, "$invite_members");
|
|
379
|
+
if (!inviteMemberPermission) {
|
|
379
380
|
return null;
|
|
380
381
|
}
|
|
381
382
|
const { register, handleSubmit, formState: { errors }, watch } = useForm({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components-page/account-settings.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { getPasswordError } from '@stackframe/stack-shared/dist/helpers/password';\nimport { useAsyncCallback } from '@stackframe/stack-shared/dist/hooks/use-async-callback';\nimport { yupObject, yupString } from '@stackframe/stack-shared/dist/schema-fields';\nimport { generateRandomValues } from '@stackframe/stack-shared/dist/utils/crypto';\nimport { throwErr } from '@stackframe/stack-shared/dist/utils/errors';\nimport { runAsynchronously, runAsynchronouslyWithAlert } from '@stackframe/stack-shared/dist/utils/promises';\nimport { Button, EditableText, Input, Label, PasswordInput, SimpleTooltip, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Typography } from '@stackframe/stack-ui';\nimport { CirclePlus, Contact, LogOut, ShieldCheck } from 'lucide-react';\nimport { TOTPController, createTOTPKeyURI } from \"oslo/otp\";\nimport * as QRCode from 'qrcode';\nimport { useEffect, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport * as yup from \"yup\";\nimport { CurrentUser, MessageCard, Project, Team, useStackApp, useUser } from '..';\nimport { FormWarningText } from '../components/elements/form-warning';\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { SidebarLayout } from '../components/elements/sidebar-layout';\nimport { UserAvatar } from '../components/elements/user-avatar';\nimport { TeamIcon } from '../components/team-icon';\n\n\nexport function AccountSettings({ fullPage=false }: { fullPage?: boolean }) {\n const user = useUser({ or: 'redirect' });\n const teams = user.useTeams();\n const project = useStackApp().useProject();\n\n return (\n <SidebarLayout\n items={([\n {\n title: 'My Profile',\n type: 'item',\n subpath: '/profile',\n icon: Contact,\n content: <ProfileSection/>,\n },\n {\n title: 'Security',\n type: 'item',\n icon: ShieldCheck,\n subpath: '/security',\n content: (\n <div className='flex flex-col gap-8'>\n <EmailVerificationSection />\n <PasswordSection />\n <MfaSection />\n </div>\n ),\n },\n {\n title: 'Sign Out',\n subpath: '/sign-out',\n type: 'item',\n icon: LogOut,\n content: <SignOutSection />,\n },\n ...(teams.length > 0 || project.config.clientTeamCreationEnabled) ? [{\n title: 'Teams',\n type: 'divider',\n }] as const : [],\n ...teams.map(team => ({\n title: <div className='flex gap-2 items-center'>\n <TeamIcon team={team}/>\n {team.displayName}\n </div>,\n type: 'item',\n subpath: `/teams/${team.id}`,\n content: (\n <div className=\"flex flex-col gap-8\">\n <ProfileSettings team={team}/>\n <ManagementSettings team={team}/>\n <MemberInvitation team={team}/>\n <MembersSettings team={team}/>\n <UserSettings team={team}/>\n </div>\n ),\n } as const)),\n ...project.config.clientTeamCreationEnabled ? [{\n title: 'Create a team',\n icon: CirclePlus,\n type: 'item',\n subpath: '/team-creation',\n content: <TeamCreation />,\n }] as const : [],\n ] as const).filter((p) => p.type === 'divider' || (p as any).content )}\n title='Account Settings'\n basePath='/handler/account-settings'\n />\n );\n}\n\nfunction ProfileSection() {\n const user = useUser({ or: 'redirect' });\n\n return (\n <div>\n <div>\n <Label>Display name</Label>\n <EditableText value={user.displayName || ''} onSave={async (newDisplayName) => {\n await user.update({ displayName: newDisplayName });\n }}/>\n </div>\n </div>\n );\n}\n\nfunction EmailVerificationSection() {\n const user = useUser({ or: 'redirect' });\n const [emailSent, setEmailSent] = useState(false);\n\n if (!user.primaryEmail) {\n return null;\n }\n\n return (\n <>\n <div>\n <Label>Email Verification</Label>\n {user.primaryEmailVerified ? (\n <Typography variant='success'>Your email has been verified.</Typography>\n ) : (\n <>\n <Typography variant='destructive'>Your email has not been verified.</Typography>\n <div className='flex mt-4'>\n <Button\n disabled={emailSent}\n onClick={async () => {\n await user.sendVerificationEmail();\n setEmailSent(true);\n }}\n >\n {emailSent ? 'Email sent!' : 'Send Verification Email'}\n </Button>\n </div>\n </>\n )}\n\n </div>\n </>\n );\n}\n\nconst passwordSchema = yupObject({\n oldPassword: yupString().required('Please enter your old password'),\n newPassword: yupString().required('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 newPasswordRepeat: yupString().nullable().oneOf([yup.ref('newPassword'), \"\", null], 'Passwords do not match').required('Please repeat your password')\n});\n\nfunction PasswordSection() {\n const user = useUser({ or: \"throw\" });\n const [changingPassword, setChangingPassword] = useState(false);\n const { register, handleSubmit, setError, formState: { errors }, clearErrors, reset } = useForm({\n resolver: yupResolver(passwordSchema)\n });\n const [alreadyReset, setAlreadyReset] = useState(false);\n const [loading, setLoading] = useState(false);\n\n const onSubmit = async (data: yup.InferType<typeof passwordSchema>) => {\n setLoading(true);\n try {\n const { oldPassword, newPassword } = data;\n const error = await user.updatePassword({ oldPassword, newPassword });\n if (error) {\n setError('oldPassword', { type: 'manual', message: 'Incorrect password' });\n } else {\n reset();\n setAlreadyReset(true);\n }\n } finally {\n setLoading(false);\n }\n };\n\n const registerPassword = register('newPassword');\n const registerPasswordRepeat = register('newPasswordRepeat');\n\n if (!user.hasPassword) {\n return null;\n }\n\n return (\n <div>\n <Label>Change password</Label>\n <div>\n {\n alreadyReset ?\n <Typography variant='success'>Password changed successfully!</Typography> :\n !changingPassword ?\n <Button\n variant='secondary'\n onClick={async () => {\n setChangingPassword(true);\n }}\n >\n Change Password\n </Button> :\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <Label htmlFor=\"old-password\" className=\"mb-1\">Old password</Label>\n <Input\n id=\"old-password\"\n type=\"password\"\n {...register('oldPassword')}\n />\n <FormWarningText text={errors.oldPassword?.message?.toString()} />\n\n <Label htmlFor=\"new-password\" className=\"mt-4 mb-1\">Password</Label>\n <PasswordInput\n id=\"new-password\"\n {...registerPassword}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPassword.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPassword?.message?.toString()} />\n\n <Label htmlFor=\"repeat-password\" className=\"mt-4 mb-1\">Repeat password</Label>\n <PasswordInput\n id=\"repeat-password\"\n {...registerPasswordRepeat}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPasswordRepeat.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPasswordRepeat?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n Change Password\n </Button>\n </form>\n }\n </div>\n </div>\n );\n}\n\nfunction MfaSection() {\n const project = useStackApp().useProject();\n const user = useUser({ or: \"throw\" });\n const [generatedSecret, setGeneratedSecret] = useState<Uint8Array | null>(null);\n const [qrCodeUrl, setQrCodeUrl] = useState<string | null>(null);\n const [mfaCode, setMfaCode] = useState<string>(\"\");\n const [isMaybeWrong, setIsMaybeWrong] = useState(false);\n const isEnabled = user.isMultiFactorRequired;\n\n const [handleSubmit, isLoading] = useAsyncCallback(async () => {\n await user.update({\n totpMultiFactorSecret: generatedSecret,\n });\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }, [generatedSecret, user]);\n\n useEffect(() => {\n setIsMaybeWrong(false);\n runAsynchronouslyWithAlert(async () => {\n if (generatedSecret && await new TOTPController().verify(mfaCode, generatedSecret)) {\n await handleSubmit();\n }\n setIsMaybeWrong(true);\n });\n }, [mfaCode, generatedSecret, handleSubmit]);\n\n return (\n <div>\n <div>\n <Label>Multi-factor Authentication</Label>\n\n <div>\n {isEnabled ? (\n <Typography variant=\"success\">Multi-factor authentication is currently enabled.</Typography>\n ) : (\n generatedSecret ? (\n <div className='flex flex-col gap-4 items-center'>\n <Typography>Scan this QR code with your authenticator app:</Typography>\n <img width={200} height={200} src={qrCodeUrl ?? throwErr(\"TOTP QR code failed to generate\")} alt=\"TOTP multi-factor authentication QR code\" />\n <Typography>Then, enter your six-digit MFA code:</Typography>\n <Input\n value={mfaCode}\n onChange={(e) => {\n setIsMaybeWrong(false);\n setMfaCode(e.target.value);\n }}\n placeholder=\"123456\"\n maxLength={6}\n disabled={isLoading}\n />\n {isMaybeWrong && mfaCode.length === 6 && (\n <Typography variant=\"destructive\">Incorrect code. Please try again.</Typography>\n )}\n </div>\n ) : (\n <Typography variant=\"destructive\">Multi-factor authentication is currently disabled.</Typography>\n )\n )}\n\n <Button\n className=\"mt-4\"\n variant={isEnabled ? 'secondary' : 'default'}\n onClick={async () => {\n if (isEnabled) {\n await user.update({\n totpMultiFactorSecret: null,\n });\n } else if (!generatedSecret) {\n const secret = generateRandomValues(new Uint8Array(20));\n setQrCodeUrl(await generateTotpQrCode(project, user, secret));\n setGeneratedSecret(secret);\n } else {\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }\n }}\n >\n {isEnabled ? 'Disable' : (generatedSecret ? 'Cancel' : 'Enable')}\n </Button>\n </div>\n </div>\n </div>\n );\n}\n\nasync function generateTotpQrCode(project: Project, user: CurrentUser, secret: Uint8Array) {\n const uri = createTOTPKeyURI(project.displayName, user.primaryEmail ?? user.id, secret);\n return await QRCode.toDataURL(uri) as any;\n}\n\nfunction SignOutSection() {\n const user = useUser({ or: \"throw\" });\n return (\n <div className='flex flex-col gap-2'>\n <div>\n <Button\n variant='secondary'\n onClick={() => user.signOut()}\n >\n Sign Out\n </Button>\n </div>\n </div>\n );\n}\n\nfunction UserSettings(props: { team: Team }) {\n const app = useStackApp();\n const user = useUser({ or: 'redirect' });\n const [leaving, setLeaving] = useState(false);\n\n return (\n <div className='flex flex-col gap-2'>\n <div>\n { !leaving ?\n <Button\n variant='secondary'\n onClick={async () => setLeaving(true)}\n >\n Leave team\n </Button> :\n <div className=''>\n <Typography variant='destructive'>Are you sure you want to leave the team?</Typography>\n <div className='flex gap-2'>\n <Button variant='destructive' onClick={async () => {\n await user.leaveTeam(props.team);\n window.location.reload();\n }}>\n Leave\n </Button>\n <Button variant='secondary' onClick={() => setLeaving(false)}>\n Cancel\n </Button>\n </div>\n </div>}\n </div>\n </div>\n );\n}\n\nfunction ManagementSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const updateTeamPermission = user.usePermission(props.team, '$update_team');\n\n if (!updateTeamPermission) {\n return null;\n }\n\n return (\n <>\n <div>\n <Label>Team display name</Label>\n <EditableText\n value={props.team.displayName}\n onSave={async (newDisplayName) => await props.team.update({ displayName: newDisplayName })}\n />\n </div>\n </>\n );\n}\n\nfunction ProfileSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const profile = user.useTeamProfile(props.team);\n\n return (\n <div className=\"flex flex-col\">\n <div className=\"flex flex-col\">\n <Label className=\"flex gap-2\">User display name <SimpleTooltip tooltip=\"This overwrites your user display name in the account setting\" type='info'/></Label>\n <EditableText\n value={profile.displayName || ''}\n onSave={async (newDisplayName) => {\n await profile.update({ displayName: newDisplayName });\n }}/>\n </div>\n </div>\n );\n}\n\nconst invitationSchema = yupObject({\n email: yupString().email().required('Please enter an email address'),\n});\n\nfunction MemberInvitation(props: { team: Team }) {\n const project = useStackApp().useProject();\n\n if (!project.config.clientTeamCreationEnabled) {\n return null;\n }\n\n const { register, handleSubmit, formState: { errors }, watch } = useForm({\n resolver: yupResolver(invitationSchema)\n });\n const [loading, setLoading] = useState(false);\n const [invitedEmail, setInvitedEmail] = useState<string | null>(null);\n\n const onSubmit = async (data: yup.InferType<typeof invitationSchema>) => {\n setLoading(true);\n\n try {\n await props.team.inviteUser({ email: data.email });\n setInvitedEmail(data.email);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n setInvitedEmail(null);\n }, [watch('email')]);\n\n return (\n <div>\n <Label>Invite a user to team</Label>\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <div className=\"flex flex-col gap-4 md:flex-row\">\n <div>\n <Input\n placeholder=\"Email\"\n {...register('email')}\n />\n </div>\n <Button type=\"submit\" loading={loading}>\n Invite User\n </Button>\n </div>\n <FormWarningText text={errors.email?.message?.toString()} />\n {invitedEmail && <Typography type='label' variant='secondary'>Invited {invitedEmail}</Typography>}\n </form>\n </div>\n );\n}\n\n\nfunction MembersSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const readMemberPermission = user.usePermission(props.team, '$read_members');\n const inviteMemberPermission = user.usePermission(props.team, '$invite_members');\n\n if (!readMemberPermission && !inviteMemberPermission) {\n return null;\n }\n\n const users = props.team.useUsers();\n\n if (!readMemberPermission) {\n return null;\n }\n\n return (\n <div>\n <Label>Members</Label>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[100px]\">User</TableHead>\n <TableHead className=\"w-[200px]\">Name</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {users.map(({ id, teamProfile }, i) => (\n <TableRow key={id}>\n <TableCell>\n <UserAvatar user={teamProfile}/>\n </TableCell>\n <TableCell>\n <Typography>{teamProfile.displayName}</Typography>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n );\n}\n\nconst teamCreationSchema = yupObject({\n displayName: yupString().required('Please enter a team name'),\n});\n\nexport function TeamCreation() {\n const { register, handleSubmit, formState: { errors } } = useForm({\n resolver: yupResolver(teamCreationSchema)\n });\n const app = useStackApp();\n const project = app.useProject();\n const user = useUser({ or: 'redirect' });\n const [loading, setLoading] = useState(false);\n\n if (!project.config.clientTeamCreationEnabled) {\n return <MessageCard title='Team creation is not enabled' />;\n }\n\n const onSubmit = async (data: yup.InferType<typeof teamCreationSchema>) => {\n setLoading(true);\n\n try {\n const team = await user.createTeam({ displayName: data.displayName });\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <div className='stack-scope flex flex-col items-stretch'>\n <div className=\"mb-6\">\n <form\n className=\"flex flex-col items-stretch stack-scope\"\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <div className=\"flex items-end gap-4\">\n <div>\n <Label htmlFor=\"email\" className=\"mb-1\">Display name</Label>\n <Input\n id=\"email\"\n type=\"email\"\n {...register('displayName')}\n />\n </div>\n <FormWarningText text={errors.displayName?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n Create\n </Button>\n </div>\n </form>\n </div>\n </div>\n );\n}"],"mappings":";;;AAEA,SAAS,mBAAmB;AAC5B,SAAS,wBAAwB;AACjC,SAAS,wBAAwB;AACjC,SAAS,WAAW,iBAAiB;AACrC,SAAS,4BAA4B;AACrC,SAAS,gBAAgB;AACzB,SAAS,mBAAmB,kCAAkC;AAC9D,SAAS,QAAQ,cAAc,OAAO,OAAO,eAAe,eAAe,OAAO,WAAW,WAAW,WAAW,aAAa,UAAU,kBAAkB;AAC5J,SAAS,YAAY,SAAS,QAAQ,mBAAmB;AACzD,SAAS,gBAAgB,wBAAwB;AACjD,YAAY,YAAY;AACxB,SAAS,WAAW,gBAAgB;AACpC,SAAS,eAAe;AACxB,YAAY,SAAS;AACrB,SAAsB,aAA4B,aAAa,eAAe;AAC9E,SAAS,uBAAuB;AAEhC,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AAgBN,SAuFT,UAvFS,KAQP,YARO;AAbZ,SAAS,gBAAgB,EAAE,WAAS,MAAM,GAA2B;AAC1E,QAAM,OAAO,QAAQ,EAAE,IAAI,WAAW,CAAC;AACvC,QAAM,QAAQ,KAAK,SAAS;AAC5B,QAAM,UAAU,YAAY,EAAE,WAAW;AAEzC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAQ;AAAA,QACN;AAAA,UACE,OAAO;AAAA,UACP,MAAM;AAAA,UACN,SAAS;AAAA,UACT,MAAM;AAAA,UACN,SAAS,oBAAC,kBAAc;AAAA,QAC1B;AAAA,QACA;AAAA,UACE,OAAO;AAAA,UACP,MAAM;AAAA,UACN,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SACE,qBAAC,SAAI,WAAU,uBACb;AAAA,gCAAC,4BAAyB;AAAA,YAC1B,oBAAC,mBAAgB;AAAA,YACjB,oBAAC,cAAW;AAAA,aACd;AAAA,QAEJ;AAAA,QACA;AAAA,UACE,OAAO;AAAA,UACP,SAAS;AAAA,UACT,MAAM;AAAA,UACN,MAAM;AAAA,UACN,SAAS,oBAAC,kBAAe;AAAA,QAC3B;AAAA,QACA,GAAI,MAAM,SAAS,KAAK,QAAQ,OAAO,4BAA6B,CAAC;AAAA,UACnE,OAAO;AAAA,UACP,MAAM;AAAA,QACR,CAAC,IAAa,CAAC;AAAA,QACf,GAAG,MAAM,IAAI,WAAS;AAAA,UACpB,OAAO,qBAAC,SAAI,WAAU,2BACpB;AAAA,gCAAC,YAAS,MAAW;AAAA,YACpB,KAAK;AAAA,aACR;AAAA,UACA,MAAM;AAAA,UACN,SAAS,UAAU,KAAK,EAAE;AAAA,UAC1B,SACE,qBAAC,SAAI,WAAU,uBACb;AAAA,gCAAC,mBAAgB,MAAW;AAAA,YAC5B,oBAAC,sBAAmB,MAAW;AAAA,YAC/B,oBAAC,oBAAiB,MAAW;AAAA,YAC7B,oBAAC,mBAAgB,MAAW;AAAA,YAC5B,oBAAC,gBAAa,MAAW;AAAA,aAC3B;AAAA,QAEJ,EAAW;AAAA,QACX,GAAG,QAAQ,OAAO,4BAA4B,CAAC;AAAA,UAC7C,OAAO;AAAA,UACP,MAAM;AAAA,UACN,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS,oBAAC,gBAAa;AAAA,QACzB,CAAC,IAAa,CAAC;AAAA,MACjB,EAAY,OAAO,CAAC,MAAM,EAAE,SAAS,aAAc,EAAU,OAAQ;AAAA,MACrE,OAAM;AAAA,MACN,UAAS;AAAA;AAAA,EACX;AAEJ;AAEA,SAAS,iBAAiB;AACxB,QAAM,OAAO,QAAQ,EAAE,IAAI,WAAW,CAAC;AAEvC,SACE,oBAAC,SACC,+BAAC,SACC;AAAA,wBAAC,SAAM,0BAAY;AAAA,IACnB,oBAAC,gBAAa,OAAO,KAAK,eAAe,IAAI,QAAQ,OAAO,mBAAmB;AAC7E,YAAM,KAAK,OAAO,EAAE,aAAa,eAAe,CAAC;AAAA,IACnD,GAAE;AAAA,KACJ,GACF;AAEJ;AAEA,SAAS,2BAA2B;AAClC,QAAM,OAAO,QAAQ,EAAE,IAAI,WAAW,CAAC;AACvC,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAEhD,MAAI,CAAC,KAAK,cAAc;AACtB,WAAO;AAAA,EACT;AAEA,SACE,gCACE,+BAAC,SACC;AAAA,wBAAC,SAAM,gCAAkB;AAAA,IACxB,KAAK,uBACJ,oBAAC,cAAW,SAAQ,WAAU,2CAA6B,IAE3D,iCACE;AAAA,0BAAC,cAAW,SAAQ,eAAc,+CAAiC;AAAA,MACnE,oBAAC,SAAI,WAAU,aACb;AAAA,QAAC;AAAA;AAAA,UACC,UAAU;AAAA,UACV,SAAS,YAAY;AACnB,kBAAM,KAAK,sBAAsB;AACjC,yBAAa,IAAI;AAAA,UACnB;AAAA,UAEC,sBAAY,gBAAgB;AAAA;AAAA,MAC/B,GACF;AAAA,OACF;AAAA,KAGJ,GACF;AAEJ;AAEA,IAAM,iBAAiB,UAAU;AAAA,EAC/B,aAAa,UAAU,EAAE,SAAS,gCAAgC;AAAA,EAClE,aAAa,UAAU,EAAE,SAAS,4BAA4B,EAAE,KAAK;AAAA,IACnE,MAAM;AAAA,IACN,MAAM,CAAC,OAAO,QAAQ;AACpB,YAAM,QAAQ,iBAAiB,KAAK;AACpC,UAAI,OAAO;AACT,eAAO,IAAI,YAAY,EAAE,SAAS,MAAM,QAAQ,CAAC;AAAA,MACnD,OAAO;AACL,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF,CAAC;AAAA,EACD,mBAAmB,UAAU,EAAE,SAAS,EAAE,MAAM,CAAK,QAAI,aAAa,GAAG,IAAI,IAAI,GAAG,wBAAwB,EAAE,SAAS,6BAA6B;AACtJ,CAAC;AAED,SAAS,kBAAkB;AACzB,QAAM,OAAO,QAAQ,EAAE,IAAI,QAAQ,CAAC;AACpC,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,SAAS,KAAK;AAC9D,QAAM,EAAE,UAAU,cAAc,UAAU,WAAW,EAAE,OAAO,GAAG,aAAa,MAAM,IAAI,QAAQ;AAAA,IAC9F,UAAU,YAAY,cAAc;AAAA,EACtC,CAAC;AACD,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AACtD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,QAAM,WAAW,OAAO,SAA+C;AACrE,eAAW,IAAI;AACf,QAAI;AACF,YAAM,EAAE,aAAa,YAAY,IAAI;AACrC,YAAM,QAAQ,MAAM,KAAK,eAAe,EAAE,aAAa,YAAY,CAAC;AACpE,UAAI,OAAO;AACT,iBAAS,eAAe,EAAE,MAAM,UAAU,SAAS,qBAAqB,CAAC;AAAA,MAC3E,OAAO;AACL,cAAM;AACN,wBAAgB,IAAI;AAAA,MACtB;AAAA,IACF,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,mBAAmB,SAAS,aAAa;AAC/C,QAAM,yBAAyB,SAAS,mBAAmB;AAE3D,MAAI,CAAC,KAAK,aAAa;AACrB,WAAO;AAAA,EACT;AAEA,SACE,qBAAC,SACC;AAAA,wBAAC,SAAM,6BAAe;AAAA,IACtB,oBAAC,SAEG,yBACE,oBAAC,cAAW,SAAQ,WAAU,4CAA8B,IAC5D,CAAC,mBACC;AAAA,MAAC;AAAA;AAAA,QACC,SAAQ;AAAA,QACR,SAAS,YAAY;AACnB,8BAAoB,IAAI;AAAA,QAC1B;AAAA,QACD;AAAA;AAAA,IAED,IACA;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,OAAK,2BAA2B,aAAa,QAAQ,EAAE,CAAC,CAAC;AAAA,QACnE,YAAU;AAAA,QAEV;AAAA,8BAAC,SAAM,SAAQ,gBAAe,WAAU,QAAO,0BAAY;AAAA,UAC3D;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,MAAK;AAAA,cACJ,GAAG,SAAS,aAAa;AAAA;AAAA,UAC5B;AAAA,UACA,oBAAC,mBAAgB,MAAM,OAAO,aAAa,SAAS,SAAS,GAAG;AAAA,UAEhE,oBAAC,SAAM,SAAQ,gBAAe,WAAU,aAAY,sBAAQ;AAAA,UAC5D;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACF,GAAG;AAAA,cACJ,UAAU,CAAC,MAAM;AACf,4BAAY,aAAa;AACzB,4BAAY,mBAAmB;AAC/B,kCAAkB,iBAAiB,SAAS,CAAC,CAAC;AAAA,cAChD;AAAA;AAAA,UACF;AAAA,UACA,oBAAC,mBAAgB,MAAM,OAAO,aAAa,SAAS,SAAS,GAAG;AAAA,UAEhE,oBAAC,SAAM,SAAQ,mBAAkB,WAAU,aAAY,6BAAe;AAAA,UACtE;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACF,GAAG;AAAA,cACJ,UAAU,CAAC,MAAM;AACf,4BAAY,aAAa;AACzB,4BAAY,mBAAmB;AAC/B,kCAAkB,uBAAuB,SAAS,CAAC,CAAC;AAAA,cACtD;AAAA;AAAA,UACF;AAAA,UACA,oBAAC,mBAAgB,MAAM,OAAO,mBAAmB,SAAS,SAAS,GAAG;AAAA,UAEtE,oBAAC,UAAO,MAAK,UAAS,WAAU,QAAO,SAAkB,6BAEzD;AAAA;AAAA;AAAA,IACF,GAER;AAAA,KACF;AAEJ;AAEA,SAAS,aAAa;AACpB,QAAM,UAAU,YAAY,EAAE,WAAW;AACzC,QAAM,OAAO,QAAQ,EAAE,IAAI,QAAQ,CAAC;AACpC,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,SAA4B,IAAI;AAC9E,QAAM,CAAC,WAAW,YAAY,IAAI,SAAwB,IAAI;AAC9D,QAAM,CAAC,SAAS,UAAU,IAAI,SAAiB,EAAE;AACjD,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AACtD,QAAM,YAAY,KAAK;AAEvB,QAAM,CAAC,cAAc,SAAS,IAAI,iBAAiB,YAAY;AAC7D,UAAM,KAAK,OAAO;AAAA,MAChB,uBAAuB;AAAA,IACzB,CAAC;AACD,uBAAmB,IAAI;AACvB,iBAAa,IAAI;AACjB,eAAW,EAAE;AAAA,EACf,GAAG,CAAC,iBAAiB,IAAI,CAAC;AAE1B,YAAU,MAAM;AACd,oBAAgB,KAAK;AACrB,+BAA2B,YAAY;AACrC,UAAI,mBAAmB,MAAM,IAAI,eAAe,EAAE,OAAO,SAAS,eAAe,GAAG;AAClF,cAAM,aAAa;AAAA,MACrB;AACA,sBAAgB,IAAI;AAAA,IACtB,CAAC;AAAA,EACH,GAAG,CAAC,SAAS,iBAAiB,YAAY,CAAC;AAE3C,SACE,oBAAC,SACC,+BAAC,SACC;AAAA,wBAAC,SAAM,yCAA2B;AAAA,IAElC,qBAAC,SACE;AAAA,kBACC,oBAAC,cAAW,SAAQ,WAAU,+DAAiD,IAE/E,kBACE,qBAAC,SAAI,WAAU,oCACb;AAAA,4BAAC,cAAW,4DAA8C;AAAA,QAC1D,oBAAC,SAAI,OAAO,KAAK,QAAQ,KAAK,KAAK,aAAa,SAAS,iCAAiC,GAAG,KAAI,4CAA2C;AAAA,QAC5I,oBAAC,cAAW,kDAAoC;AAAA,QAChD;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,YACP,UAAU,CAAC,MAAM;AACnB,8BAAgB,KAAK;AACrB,yBAAW,EAAE,OAAO,KAAK;AAAA,YACvB;AAAA,YACA,aAAY;AAAA,YACZ,WAAW;AAAA,YACX,UAAU;AAAA;AAAA,QACZ;AAAA,QACC,gBAAgB,QAAQ,WAAW,KAClC,oBAAC,cAAW,SAAQ,eAAc,+CAAiC;AAAA,SAEvE,IAEA,oBAAC,cAAW,SAAQ,eAAc,gEAAkD;AAAA,MAIxF;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAS,YAAY,cAAc;AAAA,UACnC,SAAS,YAAY;AACnB,gBAAI,WAAW;AACb,oBAAM,KAAK,OAAO;AAAA,gBAChB,uBAAuB;AAAA,cACzB,CAAC;AAAA,YACH,WAAW,CAAC,iBAAiB;AAC3B,oBAAM,SAAS,qBAAqB,IAAI,WAAW,EAAE,CAAC;AACtD,2BAAa,MAAM,mBAAmB,SAAS,MAAM,MAAM,CAAC;AAC5D,iCAAmB,MAAM;AAAA,YAC3B,OAAO;AACL,iCAAmB,IAAI;AACvB,2BAAa,IAAI;AACjB,yBAAW,EAAE;AAAA,YACf;AAAA,UACF;AAAA,UAEC,sBAAY,YAAa,kBAAkB,WAAW;AAAA;AAAA,MACzD;AAAA,OACF;AAAA,KACF,GACF;AAEJ;AAEA,eAAe,mBAAmB,SAAkB,MAAmB,QAAoB;AACzF,QAAM,MAAM,iBAAiB,QAAQ,aAAa,KAAK,gBAAgB,KAAK,IAAI,MAAM;AACtF,SAAO,MAAa,iBAAU,GAAG;AACnC;AAEA,SAAS,iBAAiB;AACxB,QAAM,OAAO,QAAQ,EAAE,IAAI,QAAQ,CAAC;AACpC,SACE,oBAAC,SAAI,WAAU,uBACb,8BAAC,SACC;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,SAAS,MAAM,KAAK,QAAQ;AAAA,MAC7B;AAAA;AAAA,EAED,GACF,GACF;AAEJ;AAEA,SAAS,aAAa,OAAuB;AAC3C,QAAM,MAAM,YAAY;AACxB,QAAM,OAAO,QAAQ,EAAE,IAAI,WAAW,CAAC;AACvC,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,SACE,oBAAC,SAAI,WAAU,uBACb,8BAAC,SACG,WAAC,UACD;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,SAAS,YAAY,WAAW,IAAI;AAAA,MACrC;AAAA;AAAA,EAED,IACA,qBAAC,SAAI,WAAU,IACb;AAAA,wBAAC,cAAW,SAAQ,eAAc,sDAAwC;AAAA,IAC1E,qBAAC,SAAI,WAAU,cACb;AAAA,0BAAC,UAAO,SAAQ,eAAc,SAAS,YAAY;AACjD,cAAM,KAAK,UAAU,MAAM,IAAI;AAC/B,eAAO,SAAS,OAAO;AAAA,MACzB,GAAG,mBAEH;AAAA,MACA,oBAAC,UAAO,SAAQ,aAAY,SAAS,MAAM,WAAW,KAAK,GAAG,oBAE9D;AAAA,OACF;AAAA,KACF,GACJ,GACF;AAEJ;AAEA,SAAS,mBAAmB,OAAuB;AACjD,QAAM,OAAO,QAAQ,EAAE,IAAI,WAAW,CAAC;AACvC,QAAM,uBAAuB,KAAK,cAAc,MAAM,MAAM,cAAc;AAE1E,MAAI,CAAC,sBAAsB;AACzB,WAAO;AAAA,EACT;AAEA,SACE,gCACE,+BAAC,SACC;AAAA,wBAAC,SAAM,+BAAiB;AAAA,IACxB;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,MAAM,KAAK;AAAA,QAClB,QAAQ,OAAO,mBAAmB,MAAM,MAAM,KAAK,OAAO,EAAE,aAAa,eAAe,CAAC;AAAA;AAAA,IAC3F;AAAA,KACF,GACF;AAEJ;AAEA,SAAS,gBAAgB,OAAuB;AAC9C,QAAM,OAAO,QAAQ,EAAE,IAAI,WAAW,CAAC;AACvC,QAAM,UAAU,KAAK,eAAe,MAAM,IAAI;AAE9C,SACE,oBAAC,SAAI,WAAU,iBACb,+BAAC,SAAI,WAAU,iBACb;AAAA,yBAAC,SAAM,WAAU,cAAa;AAAA;AAAA,MAAkB,oBAAC,iBAAc,SAAQ,iEAAgE,MAAK,QAAM;AAAA,OAAE;AAAA,IACpJ;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,QAAQ,eAAe;AAAA,QAC9B,QAAQ,OAAO,mBAAmB;AAChC,gBAAM,QAAQ,OAAO,EAAE,aAAa,eAAe,CAAC;AAAA,QACtD;AAAA;AAAA,IAAE;AAAA,KACN,GACF;AAEJ;AAEA,IAAM,mBAAmB,UAAU;AAAA,EACjC,OAAO,UAAU,EAAE,MAAM,EAAE,SAAS,+BAA+B;AACrE,CAAC;AAED,SAAS,iBAAiB,OAAuB;AAC/C,QAAM,UAAU,YAAY,EAAE,WAAW;AAEzC,MAAI,CAAC,QAAQ,OAAO,2BAA2B;AAC7C,WAAO;AAAA,EACT;AAEA,QAAM,EAAE,UAAU,cAAc,WAAW,EAAE,OAAO,GAAG,MAAM,IAAI,QAAQ;AAAA,IACvE,UAAU,YAAY,gBAAgB;AAAA,EACxC,CAAC;AACD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,CAAC,cAAc,eAAe,IAAI,SAAwB,IAAI;AAEpE,QAAM,WAAW,OAAO,SAAiD;AACvE,eAAW,IAAI;AAEf,QAAI;AACF,YAAM,MAAM,KAAK,WAAW,EAAE,OAAO,KAAK,MAAM,CAAC;AACjD,sBAAgB,KAAK,KAAK;AAAA,IAC5B,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAEA,YAAU,MAAM;AACd,oBAAgB,IAAI;AAAA,EACtB,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC;AAEnB,SACE,qBAAC,SACC;AAAA,wBAAC,SAAM,mCAAqB;AAAA,IAC5B;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,OAAK,2BAA2B,aAAa,QAAQ,EAAE,CAAC,CAAC;AAAA,QACnE,YAAU;AAAA,QAEV;AAAA,+BAAC,SAAI,WAAU,mCACb;AAAA,gCAAC,SACC;AAAA,cAAC;AAAA;AAAA,gBACC,aAAY;AAAA,gBACX,GAAG,SAAS,OAAO;AAAA;AAAA,YACtB,GACF;AAAA,YACA,oBAAC,UAAO,MAAK,UAAS,SAAkB,yBAExC;AAAA,aACF;AAAA,UACA,oBAAC,mBAAgB,MAAM,OAAO,OAAO,SAAS,SAAS,GAAG;AAAA,UACzD,gBAAgB,qBAAC,cAAW,MAAK,SAAQ,SAAQ,aAAY;AAAA;AAAA,YAAS;AAAA,aAAa;AAAA;AAAA;AAAA,IACtF;AAAA,KACF;AAEJ;AAGA,SAAS,gBAAgB,OAAuB;AAC9C,QAAM,OAAO,QAAQ,EAAE,IAAI,WAAW,CAAC;AACvC,QAAM,uBAAuB,KAAK,cAAc,MAAM,MAAM,eAAe;AAC3E,QAAM,yBAAyB,KAAK,cAAc,MAAM,MAAM,iBAAiB;AAE/E,MAAI,CAAC,wBAAwB,CAAC,wBAAwB;AACpD,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,MAAM,KAAK,SAAS;AAElC,MAAI,CAAC,sBAAsB;AACzB,WAAO;AAAA,EACT;AAEA,SACE,qBAAC,SACC;AAAA,wBAAC,SAAM,qBAAO;AAAA,IACd,qBAAC,SACC;AAAA,0BAAC,eACC,+BAAC,YACC;AAAA,4BAAC,aAAU,WAAU,aAAY,kBAAI;AAAA,QACrC,oBAAC,aAAU,WAAU,aAAY,kBAAI;AAAA,SACvC,GACF;AAAA,MACA,oBAAC,aACE,gBAAM,IAAI,CAAC,EAAE,IAAI,YAAY,GAAG,MAC/B,qBAAC,YACC;AAAA,4BAAC,aACC,8BAAC,cAAW,MAAM,aAAY,GAChC;AAAA,QACA,oBAAC,aACC,8BAAC,cAAY,sBAAY,aAAY,GACvC;AAAA,WANa,EAOf,CACD,GACH;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,IAAM,qBAAqB,UAAU;AAAA,EACnC,aAAa,UAAU,EAAE,SAAS,0BAA0B;AAC9D,CAAC;AAEM,SAAS,eAAe;AAC7B,QAAM,EAAE,UAAU,cAAc,WAAW,EAAE,OAAO,EAAE,IAAI,QAAQ;AAAA,IAChE,UAAU,YAAY,kBAAkB;AAAA,EAC1C,CAAC;AACD,QAAM,MAAM,YAAY;AACxB,QAAM,UAAU,IAAI,WAAW;AAC/B,QAAM,OAAO,QAAQ,EAAE,IAAI,WAAW,CAAC;AACvC,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,MAAI,CAAC,QAAQ,OAAO,2BAA2B;AAC7C,WAAO,oBAAC,eAAY,OAAM,gCAA+B;AAAA,EAC3D;AAEA,QAAM,WAAW,OAAO,SAAmD;AACzE,eAAW,IAAI;AAEf,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,WAAW,EAAE,aAAa,KAAK,YAAY,CAAC;AAAA,IACtE,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAEA,SACE,oBAAC,SAAI,WAAU,2CACb,8BAAC,SAAI,WAAU,QACb;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,UAAU,OAAK,2BAA2B,aAAa,QAAQ,EAAE,CAAC,CAAC;AAAA,MACnE,YAAU;AAAA,MAEV,+BAAC,SAAI,WAAU,wBACb;AAAA,6BAAC,SACC;AAAA,8BAAC,SAAM,SAAQ,SAAQ,WAAU,QAAO,0BAAY;AAAA,UACpD;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,MAAK;AAAA,cACJ,GAAG,SAAS,aAAa;AAAA;AAAA,UAC5B;AAAA,WACF;AAAA,QACA,oBAAC,mBAAgB,MAAM,OAAO,aAAa,SAAS,SAAS,GAAG;AAAA,QAEhE,oBAAC,UAAO,MAAK,UAAS,WAAU,QAAO,SAAkB,oBAEzD;AAAA,SACF;AAAA;AAAA,EACF,GACF,GACF;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components-page/account-settings.tsx"],"sourcesContent":["'use client';\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { getPasswordError } from '@stackframe/stack-shared/dist/helpers/password';\nimport { useAsyncCallback } from '@stackframe/stack-shared/dist/hooks/use-async-callback';\nimport { yupObject, yupString } from '@stackframe/stack-shared/dist/schema-fields';\nimport { generateRandomValues } from '@stackframe/stack-shared/dist/utils/crypto';\nimport { throwErr } from '@stackframe/stack-shared/dist/utils/errors';\nimport { runAsynchronously, runAsynchronouslyWithAlert } from '@stackframe/stack-shared/dist/utils/promises';\nimport { Button, EditableText, Input, Label, PasswordInput, SimpleTooltip, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Typography } from '@stackframe/stack-ui';\nimport { CirclePlus, Contact, LogOut, ShieldCheck } from 'lucide-react';\nimport { TOTPController, createTOTPKeyURI } from \"oslo/otp\";\nimport * as QRCode from 'qrcode';\nimport { useEffect, useState } from 'react';\nimport { useForm } from 'react-hook-form';\nimport * as yup from \"yup\";\nimport { CurrentUser, MessageCard, Project, Team, useStackApp, useUser } from '..';\nimport { FormWarningText } from '../components/elements/form-warning';\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { SidebarLayout } from '../components/elements/sidebar-layout';\nimport { UserAvatar } from '../components/elements/user-avatar';\nimport { TeamIcon } from '../components/team-icon';\n\n\nexport function AccountSettings({ fullPage=false }: { fullPage?: boolean }) {\n const user = useUser({ or: 'redirect' });\n const teams = user.useTeams();\n const project = useStackApp().useProject();\n\n return (\n <SidebarLayout\n items={([\n {\n title: 'My Profile',\n type: 'item',\n subpath: '/profile',\n icon: Contact,\n content: <ProfileSection/>,\n },\n {\n title: 'Security',\n type: 'item',\n icon: ShieldCheck,\n subpath: '/security',\n content: (\n <div className='flex flex-col gap-8'>\n <EmailVerificationSection />\n <PasswordSection />\n <MfaSection />\n </div>\n ),\n },\n {\n title: 'Sign Out',\n subpath: '/sign-out',\n type: 'item',\n icon: LogOut,\n content: <SignOutSection />,\n },\n ...(teams.length > 0 || project.config.clientTeamCreationEnabled) ? [{\n title: 'Teams',\n type: 'divider',\n }] as const : [],\n ...teams.map(team => ({\n title: <div className='flex gap-2 items-center'>\n <TeamIcon team={team}/>\n {team.displayName}\n </div>,\n type: 'item',\n subpath: `/teams/${team.id}`,\n content: (\n <div className=\"flex flex-col gap-8\">\n <ProfileSettings team={team}/>\n <ManagementSettings team={team}/>\n <MemberInvitation team={team}/>\n <MembersSettings team={team}/>\n <UserSettings team={team}/>\n </div>\n ),\n } as const)),\n ...project.config.clientTeamCreationEnabled ? [{\n title: 'Create a team',\n icon: CirclePlus,\n type: 'item',\n subpath: '/team-creation',\n content: <TeamCreation />,\n }] as const : [],\n ] as const).filter((p) => p.type === 'divider' || (p as any).content )}\n title='Account Settings'\n basePath='/handler/account-settings'\n />\n );\n}\n\nfunction ProfileSection() {\n const user = useUser({ or: 'redirect' });\n\n return (\n <div>\n <div>\n <Label>Display name</Label>\n <EditableText value={user.displayName || ''} onSave={async (newDisplayName) => {\n await user.update({ displayName: newDisplayName });\n }}/>\n </div>\n </div>\n );\n}\n\nfunction EmailVerificationSection() {\n const user = useUser({ or: 'redirect' });\n const [emailSent, setEmailSent] = useState(false);\n\n if (!user.primaryEmail) {\n return null;\n }\n\n return (\n <>\n <div>\n <Label>Email Verification</Label>\n {user.primaryEmailVerified ? (\n <Typography variant='success'>Your email has been verified.</Typography>\n ) : (\n <>\n <Typography variant='destructive'>Your email has not been verified.</Typography>\n <div className='flex mt-4'>\n <Button\n disabled={emailSent}\n onClick={async () => {\n await user.sendVerificationEmail();\n setEmailSent(true);\n }}\n >\n {emailSent ? 'Email sent!' : 'Send Verification Email'}\n </Button>\n </div>\n </>\n )}\n\n </div>\n </>\n );\n}\n\nconst passwordSchema = yupObject({\n oldPassword: yupString().required('Please enter your old password'),\n newPassword: yupString().required('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 newPasswordRepeat: yupString().nullable().oneOf([yup.ref('newPassword'), \"\", null], 'Passwords do not match').required('Please repeat your password')\n});\n\nfunction PasswordSection() {\n const user = useUser({ or: \"throw\" });\n const [changingPassword, setChangingPassword] = useState(false);\n const { register, handleSubmit, setError, formState: { errors }, clearErrors, reset } = useForm({\n resolver: yupResolver(passwordSchema)\n });\n const [alreadyReset, setAlreadyReset] = useState(false);\n const [loading, setLoading] = useState(false);\n\n const onSubmit = async (data: yup.InferType<typeof passwordSchema>) => {\n setLoading(true);\n try {\n const { oldPassword, newPassword } = data;\n const error = await user.updatePassword({ oldPassword, newPassword });\n if (error) {\n setError('oldPassword', { type: 'manual', message: 'Incorrect password' });\n } else {\n reset();\n setAlreadyReset(true);\n }\n } finally {\n setLoading(false);\n }\n };\n\n const registerPassword = register('newPassword');\n const registerPasswordRepeat = register('newPasswordRepeat');\n\n if (!user.hasPassword) {\n return null;\n }\n\n return (\n <div>\n <Label>Change password</Label>\n <div>\n {\n alreadyReset ?\n <Typography variant='success'>Password changed successfully!</Typography> :\n !changingPassword ?\n <Button\n variant='secondary'\n onClick={async () => {\n setChangingPassword(true);\n }}\n >\n Change Password\n </Button> :\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <Label htmlFor=\"old-password\" className=\"mb-1\">Old password</Label>\n <Input\n id=\"old-password\"\n type=\"password\"\n {...register('oldPassword')}\n />\n <FormWarningText text={errors.oldPassword?.message?.toString()} />\n\n <Label htmlFor=\"new-password\" className=\"mt-4 mb-1\">Password</Label>\n <PasswordInput\n id=\"new-password\"\n {...registerPassword}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPassword.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPassword?.message?.toString()} />\n\n <Label htmlFor=\"repeat-password\" className=\"mt-4 mb-1\">Repeat password</Label>\n <PasswordInput\n id=\"repeat-password\"\n {...registerPasswordRepeat}\n onChange={(e) => {\n clearErrors('newPassword');\n clearErrors('newPasswordRepeat');\n runAsynchronously(registerPasswordRepeat.onChange(e));\n }}\n />\n <FormWarningText text={errors.newPasswordRepeat?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n Change Password\n </Button>\n </form>\n }\n </div>\n </div>\n );\n}\n\nfunction MfaSection() {\n const project = useStackApp().useProject();\n const user = useUser({ or: \"throw\" });\n const [generatedSecret, setGeneratedSecret] = useState<Uint8Array | null>(null);\n const [qrCodeUrl, setQrCodeUrl] = useState<string | null>(null);\n const [mfaCode, setMfaCode] = useState<string>(\"\");\n const [isMaybeWrong, setIsMaybeWrong] = useState(false);\n const isEnabled = user.isMultiFactorRequired;\n\n const [handleSubmit, isLoading] = useAsyncCallback(async () => {\n await user.update({\n totpMultiFactorSecret: generatedSecret,\n });\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }, [generatedSecret, user]);\n\n useEffect(() => {\n setIsMaybeWrong(false);\n runAsynchronouslyWithAlert(async () => {\n if (generatedSecret && await new TOTPController().verify(mfaCode, generatedSecret)) {\n await handleSubmit();\n }\n setIsMaybeWrong(true);\n });\n }, [mfaCode, generatedSecret, handleSubmit]);\n\n return (\n <div>\n <div>\n <Label>Multi-factor Authentication</Label>\n\n <div>\n {isEnabled ? (\n <Typography variant=\"success\">Multi-factor authentication is currently enabled.</Typography>\n ) : (\n generatedSecret ? (\n <div className='flex flex-col gap-4 items-center'>\n <Typography>Scan this QR code with your authenticator app:</Typography>\n <img width={200} height={200} src={qrCodeUrl ?? throwErr(\"TOTP QR code failed to generate\")} alt=\"TOTP multi-factor authentication QR code\" />\n <Typography>Then, enter your six-digit MFA code:</Typography>\n <Input\n value={mfaCode}\n onChange={(e) => {\n setIsMaybeWrong(false);\n setMfaCode(e.target.value);\n }}\n placeholder=\"123456\"\n maxLength={6}\n disabled={isLoading}\n />\n {isMaybeWrong && mfaCode.length === 6 && (\n <Typography variant=\"destructive\">Incorrect code. Please try again.</Typography>\n )}\n </div>\n ) : (\n <Typography variant=\"destructive\">Multi-factor authentication is currently disabled.</Typography>\n )\n )}\n\n <Button\n className=\"mt-4\"\n variant={isEnabled ? 'secondary' : 'default'}\n onClick={async () => {\n if (isEnabled) {\n await user.update({\n totpMultiFactorSecret: null,\n });\n } else if (!generatedSecret) {\n const secret = generateRandomValues(new Uint8Array(20));\n setQrCodeUrl(await generateTotpQrCode(project, user, secret));\n setGeneratedSecret(secret);\n } else {\n setGeneratedSecret(null);\n setQrCodeUrl(null);\n setMfaCode(\"\");\n }\n }}\n >\n {isEnabled ? 'Disable' : (generatedSecret ? 'Cancel' : 'Enable')}\n </Button>\n </div>\n </div>\n </div>\n );\n}\n\nasync function generateTotpQrCode(project: Project, user: CurrentUser, secret: Uint8Array) {\n const uri = createTOTPKeyURI(project.displayName, user.primaryEmail ?? user.id, secret);\n return await QRCode.toDataURL(uri) as any;\n}\n\nfunction SignOutSection() {\n const user = useUser({ or: \"throw\" });\n return (\n <div className='flex flex-col gap-2'>\n <div>\n <Button\n variant='secondary'\n onClick={() => user.signOut()}\n >\n Sign Out\n </Button>\n </div>\n </div>\n );\n}\n\nfunction UserSettings(props: { team: Team }) {\n const app = useStackApp();\n const user = useUser({ or: 'redirect' });\n const [leaving, setLeaving] = useState(false);\n\n return (\n <div className='flex flex-col gap-2'>\n <div>\n { !leaving ?\n <Button\n variant='secondary'\n onClick={async () => setLeaving(true)}\n >\n Leave team\n </Button> :\n <div className=''>\n <Typography variant='destructive'>Are you sure you want to leave the team?</Typography>\n <div className='flex gap-2'>\n <Button variant='destructive' onClick={async () => {\n await user.leaveTeam(props.team);\n window.location.reload();\n }}>\n Leave\n </Button>\n <Button variant='secondary' onClick={() => setLeaving(false)}>\n Cancel\n </Button>\n </div>\n </div>}\n </div>\n </div>\n );\n}\n\nfunction ManagementSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const updateTeamPermission = user.usePermission(props.team, '$update_team');\n\n if (!updateTeamPermission) {\n return null;\n }\n\n return (\n <>\n <div>\n <Label>Team display name</Label>\n <EditableText\n value={props.team.displayName}\n onSave={async (newDisplayName) => await props.team.update({ displayName: newDisplayName })}\n />\n </div>\n </>\n );\n}\n\nfunction ProfileSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const profile = user.useTeamProfile(props.team);\n\n return (\n <div className=\"flex flex-col\">\n <div className=\"flex flex-col\">\n <Label className=\"flex gap-2\">User display name <SimpleTooltip tooltip=\"This overwrites your user display name in the account setting\" type='info'/></Label>\n <EditableText\n value={profile.displayName || ''}\n onSave={async (newDisplayName) => {\n await profile.update({ displayName: newDisplayName });\n }}/>\n </div>\n </div>\n );\n}\n\nconst invitationSchema = yupObject({\n email: yupString().email().required('Please enter an email address'),\n});\n\nfunction MemberInvitation(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const inviteMemberPermission = user.usePermission(props.team, '$invite_members');\n\n if (!inviteMemberPermission) {\n return null;\n }\n\n const { register, handleSubmit, formState: { errors }, watch } = useForm({\n resolver: yupResolver(invitationSchema)\n });\n const [loading, setLoading] = useState(false);\n const [invitedEmail, setInvitedEmail] = useState<string | null>(null);\n\n const onSubmit = async (data: yup.InferType<typeof invitationSchema>) => {\n setLoading(true);\n\n try {\n await props.team.inviteUser({ email: data.email });\n setInvitedEmail(data.email);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n setInvitedEmail(null);\n }, [watch('email')]);\n\n return (\n <div>\n <Label>Invite a user to team</Label>\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <div className=\"flex flex-col gap-4 md:flex-row\">\n <div>\n <Input\n placeholder=\"Email\"\n {...register('email')}\n />\n </div>\n <Button type=\"submit\" loading={loading}>\n Invite User\n </Button>\n </div>\n <FormWarningText text={errors.email?.message?.toString()} />\n {invitedEmail && <Typography type='label' variant='secondary'>Invited {invitedEmail}</Typography>}\n </form>\n </div>\n );\n}\n\n\nfunction MembersSettings(props: { team: Team }) {\n const user = useUser({ or: 'redirect' });\n const readMemberPermission = user.usePermission(props.team, '$read_members');\n const inviteMemberPermission = user.usePermission(props.team, '$invite_members');\n\n if (!readMemberPermission && !inviteMemberPermission) {\n return null;\n }\n\n const users = props.team.useUsers();\n\n if (!readMemberPermission) {\n return null;\n }\n\n return (\n <div>\n <Label>Members</Label>\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[100px]\">User</TableHead>\n <TableHead className=\"w-[200px]\">Name</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {users.map(({ id, teamProfile }, i) => (\n <TableRow key={id}>\n <TableCell>\n <UserAvatar user={teamProfile}/>\n </TableCell>\n <TableCell>\n <Typography>{teamProfile.displayName}</Typography>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n );\n}\n\nconst teamCreationSchema = yupObject({\n displayName: yupString().required('Please enter a team name'),\n});\n\nexport function TeamCreation() {\n const { register, handleSubmit, formState: { errors } } = useForm({\n resolver: yupResolver(teamCreationSchema)\n });\n const app = useStackApp();\n const project = app.useProject();\n const user = useUser({ or: 'redirect' });\n const [loading, setLoading] = useState(false);\n\n if (!project.config.clientTeamCreationEnabled) {\n return <MessageCard title='Team creation is not enabled' />;\n }\n\n const onSubmit = async (data: yup.InferType<typeof teamCreationSchema>) => {\n setLoading(true);\n\n try {\n const team = await user.createTeam({ displayName: data.displayName });\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <div className='stack-scope flex flex-col items-stretch'>\n <div className=\"mb-6\">\n <form\n className=\"flex flex-col items-stretch stack-scope\"\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n >\n <div className=\"flex items-end gap-4\">\n <div>\n <Label htmlFor=\"email\" className=\"mb-1\">Display name</Label>\n <Input\n id=\"email\"\n type=\"email\"\n {...register('displayName')}\n />\n </div>\n <FormWarningText text={errors.displayName?.message?.toString()} />\n\n <Button type=\"submit\" className=\"mt-6\" loading={loading}>\n Create\n </Button>\n </div>\n </form>\n </div>\n </div>\n );\n}"],"mappings":"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","names":[]}
|
|
@@ -24,7 +24,7 @@ import { constructRedirectUrl } from "../utils/url";
|
|
|
24
24
|
import { addNewOAuthProviderOrScope, callOAuthCallback, signInWithOAuth } from "./auth";
|
|
25
25
|
import { deleteCookie, getCookie, setOrDeleteCookie } from "./cookie";
|
|
26
26
|
var NextNavigation = scrambleDuringCompileTime(NextNavigationUnscrambled);
|
|
27
|
-
var clientVersion = "js @stackframe/stack@2.5.
|
|
27
|
+
var clientVersion = "js @stackframe/stack@2.5.23";
|
|
28
28
|
function getUrls(partial) {
|
|
29
29
|
const handler = partial.handler ?? "/handler";
|
|
30
30
|
const home = partial.home ?? "/";
|
|
@@ -586,6 +586,7 @@ var _StackClientAppImpl = class __StackClientAppImpl {
|
|
|
586
586
|
profileImageUrl: crud.profile_image_url,
|
|
587
587
|
signedUpAt: new Date(crud.signed_up_at_millis),
|
|
588
588
|
clientMetadata: crud.client_metadata,
|
|
589
|
+
clientReadOnlyMetadata: crud.client_read_only_metadata,
|
|
589
590
|
hasPassword: crud.has_password,
|
|
590
591
|
emailAuthEnabled: crud.auth_with_email,
|
|
591
592
|
oauthProviders: crud.oauth_providers,
|
|
@@ -1316,6 +1317,9 @@ var _StackServerAppImpl = class extends _StackClientAppImpl {
|
|
|
1316
1317
|
async setClientMetadata(metadata) {
|
|
1317
1318
|
return await this.update({ clientMetadata: metadata });
|
|
1318
1319
|
},
|
|
1320
|
+
async setClientReadOnlyMetadata(metadata) {
|
|
1321
|
+
return await this.update({ clientReadOnlyMetadata: metadata });
|
|
1322
|
+
},
|
|
1319
1323
|
async setServerMetadata(metadata) {
|
|
1320
1324
|
return await this.update({ serverMetadata: metadata });
|
|
1321
1325
|
},
|
|
@@ -1832,6 +1836,7 @@ function serverUserUpdateOptionsToCrud(options) {
|
|
|
1832
1836
|
display_name: options.displayName,
|
|
1833
1837
|
primary_email: options.primaryEmail,
|
|
1834
1838
|
client_metadata: options.clientMetadata,
|
|
1839
|
+
client_read_only_metadata: options.clientReadOnlyMetadata,
|
|
1835
1840
|
server_metadata: options.serverMetadata,
|
|
1836
1841
|
selected_team_id: options.selectedTeamId,
|
|
1837
1842
|
primary_email_auth_enabled: options.primaryEmailAuthEnabled,
|