Files
n3wt-school/Front-End/src/components/Structure/Tarification/DiscountsSection.js
2025-05-18 00:45:49 +02:00

404 lines
12 KiB
JavaScript

import React, { useState } from 'react';
import { Trash2, Edit3, Check, X, Percent, EuroIcon, Tag } 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 DiscountsSection = ({
discounts,
setDiscounts,
handleCreate,
handleEdit,
handleDelete,
type,
subscriptionMode = false,
selectedDiscounts,
handleDiscountSelection,
}) => {
const [editingDiscount, setEditingDiscount] = useState(null);
const [newDiscount, setNewDiscount] = 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 { selectedEstablishmentId } = useEstablishment();
const handleAddDiscount = () => {
setNewDiscount({
id: Date.now(),
name: '',
amount: '',
description: '',
discount_type: 0,
type: type,
establishment: selectedEstablishmentId,
});
};
const handleRemoveDiscount = (id) => {
return handleDelete(id)
.then(() => {
setDiscounts((prevDiscounts) =>
prevDiscounts.filter((discount) => discount.id !== id)
);
})
.catch((error) => {
logger.error(error);
});
};
const handleSaveNewDiscount = () => {
if (newDiscount.name && newDiscount.amount) {
const discountData = {
...newDiscount,
establishment: selectedEstablishmentId,
};
handleCreate(discountData)
.then((createdDiscount) => {
setDiscounts([createdDiscount, ...discounts]);
setNewDiscount(null);
setLocalErrors({});
})
.catch((error) => {
if (error && typeof error === 'object') {
setLocalErrors(error);
} else {
logger.error(error);
}
});
} else {
setPopupMessage('Tous les champs doivent être remplis');
setPopupVisible(true);
}
};
const handleUpdateDiscount = (id, updatedDiscount) => {
if (updatedDiscount.name && updatedDiscount.amount) {
handleEdit(id, updatedDiscount)
.then(() => {
setEditingDiscount(null);
setLocalErrors({});
})
.catch((error) => {
if (error && typeof error === 'object') {
setLocalErrors(error);
} else {
logger.error(error);
}
});
} else {
setPopupMessage('Tous les champs doivent être remplis');
setPopupVisible(true);
}
};
const handleToggleDiscountType = (id) => {
const discount = discounts.find((discount) => discount.id === id);
if (!discount) return;
const updatedData = {
...discount,
discount_type: discount.discount_type === 0 ? 1 : 0,
};
handleEdit(id, updatedData)
.then(() => {
setDiscounts((prevDiscounts) =>
prevDiscounts.map((discount) =>
discount.id === id
? { ...discount, discount_type: updatedData.discount_type }
: discount
)
);
})
.catch((error) => {
logger.error(error);
});
};
const handleToggleDiscountTypeEdition = (id) => {
if (editingDiscount) {
setFormData((prevData) => ({
...prevData,
discount_type: prevData.discount_type === 0 ? 1 : 0,
}));
} else if (newDiscount) {
setNewDiscount((prevData) => ({
...prevData,
discount_type: prevData.discount_type === 0 ? 1 : 0,
}));
}
};
const handleChange = (e) => {
const { name, value } = e.target;
if (editingDiscount) {
setFormData((prevData) => ({
...prevData,
[name]: value,
}));
} else if (newDiscount) {
setNewDiscount((prevData) => ({
...prevData,
[name]: value,
}));
}
};
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 === 'amount' ? 'number' : 'text'}
value={value}
onChange={onChange}
placeholder={placeholder}
errorMsg={
localErrors &&
localErrors[field] &&
Array.isArray(localErrors[field])
? localErrors[field][0]
: ''
}
/>
</div>
</div>
);
const renderDiscountCell = (discount, column) => {
const isEditing = editingDiscount === discount.id;
const isCreating = newDiscount && newDiscount.id === discount.id;
const currentData = isEditing ? formData : newDiscount;
if (isEditing || isCreating) {
switch (column) {
case 'LIBELLE':
return renderInputField(
'name',
currentData.name,
handleChange,
'Libellé de la réduction'
);
case 'REMISE':
return (
<div className="flex justify-center space-x-2">
{renderInputField(
'amount',
currentData.amount,
handleChange,
'Montant'
)}
<button
type="button"
onClick={() => handleToggleDiscountTypeEdition(discount.id)}
className="flex justify-center items-center text-emerald-500 hover:text-emerald-700 ml-2"
>
{currentData.discount_type === 0 ? (
<EuroIcon className="w-5 h-5" />
) : (
<Percent className="w-5 h-5" />
)}
</button>
</div>
);
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
? handleUpdateDiscount(editingDiscount, formData)
: handleSaveNewDiscount()
}
className="text-green-500 hover:text-green-700"
>
<Check className="w-5 h-5" />
</button>
<button
type="button"
onClick={() =>
isEditing ? setEditingDiscount(null) : setNewDiscount(null)
}
className="text-red-500 hover:text-red-700"
>
<X className="w-5 h-5" />
</button>
</div>
);
default:
return null;
}
} else {
switch (column) {
case 'LIBELLE':
return discount.name;
case 'REMISE':
return discount.discount_type === 0
? `${discount.amount}`
: `${discount.amount} %`;
case 'DESCRIPTION':
return discount.description;
case 'MISE A JOUR':
return discount.updated_at_formatted;
case 'ACTIONS':
return (
<div className="flex justify-center space-x-2">
<button
type="button"
onClick={() => handleToggleDiscountType(discount.id)}
className="flex justify-center items-center text-emerald-500 hover:text-emerald-700"
>
{discount.discount_type === 0 ? (
<EuroIcon className="w-5 h-5" />
) : (
<Percent className="w-5 h-5" />
)}
</button>
<button
type="button"
onClick={() =>
setEditingDiscount(discount.id) || setFormData(discount)
}
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 tarif personnalisé.\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?"
);
setRemovePopupOnConfirm(() => () => {
handleRemoveDiscount(discount.id)
.then((data) => {
logger.debug('Success:', data);
setPopupMessage('Réduction correctement supprimé');
setPopupVisible(true);
setRemovePopupVisible(false);
})
.catch((error) => {
logger.error('Error archiving data:', error);
setPopupMessage(
'Erreur lors de la suppression de la réduction'
);
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={discount}
formData={{ selectedDiscounts }}
handleChange={() => handleDiscountSelection(discount.id)}
fieldName="selectedDiscounts"
/>
</div>
);
default:
return null;
}
}
};
const columns = subscriptionMode
? [
{ name: 'LIBELLE', label: 'Libellé' },
{ name: 'DESCRIPTION', label: 'Description' },
{ name: 'REMISE', label: 'Remise' },
{ name: '', label: 'Sélection' },
]
: [
{ name: 'LIBELLE', label: 'Libellé' },
{ name: 'REMISE', label: 'Remise' },
{ name: 'DESCRIPTION', label: 'Description' },
{ name: 'MISE A JOUR', label: 'Date mise à jour' },
{ name: 'ACTIONS', label: 'Actions' },
];
let emptyMessage;
if (type === 0) {
emptyMessage = (
<AlertMessage
type="info"
title="Aucune réduction enregistrée"
message="Aucune réduction sur les frais d'inscription n'a été enregistrée"
/>
);
} else {
emptyMessage = (
<AlertMessage
type="info"
title="Aucune réduction enregistrée"
message="Aucune réduction sur les frais de scolarité n'a été enregistrée"
/>
);
}
return (
<div className="space-y-4">
{!subscriptionMode && (
<SectionHeader
icon={Tag}
discountStyle={true}
title={`${type == 0 ? "Liste des réductions sur les frais d'inscription" : 'Liste des réductions sur les frais de scolarité'}`}
description={`Gérez ${type == 0 ? " vos réductions sur les frais d'inscription" : ' vos réductions sur les frais de scolarité'}`}
button={!subscriptionMode}
onClick={handleAddDiscount}
/>
)}
<Table
data={newDiscount ? [newDiscount, ...discounts] : discounts}
columns={columns}
renderCell={renderDiscountCell}
defaultTheme="bg-yellow-50"
emptyMessage={emptyMessage}
/>
<Popup
isOpen={popupVisible}
message={popupMessage}
onConfirm={() => setPopupVisible(false)}
onCancel={() => setPopupVisible(false)}
uniqueConfirmButton={true}
/>
<Popup
isOpen={removePopupVisible}
message={removePopupMessage}
onConfirm={removePopupOnConfirm}
onCancel={() => setRemovePopupVisible(false)}
/>
</div>
);
};
export default DiscountsSection;