diff --git a/apps/dashboard/src/components/user-dialog.tsx b/apps/dashboard/src/components/user-dialog.tsx index 8a206bde8..688562744 100644 --- a/apps/dashboard/src/components/user-dialog.tsx +++ b/apps/dashboard/src/components/user-dialog.tsx @@ -3,6 +3,9 @@ import { ServerUser } from "@hexclave/next"; import { KnownErrors } from "@hexclave/shared"; import { countryCodeSchema, emailSchema, jsonStringOrEmptySchema, passwordSchema } from "@hexclave/shared/dist/schema-fields"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Button, Typography } from "@/components/ui"; +import { DesignButton, DesignDialog, DesignDialogClose } from "@/components/design-components"; +import { WarningCircleIcon } from "@phosphor-icons/react"; +import { useState } from "react"; import * as yup from "yup"; import { FormDialog } from "./form-dialog"; import { CountryCodeField } from "./country-code-select"; @@ -24,6 +27,7 @@ export function UserDialog(props: { })) { const adminApp = useAdminApp(); const project = adminApp.useProject(); + const [errorDialog, setErrorDialog] = useState<{ title: string; description: string } | null>(null); let defaultValues; if (props.type === 'edit') { @@ -127,135 +131,159 @@ export function UserDialog(props: { } } catch (error) { if (KnownErrors.UserWithEmailAlreadyExists.isInstance(error)) { - alert("Email already exists. Please choose a different email address."); - return 'prevent-close'; + setErrorDialog({ + title: "Email already exists", + description: "Please choose a different email address.", + }); + return 'prevent-close-and-prevent-reset'; } if (KnownErrors.ContactChannelAlreadyUsedForAuthBySomeoneElse.isInstance(error)) { - alert("Email already used for authentication. This email is already used for sign-in by another account. Please choose a different email address."); - return 'prevent-close'; + setErrorDialog({ + title: "Email already used for authentication", + description: "This email is already used for sign-in by another account. Please choose a different email address.", + }); + return 'prevent-close-and-prevent-reset'; } throw error; } } - return ( - <> - {props.type === 'edit' ? ID: {props.user.id} : null} + return <> + { if (!open) setErrorDialog(null); }} + size="sm" + icon={WarningCircleIcon} + title={errorDialog?.title ?? ""} + description={errorDialog?.description ?? ""} + footer={ + + OK + + } + /> + { + if (!open) setErrorDialog(null); + props.onOpenChange?.(open); + }} + trigger={props.trigger} + title={props.type === 'edit' ? "Edit User" : "Create User"} + formSchema={formSchema} + defaultValues={defaultValues} + okButton={{ label: props.type === 'edit' ? "Save" : "Create" }} + render={(form) => ( + <> + {props.type === 'edit' ? ID: {props.user.id} : null} -
-
- +
+
+ +
+
+ +
-
- -
-
- + - + - {project.config.magicLinkEnabled && } - {project.config.credentialEnabled && } - {form.watch("passwordEnabled") && ( - props.type === 'edit' && !form.watch("password") && !form.watch("updatePassword") ? ( - - ) : ( - - ) - )} - {!form.watch("primaryEmailVerified") && form.watch("otpAuthEnabled") && Primary email must be verified if OTP/magic link sign-in is enabled} + {project.config.magicLinkEnabled && } + {project.config.credentialEnabled && } + {form.watch("passwordEnabled") && ( + props.type === 'edit' && !form.watch("password") && !form.watch("updatePassword") ? ( + + ) : ( + + ) + )} + {!form.watch("primaryEmailVerified") && form.watch("otpAuthEnabled") && Primary email must be verified if OTP/magic link sign-in is enabled} + + {props.type === "create" && ( + + + Risk and Geo + + +
+ + +
+ + Optional admin-only values for imports or custom anti-abuse systems. Leave blank to use the defaults. + +
+
+
+ )} - {props.type === "create" && ( - - Risk and Geo + + Metadata - -
- - -
- - Optional admin-only values for imports or custom anti-abuse systems. Leave blank to use the defaults. - + + Custom JSON clients can read and update; avoid sensitive data.{" "} + Learn more in the docs. + + } + /> + + Custom JSON clients can read but only your backend can change.{" "} + Learn more in the docs. + + } + /> + + Custom JSON reserved for server-side logic and never exposed to clients.{" "} + Learn more in the docs. + + } + />
- )} - - - - Metadata - - - Custom JSON clients can read and update; avoid sensitive data.{" "} - Learn more in the docs. - - } - /> - - Custom JSON clients can read but only your backend can change.{" "} - Learn more in the docs. - - } - /> - - Custom JSON reserved for server-side logic and never exposed to clients.{" "} - Learn more in the docs. - - } - /> - - - - - )} - onSubmit={handleSubmit} - cancelButton - />; + + )} + onSubmit={handleSubmit} + cancelButton + /> + ; }