import { useEffect, useMemo, useRef } from "react"; import { View, Text, ScrollView, Dimensions } from "react-native"; import { Dialog, TextInput, IconButton } from "react-native-paper"; import { Controller, useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { Button } from "@/components/ui/Button"; import { LoadingSpinner } from "@/components/ui/LoadingSpinner"; import { User } from "@/store/models/User.model"; import { RoleEnum } from "@/constants/roleEnum"; import { RiskEnum } from "@/constants/riskEnum"; import { OperationMode } from "@/constants/operationModeEnum"; import { DialogContainer } from "@/components/ui/DialogContainer"; import { useAuthContext } from "@/auth/AuthContext"; import { useGetUsersQuery } from "@/store/api/usersApi"; import { CustomPicker, PickerItem } from "@/components/ui/CustomPicker"; import { adminSchema, AdminFormValues, } from "@/components/features/admins/schemas/admin.schema"; interface AdminModalProps { visible: boolean; mode?: OperationMode; admin?: User | null; isLoading: boolean; onClose: () => void; onSubmit: (payload: Partial) => void; } export const AdminModal = ({ visible, mode = OperationMode.ADD, admin = null, isLoading, onClose, onSubmit, }: AdminModalProps) => { const isEdit = mode === OperationMode.EDIT; const { user: currentUser } = useAuthContext(); const { data: adminsData } = useGetUsersQuery( { roleType: "admin", limit: 1000, }, { skip: !visible }, ); const managerOptions = useMemo( () => (adminsData?.items || []).filter((u) => u.role === RoleEnum.MANAGER), [adminsData], ); const adminRef = useRef(admin); adminRef.current = admin; const currentUserRef = useRef(currentUser); currentUserRef.current = currentUser; const defaultValues: AdminFormValues = { id: admin?.id, email: admin?.email ?? "", firstName: admin?.firstName ?? "", lastName: admin?.lastName ?? "", title: admin?.title ?? "", role: admin?.role ?? RoleEnum.ADMIN, riskStatus: admin?.riskStatus ?? RiskEnum.LOW_RISK, managerId: admin?.managerId ?? (currentUser?.role === RoleEnum.MANAGER ? currentUser.id : undefined), }; const { control, handleSubmit, reset, watch, formState: { errors, isDirty, isValid }, } = useForm({ resolver: zodResolver(adminSchema), defaultValues, mode: "onChange", shouldUnregister: false, }); useEffect(() => { if (!visible) return; const nextDefaults: AdminFormValues = { id: adminRef.current?.id, email: adminRef.current?.email ?? "", firstName: adminRef.current?.firstName ?? "", lastName: adminRef.current?.lastName ?? "", title: adminRef.current?.title ?? "", role: adminRef.current?.role ?? RoleEnum.ADMIN, riskStatus: adminRef.current?.riskStatus ?? RiskEnum.LOW_RISK, managerId: adminRef.current?.managerId ?? (currentUserRef.current?.role === RoleEnum.MANAGER ? currentUserRef.current?.id : undefined), }; reset(nextDefaults, { keepDefaultValues: false }); }, [visible, reset, admin?.id, currentUser?.id, currentUser?.role]); const windowHeight = Dimensions.get("window").height; const dialogVerticalMargin = 24; const dialogMaxHeight = windowHeight - dialogVerticalMargin - 60; const approxChrome = 140; const maxDialogContentHeight = Math.max(200, dialogMaxHeight - approxChrome); const selectedRole = watch("role"); const submit = (vals: AdminFormValues) => { const payload: Partial = { id: vals.id, email: vals.email.trim().toLowerCase(), firstName: vals.firstName.trim(), lastName: vals.lastName.trim(), title: vals.title.trim(), role: vals.role || RoleEnum.ADMIN, riskStatus: vals.riskStatus || RiskEnum.LOW_RISK, // Only Managers can assign Admins to a Manager (Managers themselves cannot be reassigned) ...(currentUser?.role === RoleEnum.MANAGER && vals.role === RoleEnum.ADMIN ? { managerId: vals.managerId ?? undefined } : {}), }; onSubmit(payload); }; const titleText = isEdit ? "Edit Admin" : "Add Admin"; const submitText = isEdit ? "Edit" : "Add"; return ( {titleText} Email ( <> {errors.email ? ( {errors.email.message as string} ) : null} )} /> First Name ( <> {errors.firstName ? ( {errors.firstName.message as string} ) : null} )} /> Last Name ( <> {errors.lastName ? ( {errors.lastName.message as string} ) : null} )} /> {/* Password field removed for invitation-only flow */} Title ( <> {errors.title ? ( {errors.title.message as string} ) : null} )} /> Role ( onChange(v)} > )} /> {currentUser?.role === RoleEnum.MANAGER && selectedRole === RoleEnum.ADMIN ? ( Assign to Manager ( onChange(v)} > {managerOptions.map((m) => ( ))} )} /> ) : null} {isLoading && ( )} ); };