@alepha/ui 0.19.0 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/{AdminApiKeys-Bt1PjO6o.js → AdminApiKeys-C2ze85eD.js} +2 -2
- package/dist/admin/{AdminApiKeys-Bt1PjO6o.js.map → AdminApiKeys-C2ze85eD.js.map} +1 -1
- package/dist/admin/{AdminAudits-C7c1CN4c.js → AdminAudits-BIj81e4k.js} +2 -2
- package/dist/admin/{AdminAudits-C7c1CN4c.js.map → AdminAudits-BIj81e4k.js.map} +1 -1
- package/dist/admin/{AdminDashboard-C3RXpTp6.js → AdminDashboard-PMVzrwSu.js} +2 -2
- package/dist/admin/{AdminDashboard-C3RXpTp6.js.map → AdminDashboard-PMVzrwSu.js.map} +1 -1
- package/dist/admin/AdminFiles-Bq03BLt-.js +189 -0
- package/dist/admin/AdminFiles-Bq03BLt-.js.map +1 -0
- package/dist/admin/{AdminJobExecutions-D-G8RIlr.js → AdminJobs-D1_QGCDy.js} +400 -356
- package/dist/admin/AdminJobs-D1_QGCDy.js.map +1 -0
- package/dist/admin/{AdminLayout-BmZ9mtXh.js → AdminLayout-BNiwiw2D.js} +2 -2
- package/dist/admin/{AdminLayout-BmZ9mtXh.js.map → AdminLayout-BNiwiw2D.js.map} +1 -1
- package/dist/admin/{AdminNotifications-DHdzksww.js → AdminNotifications-DSKQtUfn.js} +84 -122
- package/dist/admin/AdminNotifications-DSKQtUfn.js.map +1 -0
- package/dist/admin/{AdminParameters-CyZQSXnN.js → AdminParameters-CoB7EhyM.js} +2 -2
- package/dist/admin/{AdminParameters-CyZQSXnN.js.map → AdminParameters-CoB7EhyM.js.map} +1 -1
- package/dist/admin/{AdminSessions--xwELDSO.js → AdminSessions-DFbFcrJQ.js} +2 -2
- package/dist/admin/{AdminSessions--xwELDSO.js.map → AdminSessions-DFbFcrJQ.js.map} +1 -1
- package/dist/admin/{AdminUserLayout-DvBTG5gd.js → AdminUserLayout-fSfi3KMm.js} +3 -3
- package/dist/admin/{AdminUserLayout-DvBTG5gd.js.map → AdminUserLayout-fSfi3KMm.js.map} +1 -1
- package/dist/admin/{AdminUserProfile-CzsPBl6Z.js → AdminUserProfile-_C-h8vUK.js} +3 -3
- package/dist/admin/{AdminUserProfile-CzsPBl6Z.js.map → AdminUserProfile-_C-h8vUK.js.map} +1 -1
- package/dist/admin/{AdminUserSessions-C-aUnhVN.js → AdminUserSessions-KpJHIeQo.js} +2 -2
- package/dist/admin/{AdminUserSessions-C-aUnhVN.js.map → AdminUserSessions-KpJHIeQo.js.map} +1 -1
- package/dist/admin/{AdminUsers-BYwei5sj.js → AdminUsers-DcVrzdQP.js} +2 -2
- package/dist/admin/{AdminUsers-BYwei5sj.js.map → AdminUsers-DcVrzdQP.js.map} +1 -1
- package/dist/admin/{AuthLayout-CkPGLJku.js → AuthLayout-CazfLzcf.js} +2 -2
- package/dist/admin/{AuthLayout-CkPGLJku.js.map → AuthLayout-CazfLzcf.js.map} +1 -1
- package/dist/admin/{Login-DSBqNsZc.js → Login-CaMjUrDP.js} +2 -2
- package/dist/admin/{Login-DSBqNsZc.js.map → Login-CaMjUrDP.js.map} +1 -1
- package/dist/admin/{Profile-CDRjJo0P.js → Profile-Ca4fZX15.js} +2 -2
- package/dist/{auth/Profile-Cy93pNTw.js.map → admin/Profile-Ca4fZX15.js.map} +1 -1
- package/dist/admin/{Register-4QGFOnfh.js → Register-C5DyKWPO.js} +2 -2
- package/dist/{demo/Register-KKZwr_lL.js.map → admin/Register-C5DyKWPO.js.map} +1 -1
- package/dist/admin/{ResetPassword-Gxc9L_mY.js → ResetPassword-BA5sAgXo.js} +2 -2
- package/dist/{auth/ResetPassword-B61QPlQi.js.map → admin/ResetPassword-BA5sAgXo.js.map} +1 -1
- package/dist/admin/{VerifyEmail-D7G5NnaN.js → VerifyEmail-DKNXROj_.js} +2 -2
- package/dist/{auth/VerifyEmail-CqBJ11id.js.map → admin/VerifyEmail-DKNXROj_.js.map} +1 -1
- package/dist/admin/{adminUserAtom-DCi4wf-v.js → adminUserAtom-BLNc7XbT.js} +1 -1
- package/dist/admin/{adminUserAtom-DCi4wf-v.js.map → adminUserAtom-BLNc7XbT.js.map} +1 -1
- package/dist/admin/{core-D1AbU50V.js → core-CJCEx18C.js} +111 -4
- package/dist/admin/core-CJCEx18C.js.map +1 -0
- package/dist/admin/index.d.ts +21 -3
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +29 -58
- package/dist/admin/index.js.map +1 -1
- package/dist/auth/{AuthLayout-CfRKcTqP.js → AuthLayout-vXPcCVzp.js} +2 -2
- package/dist/auth/{AuthLayout-CfRKcTqP.js.map → AuthLayout-vXPcCVzp.js.map} +1 -1
- package/dist/auth/{Login-DJyweoPS.js → Login-Dg08QR20.js} +2 -2
- package/dist/{demo/Login-CqG1iJbn.js.map → auth/Login-Dg08QR20.js.map} +1 -1
- package/dist/{demo/Profile-C0ojJCaG.js → auth/Profile-Bb5O1yeh.js} +2 -2
- package/dist/{admin/Profile-CDRjJo0P.js.map → auth/Profile-Bb5O1yeh.js.map} +1 -1
- package/dist/auth/{Register-CSqzzitW.js → Register-B2AN71NC.js} +2 -2
- package/dist/auth/{Register-CSqzzitW.js.map → Register-B2AN71NC.js.map} +1 -1
- package/dist/{demo/ResetPassword-DMrLFEtr.js → auth/ResetPassword-BLxwzbDj.js} +2 -2
- package/dist/{admin/ResetPassword-Gxc9L_mY.js.map → auth/ResetPassword-BLxwzbDj.js.map} +1 -1
- package/dist/auth/{VerifyEmail-CqBJ11id.js → VerifyEmail-CSDOk3Zm.js} +2 -2
- package/dist/{demo/VerifyEmail-BFCAFz6T.js.map → auth/VerifyEmail-CSDOk3Zm.js.map} +1 -1
- package/dist/auth/{core-C6D3pazL.js → core-DuGkjPiU.js} +2 -1
- package/dist/auth/core-DuGkjPiU.js.map +1 -0
- package/dist/auth/index.d.ts +20 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +11 -11
- package/dist/core/index.d.ts +69 -17
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +110 -8
- package/dist/core/index.js.map +1 -1
- package/dist/demo/{AuthLayout-Dq5tSLSc.js → AuthLayout-DPsOOG4u.js} +2 -2
- package/dist/demo/{AuthLayout-Dq5tSLSc.js.map → AuthLayout-DPsOOG4u.js.map} +1 -1
- package/dist/demo/{DemoButton-_Ws2w-J0.js → DemoButton-wzcqGk4u.js} +3 -3
- package/dist/demo/{DemoButton-_Ws2w-J0.js.map → DemoButton-wzcqGk4u.js.map} +1 -1
- package/dist/demo/{DemoControlSelect-ChP4ZOpQ.js → DemoControlSelect-CMWvQ6Gm.js} +3 -3
- package/dist/demo/{DemoControlSelect-ChP4ZOpQ.js.map → DemoControlSelect-CMWvQ6Gm.js.map} +1 -1
- package/dist/demo/{DemoDataTable-Hwf_UUni.js → DemoDataTable-CHsAP3e2.js} +3 -3
- package/dist/demo/{DemoDataTable-Hwf_UUni.js.map → DemoDataTable-CHsAP3e2.js.map} +1 -1
- package/dist/demo/{DemoDialog-B01OMVRd.js → DemoDialog-Co2IePxX.js} +2 -2
- package/dist/demo/{DemoDialog-B01OMVRd.js.map → DemoDialog-Co2IePxX.js.map} +1 -1
- package/dist/demo/{DemoFlex-870PEl0V.js → DemoFlex-OEwQt5do.js} +3 -3
- package/dist/demo/{DemoFlex-870PEl0V.js.map → DemoFlex-OEwQt5do.js.map} +1 -1
- package/dist/demo/DemoHeading-Db-XkQIK.js +69 -0
- package/dist/demo/DemoHeading-Db-XkQIK.js.map +1 -0
- package/dist/demo/{DemoHome-DRbL2eGf.js → DemoHome-Cyp29ygy.js} +2 -2
- package/dist/demo/{DemoHome-DRbL2eGf.js.map → DemoHome-Cyp29ygy.js.map} +1 -1
- package/dist/demo/{DemoJsonViewer-DoABiqBW.js → DemoJsonViewer-DXtCeMzH.js} +3 -3
- package/dist/demo/{DemoJsonViewer-DoABiqBW.js.map → DemoJsonViewer-DXtCeMzH.js.map} +1 -1
- package/dist/demo/{DemoLayout-CN_PDCX2.js → DemoLayout-hh9VmZQP.js} +2 -2
- package/dist/demo/{DemoLayout-CN_PDCX2.js.map → DemoLayout-hh9VmZQP.js.map} +1 -1
- package/dist/demo/{DemoLogin-B5x-ug3Q.js → DemoLogin-DX7mnmkh.js} +13 -8
- package/dist/demo/{DemoLogin-B5x-ug3Q.js.map → DemoLogin-DX7mnmkh.js.map} +1 -1
- package/dist/demo/{DemoRegister-Q6sg2xuV.js → DemoRegister-DVcZl04m.js} +13 -8
- package/dist/demo/{DemoRegister-Q6sg2xuV.js.map → DemoRegister-DVcZl04m.js.map} +1 -1
- package/dist/demo/{DemoResetPassword-DrqZfmEw.js → DemoResetPassword-CPENlZH5.js} +13 -8
- package/dist/demo/{DemoResetPassword-DrqZfmEw.js.map → DemoResetPassword-CPENlZH5.js.map} +1 -1
- package/dist/demo/{DemoSidebar-CfKS6w1o.js → DemoSidebar-CGu7DZeM.js} +3 -3
- package/dist/demo/{DemoSidebar-CfKS6w1o.js.map → DemoSidebar-CGu7DZeM.js.map} +1 -1
- package/dist/demo/{DemoText-pT6Gi5b5.js → DemoText-DYUJ7bY_.js} +3 -3
- package/dist/demo/{DemoText-pT6Gi5b5.js.map → DemoText-DYUJ7bY_.js.map} +1 -1
- package/dist/demo/{DemoToast-I13NBzQQ.js → DemoToast-CgdnZNvx.js} +2 -2
- package/dist/demo/{DemoToast-I13NBzQQ.js.map → DemoToast-CgdnZNvx.js.map} +1 -1
- package/dist/demo/{DemoTypeForm-BqzcrtvN.js → DemoTypeForm-Pims-cGa.js} +3 -3
- package/dist/demo/{DemoTypeForm-BqzcrtvN.js.map → DemoTypeForm-Pims-cGa.js.map} +1 -1
- package/dist/demo/{DemoVerifyEmail-HwD8xfQw.js → DemoVerifyEmail-C7B3xxch.js} +8 -8
- package/dist/demo/{DemoVerifyEmail-HwD8xfQw.js.map → DemoVerifyEmail-C7B3xxch.js.map} +1 -1
- package/dist/demo/{Login-CqG1iJbn.js → Login-pwMF4TUj.js} +2 -2
- package/dist/{auth/Login-DJyweoPS.js.map → demo/Login-pwMF4TUj.js.map} +1 -1
- package/dist/{auth/Profile-Cy93pNTw.js → demo/Profile-BliZapZS.js} +2 -2
- package/dist/demo/{Profile-C0ojJCaG.js.map → Profile-BliZapZS.js.map} +1 -1
- package/dist/demo/{Register-KKZwr_lL.js → Register-CiwAT7Hy.js} +2 -2
- package/dist/{admin/Register-4QGFOnfh.js.map → demo/Register-CiwAT7Hy.js.map} +1 -1
- package/dist/{auth/ResetPassword-B61QPlQi.js → demo/ResetPassword-l9Vg4JE-.js} +2 -2
- package/dist/demo/{ResetPassword-DMrLFEtr.js.map → ResetPassword-l9Vg4JE-.js.map} +1 -1
- package/dist/demo/{Showcase-D49Wud2v.js → Showcase-CX6bDgwe.js} +2 -2
- package/dist/demo/{Showcase-D49Wud2v.js.map → Showcase-CX6bDgwe.js.map} +1 -1
- package/dist/demo/{VerifyEmail-BFCAFz6T.js → VerifyEmail-CAB-OS7i.js} +2 -2
- package/dist/{admin/VerifyEmail-D7G5NnaN.js.map → demo/VerifyEmail-CAB-OS7i.js.map} +1 -1
- package/dist/demo/{auth-D9qTZzCa.js → auth-uegJAdKu.js} +8 -8
- package/dist/demo/{auth-D9qTZzCa.js.map → auth-uegJAdKu.js.map} +1 -1
- package/dist/demo/{core-DRtQklr3.js → core-B4LVHzPn.js} +111 -9
- package/dist/demo/core-B4LVHzPn.js.map +1 -0
- package/dist/demo/index.js +19 -19
- package/dist/demo/index.js.map +1 -1
- package/package.json +6 -9
- package/src/admin/AdminRouter.tsx +5 -37
- package/src/admin/components/files/AdminFiles.tsx +123 -1
- package/src/admin/components/jobs/{AdminJobExecutions.tsx → AdminJobs.tsx} +450 -317
- package/src/admin/components/notifications/AdminNotifications.tsx +11 -25
- package/src/core/components/Section.tsx +109 -0
- package/src/core/components/SectionHeader.tsx +106 -0
- package/src/core/index.ts +4 -1
- package/src/core/table/components/DataTable.tsx +5 -1
- package/src/demo/DemoRouter.ts +1 -1
- package/src/demo/components/auth/DemoLogin.tsx +5 -0
- package/src/demo/components/auth/DemoRegister.tsx +5 -0
- package/src/demo/components/auth/DemoResetPassword.tsx +5 -0
- package/src/demo/components/core/DemoHeading.tsx +56 -3
- package/dist/admin/AdminFiles-31ivR6Wq.js +0 -110
- package/dist/admin/AdminFiles-31ivR6Wq.js.map +0 -1
- package/dist/admin/AdminJobDashboard-BABLe7hL.js +0 -402
- package/dist/admin/AdminJobDashboard-BABLe7hL.js.map +0 -1
- package/dist/admin/AdminJobExecutions-D-G8RIlr.js.map +0 -1
- package/dist/admin/AdminJobRegistry-oIS3K9NX.js +0 -269
- package/dist/admin/AdminJobRegistry-oIS3K9NX.js.map +0 -1
- package/dist/admin/AdminNotifications-DHdzksww.js.map +0 -1
- package/dist/admin/core-D1AbU50V.js.map +0 -1
- package/dist/auth/core-C6D3pazL.js.map +0 -1
- package/dist/demo/DemoHeading-C1YR27fz.js +0 -17
- package/dist/demo/DemoHeading-C1YR27fz.js.map +0 -1
- package/dist/demo/core-DRtQklr3.js.map +0 -1
- package/src/admin/components/jobs/AdminJobDashboard.tsx +0 -380
- package/src/admin/components/jobs/AdminJobRegistry.tsx +0 -301
- package/src/core/components/Heading.tsx +0 -19
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Login-CqG1iJbn.js","names":[],"sources":["../../src/auth/components/Login.tsx"],"sourcesContent":["import { ActionButton, Control, capitalize } from \"@alepha/ui\";\nimport { Card, Flex, Image, Text, Title } from \"@mantine/core\";\nimport { IconLock, IconPhoto, IconUser } from \"@tabler/icons-react\";\nimport { AlephaError, t } from \"alepha\";\nimport type { RealmConfig } from \"alepha/api/users\";\nimport { useAuth } from \"alepha/react/auth\";\nimport { FormValidationError, useForm } from \"alepha/react/form\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouter } from \"alepha/react/router\";\nimport { HttpError } from \"alepha/server\";\nimport { useMemo } from \"react\";\nimport type { AuthI18n } from \"../AuthI18n.ts\";\nimport IconGithub from \"./icons/IconGithub.tsx\";\nimport IconGoogle from \"./icons/IconGoogle.tsx\";\n\nexport interface LoginProps {\n realmConfig: RealmConfig;\n registerPath?: string;\n resetPasswordPath?: string;\n variant?: \"card\" | \"split\";\n image?: string;\n}\n\nconst Login = (props: LoginProps) => {\n const auth = useAuth();\n const router = useRouter();\n const { tr } = useI18n<AuthI18n, \"en\">();\n const redirect = router.query.r || \"/\";\n\n const credentialsProvider = props.realmConfig.authenticationMethods.find(\n (it) => it.type === \"CREDENTIALS\",\n );\n\n const settings = props.realmConfig.settings;\n\n // Determine what login methods are available\n const loginMethods = useMemo(() => {\n const methods = [];\n if (settings.username !== \"none\") methods.push(\"username\");\n if (settings.email !== \"none\") methods.push(\"email\");\n if (settings.phoneNumber !== \"none\") methods.push(\"phone\");\n return methods;\n }, [settings]);\n\n // Create identifier title based on enabled methods\n const identifierTitle = useMemo(() => {\n if (loginMethods.length === 0) return tr(\"loginUsername\");\n if (loginMethods.length === 1) {\n if (loginMethods[0] === \"username\") return tr(\"loginUsername\");\n if (loginMethods[0] === \"email\") return tr(\"loginEmail\");\n if (loginMethods[0] === \"phone\") return tr(\"loginPhone\");\n }\n const labels = loginMethods.map((m) => {\n if (m === \"username\") return tr(\"loginUsername\").toLowerCase();\n if (m === \"email\") return tr(\"loginEmail\").toLowerCase();\n if (m === \"phone\") return tr(\"loginPhone\").toLowerCase();\n return m;\n });\n return capitalize(\n `${labels.slice(0, -1).join(\", \")} or ${labels[labels.length - 1]}`,\n );\n }, [loginMethods, tr]);\n\n const form = useForm({\n schema: t.object({\n identifier: t.string({\n minLength: 1,\n }),\n password: t.string({\n minLength: settings.passwordPolicy?.minLength || 6,\n }),\n }),\n handler: async (data) => {\n if (!credentialsProvider) {\n throw new AlephaError(\"Credentials provider not configured\");\n }\n\n try {\n await auth.login(credentialsProvider.name, {\n username: data.identifier,\n password: data.password,\n realm: props.realmConfig.realmName,\n });\n await router.push(router.query.r || \"/\");\n } catch (error) {\n if (\n error instanceof HttpError &&\n error.error === \"InvalidCredentialsError\"\n ) {\n throw new FormValidationError({\n message: \"Invalid identifier or password\",\n path: \"/password\",\n });\n }\n throw error;\n }\n },\n });\n\n const getAutoCompleteType = () => {\n if (loginMethods.includes(\"email\")) {\n return \"email\";\n }\n if (loginMethods.includes(\"username\")) {\n return \"username\";\n }\n if (loginMethods.includes(\"phone\")) {\n return \"tel\";\n }\n return \"username\";\n };\n\n const externalLoginMethods = props.realmConfig.authenticationMethods.filter(\n (method) => method.type !== \"CREDENTIALS\",\n );\n\n const showOrDivider = credentialsProvider && externalLoginMethods.length > 0;\n\n const realmQuery = props.realmConfig.realmName\n ? `?realm=${encodeURIComponent(props.realmConfig.realmName)}`\n : \"\";\n\n const formContent = (\n <Flex direction=\"column\" gap={\"md\"}>\n {/* Realm branding */}\n {(settings.logoUrl || settings.displayName || settings.description) && (\n <Flex direction=\"column\" gap={\"xs\"} align=\"center\" mb=\"xs\">\n {settings.logoUrl && (\n <Image\n src={settings.logoUrl}\n alt={settings.displayName || props.realmConfig.realmName}\n h={48}\n w=\"auto\"\n fit=\"contain\"\n />\n )}\n {settings.displayName && (\n <Title order={4} ta=\"center\">\n {settings.displayName}\n </Title>\n )}\n {settings.description && (\n <Text size=\"sm\" c=\"dimmed\" ta=\"center\">\n {settings.description}\n </Text>\n )}\n </Flex>\n )}\n\n {/* Credentials login form */}\n {credentialsProvider && (\n <>\n <form {...form.props}>\n <Flex direction=\"column\" flex={1} gap={\"md\"}>\n <Control\n label={identifierTitle}\n input={form.input.identifier}\n icon={IconUser}\n text={{\n autoComplete: getAutoCompleteType(),\n }}\n />\n <Control\n label={tr(\"loginPassword\")}\n input={form.input.password}\n icon={IconLock}\n password={{\n autoComplete: \"current-password\",\n }}\n />\n <ActionButton variant={\"filled\"} form={form}>\n {tr(\"loginSignIn\")}\n </ActionButton>\n </Flex>\n </form>\n {settings.resetPasswordAllowed && (\n <Text size=\"sm\" ta=\"center\">\n <ActionButton\n href={`${props.resetPasswordPath ?? \"/auth/reset-password\"}${realmQuery}`}\n anchorProps={{ inherit: true }}\n >\n {tr(\"loginForgotPassword\")}\n </ActionButton>\n </Text>\n )}\n </>\n )}\n\n {/* OR divider - only when both credentials AND external methods exist */}\n {showOrDivider && (\n <Flex align=\"center\" justify=\"center\" gap={\"md\"}>\n <Flex flex={1} h={\"1px\"} bg={\"var(--alepha-border)\"} />\n <Text size=\"xs\" c={\"dimmed\"}>\n {tr(\"loginOr\")}\n </Text>\n <Flex flex={1} h={\"1px\"} bg={\"var(--alepha-border)\"} />\n </Flex>\n )}\n\n {/* External login methods */}\n {externalLoginMethods.length > 0 && (\n <Flex direction=\"column\" gap={\"sm\"}>\n {externalLoginMethods.map((method) => (\n <ActionButton\n variant={\"default\"}\n key={method.type}\n leftSection={leftSection(method.name.toLowerCase())}\n onClick={() =>\n auth.login(method.name, {\n redirect,\n realm: props.realmConfig.realmName,\n })\n }\n >\n {tr(\"loginContinueWith\", {\n args: [capitalize(method.name)],\n })}\n </ActionButton>\n ))}\n </Flex>\n )}\n\n {/* Registration link */}\n {settings.registrationAllowed && (\n <Text size=\"sm\" ta=\"center\">\n {tr(\"loginNoAccount\")}{\" \"}\n <ActionButton\n href={`${props.registerPath ?? \"/auth/register\"}${realmQuery}`}\n anchorProps={{ inherit: true }}\n >\n {tr(\"loginSignUp\")}\n </ActionButton>\n </Text>\n )}\n </Flex>\n );\n\n if (props.variant === \"split\") {\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Card\n withBorder\n p={0}\n w={720}\n bg={\"var(--alepha-elevated)\"}\n style={{ overflow: \"hidden\" }}\n >\n <Flex mih={480}>\n {props.image ? (\n <Flex\n flex={1}\n style={{\n backgroundImage: `url(${props.image})`,\n backgroundSize: \"cover\",\n backgroundPosition: \"center\",\n }}\n />\n ) : (\n <Flex\n flex={1}\n justify=\"center\"\n align=\"center\"\n bg=\"var(--mantine-color-gray-light)\"\n style={{\n borderRight: \"1px solid var(--mantine-color-default-border)\",\n }}\n >\n <Flex\n justify=\"center\"\n align=\"center\"\n w={120}\n h={80}\n style={{\n border: \"2px dashed var(--mantine-color-default-border)\",\n borderRadius: \"var(--mantine-radius-sm)\",\n }}\n >\n <IconPhoto size={32} style={{ opacity: 0.3 }} />\n </Flex>\n </Flex>\n )}\n <Flex\n flex={1}\n direction=\"column\"\n gap={\"md\"}\n p={\"xl\"}\n justify={\"center\"}\n >\n {formContent}\n <ActionButton variant={\"subtle\"} href={\"/\"}>\n {tr(\"loginCancel\")}\n </ActionButton>\n </Flex>\n </Flex>\n </Card>\n </Flex>\n );\n }\n\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Flex direction=\"column\" gap={\"sm\"} w={360}>\n <Card withBorder p={\"lg\"} bg={\"var(--alepha-elevated)\"}>\n {formContent}\n </Card>\n <ActionButton variant={\"subtle\"} href={\"/\"}>\n {tr(\"loginCancel\")}\n </ActionButton>\n </Flex>\n </Flex>\n );\n};\n\nexport default Login;\n\nconst leftSection = (name: string) => {\n if (name === \"google\") {\n return <IconGoogle />;\n }\n\n if (name === \"github\") {\n return <IconGithub />;\n }\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Login-Dg08QR20.js","names":[],"sources":["../../src/auth/components/Login.tsx"],"sourcesContent":["import { ActionButton, Control, capitalize } from \"@alepha/ui\";\nimport { Card, Flex, Image, Text, Title } from \"@mantine/core\";\nimport { IconLock, IconPhoto, IconUser } from \"@tabler/icons-react\";\nimport { AlephaError, t } from \"alepha\";\nimport type { RealmConfig } from \"alepha/api/users\";\nimport { useAuth } from \"alepha/react/auth\";\nimport { FormValidationError, useForm } from \"alepha/react/form\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouter } from \"alepha/react/router\";\nimport { HttpError } from \"alepha/server\";\nimport { useMemo } from \"react\";\nimport type { AuthI18n } from \"../AuthI18n.ts\";\nimport IconGithub from \"./icons/IconGithub.tsx\";\nimport IconGoogle from \"./icons/IconGoogle.tsx\";\n\nexport interface LoginProps {\n realmConfig: RealmConfig;\n registerPath?: string;\n resetPasswordPath?: string;\n variant?: \"card\" | \"split\";\n image?: string;\n}\n\nconst Login = (props: LoginProps) => {\n const auth = useAuth();\n const router = useRouter();\n const { tr } = useI18n<AuthI18n, \"en\">();\n const redirect = router.query.r || \"/\";\n\n const credentialsProvider = props.realmConfig.authenticationMethods.find(\n (it) => it.type === \"CREDENTIALS\",\n );\n\n const settings = props.realmConfig.settings;\n\n // Determine what login methods are available\n const loginMethods = useMemo(() => {\n const methods = [];\n if (settings.username !== \"none\") methods.push(\"username\");\n if (settings.email !== \"none\") methods.push(\"email\");\n if (settings.phoneNumber !== \"none\") methods.push(\"phone\");\n return methods;\n }, [settings]);\n\n // Create identifier title based on enabled methods\n const identifierTitle = useMemo(() => {\n if (loginMethods.length === 0) return tr(\"loginUsername\");\n if (loginMethods.length === 1) {\n if (loginMethods[0] === \"username\") return tr(\"loginUsername\");\n if (loginMethods[0] === \"email\") return tr(\"loginEmail\");\n if (loginMethods[0] === \"phone\") return tr(\"loginPhone\");\n }\n const labels = loginMethods.map((m) => {\n if (m === \"username\") return tr(\"loginUsername\").toLowerCase();\n if (m === \"email\") return tr(\"loginEmail\").toLowerCase();\n if (m === \"phone\") return tr(\"loginPhone\").toLowerCase();\n return m;\n });\n return capitalize(\n `${labels.slice(0, -1).join(\", \")} or ${labels[labels.length - 1]}`,\n );\n }, [loginMethods, tr]);\n\n const form = useForm({\n schema: t.object({\n identifier: t.string({\n minLength: 1,\n }),\n password: t.string({\n minLength: settings.passwordPolicy?.minLength || 6,\n }),\n }),\n handler: async (data) => {\n if (!credentialsProvider) {\n throw new AlephaError(\"Credentials provider not configured\");\n }\n\n try {\n await auth.login(credentialsProvider.name, {\n username: data.identifier,\n password: data.password,\n realm: props.realmConfig.realmName,\n });\n await router.push(router.query.r || \"/\");\n } catch (error) {\n if (\n error instanceof HttpError &&\n error.error === \"InvalidCredentialsError\"\n ) {\n throw new FormValidationError({\n message: \"Invalid identifier or password\",\n path: \"/password\",\n });\n }\n throw error;\n }\n },\n });\n\n const getAutoCompleteType = () => {\n if (loginMethods.includes(\"email\")) {\n return \"email\";\n }\n if (loginMethods.includes(\"username\")) {\n return \"username\";\n }\n if (loginMethods.includes(\"phone\")) {\n return \"tel\";\n }\n return \"username\";\n };\n\n const externalLoginMethods = props.realmConfig.authenticationMethods.filter(\n (method) => method.type !== \"CREDENTIALS\",\n );\n\n const showOrDivider = credentialsProvider && externalLoginMethods.length > 0;\n\n const realmQuery = props.realmConfig.realmName\n ? `?realm=${encodeURIComponent(props.realmConfig.realmName)}`\n : \"\";\n\n const formContent = (\n <Flex direction=\"column\" gap={\"md\"}>\n {/* Realm branding */}\n {(settings.logoUrl || settings.displayName || settings.description) && (\n <Flex direction=\"column\" gap={\"xs\"} align=\"center\" mb=\"xs\">\n {settings.logoUrl && (\n <Image\n src={settings.logoUrl}\n alt={settings.displayName || props.realmConfig.realmName}\n h={48}\n w=\"auto\"\n fit=\"contain\"\n />\n )}\n {settings.displayName && (\n <Title order={4} ta=\"center\">\n {settings.displayName}\n </Title>\n )}\n {settings.description && (\n <Text size=\"sm\" c=\"dimmed\" ta=\"center\">\n {settings.description}\n </Text>\n )}\n </Flex>\n )}\n\n {/* Credentials login form */}\n {credentialsProvider && (\n <>\n <form {...form.props}>\n <Flex direction=\"column\" flex={1} gap={\"md\"}>\n <Control\n label={identifierTitle}\n input={form.input.identifier}\n icon={IconUser}\n text={{\n autoComplete: getAutoCompleteType(),\n }}\n />\n <Control\n label={tr(\"loginPassword\")}\n input={form.input.password}\n icon={IconLock}\n password={{\n autoComplete: \"current-password\",\n }}\n />\n <ActionButton variant={\"filled\"} form={form}>\n {tr(\"loginSignIn\")}\n </ActionButton>\n </Flex>\n </form>\n {settings.resetPasswordAllowed && (\n <Text size=\"sm\" ta=\"center\">\n <ActionButton\n href={`${props.resetPasswordPath ?? \"/auth/reset-password\"}${realmQuery}`}\n anchorProps={{ inherit: true }}\n >\n {tr(\"loginForgotPassword\")}\n </ActionButton>\n </Text>\n )}\n </>\n )}\n\n {/* OR divider - only when both credentials AND external methods exist */}\n {showOrDivider && (\n <Flex align=\"center\" justify=\"center\" gap={\"md\"}>\n <Flex flex={1} h={\"1px\"} bg={\"var(--alepha-border)\"} />\n <Text size=\"xs\" c={\"dimmed\"}>\n {tr(\"loginOr\")}\n </Text>\n <Flex flex={1} h={\"1px\"} bg={\"var(--alepha-border)\"} />\n </Flex>\n )}\n\n {/* External login methods */}\n {externalLoginMethods.length > 0 && (\n <Flex direction=\"column\" gap={\"sm\"}>\n {externalLoginMethods.map((method) => (\n <ActionButton\n variant={\"default\"}\n key={method.type}\n leftSection={leftSection(method.name.toLowerCase())}\n onClick={() =>\n auth.login(method.name, {\n redirect,\n realm: props.realmConfig.realmName,\n })\n }\n >\n {tr(\"loginContinueWith\", {\n args: [capitalize(method.name)],\n })}\n </ActionButton>\n ))}\n </Flex>\n )}\n\n {/* Registration link */}\n {settings.registrationAllowed && (\n <Text size=\"sm\" ta=\"center\">\n {tr(\"loginNoAccount\")}{\" \"}\n <ActionButton\n href={`${props.registerPath ?? \"/auth/register\"}${realmQuery}`}\n anchorProps={{ inherit: true }}\n >\n {tr(\"loginSignUp\")}\n </ActionButton>\n </Text>\n )}\n </Flex>\n );\n\n if (props.variant === \"split\") {\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Card\n withBorder\n p={0}\n w={720}\n bg={\"var(--alepha-elevated)\"}\n style={{ overflow: \"hidden\" }}\n >\n <Flex mih={480}>\n {props.image ? (\n <Flex\n flex={1}\n style={{\n backgroundImage: `url(${props.image})`,\n backgroundSize: \"cover\",\n backgroundPosition: \"center\",\n }}\n />\n ) : (\n <Flex\n flex={1}\n justify=\"center\"\n align=\"center\"\n bg=\"var(--mantine-color-gray-light)\"\n style={{\n borderRight: \"1px solid var(--mantine-color-default-border)\",\n }}\n >\n <Flex\n justify=\"center\"\n align=\"center\"\n w={120}\n h={80}\n style={{\n border: \"2px dashed var(--mantine-color-default-border)\",\n borderRadius: \"var(--mantine-radius-sm)\",\n }}\n >\n <IconPhoto size={32} style={{ opacity: 0.3 }} />\n </Flex>\n </Flex>\n )}\n <Flex\n flex={1}\n direction=\"column\"\n gap={\"md\"}\n p={\"xl\"}\n justify={\"center\"}\n >\n {formContent}\n <ActionButton variant={\"subtle\"} href={\"/\"}>\n {tr(\"loginCancel\")}\n </ActionButton>\n </Flex>\n </Flex>\n </Card>\n </Flex>\n );\n }\n\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Flex direction=\"column\" gap={\"sm\"} w={360}>\n <Card withBorder p={\"lg\"} bg={\"var(--alepha-elevated)\"}>\n {formContent}\n </Card>\n <ActionButton variant={\"subtle\"} href={\"/\"}>\n {tr(\"loginCancel\")}\n </ActionButton>\n </Flex>\n </Flex>\n );\n};\n\nexport default Login;\n\nconst leftSection = (name: string) => {\n if (name === \"google\") {\n return <IconGoogle />;\n }\n\n if (name === \"github\") {\n return <IconGithub />;\n }\n};\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as ActionButton } from "./core-DuGkjPiU.js";
|
|
2
2
|
import { Avatar, Badge, Card, Flex, Text, Title } from "@mantine/core";
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
import { IconAt, IconCalendar, IconId, IconShield, IconUser } from "@tabler/icons-react";
|
|
@@ -154,4 +154,4 @@ const Profile = () => {
|
|
|
154
154
|
//#endregion
|
|
155
155
|
export { Profile as default };
|
|
156
156
|
|
|
157
|
-
//# sourceMappingURL=Profile-
|
|
157
|
+
//# sourceMappingURL=Profile-Bb5O1yeh.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Profile-
|
|
1
|
+
{"version":3,"file":"Profile-Bb5O1yeh.js","names":[],"sources":["../../src/auth/components/ProfileField.tsx","../../src/auth/components/Profile.tsx"],"sourcesContent":["import { Flex, Text } from \"@mantine/core\";\nimport type { ReactNode } from \"react\";\n\nexport interface ProfileFieldProps {\n /**\n * Icon to display\n */\n icon: ReactNode;\n\n /**\n * Field label\n */\n label: string;\n\n /**\n * Field content\n */\n children: ReactNode;\n}\n\nconst ProfileField = (props: ProfileFieldProps) => {\n const { icon, label, children } = props;\n\n return (\n <Flex gap=\"sm\" align=\"flex-start\">\n <Flex c=\"dimmed\" mt={2}>\n {icon}\n </Flex>\n <Flex direction=\"column\" gap={2} flex={1}>\n <Text size=\"xs\" c=\"dimmed\" tt=\"uppercase\" fw={500}>\n {label}\n </Text>\n <Text size=\"sm\">{children}</Text>\n </Flex>\n </Flex>\n );\n};\n\nexport default ProfileField;\n","import { ActionButton } from \"@alepha/ui\";\nimport { Avatar, Badge, Card, Flex, Text, Title } from \"@mantine/core\";\nimport {\n IconAt,\n IconCalendar,\n IconId,\n IconShield,\n IconUser,\n} from \"@tabler/icons-react\";\nimport { useAuth } from \"alepha/react/auth\";\nimport { useRouter } from \"alepha/react/router\";\nimport type { AuthRouter } from \"../AuthRouter.ts\";\nimport ProfileField from \"./ProfileField.tsx\";\n\nconst Profile = () => {\n const auth = useAuth();\n const router = useRouter<AuthRouter>();\n\n if (!auth.user) {\n return null;\n }\n\n const { id, name, email, username, picture, roles, organizations } =\n auth.user;\n\n const displayName = name || username || email || \"User\";\n\n return (\n <Flex flex={1} justify=\"center\" align=\"center\">\n <Flex direction=\"column\" gap=\"md\" w={400}>\n <Card withBorder p=\"xl\" bg=\"var(--alepha-elevated)\">\n <Flex direction=\"column\" gap=\"lg\">\n {/* Avatar and name */}\n <Flex direction=\"column\" align=\"center\" gap=\"md\">\n <Avatar\n src={picture ? `/api/files/${picture}` : undefined}\n size={96}\n radius=\"xl\"\n color=\"blue\"\n >\n {!picture && <IconUser size={48} />}\n </Avatar>\n <Flex direction=\"column\" gap={4} align=\"center\">\n <Title order={3}>{displayName}</Title>\n {email && username && (\n <Text size=\"sm\" c=\"dimmed\">\n @{username}\n </Text>\n )}\n </Flex>\n </Flex>\n\n {/* User details */}\n <Flex direction=\"column\" gap=\"sm\">\n {email && (\n <ProfileField icon={<IconAt size={18} />} label=\"Email\">\n {email}\n </ProfileField>\n )}\n\n {username && (\n <ProfileField icon={<IconUser size={18} />} label=\"Username\">\n {username}\n </ProfileField>\n )}\n\n {id && (\n <ProfileField icon={<IconId size={18} />} label=\"User ID\">\n <Text size=\"xs\" c=\"dimmed\" ff=\"monospace\">\n {id}\n </Text>\n </ProfileField>\n )}\n\n {/* Roles */}\n {roles && roles.length > 0 && (\n <ProfileField icon={<IconShield size={18} />} label=\"Roles\">\n <Flex gap=\"xs\">\n {roles.map((role) => (\n <Badge key={role} size=\"sm\" variant=\"light\">\n {role}\n </Badge>\n ))}\n </Flex>\n </ProfileField>\n )}\n\n {/* Organizations */}\n {organizations && organizations.length > 0 && (\n <ProfileField\n icon={<IconCalendar size={18} />}\n label=\"Organizations\"\n >\n <Flex gap=\"xs\">\n {organizations.map((org) => (\n <Badge key={org} size=\"sm\" variant=\"outline\">\n {org}\n </Badge>\n ))}\n </Flex>\n </ProfileField>\n )}\n </Flex>\n\n {/* Actions */}\n <Flex direction=\"column\" gap=\"sm\" mt=\"md\">\n <ActionButton\n variant=\"light\"\n color=\"red\"\n onClick={() => auth.logout()}\n fullWidth\n >\n Sign out\n </ActionButton>\n </Flex>\n </Flex>\n </Card>\n\n <ActionButton variant=\"subtle\" href=\"/\">\n Back to home\n </ActionButton>\n </Flex>\n </Flex>\n );\n};\n\nexport default Profile;\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-CiIaOW0V.js";
|
|
2
|
-
import { i as ActionButton, n as capitalize, r as Control } from "./core-
|
|
2
|
+
import { i as ActionButton, n as capitalize, r as Control } from "./core-DuGkjPiU.js";
|
|
3
3
|
import { n as IconGithub, t as IconGoogle } from "./IconGoogle-8Nkx6yax.js";
|
|
4
4
|
import { TypeBoxError, t } from "alepha";
|
|
5
5
|
import { useForm } from "alepha/react/form";
|
|
@@ -427,4 +427,4 @@ const leftSection = (name) => {
|
|
|
427
427
|
//#endregion
|
|
428
428
|
export { Register_exports as n, Register as t };
|
|
429
429
|
|
|
430
|
-
//# sourceMappingURL=Register-
|
|
430
|
+
//# sourceMappingURL=Register-B2AN71NC.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Register-CSqzzitW.js","names":[],"sources":["../../src/auth/components/Register.tsx"],"sourcesContent":["import { ActionButton, Control, capitalize } from \"@alepha/ui\";\nimport { Alert, Card, Flex, Image, PinInput, Text, Title } from \"@mantine/core\";\nimport {\n IconAlertCircle,\n IconLock,\n IconMail,\n IconPhone,\n IconPhoto,\n IconUser,\n} from \"@tabler/icons-react\";\nimport { TypeBoxError, t } from \"alepha\";\nimport type {\n RealmConfig,\n RegistrationIntentResponse,\n UserController,\n} from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useAuth } from \"alepha/react/auth\";\nimport { useForm } from \"alepha/react/form\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouter } from \"alepha/react/router\";\nimport { useMemo, useState } from \"react\";\nimport type { AuthI18n } from \"../AuthI18n.ts\";\nimport IconGithub from \"./icons/IconGithub.tsx\";\nimport IconGoogle from \"./icons/IconGoogle.tsx\";\n\nexport interface RegisterProps {\n realmConfig: RealmConfig;\n loginPath?: string;\n variant?: \"card\" | \"split\";\n image?: string;\n}\n\ntype RegistrationPhase = \"form\" | \"verification\";\n\ninterface RegistrationState {\n phase: RegistrationPhase;\n intent?: RegistrationIntentResponse;\n credentials?: {\n identifier: string;\n password: string;\n };\n}\n\nconst Register = (props: RegisterProps) => {\n const auth = useAuth();\n const userCtrl = useClient<UserController>();\n const router = useRouter();\n const { tr } = useI18n<AuthI18n, \"en\">();\n const redirect = router.query.r || \"/\";\n\n const [registrationState, setRegistrationState] = useState<RegistrationState>(\n {\n phase: \"form\",\n },\n );\n const [emailCode, setEmailCode] = useState(\"\");\n const [phoneCode, setPhoneCode] = useState(\"\");\n const [verificationError, setVerificationError] = useState<string | null>(\n null,\n );\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const credentialsProvider = props.realmConfig.authenticationMethods.find(\n (it) => it.type === \"CREDENTIALS\",\n );\n\n const settings = props.realmConfig.settings || {};\n const isRegistrationAllowed = settings.registrationAllowed !== false;\n\n const registerSchema = useMemo(() => {\n const registerSchema = t.object({\n username: t.optional(\n t.text({\n trim: true,\n pattern: settings.usernameRegExp,\n }),\n ),\n email: t.optional(t.email()),\n phoneNumber: t.optional(t.e164()),\n password: t.string({ minLength: 8 }),\n confirmPassword: t.string({ minLength: 8 }),\n });\n\n const required = registerSchema.required as string[];\n\n if (settings.username === \"required\") required.push(\"username\");\n if (settings.email === \"required\") required.push(\"email\");\n if (settings.phoneNumber === \"required\") required.push(\"phoneNumber\");\n\n return registerSchema;\n }, []);\n\n const form = useForm({\n schema: registerSchema,\n handler: async (data) => {\n if (data.password !== data.confirmPassword) {\n throw new TypeBoxError({\n message: \"Passwords do not match\",\n instancePath: \"/confirmPassword\",\n keyword: \"not\",\n schemaPath: \"\",\n params: {},\n });\n }\n\n // Phase 1: Create registration intent\n const intent = await userCtrl.createRegistrationIntent({\n query: { userRealmName: props.realmConfig.realmName },\n body: {\n username: data.username,\n email: data.email,\n phoneNumber: data.phoneNumber,\n password: data.password,\n },\n });\n\n const identifier = data.username ?? data.email ?? data.phoneNumber;\n\n // Check if verification is needed\n if (\n intent.expectEmailVerification ||\n intent.expectPhoneVerification ||\n intent.expectCaptcha\n ) {\n // Move to verification phase\n setRegistrationState({\n phase: \"verification\",\n intent,\n credentials: identifier\n ? { identifier, password: data.password }\n : undefined,\n });\n return;\n }\n\n // No verification needed - complete registration immediately\n await userCtrl.createUserFromIntent({\n body: { intentId: intent.intentId },\n });\n\n // Auto-login after registration\n if (identifier && credentialsProvider) {\n await auth.login(credentialsProvider.name, {\n username: identifier,\n password: data.password,\n realm: props.realmConfig.realmName,\n });\n }\n\n await router.push(router.query.r || \"/\");\n },\n });\n\n const handleVerificationSubmit = async () => {\n if (!registrationState.intent) return;\n\n setIsSubmitting(true);\n setVerificationError(null);\n\n try {\n // Phase 2: Complete registration with verification codes\n await userCtrl.createUserFromIntent({\n body: {\n intentId: registrationState.intent.intentId,\n emailCode: registrationState.intent.expectEmailVerification\n ? emailCode\n : undefined,\n phoneCode: registrationState.intent.expectPhoneVerification\n ? phoneCode\n : undefined,\n },\n });\n\n // Auto-login after registration\n if (registrationState.credentials && credentialsProvider) {\n await auth.login(credentialsProvider.name, {\n username: registrationState.credentials.identifier,\n password: registrationState.credentials.password,\n realm: props.realmConfig.realmName,\n });\n }\n\n await router.push(router.query.r || \"/\");\n } catch (error) {\n setVerificationError(\n error instanceof Error ? error.message : \"Verification failed\",\n );\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const canSubmitVerification = () => {\n if (!registrationState.intent) return false;\n\n if (\n registrationState.intent.expectEmailVerification &&\n emailCode.length !== 6\n ) {\n return false;\n }\n\n if (\n registrationState.intent.expectPhoneVerification &&\n phoneCode.length !== 6\n ) {\n return false;\n }\n\n return true;\n };\n\n // Verification phase UI (always card layout)\n if (registrationState.phase === \"verification\" && registrationState.intent) {\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Flex direction=\"column\" gap={\"sm\"} w={360}>\n <Card withBorder p={\"lg\"} bg={\"var(--alepha-elevated)\"}>\n <Flex direction=\"column\" gap={\"md\"}>\n <Text size=\"lg\" fw={500} ta=\"center\">\n {tr(\"registerVerifyTitle\") ?? \"Verify your account\"}\n </Text>\n <Text size=\"sm\" c=\"dimmed\" ta=\"center\">\n {tr(\"registerVerifyDescription\") ??\n \"Please enter the verification code(s) sent to you.\"}\n </Text>\n\n {verificationError && (\n <Alert variant=\"light\" color=\"red\" icon={<IconAlertCircle />}>\n <Text size=\"sm\">{verificationError}</Text>\n </Alert>\n )}\n\n {registrationState.intent.expectEmailVerification && (\n <Flex direction=\"column\" gap={\"xs\"}>\n <Text size=\"sm\" fw={500}>\n {tr(\"registerEmailCode\")}\n </Text>\n <Flex justify=\"center\">\n <PinInput\n length={6}\n value={emailCode}\n onChange={setEmailCode}\n type=\"number\"\n oneTimeCode\n aria-label=\"Email verification code\"\n />\n </Flex>\n </Flex>\n )}\n\n {registrationState.intent.expectPhoneVerification && (\n <Flex direction=\"column\" gap={\"xs\"}>\n <Text size=\"sm\" fw={500}>\n {tr(\"registerPhoneCode\")}\n </Text>\n <Flex justify=\"center\">\n <PinInput\n length={6}\n value={phoneCode}\n onChange={setPhoneCode}\n type=\"number\"\n oneTimeCode\n aria-label=\"Phone verification code\"\n />\n </Flex>\n </Flex>\n )}\n\n <ActionButton\n color={\"blue\"}\n onClick={handleVerificationSubmit}\n loading={isSubmitting}\n disabled={!canSubmitVerification()}\n >\n {tr(\"registerVerifySubmit\")}\n </ActionButton>\n\n <ActionButton\n variant=\"subtle\"\n onClick={() =>\n setRegistrationState({ phase: \"form\", intent: undefined })\n }\n >\n {tr(\"registerVerifyBack\") ?? \"Back to registration\"}\n </ActionButton>\n </Flex>\n </Card>\n </Flex>\n </Flex>\n );\n }\n\n // External login methods\n const externalMethods = props.realmConfig.authenticationMethods.filter(\n (method) => method.type !== \"CREDENTIALS\",\n );\n\n const showOrDivider = credentialsProvider && externalMethods.length > 0;\n\n const realmQuery = props.realmConfig.realmName\n ? `?realm=${encodeURIComponent(props.realmConfig.realmName)}`\n : \"\";\n\n const formContent = (\n <Flex direction=\"column\" gap={\"md\"}>\n {/* Realm branding */}\n {(settings.logoUrl || settings.displayName || settings.description) && (\n <Flex direction=\"column\" gap={\"xs\"} align=\"center\" mb=\"xs\">\n {settings.logoUrl && (\n <Image\n src={settings.logoUrl}\n alt={settings.displayName || props.realmConfig.realmName}\n h={48}\n w=\"auto\"\n fit=\"contain\"\n />\n )}\n {settings.displayName && (\n <Title order={4} ta=\"center\">\n {settings.displayName}\n </Title>\n )}\n {settings.description && (\n <Text size=\"sm\" c=\"dimmed\" ta=\"center\">\n {settings.description}\n </Text>\n )}\n </Flex>\n )}\n\n {!isRegistrationAllowed ? (\n <>\n <Alert variant=\"light\" color=\"yellow\" icon={<IconAlertCircle />}>\n <Text size=\"sm\">{tr(\"registerDisabled\")}</Text>\n </Alert>\n <ActionButton\n href={`${props.loginPath ?? \"/auth/login\"}${realmQuery}`}\n >\n {tr(\"registerBackToSignIn\")}\n </ActionButton>\n </>\n ) : (\n <>\n {/* Credentials registration form */}\n {credentialsProvider && (\n <form {...form.props}>\n <Flex direction=\"column\" flex={1} gap={\"md\"}>\n {settings.username !== \"none\" && form.input.username && (\n <Control\n label={tr(\"registerUsername\")}\n input={form.input.username}\n icon={<IconUser />}\n text={{\n autoComplete: \"username\",\n }}\n />\n )}\n {settings.email !== \"none\" && form.input.email && (\n <Control\n label={tr(\"registerEmail\")}\n input={form.input.email}\n icon={<IconMail />}\n text={{\n autoComplete: \"email\",\n }}\n />\n )}\n {settings.phoneNumber !== \"none\" && form.input.phoneNumber && (\n <Control\n label={tr(\"registerPhone\")}\n input={form.input.phoneNumber}\n icon={<IconPhone />}\n text={{\n autoComplete: \"tel\",\n }}\n />\n )}\n <Control\n label={tr(\"registerPassword\")}\n input={form.input.password}\n icon={<IconLock />}\n password={{\n autoComplete: \"new-password\",\n }}\n />\n <Control\n label={tr(\"registerConfirmPassword\")}\n input={form.input.confirmPassword}\n icon={<IconLock />}\n password={{\n autoComplete: \"new-password\",\n }}\n />\n <ActionButton form={form} color={\"blue\"} variant={\"filled\"}>\n {tr(\"registerCreateAccount\")}\n </ActionButton>\n </Flex>\n </form>\n )}\n\n {/* OR divider - only when both credentials AND external methods exist */}\n {showOrDivider && (\n <Flex align=\"center\" justify=\"center\" gap={\"md\"}>\n <Flex flex={1} h={\"1px\"} bg={\"var(--alepha-border)\"} />\n <Text size=\"xs\" c=\"dimmed\">\n {tr(\"registerOr\")}\n </Text>\n <Flex flex={1} h={\"1px\"} bg={\"var(--alepha-border)\"} />\n </Flex>\n )}\n\n {/* External login methods */}\n {externalMethods.length > 0 && (\n <Flex direction=\"column\" gap={\"sm\"}>\n {externalMethods.map((method) => (\n <ActionButton\n variant={\"default\"}\n key={method.type}\n leftSection={leftSection(method.name.toLowerCase())}\n onClick={() =>\n auth.login(method.name, {\n redirect,\n realm: props.realmConfig.realmName,\n })\n }\n >\n {tr(\"registerContinueWith\", {\n args: [capitalize(method.name)],\n })}\n </ActionButton>\n ))}\n </Flex>\n )}\n\n {/* Sign in link */}\n <Text size=\"sm\" ta=\"center\">\n {tr(\"registerHaveAccount\")}{\" \"}\n <ActionButton\n href={`${props.loginPath ?? \"/auth/login\"}${realmQuery}`}\n anchorProps={{ inherit: true }}\n >\n {tr(\"registerSignIn\")}\n </ActionButton>\n </Text>\n </>\n )}\n </Flex>\n );\n\n if (props.variant === \"split\") {\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Card\n withBorder\n p={0}\n w={720}\n bg={\"var(--alepha-elevated)\"}\n style={{ overflow: \"hidden\" }}\n >\n <Flex mih={480}>\n {props.image ? (\n <Flex\n flex={1}\n style={{\n backgroundImage: `url(${props.image})`,\n backgroundSize: \"cover\",\n backgroundPosition: \"center\",\n }}\n />\n ) : (\n <Flex\n flex={1}\n justify=\"center\"\n align=\"center\"\n bg=\"var(--mantine-color-gray-light)\"\n style={{\n borderRight: \"1px solid var(--mantine-color-default-border)\",\n }}\n >\n <Flex\n justify=\"center\"\n align=\"center\"\n w={120}\n h={80}\n style={{\n border: \"2px dashed var(--mantine-color-default-border)\",\n borderRadius: \"var(--mantine-radius-sm)\",\n }}\n >\n <IconPhoto size={32} style={{ opacity: 0.3 }} />\n </Flex>\n </Flex>\n )}\n <Flex\n flex={1}\n direction=\"column\"\n gap={\"md\"}\n p={\"xl\"}\n justify={\"center\"}\n >\n {formContent}\n <ActionButton variant={\"subtle\"} href={redirect}>\n {tr(\"registerCancel\")}\n </ActionButton>\n </Flex>\n </Flex>\n </Card>\n </Flex>\n );\n }\n\n // Default card variant\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Flex direction=\"column\" gap={\"sm\"} w={360}>\n <Card withBorder p={\"lg\"} bg={\"var(--alepha-elevated)\"}>\n {formContent}\n </Card>\n <ActionButton variant={\"subtle\"} href={redirect}>\n {tr(\"registerCancel\")}\n </ActionButton>\n </Flex>\n </Flex>\n );\n};\n\nexport default Register;\n\nconst leftSection = (name: string) => {\n if (name === \"google\") {\n return <IconGoogle />;\n }\n\n if (name === \"github\") {\n return <IconGithub />;\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;AA4CA,MAAM,YAAY,UAAyB;CACzC,MAAM,OAAO,SAAS;CACtB,MAAM,WAAW,WAA2B;CAC5C,MAAM,SAAS,WAAW;CAC1B,MAAM,EAAE,OAAO,SAAyB;CACxC,MAAM,WAAW,OAAO,MAAM,KAAK;CAEnC,MAAM,CAAC,mBAAmB,wBAAwB,SAChD,EACE,OAAO,QACR,CACF;CACD,MAAM,CAAC,WAAW,gBAAgB,SAAS,GAAG;CAC9C,MAAM,CAAC,WAAW,gBAAgB,SAAS,GAAG;CAC9C,MAAM,CAAC,mBAAmB,wBAAwB,SAChD,KACD;CACD,MAAM,CAAC,cAAc,mBAAmB,SAAS,MAAM;CAEvD,MAAM,sBAAsB,MAAM,YAAY,sBAAsB,MACjE,OAAO,GAAG,SAAS,cACrB;CAED,MAAM,WAAW,MAAM,YAAY,YAAY,EAAE;CACjD,MAAM,wBAAwB,SAAS,wBAAwB;CAyB/D,MAAM,OAAO,QAAQ;EACnB,QAxBqB,cAAc;GACnC,MAAM,iBAAiB,EAAE,OAAO;IAC9B,UAAU,EAAE,SACV,EAAE,KAAK;KACL,MAAM;KACN,SAAS,SAAS;KACnB,CAAC,CACH;IACD,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC;IAC5B,aAAa,EAAE,SAAS,EAAE,MAAM,CAAC;IACjC,UAAU,EAAE,OAAO,EAAE,WAAW,GAAG,CAAC;IACpC,iBAAiB,EAAE,OAAO,EAAE,WAAW,GAAG,CAAC;IAC5C,CAAC;GAEF,MAAM,WAAW,eAAe;AAEhC,OAAI,SAAS,aAAa,WAAY,UAAS,KAAK,WAAW;AAC/D,OAAI,SAAS,UAAU,WAAY,UAAS,KAAK,QAAQ;AACzD,OAAI,SAAS,gBAAgB,WAAY,UAAS,KAAK,cAAc;AAErE,UAAO;KACN,EAAE,CAAC;EAIJ,SAAS,OAAO,SAAS;AACvB,OAAI,KAAK,aAAa,KAAK,gBACzB,OAAM,IAAI,aAAa;IACrB,SAAS;IACT,cAAc;IACd,SAAS;IACT,YAAY;IACZ,QAAQ,EAAE;IACX,CAAC;GAIJ,MAAM,SAAS,MAAM,SAAS,yBAAyB;IACrD,OAAO,EAAE,eAAe,MAAM,YAAY,WAAW;IACrD,MAAM;KACJ,UAAU,KAAK;KACf,OAAO,KAAK;KACZ,aAAa,KAAK;KAClB,UAAU,KAAK;KAChB;IACF,CAAC;GAEF,MAAM,aAAa,KAAK,YAAY,KAAK,SAAS,KAAK;AAGvD,OACE,OAAO,2BACP,OAAO,2BACP,OAAO,eACP;AAEA,yBAAqB;KACnB,OAAO;KACP;KACA,aAAa,aACT;MAAE;MAAY,UAAU,KAAK;MAAU,GACvC,KAAA;KACL,CAAC;AACF;;AAIF,SAAM,SAAS,qBAAqB,EAClC,MAAM,EAAE,UAAU,OAAO,UAAU,EACpC,CAAC;AAGF,OAAI,cAAc,oBAChB,OAAM,KAAK,MAAM,oBAAoB,MAAM;IACzC,UAAU;IACV,UAAU,KAAK;IACf,OAAO,MAAM,YAAY;IAC1B,CAAC;AAGJ,SAAM,OAAO,KAAK,OAAO,MAAM,KAAK,IAAI;;EAE3C,CAAC;CAEF,MAAM,2BAA2B,YAAY;AAC3C,MAAI,CAAC,kBAAkB,OAAQ;AAE/B,kBAAgB,KAAK;AACrB,uBAAqB,KAAK;AAE1B,MAAI;AAEF,SAAM,SAAS,qBAAqB,EAClC,MAAM;IACJ,UAAU,kBAAkB,OAAO;IACnC,WAAW,kBAAkB,OAAO,0BAChC,YACA,KAAA;IACJ,WAAW,kBAAkB,OAAO,0BAChC,YACA,KAAA;IACL,EACF,CAAC;AAGF,OAAI,kBAAkB,eAAe,oBACnC,OAAM,KAAK,MAAM,oBAAoB,MAAM;IACzC,UAAU,kBAAkB,YAAY;IACxC,UAAU,kBAAkB,YAAY;IACxC,OAAO,MAAM,YAAY;IAC1B,CAAC;AAGJ,SAAM,OAAO,KAAK,OAAO,MAAM,KAAK,IAAI;WACjC,OAAO;AACd,wBACE,iBAAiB,QAAQ,MAAM,UAAU,sBAC1C;YACO;AACR,mBAAgB,MAAM;;;CAI1B,MAAM,8BAA8B;AAClC,MAAI,CAAC,kBAAkB,OAAQ,QAAO;AAEtC,MACE,kBAAkB,OAAO,2BACzB,UAAU,WAAW,EAErB,QAAO;AAGT,MACE,kBAAkB,OAAO,2BACzB,UAAU,WAAW,EAErB,QAAO;AAGT,SAAO;;AAIT,KAAI,kBAAkB,UAAU,kBAAkB,kBAAkB,OAClE,QACE,oBAAC,MAAD;EAAM,MAAM;EAAG,SAAS;EAAU,OAAO;YACvC,oBAAC,MAAD;GAAM,WAAU;GAAS,KAAK;GAAM,GAAG;aACrC,oBAAC,MAAD;IAAM,YAAA;IAAW,GAAG;IAAM,IAAI;cAC5B,qBAAC,MAAD;KAAM,WAAU;KAAS,KAAK;eAA9B;MACE,oBAAC,MAAD;OAAM,MAAK;OAAK,IAAI;OAAK,IAAG;iBACzB,GAAG,sBAAsB,IAAI;OACzB,CAAA;MACP,oBAAC,MAAD;OAAM,MAAK;OAAK,GAAE;OAAS,IAAG;iBAC3B,GAAG,4BAA4B,IAC9B;OACG,CAAA;MAEN,qBACC,oBAAC,OAAD;OAAO,SAAQ;OAAQ,OAAM;OAAM,MAAM,oBAAC,iBAAD,EAAmB,CAAA;iBAC1D,oBAAC,MAAD;QAAM,MAAK;kBAAM;QAAyB,CAAA;OACpC,CAAA;MAGT,kBAAkB,OAAO,2BACxB,qBAAC,MAAD;OAAM,WAAU;OAAS,KAAK;iBAA9B,CACE,oBAAC,MAAD;QAAM,MAAK;QAAK,IAAI;kBACjB,GAAG,oBAAoB;QACnB,CAAA,EACP,oBAAC,MAAD;QAAM,SAAQ;kBACZ,oBAAC,UAAD;SACE,QAAQ;SACR,OAAO;SACP,UAAU;SACV,MAAK;SACL,aAAA;SACA,cAAW;SACX,CAAA;QACG,CAAA,CACF;;MAGR,kBAAkB,OAAO,2BACxB,qBAAC,MAAD;OAAM,WAAU;OAAS,KAAK;iBAA9B,CACE,oBAAC,MAAD;QAAM,MAAK;QAAK,IAAI;kBACjB,GAAG,oBAAoB;QACnB,CAAA,EACP,oBAAC,MAAD;QAAM,SAAQ;kBACZ,oBAAC,UAAD;SACE,QAAQ;SACR,OAAO;SACP,UAAU;SACV,MAAK;SACL,aAAA;SACA,cAAW;SACX,CAAA;QACG,CAAA,CACF;;MAGT,oBAAC,cAAD;OACE,OAAO;OACP,SAAS;OACT,SAAS;OACT,UAAU,CAAC,uBAAuB;iBAEjC,GAAG,uBAAuB;OACd,CAAA;MAEf,oBAAC,cAAD;OACE,SAAQ;OACR,eACE,qBAAqB;QAAE,OAAO;QAAQ,QAAQ,KAAA;QAAW,CAAC;iBAG3D,GAAG,qBAAqB,IAAI;OAChB,CAAA;MACV;;IACF,CAAA;GACF,CAAA;EACF,CAAA;CAKX,MAAM,kBAAkB,MAAM,YAAY,sBAAsB,QAC7D,WAAW,OAAO,SAAS,cAC7B;CAED,MAAM,gBAAgB,uBAAuB,gBAAgB,SAAS;CAEtE,MAAM,aAAa,MAAM,YAAY,YACjC,UAAU,mBAAmB,MAAM,YAAY,UAAU,KACzD;CAEJ,MAAM,cACJ,qBAAC,MAAD;EAAM,WAAU;EAAS,KAAK;YAA9B,EAEI,SAAS,WAAW,SAAS,eAAe,SAAS,gBACrD,qBAAC,MAAD;GAAM,WAAU;GAAS,KAAK;GAAM,OAAM;GAAS,IAAG;aAAtD;IACG,SAAS,WACR,oBAAC,OAAD;KACE,KAAK,SAAS;KACd,KAAK,SAAS,eAAe,MAAM,YAAY;KAC/C,GAAG;KACH,GAAE;KACF,KAAI;KACJ,CAAA;IAEH,SAAS,eACR,oBAAC,OAAD;KAAO,OAAO;KAAG,IAAG;eACjB,SAAS;KACJ,CAAA;IAET,SAAS,eACR,oBAAC,MAAD;KAAM,MAAK;KAAK,GAAE;KAAS,IAAG;eAC3B,SAAS;KACL,CAAA;IAEJ;MAGR,CAAC,wBACA,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,OAAD;GAAO,SAAQ;GAAQ,OAAM;GAAS,MAAM,oBAAC,iBAAD,EAAmB,CAAA;aAC7D,oBAAC,MAAD;IAAM,MAAK;cAAM,GAAG,mBAAmB;IAAQ,CAAA;GACzC,CAAA,EACR,oBAAC,cAAD;GACE,MAAM,GAAG,MAAM,aAAa,gBAAgB;aAE3C,GAAG,uBAAuB;GACd,CAAA,CACd,EAAA,CAAA,GAEH,qBAAA,UAAA,EAAA,UAAA;GAEG,uBACC,oBAAC,QAAD;IAAM,GAAI,KAAK;cACb,qBAAC,MAAD;KAAM,WAAU;KAAS,MAAM;KAAG,KAAK;eAAvC;MACG,SAAS,aAAa,UAAU,KAAK,MAAM,YAC1C,oBAAC,SAAD;OACE,OAAO,GAAG,mBAAmB;OAC7B,OAAO,KAAK,MAAM;OAClB,MAAM,oBAAC,UAAD,EAAY,CAAA;OAClB,MAAM,EACJ,cAAc,YACf;OACD,CAAA;MAEH,SAAS,UAAU,UAAU,KAAK,MAAM,SACvC,oBAAC,SAAD;OACE,OAAO,GAAG,gBAAgB;OAC1B,OAAO,KAAK,MAAM;OAClB,MAAM,oBAAC,UAAD,EAAY,CAAA;OAClB,MAAM,EACJ,cAAc,SACf;OACD,CAAA;MAEH,SAAS,gBAAgB,UAAU,KAAK,MAAM,eAC7C,oBAAC,SAAD;OACE,OAAO,GAAG,gBAAgB;OAC1B,OAAO,KAAK,MAAM;OAClB,MAAM,oBAAC,WAAD,EAAa,CAAA;OACnB,MAAM,EACJ,cAAc,OACf;OACD,CAAA;MAEJ,oBAAC,SAAD;OACE,OAAO,GAAG,mBAAmB;OAC7B,OAAO,KAAK,MAAM;OAClB,MAAM,oBAAC,UAAD,EAAY,CAAA;OAClB,UAAU,EACR,cAAc,gBACf;OACD,CAAA;MACF,oBAAC,SAAD;OACE,OAAO,GAAG,0BAA0B;OACpC,OAAO,KAAK,MAAM;OAClB,MAAM,oBAAC,UAAD,EAAY,CAAA;OAClB,UAAU,EACR,cAAc,gBACf;OACD,CAAA;MACF,oBAAC,cAAD;OAAoB;OAAM,OAAO;OAAQ,SAAS;iBAC/C,GAAG,wBAAwB;OACf,CAAA;MACV;;IACF,CAAA;GAIR,iBACC,qBAAC,MAAD;IAAM,OAAM;IAAS,SAAQ;IAAS,KAAK;cAA3C;KACE,oBAAC,MAAD;MAAM,MAAM;MAAG,GAAG;MAAO,IAAI;MAA0B,CAAA;KACvD,oBAAC,MAAD;MAAM,MAAK;MAAK,GAAE;gBACf,GAAG,aAAa;MACZ,CAAA;KACP,oBAAC,MAAD;MAAM,MAAM;MAAG,GAAG;MAAO,IAAI;MAA0B,CAAA;KAClD;;GAIR,gBAAgB,SAAS,KACxB,oBAAC,MAAD;IAAM,WAAU;IAAS,KAAK;cAC3B,gBAAgB,KAAK,WACpB,oBAAC,cAAD;KACE,SAAS;KAET,aAAa,YAAY,OAAO,KAAK,aAAa,CAAC;KACnD,eACE,KAAK,MAAM,OAAO,MAAM;MACtB;MACA,OAAO,MAAM,YAAY;MAC1B,CAAC;eAGH,GAAG,wBAAwB,EAC1B,MAAM,CAAC,WAAW,OAAO,KAAK,CAAC,EAChC,CAAC;KACW,EAZR,OAAO,KAYC,CACf;IACG,CAAA;GAIT,qBAAC,MAAD;IAAM,MAAK;IAAK,IAAG;cAAnB;KACG,GAAG,sBAAsB;KAAE;KAC5B,oBAAC,cAAD;MACE,MAAM,GAAG,MAAM,aAAa,gBAAgB;MAC5C,aAAa,EAAE,SAAS,MAAM;gBAE7B,GAAG,iBAAiB;MACR,CAAA;KACV;;GACN,EAAA,CAAA,CAEA;;AAGT,KAAI,MAAM,YAAY,QACpB,QACE,oBAAC,MAAD;EAAM,MAAM;EAAG,SAAS;EAAU,OAAO;YACvC,oBAAC,MAAD;GACE,YAAA;GACA,GAAG;GACH,GAAG;GACH,IAAI;GACJ,OAAO,EAAE,UAAU,UAAU;aAE7B,qBAAC,MAAD;IAAM,KAAK;cAAX,CACG,MAAM,QACL,oBAAC,MAAD;KACE,MAAM;KACN,OAAO;MACL,iBAAiB,OAAO,MAAM,MAAM;MACpC,gBAAgB;MAChB,oBAAoB;MACrB;KACD,CAAA,GAEF,oBAAC,MAAD;KACE,MAAM;KACN,SAAQ;KACR,OAAM;KACN,IAAG;KACH,OAAO,EACL,aAAa,iDACd;eAED,oBAAC,MAAD;MACE,SAAQ;MACR,OAAM;MACN,GAAG;MACH,GAAG;MACH,OAAO;OACL,QAAQ;OACR,cAAc;OACf;gBAED,oBAAC,WAAD;OAAW,MAAM;OAAI,OAAO,EAAE,SAAS,IAAK;OAAI,CAAA;MAC3C,CAAA;KACF,CAAA,EAET,qBAAC,MAAD;KACE,MAAM;KACN,WAAU;KACV,KAAK;KACL,GAAG;KACH,SAAS;eALX,CAOG,aACD,oBAAC,cAAD;MAAc,SAAS;MAAU,MAAM;gBACpC,GAAG,iBAAiB;MACR,CAAA,CACV;OACF;;GACF,CAAA;EACF,CAAA;AAKX,QACE,oBAAC,MAAD;EAAM,MAAM;EAAG,SAAS;EAAU,OAAO;YACvC,qBAAC,MAAD;GAAM,WAAU;GAAS,KAAK;GAAM,GAAG;aAAvC,CACE,oBAAC,MAAD;IAAM,YAAA;IAAW,GAAG;IAAM,IAAI;cAC3B;IACI,CAAA,EACP,oBAAC,cAAD;IAAc,SAAS;IAAU,MAAM;cACpC,GAAG,iBAAiB;IACR,CAAA,CACV;;EACF,CAAA;;AAMX,MAAM,eAAe,SAAiB;AACpC,KAAI,SAAS,SACX,QAAO,oBAAC,YAAD,EAAc,CAAA;AAGvB,KAAI,SAAS,SACX,QAAO,oBAAC,YAAD,EAAc,CAAA"}
|
|
1
|
+
{"version":3,"file":"Register-B2AN71NC.js","names":[],"sources":["../../src/auth/components/Register.tsx"],"sourcesContent":["import { ActionButton, Control, capitalize } from \"@alepha/ui\";\nimport { Alert, Card, Flex, Image, PinInput, Text, Title } from \"@mantine/core\";\nimport {\n IconAlertCircle,\n IconLock,\n IconMail,\n IconPhone,\n IconPhoto,\n IconUser,\n} from \"@tabler/icons-react\";\nimport { TypeBoxError, t } from \"alepha\";\nimport type {\n RealmConfig,\n RegistrationIntentResponse,\n UserController,\n} from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useAuth } from \"alepha/react/auth\";\nimport { useForm } from \"alepha/react/form\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouter } from \"alepha/react/router\";\nimport { useMemo, useState } from \"react\";\nimport type { AuthI18n } from \"../AuthI18n.ts\";\nimport IconGithub from \"./icons/IconGithub.tsx\";\nimport IconGoogle from \"./icons/IconGoogle.tsx\";\n\nexport interface RegisterProps {\n realmConfig: RealmConfig;\n loginPath?: string;\n variant?: \"card\" | \"split\";\n image?: string;\n}\n\ntype RegistrationPhase = \"form\" | \"verification\";\n\ninterface RegistrationState {\n phase: RegistrationPhase;\n intent?: RegistrationIntentResponse;\n credentials?: {\n identifier: string;\n password: string;\n };\n}\n\nconst Register = (props: RegisterProps) => {\n const auth = useAuth();\n const userCtrl = useClient<UserController>();\n const router = useRouter();\n const { tr } = useI18n<AuthI18n, \"en\">();\n const redirect = router.query.r || \"/\";\n\n const [registrationState, setRegistrationState] = useState<RegistrationState>(\n {\n phase: \"form\",\n },\n );\n const [emailCode, setEmailCode] = useState(\"\");\n const [phoneCode, setPhoneCode] = useState(\"\");\n const [verificationError, setVerificationError] = useState<string | null>(\n null,\n );\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const credentialsProvider = props.realmConfig.authenticationMethods.find(\n (it) => it.type === \"CREDENTIALS\",\n );\n\n const settings = props.realmConfig.settings || {};\n const isRegistrationAllowed = settings.registrationAllowed !== false;\n\n const registerSchema = useMemo(() => {\n const registerSchema = t.object({\n username: t.optional(\n t.text({\n trim: true,\n pattern: settings.usernameRegExp,\n }),\n ),\n email: t.optional(t.email()),\n phoneNumber: t.optional(t.e164()),\n password: t.string({ minLength: 8 }),\n confirmPassword: t.string({ minLength: 8 }),\n });\n\n const required = registerSchema.required as string[];\n\n if (settings.username === \"required\") required.push(\"username\");\n if (settings.email === \"required\") required.push(\"email\");\n if (settings.phoneNumber === \"required\") required.push(\"phoneNumber\");\n\n return registerSchema;\n }, []);\n\n const form = useForm({\n schema: registerSchema,\n handler: async (data) => {\n if (data.password !== data.confirmPassword) {\n throw new TypeBoxError({\n message: \"Passwords do not match\",\n instancePath: \"/confirmPassword\",\n keyword: \"not\",\n schemaPath: \"\",\n params: {},\n });\n }\n\n // Phase 1: Create registration intent\n const intent = await userCtrl.createRegistrationIntent({\n query: { userRealmName: props.realmConfig.realmName },\n body: {\n username: data.username,\n email: data.email,\n phoneNumber: data.phoneNumber,\n password: data.password,\n },\n });\n\n const identifier = data.username ?? data.email ?? data.phoneNumber;\n\n // Check if verification is needed\n if (\n intent.expectEmailVerification ||\n intent.expectPhoneVerification ||\n intent.expectCaptcha\n ) {\n // Move to verification phase\n setRegistrationState({\n phase: \"verification\",\n intent,\n credentials: identifier\n ? { identifier, password: data.password }\n : undefined,\n });\n return;\n }\n\n // No verification needed - complete registration immediately\n await userCtrl.createUserFromIntent({\n body: { intentId: intent.intentId },\n });\n\n // Auto-login after registration\n if (identifier && credentialsProvider) {\n await auth.login(credentialsProvider.name, {\n username: identifier,\n password: data.password,\n realm: props.realmConfig.realmName,\n });\n }\n\n await router.push(router.query.r || \"/\");\n },\n });\n\n const handleVerificationSubmit = async () => {\n if (!registrationState.intent) return;\n\n setIsSubmitting(true);\n setVerificationError(null);\n\n try {\n // Phase 2: Complete registration with verification codes\n await userCtrl.createUserFromIntent({\n body: {\n intentId: registrationState.intent.intentId,\n emailCode: registrationState.intent.expectEmailVerification\n ? emailCode\n : undefined,\n phoneCode: registrationState.intent.expectPhoneVerification\n ? phoneCode\n : undefined,\n },\n });\n\n // Auto-login after registration\n if (registrationState.credentials && credentialsProvider) {\n await auth.login(credentialsProvider.name, {\n username: registrationState.credentials.identifier,\n password: registrationState.credentials.password,\n realm: props.realmConfig.realmName,\n });\n }\n\n await router.push(router.query.r || \"/\");\n } catch (error) {\n setVerificationError(\n error instanceof Error ? error.message : \"Verification failed\",\n );\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const canSubmitVerification = () => {\n if (!registrationState.intent) return false;\n\n if (\n registrationState.intent.expectEmailVerification &&\n emailCode.length !== 6\n ) {\n return false;\n }\n\n if (\n registrationState.intent.expectPhoneVerification &&\n phoneCode.length !== 6\n ) {\n return false;\n }\n\n return true;\n };\n\n // Verification phase UI (always card layout)\n if (registrationState.phase === \"verification\" && registrationState.intent) {\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Flex direction=\"column\" gap={\"sm\"} w={360}>\n <Card withBorder p={\"lg\"} bg={\"var(--alepha-elevated)\"}>\n <Flex direction=\"column\" gap={\"md\"}>\n <Text size=\"lg\" fw={500} ta=\"center\">\n {tr(\"registerVerifyTitle\") ?? \"Verify your account\"}\n </Text>\n <Text size=\"sm\" c=\"dimmed\" ta=\"center\">\n {tr(\"registerVerifyDescription\") ??\n \"Please enter the verification code(s) sent to you.\"}\n </Text>\n\n {verificationError && (\n <Alert variant=\"light\" color=\"red\" icon={<IconAlertCircle />}>\n <Text size=\"sm\">{verificationError}</Text>\n </Alert>\n )}\n\n {registrationState.intent.expectEmailVerification && (\n <Flex direction=\"column\" gap={\"xs\"}>\n <Text size=\"sm\" fw={500}>\n {tr(\"registerEmailCode\")}\n </Text>\n <Flex justify=\"center\">\n <PinInput\n length={6}\n value={emailCode}\n onChange={setEmailCode}\n type=\"number\"\n oneTimeCode\n aria-label=\"Email verification code\"\n />\n </Flex>\n </Flex>\n )}\n\n {registrationState.intent.expectPhoneVerification && (\n <Flex direction=\"column\" gap={\"xs\"}>\n <Text size=\"sm\" fw={500}>\n {tr(\"registerPhoneCode\")}\n </Text>\n <Flex justify=\"center\">\n <PinInput\n length={6}\n value={phoneCode}\n onChange={setPhoneCode}\n type=\"number\"\n oneTimeCode\n aria-label=\"Phone verification code\"\n />\n </Flex>\n </Flex>\n )}\n\n <ActionButton\n color={\"blue\"}\n onClick={handleVerificationSubmit}\n loading={isSubmitting}\n disabled={!canSubmitVerification()}\n >\n {tr(\"registerVerifySubmit\")}\n </ActionButton>\n\n <ActionButton\n variant=\"subtle\"\n onClick={() =>\n setRegistrationState({ phase: \"form\", intent: undefined })\n }\n >\n {tr(\"registerVerifyBack\") ?? \"Back to registration\"}\n </ActionButton>\n </Flex>\n </Card>\n </Flex>\n </Flex>\n );\n }\n\n // External login methods\n const externalMethods = props.realmConfig.authenticationMethods.filter(\n (method) => method.type !== \"CREDENTIALS\",\n );\n\n const showOrDivider = credentialsProvider && externalMethods.length > 0;\n\n const realmQuery = props.realmConfig.realmName\n ? `?realm=${encodeURIComponent(props.realmConfig.realmName)}`\n : \"\";\n\n const formContent = (\n <Flex direction=\"column\" gap={\"md\"}>\n {/* Realm branding */}\n {(settings.logoUrl || settings.displayName || settings.description) && (\n <Flex direction=\"column\" gap={\"xs\"} align=\"center\" mb=\"xs\">\n {settings.logoUrl && (\n <Image\n src={settings.logoUrl}\n alt={settings.displayName || props.realmConfig.realmName}\n h={48}\n w=\"auto\"\n fit=\"contain\"\n />\n )}\n {settings.displayName && (\n <Title order={4} ta=\"center\">\n {settings.displayName}\n </Title>\n )}\n {settings.description && (\n <Text size=\"sm\" c=\"dimmed\" ta=\"center\">\n {settings.description}\n </Text>\n )}\n </Flex>\n )}\n\n {!isRegistrationAllowed ? (\n <>\n <Alert variant=\"light\" color=\"yellow\" icon={<IconAlertCircle />}>\n <Text size=\"sm\">{tr(\"registerDisabled\")}</Text>\n </Alert>\n <ActionButton\n href={`${props.loginPath ?? \"/auth/login\"}${realmQuery}`}\n >\n {tr(\"registerBackToSignIn\")}\n </ActionButton>\n </>\n ) : (\n <>\n {/* Credentials registration form */}\n {credentialsProvider && (\n <form {...form.props}>\n <Flex direction=\"column\" flex={1} gap={\"md\"}>\n {settings.username !== \"none\" && form.input.username && (\n <Control\n label={tr(\"registerUsername\")}\n input={form.input.username}\n icon={<IconUser />}\n text={{\n autoComplete: \"username\",\n }}\n />\n )}\n {settings.email !== \"none\" && form.input.email && (\n <Control\n label={tr(\"registerEmail\")}\n input={form.input.email}\n icon={<IconMail />}\n text={{\n autoComplete: \"email\",\n }}\n />\n )}\n {settings.phoneNumber !== \"none\" && form.input.phoneNumber && (\n <Control\n label={tr(\"registerPhone\")}\n input={form.input.phoneNumber}\n icon={<IconPhone />}\n text={{\n autoComplete: \"tel\",\n }}\n />\n )}\n <Control\n label={tr(\"registerPassword\")}\n input={form.input.password}\n icon={<IconLock />}\n password={{\n autoComplete: \"new-password\",\n }}\n />\n <Control\n label={tr(\"registerConfirmPassword\")}\n input={form.input.confirmPassword}\n icon={<IconLock />}\n password={{\n autoComplete: \"new-password\",\n }}\n />\n <ActionButton form={form} color={\"blue\"} variant={\"filled\"}>\n {tr(\"registerCreateAccount\")}\n </ActionButton>\n </Flex>\n </form>\n )}\n\n {/* OR divider - only when both credentials AND external methods exist */}\n {showOrDivider && (\n <Flex align=\"center\" justify=\"center\" gap={\"md\"}>\n <Flex flex={1} h={\"1px\"} bg={\"var(--alepha-border)\"} />\n <Text size=\"xs\" c=\"dimmed\">\n {tr(\"registerOr\")}\n </Text>\n <Flex flex={1} h={\"1px\"} bg={\"var(--alepha-border)\"} />\n </Flex>\n )}\n\n {/* External login methods */}\n {externalMethods.length > 0 && (\n <Flex direction=\"column\" gap={\"sm\"}>\n {externalMethods.map((method) => (\n <ActionButton\n variant={\"default\"}\n key={method.type}\n leftSection={leftSection(method.name.toLowerCase())}\n onClick={() =>\n auth.login(method.name, {\n redirect,\n realm: props.realmConfig.realmName,\n })\n }\n >\n {tr(\"registerContinueWith\", {\n args: [capitalize(method.name)],\n })}\n </ActionButton>\n ))}\n </Flex>\n )}\n\n {/* Sign in link */}\n <Text size=\"sm\" ta=\"center\">\n {tr(\"registerHaveAccount\")}{\" \"}\n <ActionButton\n href={`${props.loginPath ?? \"/auth/login\"}${realmQuery}`}\n anchorProps={{ inherit: true }}\n >\n {tr(\"registerSignIn\")}\n </ActionButton>\n </Text>\n </>\n )}\n </Flex>\n );\n\n if (props.variant === \"split\") {\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Card\n withBorder\n p={0}\n w={720}\n bg={\"var(--alepha-elevated)\"}\n style={{ overflow: \"hidden\" }}\n >\n <Flex mih={480}>\n {props.image ? (\n <Flex\n flex={1}\n style={{\n backgroundImage: `url(${props.image})`,\n backgroundSize: \"cover\",\n backgroundPosition: \"center\",\n }}\n />\n ) : (\n <Flex\n flex={1}\n justify=\"center\"\n align=\"center\"\n bg=\"var(--mantine-color-gray-light)\"\n style={{\n borderRight: \"1px solid var(--mantine-color-default-border)\",\n }}\n >\n <Flex\n justify=\"center\"\n align=\"center\"\n w={120}\n h={80}\n style={{\n border: \"2px dashed var(--mantine-color-default-border)\",\n borderRadius: \"var(--mantine-radius-sm)\",\n }}\n >\n <IconPhoto size={32} style={{ opacity: 0.3 }} />\n </Flex>\n </Flex>\n )}\n <Flex\n flex={1}\n direction=\"column\"\n gap={\"md\"}\n p={\"xl\"}\n justify={\"center\"}\n >\n {formContent}\n <ActionButton variant={\"subtle\"} href={redirect}>\n {tr(\"registerCancel\")}\n </ActionButton>\n </Flex>\n </Flex>\n </Card>\n </Flex>\n );\n }\n\n // Default card variant\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Flex direction=\"column\" gap={\"sm\"} w={360}>\n <Card withBorder p={\"lg\"} bg={\"var(--alepha-elevated)\"}>\n {formContent}\n </Card>\n <ActionButton variant={\"subtle\"} href={redirect}>\n {tr(\"registerCancel\")}\n </ActionButton>\n </Flex>\n </Flex>\n );\n};\n\nexport default Register;\n\nconst leftSection = (name: string) => {\n if (name === \"google\") {\n return <IconGoogle />;\n }\n\n if (name === \"github\") {\n return <IconGithub />;\n }\n};\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-CiIaOW0V.js";
|
|
2
|
-
import {
|
|
2
|
+
import { i as ActionButton, r as Control } from "./core-DuGkjPiU.js";
|
|
3
3
|
import { AlephaError, t } from "alepha";
|
|
4
4
|
import { useForm } from "alepha/react/form";
|
|
5
5
|
import { useI18n } from "alepha/react/i18n";
|
|
@@ -282,4 +282,4 @@ const ResetPassword = (props) => {
|
|
|
282
282
|
//#endregion
|
|
283
283
|
export { ResetPassword_exports as n, ResetPassword as t };
|
|
284
284
|
|
|
285
|
-
//# sourceMappingURL=ResetPassword-
|
|
285
|
+
//# sourceMappingURL=ResetPassword-BLxwzbDj.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResetPassword-Gxc9L_mY.js","names":[],"sources":["../../src/auth/components/ResetPassword.tsx"],"sourcesContent":["import { ActionButton, Control } from \"@alepha/ui\";\nimport { Alert, Card, Flex, Image, PinInput, Text, Title } from \"@mantine/core\";\nimport {\n IconAlertCircle,\n IconCheck,\n IconInfoCircle,\n IconLock,\n IconMail,\n} from \"@tabler/icons-react\";\nimport { AlephaError, t } from \"alepha\";\nimport type {\n PasswordResetIntentResponse,\n RealmConfig,\n UserController,\n} from \"alepha/api/users\";\nimport { resetPasswordRequestSchema } from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useForm } from \"alepha/react/form\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouter } from \"alepha/react/router\";\nimport { useState } from \"react\";\nimport type { AuthI18n } from \"../AuthI18n.ts\";\n\nexport interface ResetPasswordProps {\n realmConfig: RealmConfig;\n loginPath?: string;\n}\n\ntype Step = \"email\" | \"code\" | \"password\" | \"success\";\n\ninterface ResetState {\n step: Step;\n intent?: PasswordResetIntentResponse;\n email?: string;\n code?: string;\n}\n\nconst ResetPassword = (props: ResetPasswordProps) => {\n const router = useRouter();\n const userCtrl = useClient<UserController>();\n const { tr } = useI18n<AuthI18n, \"en\">();\n const [resetState, setResetState] = useState<ResetState>({ step: \"email\" });\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const redirect = router.query.r || \"/\";\n\n const settings = props.realmConfig.settings;\n const isResetPasswordAllowed = settings?.resetPasswordAllowed !== false;\n\n // Phase 1: Request password reset intent\n const emailForm = useForm({\n schema: resetPasswordRequestSchema,\n handler: async (data) => {\n setError(null);\n const intent = await userCtrl.createPasswordResetIntent({\n query: { userRealmName: props.realmConfig.realmName },\n body: { email: data.email },\n });\n\n setResetState({\n step: \"code\",\n intent,\n email: data.email,\n });\n },\n });\n\n // Phase 2: Complete password reset\n const passwordForm = useForm(\n {\n schema: t.object({\n password: t.string({ minLength: 8 }),\n confirmPassword: t.string({ minLength: 8 }),\n }),\n handler: async (data) => {\n if (data.password !== data.confirmPassword) {\n throw new AlephaError(\"Passwords do not match\");\n }\n\n if (!resetState.intent || !resetState.code) {\n throw new AlephaError(\"Invalid reset state\");\n }\n\n await userCtrl.completePasswordReset({\n body: {\n intentId: resetState.intent.intentId,\n code: resetState.code,\n newPassword: data.password,\n },\n });\n\n setResetState({ step: \"success\" });\n },\n },\n [resetState.intent, resetState.code],\n );\n\n const handleCodeComplete = (value: string) => {\n if (value.length === 6) {\n setResetState((prev) => ({\n ...prev,\n step: \"password\",\n code: value,\n }));\n }\n };\n\n const handleResendCode = async () => {\n if (!resetState.email) return;\n\n setIsSubmitting(true);\n setError(null);\n\n try {\n const intent = await userCtrl.createPasswordResetIntent({\n query: { userRealmName: props.realmConfig.realmName },\n body: { email: resetState.email },\n });\n\n setResetState((prev) => ({\n ...prev,\n intent,\n }));\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to resend code\");\n } finally {\n setIsSubmitting(false);\n }\n };\n\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Flex direction=\"column\" gap={\"sm\"} w={360}>\n <Card withBorder p={\"lg\"} bg={\"var(--alepha-elevated)\"}>\n <Flex direction=\"column\" gap={\"md\"}>\n {/* Realm branding */}\n {(settings.logoUrl ||\n settings.displayName ||\n settings.description) && (\n <Flex direction=\"column\" gap={\"xs\"} align=\"center\" mb=\"xs\">\n {settings.logoUrl && (\n <Image\n src={settings.logoUrl}\n alt={settings.displayName || props.realmConfig.realmName}\n h={48}\n w=\"auto\"\n fit=\"contain\"\n />\n )}\n {settings.displayName && (\n <Title order={4} ta=\"center\">\n {settings.displayName}\n </Title>\n )}\n {settings.description && (\n <Text size=\"sm\" c=\"dimmed\" ta=\"center\">\n {settings.description}\n </Text>\n )}\n </Flex>\n )}\n\n {error && (\n <Alert variant=\"light\" color=\"red\" icon={<IconAlertCircle />}>\n <Text size=\"sm\">{error}</Text>\n </Alert>\n )}\n\n {!isResetPasswordAllowed ? (\n <>\n <Alert\n variant=\"light\"\n color=\"yellow\"\n icon={<IconAlertCircle />}\n >\n <Text size=\"sm\">{tr(\"resetPasswordDisabled\")}</Text>\n </Alert>\n <ActionButton\n href={`${props.loginPath ?? \"/auth/login\"}${props.realmConfig.realmName ? `?realm=${encodeURIComponent(props.realmConfig.realmName)}` : \"\"}`}\n >\n {tr(\"resetPasswordBackToSignIn\")}\n </ActionButton>\n </>\n ) : resetState.step === \"email\" ? (\n <form {...emailForm.props}>\n <Flex direction=\"column\" flex={1} gap={\"md\"}>\n <Text size=\"lg\" fw={500} ta=\"center\">\n {tr(\"resetPasswordTitle\")}\n </Text>\n <Text size=\"sm\" c=\"dimmed\">\n {tr(\"resetPasswordEnterEmail\")}\n </Text>\n <Control\n label={tr(\"resetPasswordEmail\")}\n input={emailForm.input.email}\n icon={<IconMail />}\n text={{\n autoComplete: \"email\",\n autoFocus: true,\n disabled: !isResetPasswordAllowed,\n }}\n />\n <ActionButton\n form={emailForm}\n disabled={!isResetPasswordAllowed}\n >\n {tr(\"resetPasswordSendCode\")}\n </ActionButton>\n </Flex>\n </form>\n ) : resetState.step === \"code\" ? (\n <Flex direction=\"column\" gap={\"md\"}>\n <Text size=\"lg\" fw={500} ta=\"center\">\n {tr(\"resetPasswordTitle\")}\n </Text>\n <Alert variant=\"light\" color=\"blue\" icon={<IconInfoCircle />}>\n <Text size=\"sm\">{tr(\"resetPasswordCodeSent\")}</Text>\n </Alert>\n <Text size=\"sm\" c=\"dimmed\" ta=\"center\">\n {tr(\"resetPasswordEnterCode\")}\n </Text>\n <Flex justify=\"center\">\n <PinInput\n length={6}\n type=\"number\"\n autoFocus\n oneTimeCode\n onComplete={handleCodeComplete}\n aria-label=\"Password reset verification code\"\n />\n </Flex>\n <ActionButton\n variant=\"subtle\"\n onClick={handleResendCode}\n loading={isSubmitting}\n >\n {tr(\"resetPasswordResendCode\")}\n </ActionButton>\n </Flex>\n ) : resetState.step === \"password\" ? (\n <form {...passwordForm.props}>\n <Flex direction=\"column\" flex={1} gap={\"md\"}>\n <Text size=\"lg\" fw={500} ta=\"center\">\n {tr(\"resetPasswordTitle\")}\n </Text>\n <Text size=\"sm\" c=\"dimmed\">\n {tr(\"resetPasswordEnterNewPassword\")}\n </Text>\n <Control\n label={tr(\"resetPasswordNewPassword\")}\n input={passwordForm.input.password}\n icon={<IconLock />}\n password={{\n autoComplete: \"new-password\",\n autoFocus: true,\n }}\n />\n <Control\n label={tr(\"resetPasswordConfirmPassword\")}\n input={passwordForm.input.confirmPassword}\n icon={<IconLock />}\n password={{\n autoComplete: \"new-password\",\n }}\n />\n <ActionButton form={passwordForm}>\n {tr(\"resetPasswordSetNewPassword\")}\n </ActionButton>\n </Flex>\n </form>\n ) : (\n <>\n <Alert variant=\"light\" color=\"green\" icon={<IconCheck />}>\n <Text size=\"sm\">{tr(\"resetPasswordSuccess\")}</Text>\n </Alert>\n <ActionButton\n href={`${props.loginPath ?? \"/auth/login\"}${props.realmConfig.realmName ? `?realm=${encodeURIComponent(props.realmConfig.realmName)}` : \"\"}`}\n >\n {tr(\"resetPasswordBackToSignIn\")}\n </ActionButton>\n </>\n )}\n </Flex>\n </Card>\n <ActionButton variant={\"subtle\"} href={redirect}>\n {tr(\"resetPasswordCancel\")}\n </ActionButton>\n </Flex>\n </Flex>\n );\n};\n\nexport default ResetPassword;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ResetPassword-BLxwzbDj.js","names":[],"sources":["../../src/auth/components/ResetPassword.tsx"],"sourcesContent":["import { ActionButton, Control } from \"@alepha/ui\";\nimport { Alert, Card, Flex, Image, PinInput, Text, Title } from \"@mantine/core\";\nimport {\n IconAlertCircle,\n IconCheck,\n IconInfoCircle,\n IconLock,\n IconMail,\n} from \"@tabler/icons-react\";\nimport { AlephaError, t } from \"alepha\";\nimport type {\n PasswordResetIntentResponse,\n RealmConfig,\n UserController,\n} from \"alepha/api/users\";\nimport { resetPasswordRequestSchema } from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useForm } from \"alepha/react/form\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouter } from \"alepha/react/router\";\nimport { useState } from \"react\";\nimport type { AuthI18n } from \"../AuthI18n.ts\";\n\nexport interface ResetPasswordProps {\n realmConfig: RealmConfig;\n loginPath?: string;\n}\n\ntype Step = \"email\" | \"code\" | \"password\" | \"success\";\n\ninterface ResetState {\n step: Step;\n intent?: PasswordResetIntentResponse;\n email?: string;\n code?: string;\n}\n\nconst ResetPassword = (props: ResetPasswordProps) => {\n const router = useRouter();\n const userCtrl = useClient<UserController>();\n const { tr } = useI18n<AuthI18n, \"en\">();\n const [resetState, setResetState] = useState<ResetState>({ step: \"email\" });\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const redirect = router.query.r || \"/\";\n\n const settings = props.realmConfig.settings;\n const isResetPasswordAllowed = settings?.resetPasswordAllowed !== false;\n\n // Phase 1: Request password reset intent\n const emailForm = useForm({\n schema: resetPasswordRequestSchema,\n handler: async (data) => {\n setError(null);\n const intent = await userCtrl.createPasswordResetIntent({\n query: { userRealmName: props.realmConfig.realmName },\n body: { email: data.email },\n });\n\n setResetState({\n step: \"code\",\n intent,\n email: data.email,\n });\n },\n });\n\n // Phase 2: Complete password reset\n const passwordForm = useForm(\n {\n schema: t.object({\n password: t.string({ minLength: 8 }),\n confirmPassword: t.string({ minLength: 8 }),\n }),\n handler: async (data) => {\n if (data.password !== data.confirmPassword) {\n throw new AlephaError(\"Passwords do not match\");\n }\n\n if (!resetState.intent || !resetState.code) {\n throw new AlephaError(\"Invalid reset state\");\n }\n\n await userCtrl.completePasswordReset({\n body: {\n intentId: resetState.intent.intentId,\n code: resetState.code,\n newPassword: data.password,\n },\n });\n\n setResetState({ step: \"success\" });\n },\n },\n [resetState.intent, resetState.code],\n );\n\n const handleCodeComplete = (value: string) => {\n if (value.length === 6) {\n setResetState((prev) => ({\n ...prev,\n step: \"password\",\n code: value,\n }));\n }\n };\n\n const handleResendCode = async () => {\n if (!resetState.email) return;\n\n setIsSubmitting(true);\n setError(null);\n\n try {\n const intent = await userCtrl.createPasswordResetIntent({\n query: { userRealmName: props.realmConfig.realmName },\n body: { email: resetState.email },\n });\n\n setResetState((prev) => ({\n ...prev,\n intent,\n }));\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Failed to resend code\");\n } finally {\n setIsSubmitting(false);\n }\n };\n\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Flex direction=\"column\" gap={\"sm\"} w={360}>\n <Card withBorder p={\"lg\"} bg={\"var(--alepha-elevated)\"}>\n <Flex direction=\"column\" gap={\"md\"}>\n {/* Realm branding */}\n {(settings.logoUrl ||\n settings.displayName ||\n settings.description) && (\n <Flex direction=\"column\" gap={\"xs\"} align=\"center\" mb=\"xs\">\n {settings.logoUrl && (\n <Image\n src={settings.logoUrl}\n alt={settings.displayName || props.realmConfig.realmName}\n h={48}\n w=\"auto\"\n fit=\"contain\"\n />\n )}\n {settings.displayName && (\n <Title order={4} ta=\"center\">\n {settings.displayName}\n </Title>\n )}\n {settings.description && (\n <Text size=\"sm\" c=\"dimmed\" ta=\"center\">\n {settings.description}\n </Text>\n )}\n </Flex>\n )}\n\n {error && (\n <Alert variant=\"light\" color=\"red\" icon={<IconAlertCircle />}>\n <Text size=\"sm\">{error}</Text>\n </Alert>\n )}\n\n {!isResetPasswordAllowed ? (\n <>\n <Alert\n variant=\"light\"\n color=\"yellow\"\n icon={<IconAlertCircle />}\n >\n <Text size=\"sm\">{tr(\"resetPasswordDisabled\")}</Text>\n </Alert>\n <ActionButton\n href={`${props.loginPath ?? \"/auth/login\"}${props.realmConfig.realmName ? `?realm=${encodeURIComponent(props.realmConfig.realmName)}` : \"\"}`}\n >\n {tr(\"resetPasswordBackToSignIn\")}\n </ActionButton>\n </>\n ) : resetState.step === \"email\" ? (\n <form {...emailForm.props}>\n <Flex direction=\"column\" flex={1} gap={\"md\"}>\n <Text size=\"lg\" fw={500} ta=\"center\">\n {tr(\"resetPasswordTitle\")}\n </Text>\n <Text size=\"sm\" c=\"dimmed\">\n {tr(\"resetPasswordEnterEmail\")}\n </Text>\n <Control\n label={tr(\"resetPasswordEmail\")}\n input={emailForm.input.email}\n icon={<IconMail />}\n text={{\n autoComplete: \"email\",\n autoFocus: true,\n disabled: !isResetPasswordAllowed,\n }}\n />\n <ActionButton\n form={emailForm}\n disabled={!isResetPasswordAllowed}\n >\n {tr(\"resetPasswordSendCode\")}\n </ActionButton>\n </Flex>\n </form>\n ) : resetState.step === \"code\" ? (\n <Flex direction=\"column\" gap={\"md\"}>\n <Text size=\"lg\" fw={500} ta=\"center\">\n {tr(\"resetPasswordTitle\")}\n </Text>\n <Alert variant=\"light\" color=\"blue\" icon={<IconInfoCircle />}>\n <Text size=\"sm\">{tr(\"resetPasswordCodeSent\")}</Text>\n </Alert>\n <Text size=\"sm\" c=\"dimmed\" ta=\"center\">\n {tr(\"resetPasswordEnterCode\")}\n </Text>\n <Flex justify=\"center\">\n <PinInput\n length={6}\n type=\"number\"\n autoFocus\n oneTimeCode\n onComplete={handleCodeComplete}\n aria-label=\"Password reset verification code\"\n />\n </Flex>\n <ActionButton\n variant=\"subtle\"\n onClick={handleResendCode}\n loading={isSubmitting}\n >\n {tr(\"resetPasswordResendCode\")}\n </ActionButton>\n </Flex>\n ) : resetState.step === \"password\" ? (\n <form {...passwordForm.props}>\n <Flex direction=\"column\" flex={1} gap={\"md\"}>\n <Text size=\"lg\" fw={500} ta=\"center\">\n {tr(\"resetPasswordTitle\")}\n </Text>\n <Text size=\"sm\" c=\"dimmed\">\n {tr(\"resetPasswordEnterNewPassword\")}\n </Text>\n <Control\n label={tr(\"resetPasswordNewPassword\")}\n input={passwordForm.input.password}\n icon={<IconLock />}\n password={{\n autoComplete: \"new-password\",\n autoFocus: true,\n }}\n />\n <Control\n label={tr(\"resetPasswordConfirmPassword\")}\n input={passwordForm.input.confirmPassword}\n icon={<IconLock />}\n password={{\n autoComplete: \"new-password\",\n }}\n />\n <ActionButton form={passwordForm}>\n {tr(\"resetPasswordSetNewPassword\")}\n </ActionButton>\n </Flex>\n </form>\n ) : (\n <>\n <Alert variant=\"light\" color=\"green\" icon={<IconCheck />}>\n <Text size=\"sm\">{tr(\"resetPasswordSuccess\")}</Text>\n </Alert>\n <ActionButton\n href={`${props.loginPath ?? \"/auth/login\"}${props.realmConfig.realmName ? `?realm=${encodeURIComponent(props.realmConfig.realmName)}` : \"\"}`}\n >\n {tr(\"resetPasswordBackToSignIn\")}\n </ActionButton>\n </>\n )}\n </Flex>\n </Card>\n <ActionButton variant={\"subtle\"} href={redirect}>\n {tr(\"resetPasswordCancel\")}\n </ActionButton>\n </Flex>\n </Flex>\n );\n};\n\nexport default ResetPassword;\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-CiIaOW0V.js";
|
|
2
|
-
import { i as ActionButton } from "./core-
|
|
2
|
+
import { i as ActionButton } from "./core-DuGkjPiU.js";
|
|
3
3
|
import { useI18n } from "alepha/react/i18n";
|
|
4
4
|
import { Alert, Card, Flex, Loader, Text } from "@mantine/core";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -146,4 +146,4 @@ const VerifyEmail = (props) => {
|
|
|
146
146
|
//#endregion
|
|
147
147
|
export { VerifyEmail_exports as n, VerifyEmail as t };
|
|
148
148
|
|
|
149
|
-
//# sourceMappingURL=VerifyEmail-
|
|
149
|
+
//# sourceMappingURL=VerifyEmail-CSDOk3Zm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VerifyEmail-
|
|
1
|
+
{"version":3,"file":"VerifyEmail-CSDOk3Zm.js","names":[],"sources":["../../src/auth/components/VerifyEmail.tsx"],"sourcesContent":["import { ActionButton } from \"@alepha/ui\";\nimport { Alert, Card, Flex, Loader, Text } from \"@mantine/core\";\nimport { IconAlertCircle, IconCheck, IconMailCheck } from \"@tabler/icons-react\";\nimport type { UserController } from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouterState } from \"alepha/react/router\";\nimport { useEffect, useState } from \"react\";\nimport type { AuthI18n } from \"../AuthI18n.ts\";\n\nexport type VerifyEmailStep = \"verifying\" | \"success\" | \"error\";\n\nexport interface VerifyEmailProps {\n loginPath?: string;\n step?: VerifyEmailStep;\n}\n\nconst VerifyEmailStateful = (props: VerifyEmailProps) => {\n const state = useRouterState();\n const userCtrl = useClient<UserController>();\n const { tr } = useI18n<AuthI18n, \"en\">();\n\n const [step, setStep] = useState<VerifyEmailStep>(\"verifying\");\n const [error, setError] = useState<string | null>(null);\n\n const email = state.query.email as string | undefined;\n const token = state.query.token as string | undefined;\n\n useEffect(() => {\n const verify = async () => {\n if (!email || !token) {\n setError(tr(\"verifyEmailMissingParams\"));\n setStep(\"error\");\n return;\n }\n\n try {\n await userCtrl.verifyEmail({\n body: { email, token },\n });\n setStep(\"success\");\n } catch (err) {\n setError(err instanceof Error ? err.message : tr(\"verifyEmailFailed\"));\n setStep(\"error\");\n }\n };\n\n verify();\n }, [email, token]);\n\n return (\n <VerifyEmailView step={step} error={error} loginPath={props.loginPath} />\n );\n};\n\ninterface VerifyEmailViewProps {\n step: VerifyEmailStep;\n error?: string | null;\n loginPath?: string;\n}\n\nconst VerifyEmailView = (props: VerifyEmailViewProps) => {\n const { tr } = useI18n<AuthI18n, \"en\">();\n const { step } = props;\n\n return (\n <Flex flex={1} justify=\"center\" align=\"center\">\n <Flex direction=\"column\" gap=\"sm\" w={400}>\n <Card withBorder p=\"lg\" bg=\"var(--alepha-elevated)\">\n <Flex direction=\"column\" gap=\"md\" align=\"center\">\n {step === \"verifying\" && (\n <>\n <Loader size=\"lg\" />\n <Text size=\"lg\" fw={500} ta=\"center\">\n {tr(\"verifyEmailVerifying\")}\n </Text>\n <Text size=\"sm\" c=\"dimmed\" ta=\"center\">\n {tr(\"verifyEmailPleaseWait\")}\n </Text>\n </>\n )}\n\n {step === \"success\" && (\n <>\n <IconMailCheck size={48} color=\"var(--mantine-color-green-6)\" />\n <Text size=\"lg\" fw={500} ta=\"center\">\n {tr(\"verifyEmailTitle\")}\n </Text>\n <Alert variant=\"light\" color=\"green\" icon={<IconCheck />}>\n <Text size=\"sm\">{tr(\"verifyEmailSuccess\")}</Text>\n </Alert>\n <ActionButton href={props.loginPath ?? \"/auth/login\"} fullWidth>\n {tr(\"verifyEmailSignIn\")}\n </ActionButton>\n </>\n )}\n\n {step === \"error\" && (\n <>\n <IconAlertCircle size={48} color=\"var(--mantine-color-red-6)\" />\n <Text size=\"lg\" fw={500} ta=\"center\">\n {tr(\"verifyEmailTitle\")}\n </Text>\n <Alert variant=\"light\" color=\"red\" icon={<IconAlertCircle />}>\n <Text size=\"sm\">\n {props.error || tr(\"verifyEmailFailed\")}\n </Text>\n </Alert>\n <ActionButton href={props.loginPath ?? \"/auth/login\"} fullWidth>\n {tr(\"verifyEmailBackToSignIn\")}\n </ActionButton>\n </>\n )}\n </Flex>\n </Card>\n </Flex>\n </Flex>\n );\n};\n\nconst VerifyEmail = (props: VerifyEmailProps) => {\n if (props.step) {\n return <VerifyEmailView step={props.step} loginPath={props.loginPath} />;\n }\n return <VerifyEmailStateful {...props} />;\n};\n\nexport default VerifyEmail;\n"],"mappings":"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"}
|
|
@@ -1889,6 +1889,7 @@ const Text$1 = forwardRef((props, ref) => {
|
|
|
1889
1889
|
});
|
|
1890
1890
|
});
|
|
1891
1891
|
Text$1.displayName = "Text";
|
|
1892
|
+
ui.sizes.icon.xs, ui.sizes.icon.sm, ui.sizes.icon.md;
|
|
1892
1893
|
//#endregion
|
|
1893
1894
|
//#region ../../src/core/form/utils/parseInput.ts
|
|
1894
1895
|
const parseInput = (props, form) => {
|
|
@@ -3285,4 +3286,4 @@ const AlephaUI = $module({
|
|
|
3285
3286
|
//#endregion
|
|
3286
3287
|
export { ui as a, ActionButton as i, capitalize as n, AlephaMantineProvider as o, Control as r, AlephaUI as t };
|
|
3287
3288
|
|
|
3288
|
-
//# sourceMappingURL=core-
|
|
3289
|
+
//# sourceMappingURL=core-DuGkjPiU.js.map
|