mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 07:53:23 +00:00
chore: merge conflicts
This commit is contained in:
@ -66,6 +66,7 @@ MIDDLEWARE = [
|
|||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
'N3wtSchool.middleware.ContentSecurityPolicyMiddleware'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -261,7 +262,6 @@ CSRF_COOKIE_HTTPONLY = False
|
|||||||
CSRF_COOKIE_SECURE = False
|
CSRF_COOKIE_SECURE = False
|
||||||
CSRF_COOKIE_NAME = 'csrftoken'
|
CSRF_COOKIE_NAME = 'csrftoken'
|
||||||
|
|
||||||
|
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
TZ_APPLI = 'Europe/Paris'
|
TZ_APPLI = 'Europe/Paris'
|
||||||
|
|
||||||
@ -328,3 +328,10 @@ SIMPLE_JWT = {
|
|||||||
'TOKEN_TYPE_CLAIM': 'token_type',
|
'TOKEN_TYPE_CLAIM': 'token_type',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Configuration for DocuSeal JWT
|
||||||
|
DOCUSEAL_JWT = {
|
||||||
|
'ALGORITHM': 'HS256',
|
||||||
|
'SIGNING_KEY': SECRET_KEY,
|
||||||
|
'EXPIRATION_DELTA': timedelta(hours=1),
|
||||||
|
'API_KEY': '1kzHsXqN8P2ezUGT7TjVuBwM1hqtLsztrVSsQ87T7Mz'
|
||||||
|
}
|
||||||
@ -44,6 +44,7 @@ urlpatterns = [
|
|||||||
path("GestionMessagerie/", include(("GestionMessagerie.urls", 'GestionMessagerie'), namespace='GestionMessagerie')),
|
path("GestionMessagerie/", include(("GestionMessagerie.urls", 'GestionMessagerie'), namespace='GestionMessagerie')),
|
||||||
path("GestionNotification/", include(("GestionNotification.urls", 'GestionNotification'), namespace='GestionNotification')),
|
path("GestionNotification/", include(("GestionNotification.urls", 'GestionNotification'), namespace='GestionNotification')),
|
||||||
path("School/", include(("School.urls", 'School'), namespace='School')),
|
path("School/", include(("School.urls", 'School'), namespace='School')),
|
||||||
|
path("DocuSeal/", include(("DocuSeal.urls", 'DocuSeal'), namespace='DocuSeal')),
|
||||||
# Documentation Api
|
# Documentation Api
|
||||||
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
|
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
|
||||||
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
|
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
|
||||||
|
|||||||
@ -25,6 +25,18 @@ const nextConfig = {
|
|||||||
AUTH_SECRET: process.env.AUTH_SECRET || 'false',
|
AUTH_SECRET: process.env.AUTH_SECRET || 'false',
|
||||||
NEXTAUTH_URL: process.env.NEXTAUTH_URL || "http://localhost:3000",
|
NEXTAUTH_URL: process.env.NEXTAUTH_URL || "http://localhost:3000",
|
||||||
},
|
},
|
||||||
|
async rewrites() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/api/documents/:path*',
|
||||||
|
destination: 'https://api.docuseal.com/v1/documents/:path*',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
source: '/api/auth/:path*',
|
||||||
|
destination: '/api/auth/:path*', // Exclure les routes NextAuth des réécritures de proxy
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withNextIntl(nextConfig);
|
export default withNextIntl(nextConfig);
|
||||||
7
Front-End/package-lock.json
generated
7
Front-End/package-lock.json
generated
@ -8,6 +8,7 @@
|
|||||||
"name": "n3wt-school-front-end",
|
"name": "n3wt-school-front-end",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@docuseal/react": "^1.0.56",
|
||||||
"@radix-ui/react-dialog": "^1.1.2",
|
"@radix-ui/react-dialog": "^1.1.2",
|
||||||
"@tailwindcss/forms": "^0.5.9",
|
"@tailwindcss/forms": "^0.5.9",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
@ -201,6 +202,12 @@
|
|||||||
"kuler": "^2.0.0"
|
"kuler": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@docuseal/react": {
|
||||||
|
"version": "1.0.56",
|
||||||
|
"resolved": "https://registry.npmjs.org/@docuseal/react/-/react-1.0.56.tgz",
|
||||||
|
"integrity": "sha512-xna62Op4WLIVmgz2U0mi4paFayslxBUk2P8u3D70e1JgVRXsPFwzH6b1WhotedN9PMPS+cG2HP1PmpYoEzdZTQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@eslint-community/eslint-utils": {
|
"node_modules/@eslint-community/eslint-utils": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
"check-strings": "node scripts/check-hardcoded-strings.js"
|
"check-strings": "node scripts/check-hardcoded-strings.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@docuseal/react": "^1.0.56",
|
||||||
"@radix-ui/react-dialog": "^1.1.2",
|
"@radix-ui/react-dialog": "^1.1.2",
|
||||||
"@tailwindcss/forms": "^0.5.9",
|
"@tailwindcss/forms": "^0.5.9",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
|
||||||
export default function InputPhone({ name, label, value, onChange, errorMsg, placeholder, className }) {
|
export default function InputPhone({ name, label, value, onChange, errorMsg, placeholder, className, required }) {
|
||||||
const inputRef = useRef(null);
|
const inputRef = useRef(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -18,7 +18,10 @@ export default function InputPhone({ name, label, value, onChange, errorMsg, pla
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={`mb-4 ${className}`}>
|
<div className={`mb-4 ${className}`}>
|
||||||
<label htmlFor={name} className="block text-sm font-medium text-gray-700">{label}</label>
|
<label htmlFor={name} 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 items-center border border-gray-200 rounded-md ${errorMsg ? 'border-red-500' : ''} hover:border-gray-400 focus-within:border-gray-500`}>
|
<div className={`mt-1 flex items-center border border-gray-200 rounded-md ${errorMsg ? 'border-red-500' : ''} hover:border-gray-400 focus-within:border-gray-500`}>
|
||||||
<input
|
<input
|
||||||
type="tel"
|
type="tel"
|
||||||
|
|||||||
@ -15,14 +15,9 @@ import DraggableFileUpload from '@/components/DraggableFileUpload';
|
|||||||
import Modal from '@/components/Modal';
|
import Modal from '@/components/Modal';
|
||||||
import FileStatusLabel from '@/components/FileStatusLabel';
|
import FileStatusLabel from '@/components/FileStatusLabel';
|
||||||
import logger from '@/utils/logger';
|
import logger from '@/utils/logger';
|
||||||
|
import StudentInfoForm from '@/components/Inscription/StudentInfoForm';
|
||||||
// Définition des niveaux scolaires disponibles
|
import FilesToSign from '@/components/Inscription/FilesToSign';
|
||||||
const levels = [
|
import FilesToUpload from '@/components/Inscription/FilesToUpload';
|
||||||
{ value:'1', label: 'TPS - Très Petite Section'},
|
|
||||||
{ value:'2', label: 'PS - Petite Section'},
|
|
||||||
{ value:'3', label: 'MS - Moyenne Section'},
|
|
||||||
{ value:'4', label: 'GS - Grande Section'},
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Composant de formulaire d'inscription partagé
|
* Composant de formulaire d'inscription partagé
|
||||||
@ -65,6 +60,8 @@ export default function InscriptionFormShared({
|
|||||||
const [showUploadModal, setShowUploadModal] = useState(false);
|
const [showUploadModal, setShowUploadModal] = useState(false);
|
||||||
const [currentTemplateId, setCurrentTemplateId] = useState(null);
|
const [currentTemplateId, setCurrentTemplateId] = useState(null);
|
||||||
|
|
||||||
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
|
||||||
// Chargement initial des données
|
// Chargement initial des données
|
||||||
// Mettre à jour les données quand initialData change
|
// Mettre à jour les données quand initialData change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -185,6 +182,21 @@ export default function InscriptionFormShared({
|
|||||||
return errors?.student?.[field]?.[0];
|
return errors?.student?.[field]?.[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleNextPage = () => {
|
||||||
|
setCurrentPage(currentPage + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePreviousPage = () => {
|
||||||
|
setCurrentPage(currentPage - 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const requiredFileTemplates = fileTemplates.filter(template => template.is_required);
|
||||||
|
|
||||||
|
// Ajout des logs pour débogage
|
||||||
|
console.log('BASE_URL:', BASE_URL);
|
||||||
|
console.log('requiredFileTemplates:', requiredFileTemplates);
|
||||||
|
console.log('currentPage:', currentPage);
|
||||||
|
|
||||||
// Configuration des colonnes pour le tableau des fichiers
|
// Configuration des colonnes pour le tableau des fichiers
|
||||||
const columns = [
|
const columns = [
|
||||||
{ name: 'Nom du fichier', transform: (row) => row.name },
|
{ name: 'Nom du fichier', transform: (row) => row.name },
|
||||||
@ -248,128 +260,54 @@ export default function InscriptionFormShared({
|
|||||||
<div className="max-w-4xl mx-auto p-6">
|
<div className="max-w-4xl mx-auto p-6">
|
||||||
<form onSubmit={handleSubmit} className="space-y-8">
|
<form onSubmit={handleSubmit} className="space-y-8">
|
||||||
<DjangoCSRFToken csrfToken={csrfToken}/>
|
<DjangoCSRFToken csrfToken={csrfToken}/>
|
||||||
{/* Section Élève */}
|
{/* Page 1 : Informations de l'élève et Responsables */}
|
||||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
{currentPage === 1 && (
|
||||||
<h2 className="text-xl font-bold mb-4 text-gray-800">Informations de l'élève</h2>
|
<StudentInfoForm
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
formData={formData}
|
||||||
<InputText
|
updateFormField={updateFormField}
|
||||||
name="last_name"
|
|
||||||
label="Nom"
|
|
||||||
value={formData.last_name}
|
|
||||||
onChange={(e) => updateFormField('last_name', e.target.value)}
|
|
||||||
required
|
|
||||||
errorMsg={getError('last_name')}
|
|
||||||
/>
|
|
||||||
<InputText
|
|
||||||
name="first_name"
|
|
||||||
label="Prénom"
|
|
||||||
value={formData.first_name}
|
|
||||||
onChange={(e) => updateFormField('first_name', e.target.value)}
|
|
||||||
errorMsg={getError('first_name')}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<InputText
|
|
||||||
name="nationality"
|
|
||||||
label="Nationalité"
|
|
||||||
value={formData.nationality}
|
|
||||||
onChange={(e) => updateFormField('nationality', e.target.value)}
|
|
||||||
/>
|
|
||||||
<InputText
|
|
||||||
name="birth_date"
|
|
||||||
type="date"
|
|
||||||
label="Date de Naissance"
|
|
||||||
value={formData.birth_date}
|
|
||||||
onChange={(e) => updateFormField('birth_date', e.target.value)}
|
|
||||||
required
|
|
||||||
errorMsg={getError('birth_date')}
|
|
||||||
/>
|
|
||||||
<InputText
|
|
||||||
name="birth_place"
|
|
||||||
label="Lieu de Naissance"
|
|
||||||
value={formData.birth_place}
|
|
||||||
onChange={(e) => updateFormField('birth_place', e.target.value)}
|
|
||||||
errorMsg={getError('birth_place')}
|
|
||||||
/>
|
|
||||||
<InputText
|
|
||||||
name="birth_postal_code"
|
|
||||||
label="Code Postal de Naissance"
|
|
||||||
value={formData.birth_postal_code}
|
|
||||||
onChange={(e) => updateFormField('birth_postal_code', e.target.value)}
|
|
||||||
required
|
|
||||||
errorMsg={getError('birth_postal_code')}
|
|
||||||
/>
|
|
||||||
<div className="md:col-span-2">
|
|
||||||
<InputText
|
|
||||||
name="address"
|
|
||||||
label="Adresse"
|
|
||||||
value={formData.address}
|
|
||||||
onChange={(e) => updateFormField('address', e.target.value)}
|
|
||||||
errorMsg={getError('address')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<InputText
|
|
||||||
name="attending_physician"
|
|
||||||
label="Médecin Traitant"
|
|
||||||
value={formData.attending_physician}
|
|
||||||
onChange={(e) => updateFormField('attending_physician', e.target.value)}
|
|
||||||
errorMsg={getError('attending_physician')}
|
|
||||||
/>
|
|
||||||
<SelectChoice
|
|
||||||
name="level"
|
|
||||||
label="Niveau"
|
|
||||||
placeHolder="Sélectionner un niveau"
|
|
||||||
selected={formData.level}
|
|
||||||
callback={(e) => updateFormField('level', e.target.value)}
|
|
||||||
choices={levels}
|
|
||||||
required
|
|
||||||
errorMsg={getError('level')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Section Responsables */}
|
|
||||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
|
||||||
<h2 className="text-xl font-bold mb-4 text-gray-800">Responsables</h2>
|
|
||||||
<ResponsableInputFields
|
|
||||||
guardians={guardians}
|
guardians={guardians}
|
||||||
onGuardiansChange={(id, field, value) => {
|
setGuardians={setGuardians}
|
||||||
const updatedGuardians = guardians.map(resp =>
|
errors={errors}
|
||||||
resp.id === id ? { ...resp, [field]: value } : resp
|
|
||||||
);
|
|
||||||
setGuardians(updatedGuardians);
|
|
||||||
}}
|
|
||||||
addGuardian={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setGuardians([...guardians, { id: Date.now() }]);
|
|
||||||
}}
|
|
||||||
deleteGuardian={(index) => {
|
|
||||||
const newArray = [...guardians];
|
|
||||||
newArray.splice(index, 1);
|
|
||||||
setGuardians(newArray);
|
|
||||||
}}
|
|
||||||
errors={errors?.student?.guardians || []}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
)}
|
||||||
|
|
||||||
{/* Section Fichiers d'inscription */}
|
{/* Pages suivantes : Section Fichiers d'inscription */}
|
||||||
{fileTemplates.length > 0 && (
|
{currentPage > 1 && currentPage <= requiredFileTemplates.length + 1 && (
|
||||||
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
<div className="bg-white p-6 rounded-lg shadow-sm border border-gray-200">
|
||||||
<h2 className="text-xl font-bold mb-4 text-gray-800">Fichiers à remplir</h2>
|
<h2 className="text-xl font-bold mb-4 text-gray-800">{requiredFileTemplates[currentPage - 2].name}</h2>
|
||||||
<Table
|
<iframe
|
||||||
data={fileTemplates}
|
src={`${BASE_URL}/data/${requiredFileTemplates[currentPage - 2].file}?signature=true`}
|
||||||
columns={columns}
|
width="100%"
|
||||||
itemsPerPage={5}
|
height="800px"
|
||||||
currentPage={1}
|
className="w-full" // Utiliser la classe CSS pour la largeur
|
||||||
totalPages={1}
|
title={requiredFileTemplates[currentPage - 2].name}
|
||||||
onPageChange={() => {}}
|
>
|
||||||
/>
|
<p>Votre navigateur ne prend pas en charge les fichiers PDF. Vous pouvez télécharger le fichier en cliquant <a href={`${BASE_URL}/data/${requiredFileTemplates[currentPage - 2].file}`}>ici</a>.</p>
|
||||||
|
</iframe>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Dernière page : Section Fichiers parents */}
|
||||||
|
{currentPage === requiredFileTemplates.length + 2 && (
|
||||||
|
<>
|
||||||
|
<FilesToUpload
|
||||||
|
fileTemplates={fileTemplates.filter(template => !template.is_required)}
|
||||||
|
columns={columns}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Boutons de contrôle */}
|
{/* Boutons de contrôle */}
|
||||||
<div className="flex justify-end space-x-4">
|
<div className="flex justify-end space-x-4">
|
||||||
<Button href={cancelUrl} text="Annuler" />
|
{currentPage > 1 && (
|
||||||
|
<Button text="Précédent" onClick={(e) => { e.preventDefault(); handlePreviousPage(); }} />
|
||||||
|
)}
|
||||||
|
{currentPage < requiredFileTemplates.length + 2 && (
|
||||||
|
<Button text="Suivant" onClick={(e) => { e.preventDefault(); handleNextPage(); }} />
|
||||||
|
)}
|
||||||
|
{currentPage === requiredFileTemplates.length + 2 && (
|
||||||
<Button type="submit" text="Valider" primary />
|
<Button type="submit" text="Valider" primary />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{fileTemplates.length > 0 && (
|
{fileTemplates.length > 0 && (
|
||||||
|
|||||||
@ -58,6 +58,7 @@ export default function ResponsableInputFields({guardians, onGuardiansChange, ad
|
|||||||
label={t('email')}
|
label={t('email')}
|
||||||
value={item.email}
|
value={item.email}
|
||||||
onChange={(event) => {onGuardiansChange(item.id, "email", event.target.value)}}
|
onChange={(event) => {onGuardiansChange(item.id, "email", event.target.value)}}
|
||||||
|
required
|
||||||
errorMsg={getError(index, 'email')}
|
errorMsg={getError(index, 'email')}
|
||||||
/>
|
/>
|
||||||
<InputPhone
|
<InputPhone
|
||||||
@ -65,6 +66,7 @@ export default function ResponsableInputFields({guardians, onGuardiansChange, ad
|
|||||||
label={t('phone')}
|
label={t('phone')}
|
||||||
value={item.phone}
|
value={item.phone}
|
||||||
onChange={(event) => {onGuardiansChange(item.id, "phone", event)}}
|
onChange={(event) => {onGuardiansChange(item.id, "phone", event)}}
|
||||||
|
required
|
||||||
errorMsg={getError(index, 'phone')}
|
errorMsg={getError(index, 'phone')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -76,6 +78,7 @@ export default function ResponsableInputFields({guardians, onGuardiansChange, ad
|
|||||||
label={t('birthdate')}
|
label={t('birthdate')}
|
||||||
value={item.birth_date}
|
value={item.birth_date}
|
||||||
onChange={(event) => {onGuardiansChange(item.id, "birth_date", event.target.value)}}
|
onChange={(event) => {onGuardiansChange(item.id, "birth_date", event.target.value)}}
|
||||||
|
required
|
||||||
errorMsg={getError(index, 'birth_date')}
|
errorMsg={getError(index, 'birth_date')}
|
||||||
/>
|
/>
|
||||||
<InputText
|
<InputText
|
||||||
@ -84,6 +87,7 @@ export default function ResponsableInputFields({guardians, onGuardiansChange, ad
|
|||||||
label={t('profession')}
|
label={t('profession')}
|
||||||
value={item.profession}
|
value={item.profession}
|
||||||
onChange={(event) => {onGuardiansChange(item.id, "profession", event.target.value)}}
|
onChange={(event) => {onGuardiansChange(item.id, "profession", event.target.value)}}
|
||||||
|
required
|
||||||
errorMsg={getError(index, 'profession')}
|
errorMsg={getError(index, 'profession')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -95,6 +99,7 @@ export default function ResponsableInputFields({guardians, onGuardiansChange, ad
|
|||||||
label={t('address')}
|
label={t('address')}
|
||||||
value={item.address}
|
value={item.address}
|
||||||
onChange={(event) => {onGuardiansChange(item.id, "address", event.target.value)}}
|
onChange={(event) => {onGuardiansChange(item.id, "address", event.target.value)}}
|
||||||
|
required
|
||||||
errorMsg={getError(index, 'address')}
|
errorMsg={getError(index, 'address')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
export default function SelectChoice({ type, name, label, required, placeHolder, choices, callback, selected, errorMsg, IconItem, disabled = false }) {
|
export default function SelectChoice({ type, name, label, required, placeHolder, choices, callback, selected, errorMsg, IconItem, disabled = false }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div>
|
||||||
<label htmlFor={name} className="block text-sm font-medium text-gray-700">
|
<label htmlFor={name} className="block text-sm font-medium text-gray-700">
|
||||||
{label}
|
{label}
|
||||||
{required && <span className="text-red-500 ml-1">*</span>}
|
{required && <span className="text-red-500 ml-1">*</span>}
|
||||||
@ -29,6 +30,7 @@ export default function SelectChoice({ type, name, label, required, placeHolder,
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
{errorMsg && <p className="mt-2 text-sm text-red-600">{errorMsg}</p>}
|
{errorMsg && <p className="mt-2 text-sm text-red-600">{errorMsg}</p>}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Plus, Download, Edit, Trash2, FolderPlus } from 'lucide-react';
|
import { Plus, Download, Edit, Trash2, FolderPlus, Signature } from 'lucide-react';
|
||||||
import Modal from '@/components/Modal';
|
import Modal from '@/components/Modal';
|
||||||
import Table from '@/components/Table';
|
import Table from '@/components/Table';
|
||||||
import FileUpload from '@/components/FileUpload';
|
import FileUpload from '@/components/FileUpload';
|
||||||
@ -29,6 +29,8 @@ export default function FilesManagement({ csrfToken }) {
|
|||||||
const [fileToEdit, setFileToEdit] = useState(null);
|
const [fileToEdit, setFileToEdit] = useState(null);
|
||||||
const [isGroupModalOpen, setIsGroupModalOpen] = useState(false);
|
const [isGroupModalOpen, setIsGroupModalOpen] = useState(false);
|
||||||
const [groupToEdit, setGroupToEdit] = useState(null);
|
const [groupToEdit, setGroupToEdit] = useState(null);
|
||||||
|
const [token, setToken] = useState(null);
|
||||||
|
const [selectedFile, setSelectedFile] = useState(null);
|
||||||
|
|
||||||
// Fonction pour transformer les données des fichiers avec les informations complètes du groupe
|
// Fonction pour transformer les données des fichiers avec les informations complètes du groupe
|
||||||
const transformFileData = (file, groups) => {
|
const transformFileData = (file, groups) => {
|
||||||
@ -204,6 +206,9 @@ export default function FilesManagement({ csrfToken }) {
|
|||||||
<button onClick={() => handleFileDelete(row.id)} className="text-red-500 hover:text-red-700">
|
<button onClick={() => handleFileDelete(row.id)} className="text-red-500 hover:text-red-700">
|
||||||
<Trash2 size={16} />
|
<Trash2 size={16} />
|
||||||
</button>
|
</button>
|
||||||
|
<button onClick={() => handleSignatureRequest(row)} className="text-green-500 hover:text-green-700">
|
||||||
|
<Signature size={16} />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
];
|
];
|
||||||
@ -223,6 +228,28 @@ export default function FilesManagement({ csrfToken }) {
|
|||||||
)}
|
)}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Fonction pour gérer la demande de signature
|
||||||
|
const handleSignatureRequest = (file) => {
|
||||||
|
fetch('http://localhost:8080/DocuSeal/generateToken', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
document_id: file.id,
|
||||||
|
user_email: 'anthony.casini.30@gmail.com',
|
||||||
|
url: file.file
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
console.log("token received : ", data.token);
|
||||||
|
setToken(data.token);
|
||||||
|
setSelectedFile(file);
|
||||||
|
})
|
||||||
|
.catch((error) => console.error(error));
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Modal
|
<Modal
|
||||||
@ -297,6 +324,14 @@ export default function FilesManagement({ csrfToken }) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{token && selectedFile && (
|
||||||
|
<DocusealBuilder
|
||||||
|
token={token}
|
||||||
|
headers={{
|
||||||
|
'Authorization': `Bearer Rh2CC75ZMZqirmtBGA5NRjUzj8hr9eDYTBeZxv3jgzb`
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,15 @@ services:
|
|||||||
POSTGRES_DB: school
|
POSTGRES_DB: school
|
||||||
TZ: Europe/Paris
|
TZ: Europe/Paris
|
||||||
|
|
||||||
|
docuseal:
|
||||||
|
image: docuseal/docuseal:latest
|
||||||
|
depends_on:
|
||||||
|
- database
|
||||||
|
ports:
|
||||||
|
- 3001:3000
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgresql://postgres:postgres@database:5432/docuseal
|
||||||
|
|
||||||
backend:
|
backend:
|
||||||
build:
|
build:
|
||||||
context: ./Back-End
|
context: ./Back-End
|
||||||
@ -37,19 +46,20 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
- database
|
- database
|
||||||
|
- docuseal
|
||||||
command: python start.py
|
command: python start.py
|
||||||
|
|
||||||
frontend:
|
# frontend:
|
||||||
build:
|
# build:
|
||||||
context: ./Front-End
|
# context: ./Front-End
|
||||||
args:
|
# args:
|
||||||
- BUILD_MODE=development
|
# - BUILD_MODE=development
|
||||||
ports:
|
# ports:
|
||||||
- 3000:3000
|
# - 3000:3000
|
||||||
volumes:
|
# volumes:
|
||||||
- ./Front-End:/app
|
# - ./Front-End:/app
|
||||||
environment:
|
# environment:
|
||||||
- TZ=Europe/Paris
|
# - TZ=Europe/Paris
|
||||||
depends_on:
|
# depends_on:
|
||||||
- backend
|
# - backend
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user