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

149 lines
4.0 KiB
TypeScript

"use client";
import React, { useState, useEffect } from "react";
import { Stack, Typography, Button, Alert, TextField } from "@mui/material";
import Modal from "@/app/components/Modal/Modal";
import Spinner from "@/app/components/Spinner/Spinner";
import { IAddModalProps } from "./types";
const AddModal: React.FC<IAddModalProps> = ({
open,
onClose,
onConfirm,
resourceType = "item",
fields,
isLoading = false,
error = null,
}) => {
const [formData, setFormData] = useState<Record<string, unknown>>({});
const [validationErrors, setValidationErrors] = useState<
Record<string, string>
>({});
useEffect(() => {
if (open) {
const initialData: Record<string, unknown> = {};
fields.forEach(field => {
initialData[field.name] = field.defaultValue ?? "";
});
setFormData(initialData);
setValidationErrors({});
}
}, [open, fields]);
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
if (validationErrors[name]) {
setValidationErrors(prev => {
const next = { ...prev };
delete next[name];
return next;
});
}
};
const validateForm = (): boolean => {
const errors: Record<string, string> = {};
fields.forEach(field => {
const value = formData[field.name];
const isEmpty =
value === undefined || value === null || String(value).trim() === "";
if (field.required && isEmpty) {
errors[field.name] = `${field.label} is required`;
}
if (field.type === "email" && value && !isEmpty) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(String(value))) {
errors[field.name] = "Please enter a valid email address";
}
}
});
setValidationErrors(errors);
return Object.keys(errors).length === 0;
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!validateForm()) {
return;
}
await Promise.resolve(onConfirm(formData));
};
const handleClose = () => {
if (!isLoading) {
setFormData({});
setValidationErrors({});
onClose();
}
};
const title = `Add ${resourceType.charAt(0).toUpperCase() + resourceType.slice(1)}`;
return (
<Modal open={open} onClose={handleClose} title={title}>
<form onSubmit={handleSubmit}>
<Stack spacing={3}>
{fields.map(field => (
<TextField
key={field.name}
name={field.name}
label={field.label}
type={field.type === "number" ? "number" : field.type || "text"}
value={formData[field.name] ?? ""}
onChange={handleChange}
required={field.required}
placeholder={field.placeholder}
error={!!validationErrors[field.name]}
helperText={validationErrors[field.name]}
disabled={isLoading}
multiline={field.multiline || field.type === "textarea"}
rows={field.rows || (field.multiline ? 4 : undefined)}
fullWidth
/>
))}
{error && (
<Alert severity="error" sx={{ mt: 1 }}>
{error}
</Alert>
)}
<Stack direction="row" spacing={2} justifyContent="flex-end">
<Button
variant="outlined"
onClick={handleClose}
disabled={isLoading}
>
Cancel
</Button>
<Button
type="submit"
color="primary"
variant="contained"
disabled={isLoading}
startIcon={
isLoading ? <Spinner size="small" color="#fff" /> : null
}
>
{isLoading ? "Adding..." : `Add ${resourceType}`}
</Button>
</Stack>
</Stack>
</form>
</Modal>
);
};
export default AddModal;