import { useState, useEffect, useCallback, useRef } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { api } from '../api.js'; import ConfirmModal from '../components/ConfirmModal.jsx'; import ResultBanner from '../components/ResultBanner.jsx'; import Modal from '../components/Modal.jsx'; import CountrySelect, { COUNTRIES } from '../components/CountrySelect.jsx'; /* ── Icônes nav ───────────────────────────────────────────────── */ function IconTax() { return ( ); } function IconChevronLeft() { return ; } function IconPercent() { return ; } /* ═══════════════════════════════════════════════════════════════ HELPERS — taux crédit d'impôt ═══════════════════════════════════════════════════════════════ */ function flagEmoji(code) { if (!code) return '🌐'; if (code === 'XK') return '🇽🇰'; return code.toUpperCase().replace(/./g, c => String.fromCodePoint(c.charCodeAt(0) + 127397) ); } function fmtTaux(taux, exclusif) { if (exclusif) return excl. résidence; if (taux == null) return ; return <>{taux.toFixed(1).replace('.', ',')} %; } function StatutBadge({ statut }) { const map = { active: { label: 'Active', bg: 'rgba(34,197,94,.12)', color: '#16a34a', border: 'rgba(34,197,94,.3)' }, suspendue: { label: 'Suspendue', bg: 'rgba(234,179,8,.12)', color: '#ca8a04', border: 'rgba(234,179,8,.3)' }, caduque: { label: 'Caduque', bg: 'rgba(239,68,68,.12)', color: '#dc2626', border: 'rgba(239,68,68,.3)' }, }; const s = map[statut] || map.active; return ( {s.label} ); } const EMPTY_TCI = { nom_pays: '', code_pays: '', div_taux: '', div_taux_alt: '', div_taux_alt_label: '', div_exclusif_residence: false, int_taux: '', int_taux_alt: '', int_taux_alt_label: '', int_exclusif_residence: false, notice: '', statut_convention: 'active', date_suspension: '', ref_boi: '', }; /* ── Modal création / édition pays ───────────────────────────── */ function TciModal({ row, onClose, onSaved }) { const isNew = !row?.id; const [form, setForm] = useState(isNew ? EMPTY_TCI : { nom_pays: row.nom_pays || '', code_pays: row.code_pays || '', div_taux: row.div_taux != null ? String(row.div_taux) : '', div_taux_alt: row.div_taux_alt != null ? String(row.div_taux_alt) : '', div_taux_alt_label: row.div_taux_alt_label || '', div_exclusif_residence: !!row.div_exclusif_residence, int_taux: row.int_taux != null ? String(row.int_taux) : '', int_taux_alt: row.int_taux_alt != null ? String(row.int_taux_alt) : '', int_taux_alt_label: row.int_taux_alt_label || '', int_exclusif_residence: !!row.int_exclusif_residence, notice: row.notice || '', statut_convention: row.statut_convention || 'active', date_suspension: row.date_suspension || '', ref_boi: row.ref_boi || '', }); const [err, setErr] = useState(null); const [saving, setSaving] = useState(false); const set = (k, v) => setForm(f => ({ ...f, [k]: v })); const handleSubmit = async (e) => { e.preventDefault(); if (!form.nom_pays.trim()) { setErr('Le nom du pays est requis.'); return; } setSaving(true); setErr(null); try { const payload = { nom_pays: form.nom_pays.trim(), code_pays: form.code_pays.trim().toUpperCase() || null, div_taux: form.div_exclusif_residence ? null : (form.div_taux !== '' ? Number(form.div_taux) : null), div_taux_alt: form.div_exclusif_residence ? null : (form.div_taux_alt !== '' ? Number(form.div_taux_alt) : null), div_taux_alt_label: form.div_taux_alt_label.trim() || null, div_exclusif_residence: form.div_exclusif_residence, int_taux: form.int_exclusif_residence ? null : (form.int_taux !== '' ? Number(form.int_taux) : null), int_taux_alt: form.int_exclusif_residence ? null : (form.int_taux_alt !== '' ? Number(form.int_taux_alt) : null), int_taux_alt_label: form.int_taux_alt_label.trim() || null, int_exclusif_residence: form.int_exclusif_residence, notice: form.notice.trim() || null, statut_convention: form.statut_convention, date_suspension: form.date_suspension || null, ref_boi: form.ref_boi.trim() || null, }; if (isNew) { await api.post('/taux-credit-impot', payload); } else { await api.put(`/taux-credit-impot/${row.id}`, payload); } onSaved(); onClose(); } catch (ex) { setErr(ex.message); } finally { setSaving(false); } }; const inp = { width: '100%', boxSizing: 'border-box' }; const grid = { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }; return ( }>
set('nom_pays', e.target.value)} />
{ const country = COUNTRIES.find(c => c.code === code); setForm(f => ({ ...f, code_pays: code, nom_pays: f.nom_pays.trim() ? f.nom_pays : (country?.name || f.nom_pays), })); }} />
set('date_suspension', e.target.value)} />
set('ref_boi', e.target.value)} placeholder="Ex : BOI-INT-CVB-DEU" />
{['div', 'int'].map(cat => { const excl = form[`${cat}_exclusif_residence`]; return (
{cat === 'div' ? 'Dividendes' : 'Intérêts'}
set(`${cat}_exclusif_residence`, !excl)}> {}} style={{ width: 'auto', verticalAlign: 'middle', marginRight: 15, pointerEvents: 'none' }} /> Imposable exclusivement au lieu de résidence — aucun crédit d'impôt
{!excl && (
set(`${cat}_taux`, e.target.value)} placeholder="Ex : 17.6" />
set(`${cat}_taux_alt`, e.target.value)} placeholder="Optionnel" />
{form[`${cat}_taux_alt`] !== '' && (
set(`${cat}_taux_alt_label`, e.target.value)} placeholder="Ex : Société exonérée IS" />
)}
)}
); })}