Files
n3wt-school/Front-End/src/components/Structure/Tarification/FeesSection.js
2025-05-17 14:35:33 +02:00

378 lines
11 KiB
JavaScript

import React, { useState } from 'react';
import { Trash2, Edit3, Check, X, EyeOff, Eye, CreditCard } from 'lucide-react';
import Table from '@/components/Table';
import Popup from '@/components/Popup';
import CheckBox from '@/components/CheckBox';
import InputText from '@/components/InputText';
import logger from '@/utils/logger';
import SectionHeader from '@/components/SectionHeader';
import { useEstablishment } from '@/context/EstablishmentContext';
import AlertMessage from '@/components/AlertMessage';
const FeesSection = ({
fees,
setFees,
handleCreate,
handleEdit,
handleDelete,
type,
subscriptionMode = false,
selectedFees,
handleFeeSelection,
}) => {
const [editingFee, setEditingFee] = useState(null);
const [newFee, setNewFee] = useState(null);
const [formData, setFormData] = useState({});
const [localErrors, setLocalErrors] = useState({});
const [popupVisible, setPopupVisible] = useState(false);
const [popupMessage, setPopupMessage] = useState('');
const [removePopupVisible, setRemovePopupVisible] = useState(false);
const [removePopupMessage, setRemovePopupMessage] = useState('');
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
const labelTypeFrais =
type === 0 ? "Frais d'inscription" : 'Frais de scolarité';
const { selectedEstablishmentId } = useEstablishment();
// Récupération des messages d'erreur
const getError = (field) => {
return localErrors?.[field]?.[0];
};
const handleAddFee = () => {
setNewFee({
id: Date.now(),
name: '',
base_amount: '',
description: '',
validity_start_date: '',
validity_end_date: '',
discounts: [],
type: type,
establishment: selectedEstablishmentId,
});
};
const handleRemoveFee = (id) => {
return handleDelete(id)
.then(() => {
setFees((prevFees) => prevFees.filter((fee) => fee.id !== id));
})
.catch((error) => {
logger.error(error);
});
};
const handleSaveNewFee = () => {
if (newFee.name && newFee.base_amount) {
const feeData = {
...newFee,
establishment: selectedEstablishmentId,
};
handleCreate(feeData)
.then((createdFee) => {
setFees([createdFee, ...fees]);
setNewFee(null);
setLocalErrors({});
})
.catch((error) => {
logger.error('Error:', error.message);
if (error.details) {
logger.error('Form errors:', error.details);
setLocalErrors(error.details);
}
});
} else {
setPopupMessage('Tous les champs doivent être remplis et valides');
setPopupVisible(true);
}
};
const handleUpdateFee = (id, updatedFee) => {
if (updatedFee.name && updatedFee.base_amount) {
handleEdit(id, updatedFee)
.then((updatedFee) => {
setFees(fees.map((fee) => (fee.id === id ? updatedFee : fee)));
setEditingFee(null);
setLocalErrors({});
})
.catch((error) => {
logger.error('Error:', error.message);
if (error.details) {
logger.error('Form errors:', error.details);
setLocalErrors(error.details);
}
});
} else {
setPopupMessage('Tous les champs doivent être remplis et valides');
setPopupVisible(true);
}
};
const handleToggleActive = (id, isActive) => {
const fee = fees.find((fee) => fee.id === id);
if (!fee) return;
const updatedData = {
is_active: !isActive,
discounts: fee.discounts,
};
handleEdit(id, updatedData)
.then(() => {
setFees((prevFees) =>
prevFees.map((fee) =>
fee.id === id ? { ...fee, is_active: !isActive } : fee
)
);
})
.catch((error) => {
logger.error(error);
});
};
const handleChange = (e) => {
const { name, value } = e.target;
let parsedValue = value;
if (name === 'discounts') {
parsedValue = value.split(',').map((v) => parseInt(v, 10));
}
if (editingFee) {
setFormData((prevData) => ({
...prevData,
[name]: parsedValue,
}));
} else if (newFee) {
setNewFee((prevData) => ({
...prevData,
[name]: parsedValue,
}));
}
};
const renderInputField = (field, value, onChange, placeholder) => (
<div className="flex justify-center space-x-2">
<div className="w-full max-w-xs">
<InputText
name={field}
type={field === 'base_amount' ? 'number' : 'text'}
value={value}
onChange={onChange}
placeholder={placeholder}
errorMsg={getError(field)}
/>
</div>
</div>
);
const renderFeeCell = (fee, column) => {
const isEditing = editingFee === fee.id;
const isCreating = newFee && newFee.id === fee.id;
const currentData = isEditing ? formData : newFee;
if (isEditing || isCreating) {
switch (column) {
case 'NOM':
return renderInputField(
'name',
currentData.name,
handleChange,
'Nom des frais'
);
case 'MONTANT':
return renderInputField(
'base_amount',
currentData.base_amount,
handleChange,
'Montant de base'
);
case 'DESCRIPTION':
return renderInputField(
'description',
currentData.description,
handleChange,
'Description'
);
case 'ACTIONS':
return (
<div className="flex justify-center space-x-2">
<button
type="button"
onClick={() =>
isEditing
? handleUpdateFee(editingFee, formData)
: handleSaveNewFee()
}
className="text-green-500 hover:text-green-700"
>
<Check className="w-5 h-5" />
</button>
<button
type="button"
onClick={() =>
isEditing ? setEditingFee(null) : setNewFee(null)
}
className="text-red-500 hover:text-red-700"
>
<X className="w-5 h-5" />
</button>
</div>
);
default:
return null;
}
} else {
switch (column) {
case 'NOM':
return fee.name;
case 'MONTANT':
return fee.base_amount + ' €';
case 'MISE A JOUR':
return fee.updated_at_formatted;
case 'DESCRIPTION':
return fee.description;
case 'ACTIONS':
return (
<div className="flex justify-center space-x-2">
<button
type="button"
onClick={() => handleToggleActive(fee.id, fee.is_active)}
className={`text-${fee.is_active ? 'green' : 'orange'}-500 hover:text-${fee.is_active ? 'green' : 'orange'}-700`}
>
{fee.is_active ? (
<Eye className="w-5 h-5" />
) : (
<EyeOff className="w-5 h-5" />
)}
</button>
<button
type="button"
onClick={() => setEditingFee(fee.id) || setFormData(fee)}
className="text-blue-500 hover:text-blue-700"
>
<Edit3 className="w-5 h-5" />
</button>
<button
type="button"
onClick={() => {
setRemovePopupVisible(true);
setRemovePopupMessage(
`Attentions ! \nVous êtes sur le point de supprimer un ${labelTypeFrais} .\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?`
);
setRemovePopupOnConfirm(() => () => {
handleRemoveFee(fee.id)
.then((data) => {
logger.debug('Success:', data);
setPopupMessage(
labelTypeFrais + ' correctement supprimé'
);
setPopupVisible(true);
setRemovePopupVisible(false);
})
.catch((error) => {
logger.error('Error archiving data:', error);
setPopupMessage(
'Erreur lors de la suppression du ' + labelTypeFrais
);
setPopupVisible(true);
setRemovePopupVisible(false);
});
});
}}
className="text-red-500 hover:text-red-700"
>
<Trash2 className="w-5 h-5" />
</button>
</div>
);
case '':
return (
<div className="flex justify-center">
<CheckBox
item={fee}
formData={{ selectedFees }}
handleChange={() => handleFeeSelection(fee.id)}
fieldName="selectedFees"
/>
</div>
);
default:
return null;
}
}
};
const columns = subscriptionMode
? [
{ name: 'NOM', label: 'Nom' },
{ name: 'DESCRIPTION', label: 'Description' },
{ name: 'MONTANT', label: 'Montant de base' },
{ name: '', label: 'Sélection' },
]
: [
{ name: 'NOM', label: 'Nom' },
{ name: 'MONTANT', label: 'Montant de base' },
{ name: 'DESCRIPTION', label: 'Description' },
{ name: 'MISE A JOUR', label: 'Date mise à jour' },
{ name: 'ACTIONS', label: 'Actions' },
];
let emptyMessage;
if (type === 0) {
emptyMessage = (
<AlertMessage
type="warning"
title="Aucun frais d'inscription enregistré"
message="Veuillez procéder à la création de nouveaux frais d'inscription"
/>
);
} else {
emptyMessage = (
<AlertMessage
type="warning"
title="Aucun frais de scolarité enregistré"
message="Veuillez procéder à la création de nouveaux frais de scolarité"
/>
);
}
return (
<div className="space-y-4">
{!subscriptionMode && (
<SectionHeader
icon={CreditCard}
title={`${type == 0 ? "Liste des frais d'inscription" : 'Liste des frais de scolarité'}`}
description={`Gérez${type == 0 ? " vos frais d'inscription" : ' vos frais de scolarité'}`}
button={!subscriptionMode}
onClick={handleAddFee}
/>
)}
<Table
data={newFee ? [newFee, ...fees] : fees}
columns={columns}
renderCell={renderFeeCell}
emptyMessage={emptyMessage}
/>
<Popup
isOpen={popupVisible}
setIsOpen={setPopupVisible}
message={popupMessage}
onConfirm={() => setPopupVisible(false)}
onCancel={() => setPopupVisible(false)}
uniqueConfirmButton={true}
popupClassName="w-full max-w-xs sm:max-w-md"
/>
<Popup
isOpen={removePopupVisible}
setIsOpen={setRemovePopupVisible}
message={removePopupMessage}
onConfirm={removePopupOnConfirm}
onCancel={() => setRemovePopupVisible(false)}
popupClassName="w-full max-w-xs sm:max-w-md"
/>
</div>
);
};
export default FeesSection;