Updated FolderModal and css design
This commit is contained in:
parent
e625431d26
commit
741ad90b00
@ -1,17 +1,20 @@
|
|||||||
/* Folder Modal Styles */
|
/* Container */
|
||||||
.folder-container {
|
.folder-container {
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
max-height: 70vh;
|
max-height: 70vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Form */
|
||||||
.folder-form {
|
.folder-form {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Form Sections */
|
/* Section */
|
||||||
.form-section {
|
.form-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -21,13 +24,13 @@
|
|||||||
.section-title {
|
.section-title {
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #374151;
|
color: #111827;
|
||||||
margin: 0 0 0.5rem 0;
|
margin: 0;
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
border-bottom: 2px solid #e5e7eb;
|
border-bottom: 2px solid #e5e7eb;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Form Layout */
|
/* Layout */
|
||||||
.form-row {
|
.form-row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
@ -37,43 +40,44 @@
|
|||||||
.form-field {
|
.form-field {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.5rem;
|
gap: 0.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-field label {
|
.form-field label {
|
||||||
font-size: 0.875rem;
|
font-size: 0.85rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #374151;
|
color: #374151;
|
||||||
}
|
}
|
||||||
|
|
||||||
.required {
|
.required {
|
||||||
color: #dc2626;
|
color: #dc2626;
|
||||||
|
margin-left: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Form Inputs */
|
/* Inputs */
|
||||||
.form-field input,
|
.form-field input,
|
||||||
.form-field textarea,
|
.form-field textarea,
|
||||||
.form-field select {
|
.form-field select {
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
border: 1px solid #d1d5db;
|
border: 1px solid #d1d5db;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
font-size: 0.875rem;
|
font-size: 0.9rem;
|
||||||
transition: border-color 0.2s, box-shadow 0.2s;
|
transition: border-color 0.2s, box-shadow 0.2s;
|
||||||
background-color: white;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-field input:focus,
|
.form-field input:focus,
|
||||||
.form-field textarea:focus,
|
.form-field textarea:focus,
|
||||||
.form-field select:focus {
|
.form-field select:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: #3b82f6;
|
border-color: #2563eb;
|
||||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-field input:disabled,
|
.form-field input:disabled,
|
||||||
.form-field textarea:disabled,
|
.form-field textarea:disabled,
|
||||||
.form-field select:disabled {
|
.form-field select:disabled {
|
||||||
background-color: #f9fafb;
|
background-color: #f3f4f6;
|
||||||
color: #6b7280;
|
color: #6b7280;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
@ -83,7 +87,7 @@
|
|||||||
color: #9ca3af;
|
color: #9ca3af;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tag System */
|
/* Tags */
|
||||||
.tag-list {
|
.tag-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@ -94,24 +98,25 @@
|
|||||||
.tag-item {
|
.tag-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.4rem;
|
||||||
background-color: #eff6ff;
|
background-color: #f0f9ff;
|
||||||
color: #1d4ed8;
|
color: #0369a1;
|
||||||
padding: 0.375rem 0.75rem;
|
padding: 0.35rem 0.75rem;
|
||||||
border-radius: 9999px;
|
border-radius: 9999px;
|
||||||
font-size: 0.875rem;
|
font-size: 0.85rem;
|
||||||
border: 1px solid #bfdbfe;
|
border: 1px solid #bae6fd;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tag-remove {
|
.tag-remove {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 1.25rem;
|
width: 1.1rem;
|
||||||
height: 1.25rem;
|
height: 1.1rem;
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
color: #1d4ed8;
|
color: #0369a1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
@ -120,7 +125,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tag-remove:hover {
|
.tag-remove:hover {
|
||||||
background-color: #dbeafe;
|
background-color: #e0f2fe;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tag-input-container {
|
.tag-input-container {
|
||||||
@ -134,12 +139,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-add-tag {
|
.btn-add-tag {
|
||||||
padding: 0.75rem 1rem;
|
padding: 0.6rem 1rem;
|
||||||
background-color: #3b82f6;
|
background-color: #2563eb;
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
font-size: 0.875rem;
|
font-size: 0.85rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color 0.2s;
|
transition: background-color 0.2s;
|
||||||
@ -147,10 +152,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-add-tag:hover {
|
.btn-add-tag:hover {
|
||||||
background-color: #2563eb;
|
background-color: #1d4ed8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Form Actions */
|
/* Actions */
|
||||||
.form-actions {
|
.form-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
@ -160,37 +165,37 @@
|
|||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-cancel {
|
.btn-cancel,
|
||||||
|
.btn-submit {
|
||||||
padding: 0.75rem 1.5rem;
|
padding: 0.75rem 1.5rem;
|
||||||
background-color: white;
|
|
||||||
color: #374151;
|
|
||||||
border: 1px solid #d1d5db;
|
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
font-size: 0.875rem;
|
font-size: 0.9rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Cancel button */
|
||||||
|
.btn-cancel {
|
||||||
|
background-color: white;
|
||||||
|
color: #374151;
|
||||||
|
border: 1px solid #d1d5db;
|
||||||
|
}
|
||||||
|
|
||||||
.btn-cancel:hover {
|
.btn-cancel:hover {
|
||||||
background-color: #f9fafb;
|
background-color: #f9fafb;
|
||||||
border-color: #9ca3af;
|
border-color: #9ca3af;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Submit button */
|
||||||
.btn-submit {
|
.btn-submit {
|
||||||
padding: 0.75rem 1.5rem;
|
background-color: #10b981;
|
||||||
background-color: #059669;
|
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0.5rem;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 500;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-submit:hover {
|
.btn-submit:hover {
|
||||||
background-color: #047857;
|
background-color: #059669;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-submit:disabled {
|
.btn-submit:disabled {
|
||||||
@ -198,7 +203,7 @@
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Responsive Design */
|
/* Responsive */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.folder-container {
|
.folder-container {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
@ -224,7 +229,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Custom scrollbar for the container */
|
/* Scrollbar */
|
||||||
.folder-container::-webkit-scrollbar {
|
.folder-container::-webkit-scrollbar {
|
||||||
width: 6px;
|
width: 6px;
|
||||||
}
|
}
|
||||||
@ -242,3 +247,101 @@
|
|||||||
.folder-container::-webkit-scrollbar-thumb:hover {
|
.folder-container::-webkit-scrollbar-thumb:hover {
|
||||||
background: #94a3b8;
|
background: #94a3b8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- Thèmes par type de dossier --- */
|
||||||
|
|
||||||
|
/* Contrats */
|
||||||
|
.folder-contrat .section-title {
|
||||||
|
border-bottom-color: #2563eb;
|
||||||
|
}
|
||||||
|
.folder-contrat .tag-item {
|
||||||
|
background-color: #eff6ff;
|
||||||
|
color: #2563eb;
|
||||||
|
border-color: #bfdbfe;
|
||||||
|
}
|
||||||
|
.folder-contrat .btn-submit {
|
||||||
|
background-color: #2563eb;
|
||||||
|
}
|
||||||
|
.folder-contrat .btn-submit:hover {
|
||||||
|
background-color: #1d4ed8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Projets */
|
||||||
|
.folder-projet .section-title {
|
||||||
|
border-bottom-color: #059669;
|
||||||
|
}
|
||||||
|
.folder-projet .tag-item {
|
||||||
|
background-color: #ecfdf5;
|
||||||
|
color: #059669;
|
||||||
|
border-color: #a7f3d0;
|
||||||
|
}
|
||||||
|
.folder-projet .btn-submit {
|
||||||
|
background-color: #059669;
|
||||||
|
}
|
||||||
|
.folder-projet .btn-submit:hover {
|
||||||
|
background-color: #047857;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Rapports */
|
||||||
|
.folder-rapport .section-title {
|
||||||
|
border-bottom-color: #7c3aed;
|
||||||
|
}
|
||||||
|
.folder-rapport .tag-item {
|
||||||
|
background-color: #f5f3ff;
|
||||||
|
color: #7c3aed;
|
||||||
|
border-color: #ddd6fe;
|
||||||
|
}
|
||||||
|
.folder-rapport .btn-submit {
|
||||||
|
background-color: #7c3aed;
|
||||||
|
}
|
||||||
|
.folder-rapport .btn-submit:hover {
|
||||||
|
background-color: #6d28d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finance */
|
||||||
|
.folder-finance .section-title {
|
||||||
|
border-bottom-color: #d97706;
|
||||||
|
}
|
||||||
|
.folder-finance .tag-item {
|
||||||
|
background-color: #fffbeb;
|
||||||
|
color: #d97706;
|
||||||
|
border-color: #fcd34d;
|
||||||
|
}
|
||||||
|
.folder-finance .btn-submit {
|
||||||
|
background-color: #d97706;
|
||||||
|
}
|
||||||
|
.folder-finance .btn-submit:hover {
|
||||||
|
background-color: #b45309;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ressources Humaines */
|
||||||
|
.folder-rh .section-title {
|
||||||
|
border-bottom-color: #db2777;
|
||||||
|
}
|
||||||
|
.folder-rh .tag-item {
|
||||||
|
background-color: #fdf2f8;
|
||||||
|
color: #db2777;
|
||||||
|
border-color: #f9a8d4;
|
||||||
|
}
|
||||||
|
.folder-rh .btn-submit {
|
||||||
|
background-color: #db2777;
|
||||||
|
}
|
||||||
|
.folder-rh .btn-submit:hover {
|
||||||
|
background-color: #be185d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Marketing */
|
||||||
|
.folder-marketing .section-title {
|
||||||
|
border-bottom-color: #4f46e5;
|
||||||
|
}
|
||||||
|
.folder-marketing .tag-item {
|
||||||
|
background-color: #eef2ff;
|
||||||
|
color: #4f46e5;
|
||||||
|
border-color: #c7d2fe;
|
||||||
|
}
|
||||||
|
.folder-marketing .btn-submit {
|
||||||
|
background-color: #4f46e5;
|
||||||
|
}
|
||||||
|
.folder-marketing .btn-submit:hover {
|
||||||
|
background-color: #3730a3;
|
||||||
|
}
|
||||||
@ -1,8 +1,10 @@
|
|||||||
import React, { useState, memo } from 'react';
|
import React, { useEffect, useState, memo } from 'react';
|
||||||
import Modal from './ui/modal/Modal';
|
import Modal from './ui/modal/Modal';
|
||||||
import './FolderModal.css';
|
import './FolderModal.css';
|
||||||
import type { FolderData } from '../lib/4nk/models/FolderData';
|
import type { FolderData } from '../lib/4nk/models/FolderData';
|
||||||
|
|
||||||
|
type FolderType = 'contrat' | 'projet' | 'rapport' | 'finance' | 'rh' | 'marketing' | 'autre';
|
||||||
|
|
||||||
interface FolderModalProps {
|
interface FolderModalProps {
|
||||||
folder?: FolderData;
|
folder?: FolderData;
|
||||||
onSave?: (folderData: FolderData) => void;
|
onSave?: (folderData: FolderData) => void;
|
||||||
@ -10,6 +12,11 @@ interface FolderModalProps {
|
|||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
|
folderType?: FolderType;
|
||||||
|
renderExtraFields?: (
|
||||||
|
folderData: FolderData,
|
||||||
|
setFolderData: React.Dispatch<React.SetStateAction<FolderData>>
|
||||||
|
) => React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultFolder: FolderData = {
|
const defaultFolder: FolderData = {
|
||||||
@ -27,80 +34,92 @@ const defaultFolder: FolderData = {
|
|||||||
stakeholders: []
|
stakeholders: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function capitalize(s?: string) {
|
||||||
|
if (!s) return '';
|
||||||
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
function FolderModal({
|
function FolderModal({
|
||||||
folder = defaultFolder,
|
folder = defaultFolder,
|
||||||
onSave,
|
onSave,
|
||||||
onCancel,
|
onCancel,
|
||||||
readOnly = false,
|
readOnly = false,
|
||||||
isOpen,
|
isOpen,
|
||||||
onClose
|
onClose,
|
||||||
|
folderType = 'autre',
|
||||||
|
renderExtraFields
|
||||||
}: FolderModalProps) {
|
}: FolderModalProps) {
|
||||||
const [folderData, setFolderData] = useState<FolderData>(folder);
|
const [folderData, setFolderData] = useState<FolderData>({ ...defaultFolder, ...folder });
|
||||||
const [currentCustomer, setCurrentCustomer] = useState<string>('');
|
const [currentCustomer, setCurrentCustomer] = useState<string>('');
|
||||||
const [currentStakeholder, setCurrentStakeholder] = useState<string>('');
|
const [currentStakeholder, setCurrentStakeholder] = useState<string>('');
|
||||||
const [currentNote, setCurrentNote] = useState<string>('');
|
const [currentNote, setCurrentNote] = useState<string>('');
|
||||||
|
|
||||||
if (!isOpen) return null;
|
// Sync when modal opens or when folder prop changes (useful pour Edit)
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOpen) {
|
||||||
|
// Merge with defaultFolder to ensure arrays exist
|
||||||
|
setFolderData({ ...defaultFolder, ...(folder || {}) });
|
||||||
|
setCurrentCustomer('');
|
||||||
|
setCurrentStakeholder('');
|
||||||
|
setCurrentNote('');
|
||||||
|
}
|
||||||
|
}, [isOpen, folder]);
|
||||||
|
|
||||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
|
// Generic input change handler
|
||||||
|
const handleInputChange = (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>
|
||||||
|
) => {
|
||||||
const { name, value } = e.target;
|
const { name, value } = e.target;
|
||||||
setFolderData(prev => ({
|
// cast to avoid TS complaints when updating dynamic fields
|
||||||
...prev,
|
setFolderData(prev => ({ ...(prev as any), [name]: value } as FolderData));
|
||||||
[name]: value
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* ---------- Customers ---------- */
|
||||||
const addCustomer = () => {
|
const addCustomer = () => {
|
||||||
if (currentCustomer.trim() && !folderData.customers.includes(currentCustomer.trim())) {
|
const v = currentCustomer.trim();
|
||||||
setFolderData(prev => ({
|
if (!v) return;
|
||||||
...prev,
|
if (!Array.isArray(folderData.customers)) folderData.customers = [];
|
||||||
customers: [...prev.customers, currentCustomer.trim()]
|
if (!folderData.customers.includes(v)) {
|
||||||
}));
|
setFolderData(prev => ({ ...prev, customers: [...(prev.customers || []), v] }));
|
||||||
setCurrentCustomer('');
|
|
||||||
}
|
}
|
||||||
|
setCurrentCustomer('');
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeCustomer = (customer: string) => {
|
const removeCustomer = (customer: string) => {
|
||||||
setFolderData(prev => ({
|
setFolderData(prev => ({ ...prev, customers: (prev.customers || []).filter(c => c !== customer) }));
|
||||||
...prev,
|
|
||||||
customers: prev.customers.filter(c => c !== customer)
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* ---------- Stakeholders ---------- */
|
||||||
const addStakeholder = () => {
|
const addStakeholder = () => {
|
||||||
if (currentStakeholder.trim() && !folderData.stakeholders.includes(currentStakeholder.trim())) {
|
const v = currentStakeholder.trim();
|
||||||
setFolderData(prev => ({
|
if (!v) return;
|
||||||
...prev,
|
if (!Array.isArray(folderData.stakeholders)) folderData.stakeholders = [];
|
||||||
stakeholders: [...prev.stakeholders, currentStakeholder.trim()]
|
if (!folderData.stakeholders.includes(v)) {
|
||||||
}));
|
setFolderData(prev => ({ ...prev, stakeholders: [...(prev.stakeholders || []), v] }));
|
||||||
setCurrentStakeholder('');
|
|
||||||
}
|
}
|
||||||
|
setCurrentStakeholder('');
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeStakeholder = (stakeholder: string) => {
|
const removeStakeholder = (stakeholder: string) => {
|
||||||
setFolderData(prev => ({
|
setFolderData(prev => ({ ...prev, stakeholders: (prev.stakeholders || []).filter(s => s !== stakeholder) }));
|
||||||
...prev,
|
|
||||||
stakeholders: prev.stakeholders.filter(s => s !== stakeholder)
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* ---------- Notes ---------- */
|
||||||
const addNote = () => {
|
const addNote = () => {
|
||||||
if (currentNote.trim() && !folderData.notes.includes(currentNote.trim())) {
|
const v = currentNote.trim();
|
||||||
setFolderData(prev => ({
|
if (!v) return;
|
||||||
...prev,
|
if (!Array.isArray(folderData.notes)) folderData.notes = [];
|
||||||
notes: [...prev.notes, currentNote.trim()]
|
if (!folderData.notes.includes(v)) {
|
||||||
}));
|
setFolderData(prev => ({ ...prev, notes: [...(prev.notes || []), v] }));
|
||||||
setCurrentNote('');
|
|
||||||
}
|
}
|
||||||
|
setCurrentNote('');
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeNote = (note: string) => {
|
const removeNote = (note: string) => {
|
||||||
setFolderData(prev => ({
|
setFolderData(prev => ({ ...prev, notes: (prev.notes || []).filter(n => n !== note) }));
|
||||||
...prev,
|
|
||||||
notes: prev.notes.filter(m => m !== note)
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* ---------- Submit / Cancel ---------- */
|
||||||
const handleSubmit = (e: React.FormEvent) => {
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (onSave) {
|
if (onSave) {
|
||||||
@ -109,22 +128,32 @@ function FolderModal({
|
|||||||
updated_at: new Date().toISOString()
|
updated_at: new Date().toISOString()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (onClose) {
|
||||||
|
onClose(); // ← ça ferme le modal après sauvegarde
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
if (onCancel) {
|
if (onCancel) {
|
||||||
onCancel();
|
onCancel(); // ton callback spécifique
|
||||||
} else {
|
} else if (onClose) {
|
||||||
onClose();
|
onClose(); // fallback si pas de onCancel
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Title text
|
||||||
|
const title = `Créer un dossier ${capitalize(folderType)}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={isOpen} onClose={onClose} title="Créer un nouveau dossier" size="lg">
|
// On ne fait PAS "if (!isOpen) return null" : Modal gère l'animation/visibilité
|
||||||
<div className="folder-container">
|
<Modal isOpen={isOpen} onClose={onClose} title={title} size="lg">
|
||||||
|
<div className={`folder-container folder-${folderType}`}>
|
||||||
<form className="folder-form" onSubmit={handleSubmit}>
|
<form className="folder-form" onSubmit={handleSubmit}>
|
||||||
|
|
||||||
|
{/* Informations principales */}
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<h3 className="section-title">Informations principales</h3>
|
<h3 className="section-title">Informations principales</h3>
|
||||||
|
|
||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
<div className="form-field">
|
<div className="form-field">
|
||||||
<label>
|
<label>
|
||||||
@ -133,13 +162,14 @@ function FolderModal({
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="folderNumber"
|
name="folderNumber"
|
||||||
value={folderData.folderNumber}
|
value={folderData.folderNumber || ''}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
required
|
required
|
||||||
disabled={readOnly}
|
disabled={readOnly}
|
||||||
placeholder="ex: DOC-2025-001"
|
placeholder="ex: DOC-2025-001"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="form-field">
|
<div className="form-field">
|
||||||
<label>
|
<label>
|
||||||
Nom <span className="required">*</span>
|
Nom <span className="required">*</span>
|
||||||
@ -147,7 +177,7 @@ function FolderModal({
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="name"
|
name="name"
|
||||||
value={folderData.name}
|
value={folderData.name || ''}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
required
|
required
|
||||||
disabled={readOnly}
|
disabled={readOnly}
|
||||||
@ -156,52 +186,11 @@ function FolderModal({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="form-row">
|
|
||||||
<div className="form-field">
|
|
||||||
<label>
|
|
||||||
Type d'acte <span className="required">*</span>
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
name="deedType"
|
|
||||||
value={folderData.deedType}
|
|
||||||
onChange={handleInputChange}
|
|
||||||
required
|
|
||||||
disabled={readOnly}
|
|
||||||
>
|
|
||||||
<option value="">Sélectionnez le type d'acte</option>
|
|
||||||
<option value="vente">Vente</option>
|
|
||||||
<option value="achat">Achat</option>
|
|
||||||
<option value="succession">Succession</option>
|
|
||||||
<option value="donation">Donation</option>
|
|
||||||
<option value="hypotheque">Hypothèque</option>
|
|
||||||
<option value="bail">Bail</option>
|
|
||||||
<option value="autre">Autre</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className="form-field">
|
|
||||||
<label>
|
|
||||||
Statut <span className="required">*</span>
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
name="status"
|
|
||||||
value={folderData.status}
|
|
||||||
onChange={handleInputChange}
|
|
||||||
required
|
|
||||||
disabled={readOnly}
|
|
||||||
>
|
|
||||||
<option value="active">Actif</option>
|
|
||||||
<option value="pending">En attente</option>
|
|
||||||
<option value="completed">Complété</option>
|
|
||||||
<option value="archived">Archivé</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-field">
|
<div className="form-field">
|
||||||
<label>Description</label>
|
<label>Description</label>
|
||||||
<textarea
|
<textarea
|
||||||
name="description"
|
name="description"
|
||||||
value={folderData.description}
|
value={folderData.description || ''}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
disabled={readOnly}
|
disabled={readOnly}
|
||||||
placeholder="Description du dossier"
|
placeholder="Description du dossier"
|
||||||
@ -214,7 +203,7 @@ function FolderModal({
|
|||||||
<label>Description d'archivage</label>
|
<label>Description d'archivage</label>
|
||||||
<textarea
|
<textarea
|
||||||
name="archived_description"
|
name="archived_description"
|
||||||
value={folderData.archived_description}
|
value={folderData.archived_description || ''}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
disabled={readOnly}
|
disabled={readOnly}
|
||||||
placeholder="Raison d'archivage"
|
placeholder="Raison d'archivage"
|
||||||
@ -224,100 +213,19 @@ function FolderModal({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="form-section">
|
{/* Champs spécifiques injectés */}
|
||||||
<h3 className="section-title">Clients</h3>
|
{renderExtraFields && (
|
||||||
<div className="tag-list">
|
<div className="form-section">
|
||||||
{folderData.customers.map((customer, index) => (
|
{renderExtraFields(folderData, setFolderData)}
|
||||||
<div key={index} className="tag-item">
|
|
||||||
<span>{customer}</span>
|
|
||||||
{!readOnly && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="tag-remove"
|
|
||||||
onClick={() => removeCustomer(customer)}
|
|
||||||
aria-label="Supprimer ce client"
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{!readOnly && (
|
{/* Notes */}
|
||||||
<div className="form-field tag-input-container">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={currentCustomer}
|
|
||||||
onChange={(e) => setCurrentCustomer(e.target.value)}
|
|
||||||
placeholder="Ajouter un client"
|
|
||||||
onKeyPress={(e) => {
|
|
||||||
if (e.key === 'Enter') {
|
|
||||||
e.preventDefault();
|
|
||||||
addCustomer();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn-add-tag"
|
|
||||||
onClick={addCustomer}
|
|
||||||
>
|
|
||||||
Ajouter
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-section">
|
|
||||||
<h3 className="section-title">Parties prenantes</h3>
|
|
||||||
<div className="tag-list">
|
|
||||||
{folderData.stakeholders.map((stakeholder, index) => (
|
|
||||||
<div key={index} className="tag-item">
|
|
||||||
<span>{stakeholder}</span>
|
|
||||||
{!readOnly && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="tag-remove"
|
|
||||||
onClick={() => removeStakeholder(stakeholder)}
|
|
||||||
aria-label="Supprimer cette partie prenante"
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{!readOnly && (
|
|
||||||
<div className="form-field tag-input-container">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={currentStakeholder}
|
|
||||||
onChange={(e) => setCurrentStakeholder(e.target.value)}
|
|
||||||
placeholder="Ajouter une partie prenante"
|
|
||||||
onKeyPress={(e) => {
|
|
||||||
if (e.key === 'Enter') {
|
|
||||||
e.preventDefault();
|
|
||||||
addStakeholder();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn-add-tag"
|
|
||||||
onClick={addStakeholder}
|
|
||||||
>
|
|
||||||
Ajouter
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<h3 className="section-title">Notes</h3>
|
<h3 className="section-title">Notes</h3>
|
||||||
|
|
||||||
<div className="tag-list">
|
<div className="tag-list">
|
||||||
{folderData.notes.map((note, index) => (
|
{(folderData.notes || []).map((note, index) => (
|
||||||
<div key={index} className="tag-item">
|
<div key={index} className="tag-item">
|
||||||
<span>{note}</span>
|
<span>{note}</span>
|
||||||
{!readOnly && (
|
{!readOnly && (
|
||||||
@ -341,7 +249,7 @@ function FolderModal({
|
|||||||
value={currentNote}
|
value={currentNote}
|
||||||
onChange={(e) => setCurrentNote(e.target.value)}
|
onChange={(e) => setCurrentNote(e.target.value)}
|
||||||
placeholder="Ajouter une note"
|
placeholder="Ajouter une note"
|
||||||
onKeyPress={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
addNote();
|
addNote();
|
||||||
@ -359,14 +267,16 @@ function FolderModal({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Informations système */}
|
||||||
<div className="form-section">
|
<div className="form-section">
|
||||||
<h3 className="section-title">Informations système</h3>
|
<h3 className="section-title">Informations système</h3>
|
||||||
|
|
||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
<div className="form-field">
|
<div className="form-field">
|
||||||
<label>Créé le</label>
|
<label>Créé le</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={new Date(folderData.created_at).toLocaleDateString('fr-FR', {
|
value={new Date(folderData.created_at).toLocaleString('fr-FR', {
|
||||||
day: '2-digit',
|
day: '2-digit',
|
||||||
month: '2-digit',
|
month: '2-digit',
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
@ -377,11 +287,12 @@ function FolderModal({
|
|||||||
readOnly
|
readOnly
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="form-field">
|
<div className="form-field">
|
||||||
<label>Dernière mise à jour</label>
|
<label>Dernière mise à jour</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={new Date(folderData.updated_at).toLocaleDateString('fr-FR', {
|
value={new Date(folderData.updated_at).toLocaleString('fr-FR', {
|
||||||
day: '2-digit',
|
day: '2-digit',
|
||||||
month: '2-digit',
|
month: '2-digit',
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
@ -395,19 +306,12 @@ function FolderModal({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Actions */}
|
||||||
<div className="form-actions">
|
<div className="form-actions">
|
||||||
<button
|
<button type="button" className="btn-cancel" onClick={handleCancel}>
|
||||||
type="button"
|
|
||||||
className="btn-cancel"
|
|
||||||
onClick={handleCancel}
|
|
||||||
>
|
|
||||||
Annuler
|
Annuler
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button type="submit" className="btn-submit" disabled={readOnly}>
|
||||||
type="submit"
|
|
||||||
className="btn-submit"
|
|
||||||
disabled={readOnly}
|
|
||||||
>
|
|
||||||
Enregistrer
|
Enregistrer
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -415,7 +319,7 @@ function FolderModal({
|
|||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
FolderModal.displayName = 'FolderModal';
|
FolderModal.displayName = 'FolderModal';
|
||||||
export default memo(FolderModal);
|
export default memo(FolderModal);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user