mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
chore: Application du linter
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
'use client';
|
||||
import logger from '@/utils/logger';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
export default function AnnouncementScheduler({ csrfToken }) {
|
||||
@ -8,7 +9,7 @@ export default function AnnouncementScheduler({ csrfToken }) {
|
||||
|
||||
const handleSchedule = () => {
|
||||
// Logique pour planifier une annonce
|
||||
console.log('Annonce planifiée:', { title, date, message });
|
||||
logger.debug('Annonce planifiée:', { title, date, message });
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -8,10 +8,11 @@ import { useNotification } from '@/context/NotificationContext';
|
||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||
import AlertMessage from '@/components/AlertMessage';
|
||||
import RecipientInput from '@/components/RecipientInput';
|
||||
|
||||
// Charger Quill dynamiquement pour éviter les problèmes de SSR
|
||||
const ReactQuill = dynamic(() => import('react-quill'), { ssr: false });
|
||||
import 'react-quill/dist/quill.snow.css'; // Importer les styles de Quill
|
||||
import { useRouter } from 'next/navigation'; // Ajoute cette ligne
|
||||
import WisiwigTextArea from '@/components/WisiwigTextArea';
|
||||
import logger from '@/utils/logger';
|
||||
import InputText from '@/components/InputText';
|
||||
import Button from '@/components/Button';
|
||||
|
||||
export default function EmailSender({ csrfToken }) {
|
||||
const [recipients, setRecipients] = useState([]);
|
||||
@ -23,6 +24,7 @@ export default function EmailSender({ csrfToken }) {
|
||||
const [smtpConfigured, setSmtpConfigured] = useState(false); // État pour vérifier si SMTP est configuré
|
||||
const { showNotification } = useNotification();
|
||||
const { selectedEstablishmentId } = useEstablishment(); // Récupérer l'establishment_id depuis le contexte
|
||||
const router = useRouter(); // Ajoute cette ligne
|
||||
|
||||
useEffect(() => {
|
||||
// Vérifier si les paramètres SMTP sont configurés
|
||||
@ -36,10 +38,9 @@ export default function EmailSender({ csrfToken }) {
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
'Erreur lors de la vérification des paramètres SMTP:',
|
||||
error
|
||||
);
|
||||
logger.error('Erreur lors de la vérification des paramètres SMTP:', {
|
||||
error,
|
||||
});
|
||||
setSmtpConfigured(false);
|
||||
});
|
||||
}, [csrfToken, selectedEstablishmentId]);
|
||||
@ -64,7 +65,7 @@ export default function EmailSender({ csrfToken }) {
|
||||
setSubject('');
|
||||
setMessage('');
|
||||
} catch (error) {
|
||||
console.error("Erreur lors de l'envoi de l'email:", error);
|
||||
logger.error("Erreur lors de l'envoi de l'email:", { error });
|
||||
showNotification(
|
||||
"Une erreur est survenue lors de l'envoi de l'email.",
|
||||
'error',
|
||||
@ -80,82 +81,76 @@ export default function EmailSender({ csrfToken }) {
|
||||
title="Configuration SMTP requise"
|
||||
message="Les paramètres SMTP de cet établissement ne sont pas configurés. Veuillez les configurer dans la page des paramètres."
|
||||
actionLabel="Aller aux paramètres"
|
||||
onAction={() => (window.location.href = '/admin/settings')} // Redirige vers la page des paramètres
|
||||
onAction={() => router.push('/admin/settings?tab=smtp')} // Utilise next/navigation ici
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto bg-white rounded-lg shadow-md">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between px-4 py-2 border-b">
|
||||
<h2 className="text-sm font-medium text-gray-700">
|
||||
Email from {fromEmail}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
{/* Form */}
|
||||
<div className="p-4">
|
||||
{/* To */}
|
||||
<div className="p-4 flex flex-col min-h-[600px]">
|
||||
{' '}
|
||||
{/* Ajout flex-col et min-h */}
|
||||
{/* Destinataires */}
|
||||
<RecipientInput
|
||||
label="Destinataires"
|
||||
recipients={recipients}
|
||||
setRecipients={setRecipients}
|
||||
searchRecipients={searchRecipients} // Passer l'action de recherche
|
||||
establishmentId={selectedEstablishmentId} // Passer l'ID de l'établissement
|
||||
searchRecipients={searchRecipients}
|
||||
establishmentId={selectedEstablishmentId}
|
||||
required
|
||||
/>
|
||||
|
||||
{/* Cc and Bcc */}
|
||||
<div className="flex space-x-4">
|
||||
{/* Cc */}
|
||||
<div className="mt-2">
|
||||
<RecipientInput
|
||||
label="Cc"
|
||||
placeholder="Add Cc"
|
||||
placeholder="Ajouter Cc"
|
||||
recipients={cc}
|
||||
searchRecipients={searchRecipients}
|
||||
establishmentId={selectedEstablishmentId}
|
||||
setRecipients={setCc}
|
||||
/>
|
||||
</div>
|
||||
{/* Bcc */}
|
||||
<div className="mt-2">
|
||||
<RecipientInput
|
||||
label="Bcc"
|
||||
placeholder="Add Bcc"
|
||||
label="Cci"
|
||||
placeholder="Ajouter Bcc"
|
||||
recipients={bcc}
|
||||
searchRecipients={searchRecipients}
|
||||
establishmentId={selectedEstablishmentId}
|
||||
setRecipients={setBcc}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Subject */}
|
||||
<div className="mb-4">
|
||||
<label className="block text-sm font-medium text-gray-700">
|
||||
Subject
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={subject}
|
||||
onChange={(e) => setSubject(e.target.value)}
|
||||
placeholder="Enter subject"
|
||||
className="w-full p-2 border rounded"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<InputText
|
||||
name="subject"
|
||||
label="Sujet"
|
||||
value={subject}
|
||||
onChange={(e) => setSubject(e.target.value)}
|
||||
placeholder="Saisir le sujet"
|
||||
className="mb-4 mt-2"
|
||||
required
|
||||
/>
|
||||
{/* Email Body */}
|
||||
<div className="mb-4">
|
||||
<label className="block text-sm font-medium text-gray-700">
|
||||
Your email
|
||||
</label>
|
||||
<ReactQuill
|
||||
theme="snow"
|
||||
<div className="mb-4 flex flex-col">
|
||||
<WisiwigTextArea
|
||||
label="Mail"
|
||||
value={message}
|
||||
onChange={setMessage}
|
||||
placeholder="Write your email here..."
|
||||
placeholder="Ecrivez votre mail ici..."
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="flex justify-between items-center">
|
||||
<button
|
||||
<div className="flex justify-between items-center mt-10">
|
||||
<Button
|
||||
text="Envoyer"
|
||||
onClick={handleSendEmail}
|
||||
className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
|
||||
>
|
||||
Send email
|
||||
</button>
|
||||
primary
|
||||
className="px-4 py-2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
import React from 'react';
|
||||
import Chat from '@/components/Chat';
|
||||
import { getGravatarUrl } from '@/utils/gravatar';
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
const contacts = [
|
||||
{
|
||||
@ -18,7 +19,7 @@ const contacts = [
|
||||
|
||||
export default function InstantMessaging({ csrfToken }) {
|
||||
const handleSendMessage = (contact, message) => {
|
||||
console.log(`Message envoyé à ${contact.name}: ${message}`);
|
||||
logger.debug(`Message envoyé à ${contact.name}: ${message}`);
|
||||
};
|
||||
|
||||
return <Chat contacts={contacts} onSendMessage={handleSendMessage} />;
|
||||
|
||||
@ -14,7 +14,7 @@ const AffectationClasseForm = ({ eleve = {}, onSubmit, classes }) => {
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
console.log(formData);
|
||||
logger.debug(formData);
|
||||
/*onSubmit({
|
||||
eleve: {
|
||||
...formData,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { usePlanning, PlanningModes } from '@/context/PlanningContext';
|
||||
import { Plus, Edit2, Eye, EyeOff, Check, X } from 'lucide-react';
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
export default function ScheduleNavigation({ classes, modeSet = 'event' }) {
|
||||
const {
|
||||
@ -118,7 +119,7 @@ export default function ScheduleNavigation({ classes, modeSet = 'event' }) {
|
||||
>
|
||||
<option value="">Aucune</option>
|
||||
{classes.map((classe) => {
|
||||
console.log({ classe });
|
||||
logger.debug({ classe });
|
||||
return (
|
||||
<option key={classe.id} value={classe.id}>
|
||||
{classe.atmosphere_name}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import logger from '@/utils/logger';
|
||||
import React from 'react';
|
||||
|
||||
const CheckBox = ({
|
||||
@ -8,7 +9,7 @@ const CheckBox = ({
|
||||
itemLabelFunc = () => null,
|
||||
horizontal,
|
||||
}) => {
|
||||
console.log(formData);
|
||||
logger.debug(formData);
|
||||
|
||||
// Vérifier si formData[fieldName] est un tableau ou une valeur booléenne
|
||||
const isChecked = Array.isArray(formData[fieldName])
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Check } from 'lucide-react';
|
||||
import Popup from '@/components/Popup';
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
const DateTab = ({
|
||||
dates,
|
||||
@ -29,13 +30,13 @@ const DateTab = ({
|
||||
handleEdit(paymentPlanId, dataWithType)
|
||||
.then(() => {
|
||||
setPopupMessage(
|
||||
`Mise à jour de la date d'échéance effectuée avec succès`
|
||||
"Mise à jour de la date d'échéance effectuée avec succès"
|
||||
);
|
||||
setPopupVisible(true);
|
||||
setModifiedDates({});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
logger.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -93,7 +93,6 @@ export default function FileUpload({
|
||||
{typeof existingFile === 'string'
|
||||
? existingFile.split('/').pop() // Si c'est une chaîne, utilisez split
|
||||
: existingFile?.name || 'Nom de fichier inconnu'}{' '}
|
||||
// Sinon, utilisez une propriété ou un fallback
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -22,6 +22,7 @@ const typeStyles = {
|
||||
};
|
||||
|
||||
export default function FlashNotification({
|
||||
displayPeriod = 3000,
|
||||
title,
|
||||
message,
|
||||
type = 'info',
|
||||
@ -33,9 +34,9 @@ export default function FlashNotification({
|
||||
const timer = setTimeout(() => {
|
||||
setIsVisible(false); // Déclenche la disparition
|
||||
setTimeout(onClose, 300); // Appelle onClose après l'animation
|
||||
}, 3000); // Notification visible pendant 3 secondes
|
||||
}, displayPeriod); // Notification visible pendant 3 secondes par défaut
|
||||
return () => clearTimeout(timer);
|
||||
}, [onClose]);
|
||||
}, [onClose, displayPeriod]);
|
||||
|
||||
if (!message || !isVisible) return null;
|
||||
|
||||
@ -47,14 +48,14 @@ export default function FlashNotification({
|
||||
animate={{ opacity: 1, x: 0 }} // Animation visible
|
||||
exit={{ opacity: 0, x: 50 }} // Animation de sortie
|
||||
transition={{ duration: 0.3 }} // Durée des animations
|
||||
className="fixed top-5 right-5 flex items-stretch w-96 rounded-lg shadow-lg bg-white z-50 border border-gray-200"
|
||||
className="fixed top-5 right-5 flex items-stretch rounded-lg shadow-lg bg-white z-50 border border-gray-200"
|
||||
>
|
||||
{/* Rectangle gauche avec l'icône */}
|
||||
<div className={`flex items-center justify-center w-12 ${bg}`}>
|
||||
<div className={`flex items-center justify-center w-14 ${bg}`}>
|
||||
{icon}
|
||||
</div>
|
||||
{/* Zone de texte */}
|
||||
<div className="flex-1 p-4">
|
||||
<div className="flex-1 w-96 p-4">
|
||||
<p className="font-bold text-black">{title}</p>
|
||||
<p className="text-gray-700">{message}</p>
|
||||
</div>
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
fetchParentFileTemplatesFromRegistrationFiles,
|
||||
} from '@/app/actions/subscriptionAction';
|
||||
import { BASE_URL } from '@/utils/Url';
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
const FilesModal = ({
|
||||
isOpen,
|
||||
@ -23,9 +24,7 @@ const FilesModal = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedRegisterForm?.student?.id) {
|
||||
console.error(
|
||||
'selectedRegisterForm.student.id est invalide ou manquant.'
|
||||
);
|
||||
logger.error('selectedRegisterForm.student.id est invalide ou manquant.');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -37,7 +36,7 @@ const FilesModal = ({
|
||||
)
|
||||
.then((schoolFiles) => {
|
||||
if (!Array.isArray(schoolFiles)) {
|
||||
console.error(
|
||||
logger.error(
|
||||
'Les fichiers scolaires ne sont pas un tableau :',
|
||||
schoolFiles
|
||||
);
|
||||
@ -84,7 +83,7 @@ const FilesModal = ({
|
||||
setFiles(categorizedFiles);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Erreur lors de la récupération des fichiers :', error);
|
||||
logger.error('Erreur lors de la récupération des fichiers :', error);
|
||||
});
|
||||
}, [selectedRegisterForm]);
|
||||
|
||||
@ -144,7 +143,7 @@ const FilesModal = ({
|
||||
{/* Section Fichiers École */}
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-gray-800 mb-4">
|
||||
Formulaires de l'établissement
|
||||
Formulaires de l'établissement
|
||||
</h3>
|
||||
<ul className="space-y-2">
|
||||
{files.schoolFiles.length > 0 ? (
|
||||
|
||||
@ -138,7 +138,7 @@ export default function InscriptionFormShared({
|
||||
|
||||
// Mettre à jour isPage6Valid en fonction de cette condition
|
||||
setIsPage6Valid(allRequiredUploaded);
|
||||
console.log(allRequiredUploaded);
|
||||
logger.debug(allRequiredUploaded);
|
||||
}, [parentFileTemplates]);
|
||||
|
||||
const handleTemplateSigned = (index) => {
|
||||
@ -420,7 +420,7 @@ export default function InscriptionFormShared({
|
||||
formDataToSend.append('photo', formData.photo);
|
||||
}
|
||||
|
||||
console.log('submit : ', jsonData);
|
||||
logger.debug('submit : ', jsonData);
|
||||
|
||||
// Appeler la fonction onSubmit avec les données FormData
|
||||
onSubmit(formDataToSend);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import SelectChoice from '@/components/SelectChoice';
|
||||
import RadioList from '@/components/RadioList';
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
export default function PaymentMethodSelector({
|
||||
formData,
|
||||
@ -18,7 +19,7 @@ export default function PaymentMethodSelector({
|
||||
(field) => getLocalError(field) !== ''
|
||||
);
|
||||
setIsPageValid(isValid);
|
||||
console.log('formdata : ', formData);
|
||||
logger.debug('formdata : ', formData);
|
||||
}, [formData, setIsPageValid]);
|
||||
|
||||
const paymentModesOptions = [
|
||||
@ -68,7 +69,7 @@ export default function PaymentMethodSelector({
|
||||
{/* Frais d'inscription */}
|
||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
||||
<h2 className="text-2xl font-semibold mb-6 text-gray-800 border-b pb-2">
|
||||
Frais d'inscription
|
||||
Frais d'inscription
|
||||
</h2>
|
||||
|
||||
<div className="mb-6 bg-gray-50 p-4 rounded-lg border border-gray-100">
|
||||
|
||||
@ -115,8 +115,8 @@ export default function ResponsableInputFields({
|
||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
||||
<SectionHeader
|
||||
icon={Users}
|
||||
title={`Responsables légaux`}
|
||||
description={`Remplissez les champs requis`}
|
||||
title={'Responsables légaux'}
|
||||
description={'Remplissez les champs requis'}
|
||||
/>
|
||||
{guardians.map((item, index) => (
|
||||
<div className="p-6 " key={index}>
|
||||
|
||||
@ -97,8 +97,8 @@ export default function SiblingInputFields({
|
||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
||||
<SectionHeader
|
||||
icon={Users}
|
||||
title={`Frères et Sœurs`}
|
||||
description={`Ajoutez les informations des frères et sœurs`}
|
||||
title={'Frères et Sœurs'}
|
||||
description={'Ajoutez les informations des frères et sœurs'}
|
||||
/>
|
||||
{siblings.map((item, index) => (
|
||||
<div className="p-6" key={index}>
|
||||
|
||||
@ -154,8 +154,8 @@ export default function StudentInfoForm({
|
||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200 space-y-8">
|
||||
<SectionHeader
|
||||
icon={User}
|
||||
title={`Informations de l'élève`}
|
||||
description={`Remplissez les champs requis`}
|
||||
title={"Informations de l'élève"}
|
||||
description={'Remplissez les champs requis'}
|
||||
/>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
<InputText
|
||||
|
||||
@ -126,7 +126,7 @@ export default function ValidateSubscription({
|
||||
]
|
||||
: []),
|
||||
];
|
||||
console.log(allTemplates);
|
||||
logger.debug(allTemplates);
|
||||
|
||||
return (
|
||||
<div className="mb-4 w-full mx-auto">
|
||||
|
||||
@ -4,6 +4,7 @@ import Table from '@/components/Table';
|
||||
import DateTab from '@/components/DateTab';
|
||||
import InputTextIcon from '@/components/InputTextIcon';
|
||||
import Popup from '@/components/Popup';
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
const paymentPlansOptions = [
|
||||
{ id: 0, name: '1 fois', frequency: 1 },
|
||||
@ -118,7 +119,7 @@ const PaymentPlanSelector = ({
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
logger.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
@ -222,13 +223,13 @@ const PaymentPlanSelector = ({
|
||||
handleEdit(selectedPlan.id, updatedData)
|
||||
.then(() => {
|
||||
setPopupMessage(
|
||||
`Mise à jour des dates d'échéances effectuée avec succès`
|
||||
"Mise à jour des dates d'échéances effectuée avec succès"
|
||||
);
|
||||
setPopupVisible(true);
|
||||
setIsDefaultDayModified(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
logger.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -8,10 +8,11 @@ import { NotificationProvider } from '@/context/NotificationContext';
|
||||
import { ClassesProvider } from '@/context/ClassesContext';
|
||||
import { DndProvider } from 'react-dnd';
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
export default function Providers({ children, messages, locale, session }) {
|
||||
if (!locale) {
|
||||
console.error('Locale non définie dans Providers');
|
||||
logger.error('Locale non définie dans Providers');
|
||||
locale = 'fr'; // Valeur par défaut
|
||||
}
|
||||
return (
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { getGravatarUrl } from '@/utils/gravatar'; // Assurez-vous que cette fonction est définie pour générer les URLs Gravatar
|
||||
import { getRightStr } from '@/utils/rights'; // Fonction existante pour récupérer le nom des rôles
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
export default function RecipientInput({
|
||||
label,
|
||||
@ -8,6 +9,7 @@ export default function RecipientInput({
|
||||
setRecipients,
|
||||
searchRecipients, // Fonction pour effectuer la recherche
|
||||
establishmentId, // ID de l'établissement
|
||||
required = false, // Ajout de la prop required avec valeur par défaut
|
||||
}) {
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const [suggestions, setSuggestions] = useState([]);
|
||||
@ -22,7 +24,7 @@ export default function RecipientInput({
|
||||
const results = await searchRecipients(establishmentId, value);
|
||||
setSuggestions(results);
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la recherche des destinataires:', error);
|
||||
logger.error('Erreur lors de la recherche des destinataires:', error);
|
||||
setSuggestions([]);
|
||||
}
|
||||
} else {
|
||||
@ -37,8 +39,8 @@ export default function RecipientInput({
|
||||
handleSuggestionClick(suggestions[selectedIndex]);
|
||||
} else {
|
||||
const trimmedValue = inputValue.trim();
|
||||
if (trimmedValue && !recipients.some((r) => r.email === trimmedValue)) {
|
||||
setRecipients([...recipients, { email: trimmedValue }]);
|
||||
if (trimmedValue && !recipients.includes(trimmedValue)) {
|
||||
setRecipients([...recipients, trimmedValue]);
|
||||
setInputValue('');
|
||||
setSuggestions([]);
|
||||
}
|
||||
@ -57,39 +59,44 @@ export default function RecipientInput({
|
||||
};
|
||||
|
||||
const handleSuggestionClick = (suggestion) => {
|
||||
if (!recipients.some((r) => r.email === suggestion.email)) {
|
||||
setRecipients([...recipients, suggestion]);
|
||||
if (!recipients.includes(suggestion.email)) {
|
||||
setRecipients([...recipients, suggestion.email]);
|
||||
}
|
||||
setInputValue('');
|
||||
setSuggestions([]);
|
||||
};
|
||||
|
||||
const handleRemoveRecipient = (email) => {
|
||||
setRecipients(recipients.filter((recipient) => recipient.email !== email));
|
||||
setRecipients(recipients.filter((recipient) => recipient !== email));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-4">
|
||||
<label className="block text-sm font-medium text-gray-700">{label}</label>
|
||||
<div className="flex flex-wrap items-center gap-2 p-2 border rounded">
|
||||
{recipients.map((recipient, index) => (
|
||||
<label className="block text-sm font-medium text-gray-700">
|
||||
{label}
|
||||
{required && <span className="text-red-500 ml-1">*</span>}
|
||||
</label>
|
||||
<div
|
||||
className={`
|
||||
mt-1 flex flex-wrap items-center gap-2 border rounded-md
|
||||
border-gray-200 hover:border-gray-400 focus-within:border-gray-500
|
||||
transition-colors
|
||||
`}
|
||||
>
|
||||
{recipients.map((email, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center bg-gray-100 text-gray-700 px-2 py-1 rounded-full"
|
||||
>
|
||||
<img
|
||||
src={getGravatarUrl(recipient.email)}
|
||||
alt={recipient.email}
|
||||
src={getGravatarUrl(email)}
|
||||
alt={email}
|
||||
className="w-6 h-6 rounded-full mr-2"
|
||||
/>
|
||||
<span className="mr-2">
|
||||
{recipient.first_name && recipient.last_name
|
||||
? `${recipient.first_name} ${recipient.last_name}`
|
||||
: recipient.email}
|
||||
</span>
|
||||
<span className="mr-2">{email}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRemoveRecipient(recipient.email)}
|
||||
onClick={() => handleRemoveRecipient(email)}
|
||||
className="text-gray-500 hover:text-gray-700"
|
||||
>
|
||||
×
|
||||
@ -102,7 +109,8 @@ export default function RecipientInput({
|
||||
onChange={handleInputChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder="Rechercher des destinataires"
|
||||
className="flex-1 p-1 outline-none"
|
||||
className="flex-1 px-3 py-2 block w-full sm:text-sm border-none focus:ring-0 outline-none rounded-md"
|
||||
required={required}
|
||||
/>
|
||||
</div>
|
||||
{suggestions.length > 0 && (
|
||||
|
||||
@ -52,7 +52,7 @@ export default function FileUploadDocuSeal({
|
||||
setToken(data.token);
|
||||
})
|
||||
.catch((error) =>
|
||||
console.error('Erreur lors de la génération du token:', error)
|
||||
logger.error('Erreur lors de la génération du token:', error)
|
||||
);
|
||||
}, [fileToEdit]);
|
||||
|
||||
@ -129,7 +129,7 @@ export default function FileUploadDocuSeal({
|
||||
master: templateMaster?.id,
|
||||
registration_form: guardian.registration_form,
|
||||
};
|
||||
console.log('creation : ', data);
|
||||
logger.debug('creation : ', data);
|
||||
createRegistrationSchoolFileTemplate(data, csrfToken)
|
||||
.then((response) => {
|
||||
logger.debug('Template enregistré avec succès:', response);
|
||||
@ -166,13 +166,13 @@ export default function FileUploadDocuSeal({
|
||||
<div className="flex flex-col items-center justify-center h-full text-center space-y-6">
|
||||
{/* Description de l'étape */}
|
||||
<p className="text-gray-700 text-base font-medium mb-4">
|
||||
Étape 1 - Sélectionner au moins un dossier d'inscription
|
||||
Étape 1 - Sélectionner au moins un dossier d'inscription
|
||||
</p>
|
||||
|
||||
{/* Section centrée pour la sélection des groupes */}
|
||||
<div className="bg-gray-50 p-8 rounded-lg shadow-md border border-gray-300 transform transition-transform hover:scale-105">
|
||||
<h3 className="text-xl font-semibold text-gray-800 mb-4 text-center">
|
||||
Dossiers d'inscription
|
||||
Dossiers d'inscription
|
||||
</h3>
|
||||
<MultiSelect
|
||||
name="groups"
|
||||
@ -190,7 +190,7 @@ export default function FileUploadDocuSeal({
|
||||
{/* Section Dossiers d'inscription repositionnée sur le côté */}
|
||||
<div className="col-span-2 bg-white p-4 rounded-lg shadow-md border border-gray-200">
|
||||
<h3 className="text-lg font-medium text-gray-800 mb-4">
|
||||
Dossiers d'inscription
|
||||
Dossiers d'inscription
|
||||
</h3>
|
||||
<MultiSelect
|
||||
name="groups"
|
||||
|
||||
@ -97,7 +97,7 @@ export default function FilesGroupsManagement({
|
||||
}
|
||||
)
|
||||
.catch((err) => {
|
||||
console.log(err.message);
|
||||
logger.debug(err.message);
|
||||
})
|
||||
.finally(() => {
|
||||
setReloadTemplates(false);
|
||||
@ -155,7 +155,7 @@ export default function FilesGroupsManagement({
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error deleting file from database:', error);
|
||||
logger.error('Error deleting file from database:', error);
|
||||
showNotification(
|
||||
`Erreur lors de la suppression du document "${templateMaster.name}".`,
|
||||
'error',
|
||||
@ -175,7 +175,7 @@ export default function FilesGroupsManagement({
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error removing template from DocuSeal:', error);
|
||||
logger.error('Error removing template from DocuSeal:', error);
|
||||
showNotification(
|
||||
`Erreur lors de la suppression du document "${templateMaster.name}".`,
|
||||
'error',
|
||||
@ -207,7 +207,7 @@ export default function FilesGroupsManagement({
|
||||
return response;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error removing template:', error);
|
||||
logger.error('Error removing template:', error);
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
@ -235,7 +235,7 @@ export default function FilesGroupsManagement({
|
||||
setIsModalOpen(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error uploading file:', error);
|
||||
logger.error('Error uploading file:', error);
|
||||
});
|
||||
};
|
||||
|
||||
@ -258,7 +258,7 @@ export default function FilesGroupsManagement({
|
||||
setIsModalOpen(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error editing file:', error);
|
||||
logger.error('Error editing file:', error);
|
||||
showNotification(
|
||||
'Erreur lors de la modification du fichier',
|
||||
'error',
|
||||
@ -280,7 +280,7 @@ export default function FilesGroupsManagement({
|
||||
setIsGroupModalOpen(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error handling group:', error);
|
||||
logger.error('Error handling group:', error);
|
||||
showNotification(
|
||||
"Erreur lors de l'opération sur le groupe",
|
||||
'error',
|
||||
@ -300,7 +300,7 @@ export default function FilesGroupsManagement({
|
||||
setIsGroupModalOpen(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error handling group:', error);
|
||||
logger.error('Error handling group:', error);
|
||||
showNotification(
|
||||
"Erreur lors de l'opération sur le groupe",
|
||||
'error',
|
||||
@ -349,7 +349,7 @@ export default function FilesGroupsManagement({
|
||||
showNotification('Groupe supprimé avec succès.', 'success', 'Succès');
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error deleting group:', error);
|
||||
logger.error('Error deleting group:', error);
|
||||
setRemovePopupVisible(false);
|
||||
setIsLoading(false);
|
||||
showNotification(
|
||||
|
||||
@ -54,7 +54,7 @@ const FeesManagement = ({
|
||||
<div className="w-4/5 mx-auto flex items-center mt-8">
|
||||
<hr className="flex-grow border-t-2 border-gray-300" />
|
||||
<span className="mx-4 text-gray-600 font-semibold">
|
||||
Frais d'inscription
|
||||
Frais d'inscription
|
||||
</span>
|
||||
<hr className="flex-grow border-t-2 border-gray-300" />
|
||||
</div>
|
||||
|
||||
@ -257,9 +257,7 @@ const FeesSection = ({
|
||||
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 ?"
|
||||
`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)
|
||||
|
||||
61
Front-End/src/components/WisiwigTextArea.js
Normal file
61
Front-End/src/components/WisiwigTextArea.js
Normal file
@ -0,0 +1,61 @@
|
||||
import dynamic from 'next/dynamic';
|
||||
import 'react-quill/dist/quill.snow.css';
|
||||
|
||||
const ReactQuill = dynamic(() => import('react-quill'), { ssr: false });
|
||||
|
||||
export default function WisiwigTextArea({
|
||||
label = 'Mail',
|
||||
value,
|
||||
onChange,
|
||||
placeholder = 'Ecrivez votre mail ici...',
|
||||
className = 'h-64',
|
||||
required = false,
|
||||
errorMsg,
|
||||
errorLocalMsg,
|
||||
enable = true,
|
||||
}) {
|
||||
return (
|
||||
<div className={`mb-4 ${className}`}>
|
||||
<label className="block text-sm font-medium text-gray-700">
|
||||
{label}
|
||||
{required && <span className="text-red-500 ml-1">*</span>}
|
||||
</label>
|
||||
<div
|
||||
className={`
|
||||
mt-1 border rounded-md
|
||||
${
|
||||
errorMsg || errorLocalMsg
|
||||
? 'border-red-500 hover:border-red-700'
|
||||
: 'border-gray-200 hover:border-gray-400'
|
||||
}
|
||||
${!errorMsg && !errorLocalMsg ? 'focus-within:border-gray-500' : ''}
|
||||
${!enable ? 'bg-gray-100 cursor-not-allowed' : ''}
|
||||
`}
|
||||
>
|
||||
<ReactQuill
|
||||
theme="snow"
|
||||
value={value}
|
||||
onChange={enable ? onChange : undefined}
|
||||
placeholder={placeholder}
|
||||
readOnly={!enable}
|
||||
className={`bg-white rounded-md border-0 shadow-none !border-0 !outline-none ${!enable ? 'bg-gray-100 cursor-not-allowed' : ''}`}
|
||||
style={{ minHeight: 250, border: 'none', boxShadow: 'none' }}
|
||||
/>
|
||||
</div>
|
||||
{errorMsg && <p className="mt-2 text-sm text-red-600">{errorMsg}</p>}
|
||||
{errorLocalMsg && (
|
||||
<p className="mt-2 text-sm text-red-600">{errorLocalMsg}</p>
|
||||
)}
|
||||
<style jsx global>{`
|
||||
.ql-toolbar.ql-snow {
|
||||
border: none !important;
|
||||
border-bottom: 1px solid #e5e7eb !important; /* gray-200 */
|
||||
border-radius: 0.375rem 0.375rem 0 0 !important; /* rounded-t-md */
|
||||
}
|
||||
.ql-container.ql-snow {
|
||||
border: none !important;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user