422 lines
13 KiB
TypeScript
422 lines
13 KiB
TypeScript
import React, { useState, memo } from 'react';
|
||
import Modal from './ui/modal/Modal';
|
||
import './FolderModal.css';
|
||
import type { FolderData } from '../lib/4nk/models/FolderData';
|
||
|
||
interface FolderModalProps {
|
||
folder?: FolderData;
|
||
onSave?: (folderData: FolderData) => void;
|
||
onCancel?: () => void;
|
||
readOnly?: boolean;
|
||
isOpen: boolean;
|
||
onClose: () => void;
|
||
}
|
||
|
||
const defaultFolder: FolderData = {
|
||
folderNumber: '',
|
||
name: '',
|
||
deedType: '',
|
||
description: '',
|
||
archived_description: '',
|
||
status: 'active',
|
||
created_at: new Date().toISOString(),
|
||
updated_at: new Date().toISOString(),
|
||
customers: [],
|
||
documents: [],
|
||
motes: [],
|
||
stakeholders: []
|
||
};
|
||
|
||
function FolderModal({
|
||
folder = defaultFolder,
|
||
onSave,
|
||
onCancel,
|
||
readOnly = false,
|
||
isOpen,
|
||
onClose
|
||
}: FolderModalProps) {
|
||
const [folderData, setFolderData] = useState<FolderData>(folder);
|
||
const [currentCustomer, setCurrentCustomer] = useState<string>('');
|
||
const [currentStakeholder, setCurrentStakeholder] = useState<string>('');
|
||
const [currentMote, setCurrentMote] = useState<string>('');
|
||
|
||
if (!isOpen) return null;
|
||
|
||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
|
||
const { name, value } = e.target;
|
||
setFolderData(prev => ({
|
||
...prev,
|
||
[name]: value
|
||
}));
|
||
};
|
||
|
||
const addCustomer = () => {
|
||
if (currentCustomer.trim() && !folderData.customers.includes(currentCustomer.trim())) {
|
||
setFolderData(prev => ({
|
||
...prev,
|
||
customers: [...prev.customers, currentCustomer.trim()]
|
||
}));
|
||
setCurrentCustomer('');
|
||
}
|
||
};
|
||
|
||
const removeCustomer = (customer: string) => {
|
||
setFolderData(prev => ({
|
||
...prev,
|
||
customers: prev.customers.filter(c => c !== customer)
|
||
}));
|
||
};
|
||
|
||
const addStakeholder = () => {
|
||
if (currentStakeholder.trim() && !folderData.stakeholders.includes(currentStakeholder.trim())) {
|
||
setFolderData(prev => ({
|
||
...prev,
|
||
stakeholders: [...prev.stakeholders, currentStakeholder.trim()]
|
||
}));
|
||
setCurrentStakeholder('');
|
||
}
|
||
};
|
||
|
||
const removeStakeholder = (stakeholder: string) => {
|
||
setFolderData(prev => ({
|
||
...prev,
|
||
stakeholders: prev.stakeholders.filter(s => s !== stakeholder)
|
||
}));
|
||
};
|
||
|
||
const addMote = () => {
|
||
if (currentMote.trim() && !folderData.motes.includes(currentMote.trim())) {
|
||
setFolderData(prev => ({
|
||
...prev,
|
||
motes: [...prev.motes, currentMote.trim()]
|
||
}));
|
||
setCurrentMote('');
|
||
}
|
||
};
|
||
|
||
const removeMote = (mote: string) => {
|
||
setFolderData(prev => ({
|
||
...prev,
|
||
motes: prev.motes.filter(m => m !== mote)
|
||
}));
|
||
};
|
||
|
||
const handleSubmit = (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
if (onSave) {
|
||
onSave({
|
||
...folderData,
|
||
updated_at: new Date().toISOString()
|
||
});
|
||
}
|
||
};
|
||
|
||
const handleCancel = () => {
|
||
if (onCancel) {
|
||
onCancel();
|
||
} else {
|
||
onClose();
|
||
}
|
||
};
|
||
|
||
return (
|
||
<Modal isOpen={isOpen} onClose={onClose} title="Créer un nouveau dossier" size="lg">
|
||
<div className="folder-container">
|
||
<form className="folder-form" onSubmit={handleSubmit}>
|
||
<div className="form-section">
|
||
<h3 className="section-title">Informations principales</h3>
|
||
<div className="form-row">
|
||
<div className="form-field">
|
||
<label>
|
||
Numéro de dossier <span className="required">*</span>
|
||
</label>
|
||
<input
|
||
type="text"
|
||
name="folderNumber"
|
||
value={folderData.folderNumber}
|
||
onChange={handleInputChange}
|
||
required
|
||
disabled={readOnly}
|
||
placeholder="ex: DOC-2025-001"
|
||
/>
|
||
</div>
|
||
<div className="form-field">
|
||
<label>
|
||
Nom <span className="required">*</span>
|
||
</label>
|
||
<input
|
||
type="text"
|
||
name="name"
|
||
value={folderData.name}
|
||
onChange={handleInputChange}
|
||
required
|
||
disabled={readOnly}
|
||
placeholder="Nom du dossier"
|
||
/>
|
||
</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">
|
||
<label>Description</label>
|
||
<textarea
|
||
name="description"
|
||
value={folderData.description}
|
||
onChange={handleInputChange}
|
||
disabled={readOnly}
|
||
placeholder="Description du dossier"
|
||
rows={3}
|
||
/>
|
||
</div>
|
||
|
||
{folderData.status === 'archived' && (
|
||
<div className="form-field">
|
||
<label>Description d'archivage</label>
|
||
<textarea
|
||
name="archived_description"
|
||
value={folderData.archived_description}
|
||
onChange={handleInputChange}
|
||
disabled={readOnly}
|
||
placeholder="Raison d'archivage"
|
||
rows={2}
|
||
/>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
<div className="form-section">
|
||
<h3 className="section-title">Clients</h3>
|
||
<div className="tag-list">
|
||
{folderData.customers.map((customer, index) => (
|
||
<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>
|
||
|
||
{!readOnly && (
|
||
<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">
|
||
<h3 className="section-title">Notes</h3>
|
||
<div className="tag-list">
|
||
{folderData.motes.map((mote, index) => (
|
||
<div key={index} className="tag-item">
|
||
<span>{mote}</span>
|
||
{!readOnly && (
|
||
<button
|
||
type="button"
|
||
className="tag-remove"
|
||
onClick={() => removeMote(mote)}
|
||
aria-label="Supprimer cette note"
|
||
>
|
||
×
|
||
</button>
|
||
)}
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{!readOnly && (
|
||
<div className="form-field tag-input-container">
|
||
<input
|
||
type="text"
|
||
value={currentMote}
|
||
onChange={(e) => setCurrentMote(e.target.value)}
|
||
placeholder="Ajouter une note"
|
||
onKeyPress={(e) => {
|
||
if (e.key === 'Enter') {
|
||
e.preventDefault();
|
||
addMote();
|
||
}
|
||
}}
|
||
/>
|
||
<button
|
||
type="button"
|
||
className="btn-add-tag"
|
||
onClick={addMote}
|
||
>
|
||
Ajouter
|
||
</button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
<div className="form-section">
|
||
<h3 className="section-title">Informations système</h3>
|
||
<div className="form-row">
|
||
<div className="form-field">
|
||
<label>Créé le</label>
|
||
<input
|
||
type="text"
|
||
value={new Date(folderData.created_at).toLocaleDateString('fr-FR', {
|
||
day: '2-digit',
|
||
month: '2-digit',
|
||
year: 'numeric',
|
||
hour: '2-digit',
|
||
minute: '2-digit'
|
||
})}
|
||
disabled
|
||
readOnly
|
||
/>
|
||
</div>
|
||
<div className="form-field">
|
||
<label>Dernière mise à jour</label>
|
||
<input
|
||
type="text"
|
||
value={new Date(folderData.updated_at).toLocaleDateString('fr-FR', {
|
||
day: '2-digit',
|
||
month: '2-digit',
|
||
year: 'numeric',
|
||
hour: '2-digit',
|
||
minute: '2-digit'
|
||
})}
|
||
disabled
|
||
readOnly
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="form-actions">
|
||
<button
|
||
type="button"
|
||
className="btn-cancel"
|
||
onClick={handleCancel}
|
||
>
|
||
Annuler
|
||
</button>
|
||
<button
|
||
type="submit"
|
||
className="btn-submit"
|
||
disabled={readOnly}
|
||
>
|
||
Enregistrer
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</Modal>
|
||
);
|
||
};
|
||
|
||
FolderModal.displayName = 'FolderModal';
|
||
export default memo(FolderModal);
|