2026-01-07 15:41:36 +01:00

302 lines
8.5 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 from "react";
import { useRouter } from "next/navigation";
import { useDispatch, useSelector } from "react-redux";
import { AppDispatch, RootState } from "@/app/redux/store";
import { updateUserDetails } from "@/app/redux/user/userSlice";
import { IEditUserForm, EditUserField } from "../User.interfaces";
import { IUser } from "../../Pages/Admin/Users/interfaces";
import toast from "react-hot-toast";
import { Switch, FormControlLabel } from "@mui/material";
import "./EditUser.scss";
import { selectAppMetadata } from "@/app/redux/metadata/selectors";
const EditUser = ({ user }: { user: IUser }) => {
const router = useRouter();
const dispatch = useDispatch<AppDispatch>();
const { status } = useSelector((state: RootState) => state.user);
// Get original Metadata from Redux store
const data = useSelector(selectAppMetadata);
const {
merchants: metadataMerchants = [],
groups: metadataGroups = [],
job_titles: metadataJobTitles = [],
} = data || {};
// Get original user data from the API response
const {
username,
first_name,
last_name,
email,
groups,
phone,
enabled,
job_title,
merchants,
} = user;
const [form, setForm] = React.useState<IEditUserForm>({
first_name: first_name || "",
last_name: last_name || "",
email: email || "",
phone: phone || "",
groups: groups || [],
merchants: merchants || [],
job_title: job_title || "",
username: username || "",
});
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>
) => {
const name = e.target.name as EditUserField;
const value = e.target.value;
if (name === "phone") {
const filtered = value.replace(/[^0-9+\-\s()]/g, "");
setForm(prev => ({ ...prev, phone: filtered }));
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 handleUpdate = async (
e?: React.FormEvent<HTMLFormElement> | Partial<{ enabled: boolean }>
) => {
if (e && "preventDefault" in e) e.preventDefault();
// Check if this was a toggle-only update
const isToggle = !e || ("enabled" in e && Object.keys(e).length === 1);
let updates: Record<string, unknown> = {};
// If toggle, send entire user object with updated enabled field (excluding id)
if (isToggle) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { id, ...rest } = user;
updates = {
...rest,
enabled: !(enabled ?? true),
};
} else {
// Compare form fields vs original user object
Object.entries(form).forEach(([key, value]) => {
const originalValue = (user as unknown as Record<string, unknown>)[key];
// Only include changed values and skip empty ones
if (
value !== "" &&
JSON.stringify(value) !== JSON.stringify(originalValue)
) {
updates[key] = value;
}
});
}
// Nothing changed — no need to call API
if (Object.keys(updates).length === 0) {
toast("No changes detected");
return;
}
try {
const resultAction = await dispatch(
updateUserDetails({ id: user.id, updates })
);
if (updateUserDetails.fulfilled.match(resultAction)) {
toast.success(resultAction.payload.message);
router.refresh();
} else {
toast.error(
(resultAction.payload as string) || "Failed to update user"
);
}
} catch (err) {
console.error("Failed to update user:", err);
toast.error("An unexpected error occurred");
}
};
const loading = status === "loading";
return (
<form className="edit-user" onSubmit={handleUpdate}>
<div className="edit-user__status-toggle">
<FormControlLabel
control={
<Switch
checked={enabled ?? true}
onChange={() => handleUpdate()}
disabled={loading}
color={(enabled ?? true) ? "success" : "default"}
/>
}
label={(enabled ?? true) ? "User Enabled" : "User Disabled"}
/>
</div>
<input
type="text"
placeholder="First Name"
name="first_name"
value={form.first_name}
onChange={handleChange}
/>
<input
type="text"
placeholder="Last Name"
name="last_name"
value={form.last_name}
onChange={handleChange}
/>
<input
type="email"
placeholder="Email"
name="email"
value={form.email}
onChange={handleChange}
/>
<input
type="text"
placeholder="Username"
name="username"
value={form.username}
onChange={handleChange}
/>
<div className="array-field-container">
<label>Merchants:</label>
<select
name="merchants"
value=""
onChange={handleChange}
className="edit-user__select"
>
<option value="">Select Merchant</option>
{metadataMerchants.map((merchant: string) => (
<option key={merchant} value={merchant}>
{merchant}
</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="edit-user__select"
>
<option value="">Select Group</option>
{metadataGroups.map((group: string) => (
<option key={group} value={group}>
{group}
</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>
<div className="array-field-container">
<label>Job Title:</label>
<select
name="job_title"
value={form.job_title}
onChange={handleChange}
className="edit-user__select"
>
<option value="">Select Job Title</option>
{metadataJobTitles?.map((job_title: string) => (
<option key={job_title} value={job_title}>
{job_title}
</option>
))}
</select>
</div>
<input
type="tel"
placeholder="Phone"
name="phone"
value={form.phone}
maxLength={15}
pattern="[0-9+\-\s()]*"
onChange={handleChange}
inputMode="tel"
autoComplete="tel"
/>
<div className="edit-user__button-container">
<button type="submit" disabled={loading}>
{loading ? "Saving..." : "Save"}
</button>
</div>
</form>
);
};
export default EditUser;