2025-10-28 16:42:25 +01:00

300 lines
8.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import React, { useState } from "react";
import { useRouter } from "next/navigation";
import { useDispatch, useSelector } from "react-redux";
import { AppDispatch } from "@/app/redux/store";
import "./AddUser.scss";
import { addUser } from "@/app/redux/auth/authSlice";
import { IEditUserForm } from "../User.interfaces";
import { COUNTRY_CODES } from "../constants";
import { formatPhoneDisplay, validatePhone } from "../utils";
import Spinner from "../../../components/Spinner/Spinner";
import { RootState } from "@/app/redux/store";
import toast from "react-hot-toast";
import Modal from "@/app/components/Modal/Modal";
interface AddUserProps {
open: boolean;
onClose: () => void;
}
const AddUser: React.FC<AddUserProps> = ({ open, onClose }) => {
// const router = useRouter();
const dispatch = useDispatch<AppDispatch>();
const { status, error: authError } = useSelector(
(state: RootState) => state.auth
);
const [form, setForm] = useState<IEditUserForm>({
username: "",
firstName: "",
lastName: "",
email: "",
phone: "",
role: "",
merchants: [],
groups: [],
jobTitle: "",
});
const [phoneError, setPhoneError] = useState("");
const [countryCode, setCountryCode] = useState("+1");
const loading = status === "loading";
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>
) => {
const { name, value } = e.target;
if (name === "countryCode") {
setCountryCode(value);
return;
}
// Handle array fields (merchants and groups)
if (name === "merchants" || name === "groups") {
if (value === "") {
// If empty selection, set empty array
setForm(prev => ({ ...prev, [name]: [] }));
} else {
// Add the selected value to the array if not already present
setForm(prev => {
const currentArray = prev[name as keyof IEditUserForm] as string[];
if (!currentArray.includes(value)) {
return { ...prev, [name]: [...currentArray, value] };
}
return prev;
});
}
} else {
// Handle single value fields
setForm(prev => ({ ...prev, [name]: value }));
}
};
const handleCountryCodeChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const newCountryCode = e.target.value;
setCountryCode(newCountryCode);
// Re-validate phone if it exists
if (form.phone) {
const phoneError = validatePhone(form.phone, newCountryCode);
setPhoneError(phoneError);
}
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
// Validate phone number if provided
if (form.phone && phoneError) {
return;
}
if (
!form.firstName ||
!form.lastName ||
!form.email ||
form.merchants.length === 0 ||
form.groups.length === 0 ||
!form.jobTitle
) {
return;
}
// Format phone number with country code before submission
const formattedForm = {
...form,
phone: form.phone ? formatPhoneDisplay(form.phone, countryCode) : "",
};
try {
const resultAction = await dispatch(addUser(formattedForm));
const result = addUser.fulfilled.match(resultAction);
if (result && resultAction.payload.success) {
toast.success(resultAction.payload.message);
// router.refresh();
onClose();
}
} catch (err) {
// Error is handled by Redux state
console.error("Failed to add user:", err);
}
};
return (
<Modal open={open} onClose={onClose} title="Add User">
<form className="add-user" onSubmit={handleSubmit}>
<input
name="username"
placeholder="Username"
value={form.username}
onChange={handleChange}
required
/>
<input
name="firstName"
placeholder="First Name"
value={form.firstName}
onChange={handleChange}
required
/>
<input
name="lastName"
placeholder="Last Name"
value={form.lastName}
onChange={handleChange}
required
/>
<input
name="email"
type="email"
placeholder="Email"
value={form.email}
onChange={handleChange}
required
/>
<div className="array-field-container">
<label>Merchants:</label>
<select
name="merchants"
value=""
onChange={handleChange}
className="add-user__select"
>
<option value="">Select Merchant</option>
<option value="Win Bot">Win Bot</option>
<option value="Data Spin">Data Spin</option>
</select>
{form.merchants.length > 0 && (
<div className="selected-items">
{form.merchants.map((merchant, index) => (
<span key={index} className="selected-item">
{merchant}
<button
type="button"
onClick={() => {
setForm(prev => ({
...prev,
merchants: prev.merchants.filter((_, i) => i !== index),
}));
}}
className="remove-item"
>
×
</button>
</span>
))}
</div>
)}
</div>
<div className="array-field-container">
<label>Groups:</label>
<select
name="groups"
value=""
onChange={handleChange}
className="add-user__select"
>
<option value="">Select Group</option>
<option value="Admin">Admin</option>
<option value="Reader">Reader</option>
<option value="Manager">Manager</option>
<option value="User">User</option>
</select>
{form.groups.length > 0 && (
<div className="selected-items">
{form.groups.map((group, index) => (
<span key={index} className="selected-item">
{group}
<button
type="button"
onClick={() => {
setForm(prev => ({
...prev,
groups: prev.groups.filter((_, i) => i !== index),
}));
}}
className="remove-item"
>
×
</button>
</span>
))}
</div>
)}
</div>
<select
name="jobTitle"
value={form.jobTitle}
onChange={handleChange}
required
className="add-user__select"
>
<option value="">Select Job Title</option>
<option value="Admin">Admin</option>
<option value="Reader">Reader</option>
<option value="User">User</option>
<option value="Manager">Manager</option>
<option value="Supervisor">Supervisor</option>
<option value="Director">Director</option>
</select>
<div className="phone-input-container">
<select
name="countryCode"
value={countryCode}
onChange={handleCountryCodeChange}
className="country-code-select"
>
{COUNTRY_CODES.map(country => (
<option key={country.code} value={country.code}>
{country.flag} {country.code} {country.country}
</option>
))}
</select>
<input
name="phone"
type="tel"
placeholder="Phone number (optional)"
value={form.phone}
onChange={handleChange}
className={phoneError ? "phone-input-error" : ""}
/>
</div>
{authError && (
<span style={{ color: "red", width: "100%" }}>{authError}</span>
)}
<span
className="phone-error-message"
style={{
visibility: phoneError ? "visible" : "hidden",
color: "red",
width: "100%",
}}
>
{phoneError}
</span>
<div className="add-user__button-container">
<button type="submit" disabled={loading}>
{loading ? (
<>
<Spinner size="small" color="#fff" />
Adding...
</>
) : (
"Add User"
)}
</button>
</div>
</form>
</Modal>
);
};
export default AddUser;