From c54ab2874d9d0ca05fcfb6bb270f8c009ef1a48e Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:18:16 -0700 Subject: [PATCH] Replace browser alert() with DesignDialog in user create/edit flow (#1680) ## Summary In `UserDialog`, duplicate-email errors (`UserWithEmailAlreadyExists`, `ContactChannelAlreadyUsedForAuthBySomeoneElse`) were shown via `window.alert()`. Replaced with a controlled `DesignDialog` using `WarningCircleIcon`, so the error appears as a styled modal instead of a native browser popup. Link to Devin session: https://app.devin.ai/sessions/99d73091c47a4a58b33d8724df5a7ce8 --- ## Summary by cubic Replaced `window.alert()` in the user create/edit flow with a controlled `DesignDialog` for duplicate-email errors (`UserWithEmailAlreadyExists`, `ContactChannelAlreadyUsedForAuthBySomeoneElse`). Uses `WarningCircleIcon` with an OK action, preserves form data via `prevent-close-and-prevent-reset`, clears dialog state when the form closes, and fixes a max-statements-per-line lint warning. Written for commit 274fcb8e9bb99ab1fa3b2976ca1137f378a6c167. Summary will update on new commits. Review in cubic --------- Co-authored-by: vedanta.gawande Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Armaan Jain <84474476+Developing-Gamer@users.noreply.github.com> --- apps/dashboard/src/components/user-dialog.tsx | 254 ++++++++++-------- 1 file changed, 141 insertions(+), 113 deletions(-) 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 + /> + ; }