Files
Checkmate/client/src/Pages/Account/components/AddTeamMemberDialog.tsx
T

195 lines
5.2 KiB
TypeScript
Raw Normal View History

2026-02-09 18:14:06 +00:00
import { Stack } from "@mui/material";
import MenuItem from "@mui/material/MenuItem";
import { useTheme } from "@mui/material";
import { useTranslation } from "react-i18next";
2026-02-09 18:29:36 +00:00
import { useForm, Controller } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod/dist/zod.js";
2026-02-20 18:13:39 +00:00
import { Dialog, TextField, Select } from "@/Components/inputs";
2026-02-09 18:29:36 +00:00
import { useAddTeamMemberForm } from "@/Hooks/useAddTeamMemberForm";
import type { AddTeamMemberFormData } from "@/Validation/addTeamMember";
import type { UserRole, User } from "@/Types/User";
import { usePost } from "@/Hooks/UseApi";
import { LAYOUT } from "@/Utils/Theme/constants";
2026-02-09 18:14:06 +00:00
interface AddTeamMemberDialogProps {
open: boolean;
onClose: () => void;
2026-02-09 18:29:36 +00:00
onSuccess?: () => void;
2026-02-09 18:14:06 +00:00
}
2026-02-09 18:29:36 +00:00
interface RegisterPayload {
2026-02-09 18:49:31 +00:00
firstName: string;
lastName: string;
email: string;
password: string;
role: string[];
2026-02-09 18:29:36 +00:00
}
export const AddTeamMemberDialog = ({
open,
onClose,
onSuccess,
}: AddTeamMemberDialogProps) => {
2026-02-09 18:14:06 +00:00
const theme = useTheme();
const { t } = useTranslation();
2026-02-09 18:29:36 +00:00
const { schema, defaults } = useAddTeamMemberForm();
const { post, loading } = usePost<RegisterPayload, User>();
const { control, handleSubmit, reset, setError } = useForm<AddTeamMemberFormData>({
resolver: zodResolver(schema),
defaultValues: defaults,
values: defaults,
});
2026-02-09 18:14:06 +00:00
const roleOptions: { value: UserRole; label: string }[] = [
{ value: "admin", label: t("common.auth.roles.admin") },
{ value: "user", label: t("common.auth.roles.user") },
2026-04-15 13:54:05 -07:00
{ value: "demo", label: t("common.auth.roles.demo") },
2026-02-09 18:14:06 +00:00
];
const handleClose = () => {
2026-02-09 18:29:36 +00:00
reset();
2026-02-09 18:14:06 +00:00
onClose();
};
2026-02-09 18:29:36 +00:00
const onSubmit = async (data: AddTeamMemberFormData) => {
if (loading) return;
const { confirm, ...userData } = data;
2026-02-09 18:49:31 +00:00
const payload: RegisterPayload = userData;
2026-02-09 18:29:36 +00:00
2026-02-09 18:49:31 +00:00
const result = await post("/auth/users", payload);
2026-02-09 18:29:36 +00:00
if (result?.success) {
reset();
onClose();
onSuccess?.();
} else if (result?.msg) {
if (result.msg.toLowerCase().includes("email")) {
setError("email", { message: result.msg });
}
}
};
2026-02-09 18:14:06 +00:00
return (
<Dialog
open={open}
title={t("pages.account.team.addMember.title")}
content={t("pages.account.team.addMember.description")}
onCancel={handleClose}
2026-02-09 18:29:36 +00:00
onConfirm={handleSubmit(onSubmit)}
2026-02-09 18:14:06 +00:00
confirmText={t("common.buttons.addMember")}
2026-02-09 18:29:36 +00:00
loading={loading}
2026-02-09 18:14:06 +00:00
maxWidth="sm"
fullWidth
>
<Stack gap={theme.spacing(LAYOUT.XS)}>
<Stack
direction="row"
gap={theme.spacing(LAYOUT.XS)}
>
<Controller
name="firstName"
control={control}
render={({ field, fieldState }) => (
<TextField
{...field}
fieldLabel={t("common.form.name.option.firstName.label")}
placeholder={t("common.form.name.option.firstName.placeholder")}
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
sx={{ flex: 1 }}
/>
)}
/>
<Controller
name="lastName"
control={control}
render={({ field, fieldState }) => (
<TextField
{...field}
fieldLabel={t("common.form.name.option.lastName.label")}
placeholder={t("common.form.name.option.lastName.placeholder")}
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
sx={{ flex: 1 }}
/>
)}
/>
</Stack>
2026-02-09 18:29:36 +00:00
<Controller
name="email"
control={control}
render={({ field, fieldState }) => (
<TextField
{...field}
2026-02-09 20:07:45 +00:00
fieldLabel={t("common.form.email.option.email.label")}
placeholder={t("common.form.email.option.email.placeholder")}
2026-02-09 18:29:36 +00:00
type="email"
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
fullWidth
/>
)}
2026-02-09 18:14:06 +00:00
/>
2026-02-09 18:29:36 +00:00
<Controller
name="role"
control={control}
render={({ field }) => (
<Select
{...field}
value={field.value[0] ?? "user"}
onChange={(e) => field.onChange([e.target.value])}
2026-02-09 20:07:45 +00:00
fieldLabel={t("common.form.role.option.role.label")}
2026-02-09 18:29:36 +00:00
fullWidth
2026-02-09 18:14:06 +00:00
>
2026-02-09 18:29:36 +00:00
{roleOptions.map((option) => (
<MenuItem
key={option.value}
value={option.value}
>
{option.label}
</MenuItem>
))}
</Select>
)}
/>
<Stack
direction="row"
gap={theme.spacing(LAYOUT.XS)}
>
<Controller
name="password"
control={control}
render={({ field, fieldState }) => (
<TextField
{...field}
fieldLabel={t("pages.auth.common.form.option.password.label")}
placeholder={t("pages.auth.common.form.option.password.placeholder")}
type="password"
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
sx={{ flex: 1 }}
/>
)}
/>
<Controller
name="confirm"
control={control}
render={({ field, fieldState }) => (
<TextField
{...field}
fieldLabel={t("pages.auth.common.form.option.confirmPassword.label")}
placeholder={t("pages.auth.common.form.option.password.placeholder")}
type="password"
error={!!fieldState.error}
helperText={fieldState.error?.message ?? ""}
sx={{ flex: 1 }}
/>
)}
/>
</Stack>
2026-02-09 18:14:06 +00:00
</Stack>
</Dialog>
);
};