MAJ
This commit is contained in:
@@ -273,6 +273,361 @@ function PlatDetailPanel({ plat, onEdit }) {
|
||||
/* ── Panneau de détail PFU ───────────────────────────────────── */
|
||||
|
||||
|
||||
|
||||
|
||||
/* ── Picker référentiel ──────────────────────────────────────── */
|
||||
function PlatPickerModal({ open, onClose, referentiel, onSelect, onManual, err }) {
|
||||
const [search, setSearch] = useState('');
|
||||
const [domFilter, setDomFilter] = useState('all'); // 'all' | 'fr' | 'etr'
|
||||
if (!open) return null;
|
||||
|
||||
const q = search.trim().toLowerCase();
|
||||
const filtered = referentiel.filter(r => {
|
||||
if (domFilter === 'fr' && r.domiciliation !== 'FR') return false;
|
||||
if (domFilter === 'etr' && r.domiciliation === 'FR') return false;
|
||||
if (q && !r.nom.toLowerCase().includes(q)) return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
const imgFor = (r) => {
|
||||
const f = r.icone_filename || r.logo_filename;
|
||||
return f ? (LOGO_BASE + f) : null;
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
title="Ajouter une plateforme"
|
||||
onClose={onClose}
|
||||
width={700}
|
||||
footer={
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%' }}>
|
||||
<button type="button" className="ghost" onClick={() => { onClose(); onManual(); }}>
|
||||
✏️ Définir manuellement
|
||||
</button>
|
||||
<button type="button" onClick={onClose}>Fermer</button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
||||
{err && <div className="error">{err}</div>}
|
||||
<p style={{ margin: 0, color: 'var(--text-muted)', fontSize: 'var(--fs-sm)', lineHeight: 1.5 }}>
|
||||
Sélectionnez une plateforme depuis le référentiel pour l'ajouter à votre portefeuille.
|
||||
Les informations (domiciliation, fiscalité…) seront pré-remplies automatiquement.
|
||||
</p>
|
||||
|
||||
{/* Barre de recherche + chips filtre */}
|
||||
<div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
|
||||
<input
|
||||
type="search"
|
||||
value={search}
|
||||
onChange={e => setSearch(e.target.value)}
|
||||
placeholder="Rechercher une plateforme…"
|
||||
autoFocus
|
||||
style={{ flex: 1, boxSizing: 'border-box', padding: '9px 14px', borderRadius: 8,
|
||||
border: '1.5px solid var(--border)', fontSize: 'var(--fs-sm)', background: 'var(--surface)',
|
||||
color: 'var(--text)', outline: 'none' }}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: 'flex', gap: 6 }}>
|
||||
{[
|
||||
{ key: 'all', content: 'Toutes' },
|
||||
{ key: 'fr', content: <span style={{ display:'inline-flex', alignItems:'center', gap:5 }}><FlagIcon code="FR" size={14} /> Françaises</span> },
|
||||
{ key: 'etr', content: <span style={{ display:'inline-flex', alignItems:'center', gap:5 }}>🌍 Étrangères</span> },
|
||||
].map(({ key, content }) => (
|
||||
<button key={key} type="button" onClick={() => setDomFilter(key)} style={{
|
||||
padding: '5px 14px', borderRadius: 20, fontSize: 'var(--fs-sm)', fontWeight: 500,
|
||||
cursor: 'pointer', border: '1.5px solid',
|
||||
borderColor: domFilter === key ? 'var(--primary)' : 'var(--border)',
|
||||
background: domFilter === key ? 'var(--primary)' : 'var(--surface)',
|
||||
color: domFilter === key ? '#fff' : 'var(--text-muted)',
|
||||
transition: 'all .15s',
|
||||
display: 'inline-flex', alignItems: 'center',
|
||||
}}>{content}</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Grille des plateformes */}
|
||||
<div style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))',
|
||||
gap: 10,
|
||||
maxHeight: 380,
|
||||
overflowY: 'auto',
|
||||
padding: '2px 2px 4px',
|
||||
}}>
|
||||
{filtered.length === 0 && (
|
||||
<div style={{ gridColumn: '1/-1', textAlign: 'center', color: 'var(--text-muted)',
|
||||
padding: '32px 0', fontSize: 'var(--fs-sm)' }}>
|
||||
Aucune plateforme trouvée pour « {search} »
|
||||
</div>
|
||||
)}
|
||||
{filtered.map(r => {
|
||||
const img = imgFor(r);
|
||||
return (
|
||||
<button
|
||||
key={r.id}
|
||||
type="button"
|
||||
onClick={() => onSelect(r)}
|
||||
style={{
|
||||
display: 'flex', flexDirection: 'column', alignItems: 'center',
|
||||
gap: 8, padding: '16px 10px 12px',
|
||||
background: 'var(--surface)', border: '1.5px solid var(--border)',
|
||||
borderRadius: 12, cursor: 'pointer', textAlign: 'center',
|
||||
transition: 'border-color .15s, box-shadow .15s, transform .1s',
|
||||
minHeight: 110,
|
||||
}}
|
||||
onMouseEnter={e => {
|
||||
e.currentTarget.style.borderColor = 'var(--primary)';
|
||||
e.currentTarget.style.boxShadow = '0 4px 16px rgba(0,0,0,0.10)';
|
||||
e.currentTarget.style.transform = 'translateY(-2px)';
|
||||
}}
|
||||
onMouseLeave={e => {
|
||||
e.currentTarget.style.borderColor = 'var(--border)';
|
||||
e.currentTarget.style.boxShadow = 'none';
|
||||
e.currentTarget.style.transform = 'none';
|
||||
}}
|
||||
>
|
||||
{/* Logo / Placeholder */}
|
||||
{img
|
||||
? <img src={img} alt={r.nom}
|
||||
style={{ width: 48, height: 48, objectFit: 'contain', borderRadius: 8, flexShrink: 0 }} />
|
||||
: <div style={{
|
||||
width: 48, height: 48, borderRadius: 8, flexShrink: 0,
|
||||
background: 'var(--surface-2)', border: '1px solid var(--border)',
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
fontSize: 20, color: 'var(--text-muted)',
|
||||
}}>🏦</div>
|
||||
}
|
||||
|
||||
{/* Nom */}
|
||||
<span style={{
|
||||
fontSize: 'var(--fs-sm)', fontWeight: 600, color: 'var(--text)',
|
||||
lineHeight: 1.2, wordBreak: 'break-word',
|
||||
}}>
|
||||
{r.nom}
|
||||
</span>
|
||||
|
||||
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{referentiel.length > 0 && (
|
||||
<p style={{ margin: 0, fontSize: 11, color: 'var(--text-muted)', textAlign: 'center' }}>
|
||||
{referentiel.length} plateforme{referentiel.length > 1 ? 's' : ''} dans le référentiel
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
/* ── Formulaire plateforme partagé (création + édition) ─────────── */
|
||||
function PlatForm({ state, setter, logoFile, setLogoFile, logoPreview, setLogoPreview,
|
||||
investisseurs, referentiel, categoriesInv, secteursInv, isEdit = false, onDelLogo }) {
|
||||
|
||||
const isFrance = state.domiciliation === 'FR';
|
||||
|
||||
const handleLogoChange = (e) => {
|
||||
const file = e.target.files[0];
|
||||
if (!file) return;
|
||||
setLogoFile(file);
|
||||
const reader = new FileReader();
|
||||
reader.onload = ev => setLogoPreview(ev.target.result);
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
|
||||
const row = (label, content, hint) => (
|
||||
<div>
|
||||
<label style={{ display: 'block', fontWeight: 600, marginBottom: 4, fontSize: 'var(--fs-sm)' }}>{label}</label>
|
||||
{content}
|
||||
{hint && <p style={{ margin: '3px 0 0', fontSize: 11, color: 'var(--text-muted)' }}>{hint}</p>}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Nom */}
|
||||
{row('Nom *', (
|
||||
<input required value={state.nom} onChange={e => setter(s => ({ ...s, nom: e.target.value }))}
|
||||
placeholder="Ex: Lendosphere" style={{ width: '100%', boxSizing: 'border-box' }} />
|
||||
))}
|
||||
|
||||
{/* Référentiel */}
|
||||
{referentiel.length > 0 && row('Lier au référentiel', (
|
||||
<select value={state.referentiel_id ?? ''} onChange={e => {
|
||||
const rid = e.target.value ? Number(e.target.value) : null;
|
||||
const ref = referentiel.find(r => r.id === rid);
|
||||
setter(s => ({ ...s, referentiel_id: rid, ...(ref && !s.nom ? { nom: ref.nom } : {}) }));
|
||||
}} style={{ width: '100%' }}>
|
||||
<option value="">— Aucun —</option>
|
||||
{referentiel.map(r => <option key={r.id} value={r.id}>{r.nom}</option>)}
|
||||
</select>
|
||||
))}
|
||||
|
||||
{/* URL */}
|
||||
{row('URL', (
|
||||
<input type="url" value={state.url || ''} onChange={e => setter(s => ({ ...s, url: e.target.value }))}
|
||||
placeholder="https://..." style={{ width: '100%', boxSizing: 'border-box' }} />
|
||||
))}
|
||||
|
||||
{/* Domiciliation */}
|
||||
{row('Domiciliation', (
|
||||
<CountrySelect
|
||||
value={state.domiciliation || ''}
|
||||
onChange={code => setter(s => applyDomiciliationChange(s, code))}
|
||||
placeholder="Pays de la plateforme"
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Fiscalité */}
|
||||
{row('Fiscalité', (
|
||||
<select value={state.fiscalite || 'flat_tax'} disabled={isFrance}
|
||||
onChange={e => setter(s => applyFiscaliteChange(s, e.target.value))}
|
||||
style={{ width: '100%' }}>
|
||||
{isFrance
|
||||
? <option value="flat_tax">Flat Tax (France)</option>
|
||||
: <>
|
||||
<option value="sans_fiscalite_locale">Sans fiscalité locale</option>
|
||||
<option value="avec_fiscalite_locale">Avec fiscalité locale</option>
|
||||
</>
|
||||
}
|
||||
</select>
|
||||
), isFrance ? 'Forcée à Flat Tax pour les plateformes françaises.' : null)}
|
||||
|
||||
{/* Taux fiscalité locale */}
|
||||
{state.fiscalite === 'avec_fiscalite_locale' && row('Taux de fiscalité locale (%)', (
|
||||
<input type="number" min="0" max="100" step="0.1"
|
||||
value={state.taux_fiscalite_locale || ''}
|
||||
onChange={e => setter(s => ({ ...s, taux_fiscalite_locale: e.target.value }))}
|
||||
placeholder="Ex: 15" style={{ width: '100%', boxSizing: 'border-box' }} />
|
||||
))}
|
||||
|
||||
{/* Type produit fiscal */}
|
||||
{row('Case fiscale (déclaration)', (
|
||||
<select value={state.type_produit_fiscal || '2TT'} onChange={e => setter(s => ({ ...s, type_produit_fiscal: e.target.value }))}
|
||||
style={{ width: '100%' }}>
|
||||
<option value="2TT">2TT — Intérêts soumis PFL/PFU</option>
|
||||
<option value="2TR">2TR — Intérêts soumis au barème</option>
|
||||
<option value="2BH">2BH — Intérêts bruts avant PFL</option>
|
||||
<option value="2CK">2CK — PFL déjà prélevé</option>
|
||||
<option value="2TY">2TY — Revenus de capitaux (autre)</option>
|
||||
</select>
|
||||
))}
|
||||
|
||||
{/* Méthode de remboursement */}
|
||||
{row('Versement des remboursements', (
|
||||
<select value={state.methode_remboursement || 'portefeuille'} onChange={e => setter(s => ({ ...s, methode_remboursement: e.target.value }))}
|
||||
style={{ width: '100%' }}>
|
||||
<option value="portefeuille">Porte-monnaie de la plateforme</option>
|
||||
<option value="compte_courant">Compte courant de l'investisseur</option>
|
||||
<option value="choix_investisseur">Au choix de l'investisseur</option>
|
||||
</select>
|
||||
))}
|
||||
|
||||
{/* Type prêt par défaut */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
|
||||
{row('Type de prêt par défaut', (
|
||||
<select value={state.type_pret_defaut || ''} onChange={e => setter(s => ({ ...s, type_pret_defaut: e.target.value }))}
|
||||
style={{ width: '100%' }}>
|
||||
<option value="">— Non défini —</option>
|
||||
<option value="in_fine">In fine</option>
|
||||
<option value="amortissable">Amortissable</option>
|
||||
<option value="differe">Différé</option>
|
||||
</select>
|
||||
))}
|
||||
{row('Fréquence intérêts par défaut', (
|
||||
<select value={state.freq_interets_defaut || ''} onChange={e => setter(s => ({ ...s, freq_interets_defaut: e.target.value }))}
|
||||
style={{ width: '100%' }}>
|
||||
<option value="">— Non défini —</option>
|
||||
<option value="mensuel">Mensuel</option>
|
||||
<option value="trimestriel">Trimestriel</option>
|
||||
<option value="in_fine">In fine</option>
|
||||
</select>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Date d'ouverture */}
|
||||
{row("Date d'ouverture du compte", (
|
||||
<input type="date" value={state.date_ouverture || ''} onChange={e => setter(s => ({ ...s, date_ouverture: e.target.value }))}
|
||||
style={{ width: '100%', boxSizing: 'border-box' }} />
|
||||
))}
|
||||
|
||||
{/* Détenteur */}
|
||||
{investisseurs.length > 1 && row('Détenteur', (
|
||||
<InvSelect
|
||||
value={state.investisseur_id}
|
||||
onChange={id => setter(s => ({ ...s, investisseur_id: id }))}
|
||||
investisseurs={investisseurs}
|
||||
placeholder="— Sélectionner —"
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Catégories d'investissement (édition seulement) */}
|
||||
{isEdit && categoriesInv.length > 0 && row('Catégories', (
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
{categoriesInv.map(c => {
|
||||
const inherited = (state.inherited_cat_ids || []).includes(c.id);
|
||||
const checked = (state.categories_inv_ids || []).includes(c.id);
|
||||
return (
|
||||
<label key={c.id} style={{ display: 'flex', alignItems: 'center', gap: 4, cursor: inherited ? 'default' : 'pointer',
|
||||
opacity: inherited ? 0.6 : 1 }}>
|
||||
<input type="checkbox" checked={checked} disabled={inherited} style={{ width: 'auto' }}
|
||||
onChange={e => setter(s => ({
|
||||
...s,
|
||||
categories_inv_ids: e.target.checked
|
||||
? [...(s.categories_inv_ids || []), c.id]
|
||||
: (s.categories_inv_ids || []).filter(id => id !== c.id),
|
||||
}))} />
|
||||
<span className="chip-cat" style={{ fontSize: 11 }}>{c.nom}{inherited ? ' ↗' : ''}</span>
|
||||
</label>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Secteurs (édition seulement) */}
|
||||
{isEdit && secteursInv.length > 0 && row('Secteurs', (
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
{secteursInv.map(s => {
|
||||
const inherited = (state.inherited_sect_ids || []).includes(s.id);
|
||||
const checked = (state.secteurs_inv_ids || []).includes(s.id);
|
||||
return (
|
||||
<label key={s.id} style={{ display: 'flex', alignItems: 'center', gap: 4, cursor: inherited ? 'default' : 'pointer',
|
||||
opacity: inherited ? 0.6 : 1 }}>
|
||||
<input type="checkbox" checked={checked} disabled={inherited} style={{ width: 'auto' }}
|
||||
onChange={e => setter(prev => ({
|
||||
...prev,
|
||||
secteurs_inv_ids: e.target.checked
|
||||
? [...(prev.secteurs_inv_ids || []), s.id]
|
||||
: (prev.secteurs_inv_ids || []).filter(id => id !== s.id),
|
||||
}))} />
|
||||
<span className="chip-sect" style={{ fontSize: 11 }}>{s.nom}{inherited ? ' ↗' : ''}</span>
|
||||
</label>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Logo */}
|
||||
{row('Logo', (
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
|
||||
{(logoPreview || (isEdit && state.logo_filename)) && (
|
||||
<img src={logoPreview || (LOGO_BASE + state.logo_filename)} alt="logo"
|
||||
style={{ width: 40, height: 40, objectFit: 'contain', borderRadius: 4, border: '1px solid var(--border)' }} />
|
||||
)}
|
||||
<input type="file" accept="image/*" onChange={handleLogoChange} style={{ flex: 1 }} />
|
||||
{isEdit && state.logo_filename && !logoFile && (
|
||||
<button type="button" className="danger" style={{ padding: '4px 10px', fontSize: 12 }} onClick={onDelLogo}>Supprimer</button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function PlateformesSection() {
|
||||
// ── State ──────────────────────────────────────────────────────
|
||||
const [plats, setPlats] = useState([]);
|
||||
@@ -285,6 +640,7 @@ export default function PlateformesSection() {
|
||||
const [editPlatLogoFile, setEditPlatLogoFile] = useState(null);
|
||||
const [editPlatLogoPreview, setEditPlatLogoPreview] = useState(null);
|
||||
const [selectedPlat, setSelectedPlat] = useState(null);
|
||||
const [showAddPicker, setShowAddPicker] = useState(false);
|
||||
const [showNewPlat, setShowNewPlat] = useState(false);
|
||||
const [platOpenMenu, setPlatOpenMenu] = useState(null); // { plat, x, y }
|
||||
const [platExporting, setPlatExporting] = useState(false);
|
||||
@@ -405,6 +761,23 @@ export default function PlateformesSection() {
|
||||
return api.upload(`/plateformes/${platId}/logo`, fd);
|
||||
};
|
||||
|
||||
/* ── Ajouter depuis le référentiel ──────────────────────────── */
|
||||
const addPlatFromRef = async (ref) => {
|
||||
try {
|
||||
await api.post('/plateformes', {
|
||||
nom: ref.nom,
|
||||
domiciliation: ref.domiciliation || 'FR',
|
||||
fiscalite: ref.fiscalite || 'flat_tax',
|
||||
taux_fiscalite_locale: ref.taux_fiscalite_locale ?? null,
|
||||
type_produit_fiscal: ref.type_produit_fiscal || '2TT',
|
||||
methode_remboursement: 'portefeuille',
|
||||
referentiel_id: ref.id,
|
||||
});
|
||||
setShowAddPicker(false);
|
||||
await load();
|
||||
} catch (e) { setErr(e.message); }
|
||||
};
|
||||
|
||||
/* ── Plateformes ─────────────────────────────────────────────── */
|
||||
const addPlat = async (e) => {
|
||||
e.preventDefault(); setErr(null); setMsg(null);
|
||||
@@ -590,7 +963,7 @@ export default function PlateformesSection() {
|
||||
<input ref={platImportRef} type="file" accept=".zip" style={{ display: 'none' }}
|
||||
onChange={e => { const f = e.target.files[0]; e.target.value = ''; if (f) handlePlatImportZip(f); }} />
|
||||
<button className="primary" type="button"
|
||||
onClick={() => { setNewPlat(EMPTY_PLAT); setErr(null); setShowNewPlat(true); }}>
|
||||
onClick={() => { setErr(null); setShowAddPicker(true); }}>
|
||||
+ Ajouter
|
||||
</button>
|
||||
</div>
|
||||
@@ -724,6 +1097,75 @@ export default function PlateformesSection() {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
{/* ── Picker : choisir depuis le référentiel ou manuellement ── */}
|
||||
<PlatPickerModal
|
||||
open={showAddPicker}
|
||||
onClose={() => setShowAddPicker(false)}
|
||||
referentiel={referentiel}
|
||||
onSelect={addPlatFromRef}
|
||||
onManual={() => { setNewPlat(EMPTY_PLAT); setErr(null); setShowNewPlat(true); }}
|
||||
err={err}
|
||||
/>
|
||||
|
||||
{/* ── Modal : Ajouter une plateforme ── */}
|
||||
<Modal
|
||||
open={showNewPlat}
|
||||
title="Nouvelle plateforme"
|
||||
onClose={() => { setShowNewPlat(false); setNewPlat(EMPTY_PLAT); setNewPlatLogoFile(null); setNewPlatLogoPreview(null); setErr(null); }}
|
||||
width={600}
|
||||
footer={
|
||||
<div style={{ display: 'flex', justifyContent: 'flex-end', width: '100%', gap: 8 }}>
|
||||
<button type="button" onClick={() => { setShowNewPlat(false); setNewPlat(EMPTY_PLAT); setNewPlatLogoFile(null); setNewPlatLogoPreview(null); setErr(null); }}>Annuler</button>
|
||||
<button className="primary" form="form-new-plat" type="submit">Créer</button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<form id="form-new-plat" onSubmit={addPlat} style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
|
||||
{err && <div className="error">{err}</div>}
|
||||
<PlatForm
|
||||
state={newPlat} setter={setNewPlat}
|
||||
logoFile={newPlatLogoFile} setLogoFile={setNewPlatLogoFile}
|
||||
logoPreview={newPlatLogoPreview} setLogoPreview={setNewPlatLogoPreview}
|
||||
investisseurs={investisseurs} referentiel={referentiel}
|
||||
categoriesInv={[]} secteursInv={[]}
|
||||
/>
|
||||
</form>
|
||||
</Modal>
|
||||
|
||||
{/* ── Modal : Modifier une plateforme ── */}
|
||||
<Modal
|
||||
open={!!editPlat}
|
||||
title="Modifier la plateforme"
|
||||
onClose={() => { setEditPlat(null); setEditPlatLogoFile(null); setEditPlatLogoPreview(null); setErr(null); }}
|
||||
width={600}
|
||||
footer={
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', width: '100%' }}>
|
||||
<button className="danger" type="button" onClick={() => { const p = editPlat; setEditPlat(null); delPlat(p.id); }}>Supprimer</button>
|
||||
<div style={{ display: 'flex', gap: 8 }}>
|
||||
<button type="button" onClick={() => { setEditPlat(null); setEditPlatLogoFile(null); setEditPlatLogoPreview(null); setErr(null); }}>Annuler</button>
|
||||
<button className="primary" form="form-edit-plat" type="submit">Enregistrer</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{editPlat && (
|
||||
<form id="form-edit-plat" onSubmit={saveEditPlat} style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
|
||||
{err && <div className="error">{err}</div>}
|
||||
<PlatForm
|
||||
state={editPlat} setter={setEditPlat}
|
||||
logoFile={editPlatLogoFile} setLogoFile={setEditPlatLogoFile}
|
||||
logoPreview={editPlatLogoPreview} setLogoPreview={setEditPlatLogoPreview}
|
||||
investisseurs={investisseurs} referentiel={referentiel}
|
||||
categoriesInv={categoriesInv} secteursInv={secteursInv}
|
||||
isEdit
|
||||
onDelLogo={() => delLogoPlat(editPlat.id)}
|
||||
/>
|
||||
</form>
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
<ConfirmModal
|
||||
open={!!confirmDelete}
|
||||
title="Supprimer la plateforme"
|
||||
|
||||
Reference in New Issue
Block a user