"use client"; import { useState } from "react"; import GlassModal from "@/components/admin/GlassModal"; import { AdminInput, AdminTextInput } from "@/components/admin/design-system"; type Role = "platform_admin" | "brand_admin" | "store_employee"; type Props = { isOpen: boolean; onClose: () => void; onSuccess: (user: import("@/actions/admin/users").AdminUserRow) => void; brands: { id: string; name: string }[]; currentUser: { role: string; }; }; type SuccessState = { user: import("@/actions/admin/users").AdminUserRow; tempPassword: string; emailSent: boolean; emailError?: string; authPath?: "admin" | "signup"; }; const FLAG_LABELS: Record = { can_manage_products: "Products", can_manage_stops: "Stops", can_manage_orders: "Orders", can_manage_pickup: "Pickup", can_manage_messages: "Messages", can_manage_refunds: "Refunds", can_manage_users: "Users", can_manage_water_log: "Water Log", can_manage_reports: "Reports", }; const ALL_FLAGS = Object.keys(FLAG_LABELS); const defaultFlags: Record = { can_manage_products: false, can_manage_stops: false, can_manage_orders: false, can_manage_pickup: false, can_manage_messages: false, can_manage_refunds: false, can_manage_users: false, can_manage_water_log: false, can_manage_reports: false, }; const UserIcon = ({ className }: { className?: string }) => ( ); export default function CreateUserModal({ isOpen, onClose, onSuccess, brands, currentUser }: Props) { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [displayName, setDisplayName] = useState(""); const [phoneNumber, setPhoneNumber] = useState(""); const [role, setRole] = useState("store_employee"); const [brandId, setBrandId] = useState(null); const [flags, setFlags] = useState>({ ...defaultFlags }); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); const [copied, setCopied] = useState(false); const showBrandSelect = role === "brand_admin" || role === "store_employee"; const availableRoles: Role[] = currentUser.role === "platform_admin" ? ["platform_admin", "brand_admin", "store_employee"] : ["brand_admin", "store_employee"]; function toggleFlag(flag: string) { setFlags((prev) => ({ ...prev, [flag]: !prev[flag] })); } function resetForm() { setEmail(""); setPassword(""); setDisplayName(""); setPhoneNumber(""); setRole("store_employee"); setBrandId(null); setFlags({ ...defaultFlags }); setError(null); setSuccess(null); setCopied(false); } async function handleSubmit() { if (!email.includes("@") || !password || password.length < 6) { setError("Please enter a valid email and a password with at least 6 characters."); return; } setSaving(true); setError(null); try { const { createAdminUser } = await import("@/actions/admin/users"); const result = await createAdminUser({ email, password, display_name: displayName || undefined, phone_number: phoneNumber || undefined, role, brand_id: brandId, flags, mustChangePassword: true, }); if (result.error) { setError(result.error); return; } if (result.user && result.tempPassword) { onSuccess(result.user); setSuccess({ user: result.user, tempPassword: result.tempPassword, emailSent: result.emailSent ?? false, emailError: result.emailError, authPath: result.authPath, }); // Don't close — show the success state so the caller can copy the temp password. } } catch (e: unknown) { setError(e instanceof Error ? e.message : "An unexpected error occurred."); } finally { setSaving(false); } } function handleClose() { if (!saving) { resetForm(); onClose(); } } async function copyPassword() { if (!success) return; try { await navigator.clipboard.writeText(success.tempPassword); setCopied(true); window.setTimeout(() => setCopied(false), 2000); } catch { // Clipboard not available — caller can select manually. } } const roleDescriptions: Record = { platform_admin: "Full platform access", brand_admin: "Brand-level admin", store_employee: "Pickup and order operations only", }; if (!isOpen) return null; // Success state — show temp password + email status, then "Done" closes. if (success) { return ( ); } return ( } subtitle="Add a new admin user to your organization" onClose={handleClose} maxWidth="max-w-lg" >
{/* Error banner */} {error && (
{error}
)} {/* Email */}
setEmail(e.target.value)} required aria-required="true" autoComplete="email" className="w-full rounded-xl border border-[var(--admin-border)] bg-[var(--admin-card-bg)] px-3 py-2.5 text-sm text-[var(--admin-text-primary)] outline-none focus:border-[var(--admin-accent)] focus:ring-2 focus:ring-[var(--admin-accent)]/20 placeholder:text-[var(--admin-text-muted)]" placeholder="user@example.com" />
{/* Password */}

Minimum 6 characters.

setPassword(e.target.value)} required aria-required="true" aria-describedby="create-user-password-help" autoComplete="new-password" className="w-full rounded-xl border border-[var(--admin-border)] bg-[var(--admin-card-bg)] px-3 py-2.5 text-sm text-[var(--admin-text-primary)] outline-none focus:border-[var(--admin-accent)] focus:ring-2 focus:ring-[var(--admin-accent)]/20 placeholder:text-[var(--admin-text-muted)]" placeholder="Choose a password" minLength={6} />
{/* Display Name & Phone - 2 columns on larger screens */}
setDisplayName(e.target.value)} autoComplete="name" className="w-full rounded-xl border border-[var(--admin-border)] bg-[var(--admin-card-bg)] px-3 py-2.5 text-sm text-[var(--admin-text-primary)] outline-none focus:border-[var(--admin-accent)] focus:ring-2 focus:ring-[var(--admin-accent)]/20 placeholder:text-[var(--admin-text-muted)]" placeholder="Kyle Martinez" />

Optional.

setPhoneNumber(e.target.value)} autoComplete="tel" className="w-full rounded-xl border border-[var(--admin-border)] bg-[var(--admin-card-bg)] px-3 py-2.5 text-sm text-[var(--admin-text-primary)] outline-none focus:border-[var(--admin-accent)] focus:ring-2 focus:ring-[var(--admin-accent)]/20 placeholder:text-[var(--admin-text-muted)]" placeholder="+1 (555) 000-0000" />
{/* Role */}
{availableRoles.map((r) => ( ))}
{/* Brand */} {showBrandSelect && (
)} {/* Permissions */}
{ALL_FLAGS.map((flag) => ( ))}
{/* Footer */}
); }