jeremy 4 kuukautta sitten
vanhempi
commit
6a897f4d12
1 muutettua tiedostoa jossa 28 lisäystä ja 35 poistoa
  1. 28 35
      frontend/src/pages/Charges.jsx

+ 28 - 35
frontend/src/pages/Charges.jsx

@@ -3,7 +3,19 @@ import api from '../api'
 import toast from 'react-hot-toast'
 import { useAuth } from '../context/AuthContext'
 
+const CATEGORIES = [
+  { value: 'eau', label: '💧 Eau' },
+  { value: 'gaz', label: '🔥 Gaz' },
+  { value: 'electricite', label: '⚡ Électricité' },
+  { value: 'entretien', label: '🔧 Entretien / Réparations' },
+  { value: 'ascenseur', label: '🛗 Ascenseur' },
+  { value: 'ordures', label: '🗑️ Ordures ménagères' },
+  { value: 'assurance', label: '🛡️ Assurance' },
+  { value: 'autre', label: '📦 Autre' },
+]
+
 const CURRENT_YEAR = new Date().getFullYear()
+const YEARS = Array.from({ length: 6 }, (_, i) => CURRENT_YEAR - i)
 
 function Modal({ title, onClose, children }) {
   return (
@@ -19,9 +31,9 @@ function Modal({ title, onClose, children }) {
   )
 }
 
-function CategoryBadge({ value, categories }) {
-  const cat = categories.find(c => c.value === value)
-  return <span className="inline-flex items-center gap-1 text-xs bg-blue-50 text-blue-700 px-2 py-0.5 rounded-full font-medium">{cat ? `${cat.icon} ${cat.label}` : value}</span>
+function CategoryBadge({ value }) {
+  const cat = CATEGORIES.find(c => c.value === value)
+  return <span className="inline-flex items-center gap-1 text-xs bg-blue-50 text-blue-700 px-2 py-0.5 rounded-full font-medium">{cat?.label || value}</span>
 }
 
 export default function Charges() {
@@ -41,8 +53,6 @@ export default function Charges() {
   const [editCharge, setEditCharge] = useState(null)
   const [deductibleSummary, setDeductibleSummary] = useState(null)
   const [showDeductible, setShowDeductible] = useState(false)
-  const [categories, setCategories] = useState([])
-  const [availableYears, setAvailableYears] = useState([CURRENT_YEAR])
 
   const emptyForm = {
     property_id: '',
@@ -79,20 +89,8 @@ export default function Charges() {
     } catch { setDeductibleSummary(null) }
   }
 
-  // Load all distinct years from charges (unfiltered by year) to populate year selectors
-  const loadAvailableYears = async () => {
-    const params = new URLSearchParams()
-    if (filterProperty) params.append('property_id', filterProperty)
-    try {
-      const { data } = await api.get(`/charges?${params}`)
-      const yearsFromData = [...new Set(data.map(c => c.year).filter(Boolean))]
-      const merged = [...new Set([CURRENT_YEAR, ...yearsFromData])].sort((a, b) => b - a)
-      setAvailableYears(merged)
-    } catch {}
-  }
-
-  useEffect(() => { loadProperties(); api.get('/categories').then(r => setCategories(r.data)) }, [])
-  useEffect(() => { if (filterProperty) { loadCharges(); loadDeductibleSummary(); loadAvailableYears() } }, [filterProperty, filterYear])
+  useEffect(() => { loadProperties() }, [])
+  useEffect(() => { if (filterProperty) { loadCharges(); loadDeductibleSummary() } }, [filterProperty, filterYear])
 
   const openAdd = () => {
     setEditCharge(null)
@@ -171,7 +169,7 @@ export default function Charges() {
 
   const printBilan = () => {
     if (!bilan) return
-    const catLabel = v => { const c = categories.find(c => c.value === v); return c ? `${c.icon} ${c.label}` : v }
+    const catLabel = v => CATEGORIES.find(c => c.value === v)?.label || v
     const fmtEur = v => `${Number(v).toFixed(2)} €`
     const solde = bilan.total_provisions_percues - bilan.total_charges_reelles
     const isPos = solde >= 0
@@ -413,7 +411,7 @@ export default function Charges() {
         <div className="w-36">
           <label className="label">Année</label>
           <select className="input" value={filterYear} onChange={e => setFilterYear(e.target.value)}>
-            {availableYears.map(y => <option key={y} value={y}>{y}</option>)}
+            {YEARS.map(y => <option key={y} value={y}>{y}</option>)}
           </select>
         </div>
         {filterProperty && filterYear && (
@@ -437,7 +435,7 @@ export default function Charges() {
             <div className="flex items-center gap-2">
               <span className="text-lg">💼</span>
               <div>
-                <h3 className="text-sm font-semibold text-purple-800">Charges déductibles des impôts — 11 ans</h3>
+                <h3 className="text-sm font-semibold text-purple-800">Charges déductibles des impôts — 10 ans</h3>
                 <p className="text-xs text-purple-500">
                   Total cumulé : <span className="font-bold">{fmt(deductibleSummary.grand_total)}</span>
                 </p>
@@ -451,8 +449,7 @@ export default function Charges() {
                 <thead>
                   <tr className="bg-purple-50 border-b border-purple-100">
                     <th className="text-left px-4 py-2 text-purple-700 font-semibold">Année</th>
-                    <th className="text-right px-4 py-2 text-purple-700 font-semibold">Investissement</th>
-                    <th className="text-right px-4 py-2 text-purple-700 font-semibold">Amortissement /10 ans</th>
+                    <th className="text-right px-4 py-2 text-purple-700 font-semibold">Montant déductible</th>
                     <th className="text-right px-4 py-2 text-purple-700 font-semibold">Nb factures</th>
                   </tr>
                 </thead>
@@ -463,9 +460,6 @@ export default function Charges() {
                       <td className={`px-4 py-2 text-right ${y.total > 0 ? 'text-purple-700' : 'text-gray-300'}`}>
                         {y.total > 0 ? fmt(y.total) : '—'}
                       </td>
-                      <td className={`px-4 py-2 text-right ${y.amortization > 0 ? 'text-blue-700 font-medium' : 'text-gray-300'}`}>
-                        {y.amortization > 0 ? fmt(y.amortization) : '—'}
-                      </td>
                       <td className={`px-4 py-2 text-right ${y.count > 0 ? 'text-gray-600' : 'text-gray-300'}`}>
                         {y.count > 0 ? y.count : '—'}
                       </td>
@@ -474,9 +468,8 @@ export default function Charges() {
                 </tbody>
                 <tfoot className="bg-purple-50 border-t-2 border-purple-200">
                   <tr>
-                    <td className="px-4 py-2 font-bold text-purple-800">Total (11 ans)</td>
+                    <td className="px-4 py-2 font-bold text-purple-800">Total (10 ans)</td>
                     <td className="px-4 py-2 text-right font-bold text-purple-800">{fmt(deductibleSummary.grand_total)}</td>
-                    <td className="px-4 py-2 text-right font-bold text-blue-800">{fmt(deductibleSummary.grand_amortization)}</td>
                     <td className="px-4 py-2 text-right font-bold text-gray-600">
                       {deductibleSummary.years.reduce((s, y) => s + y.count, 0)}
                     </td>
@@ -516,7 +509,7 @@ export default function Charges() {
                 {charges.map(c => (
                   <tr key={c.id} className="hover:bg-gray-50">
                     <td className="px-6 py-4 text-sm text-gray-600">{fmtDate(c.date)}</td>
-                    <td className="px-6 py-4"><CategoryBadge value={c.category} categories={categories} /></td>
+                    <td className="px-6 py-4"><CategoryBadge value={c.category} /></td>
                     <td className="px-6 py-4 text-gray-900 font-medium">{c.label}</td>
                     <td className="px-6 py-4 text-sm text-gray-500">{c.property_name}</td>
                     <td className="px-6 py-4 text-right font-semibold text-gray-900">{fmt(c.amount)}</td>
@@ -559,7 +552,7 @@ export default function Charges() {
                   <div className="flex-1 min-w-0">
                     <p className="font-semibold text-gray-900 truncate">{c.label}</p>
                     <div className="flex items-center gap-2 mt-1 flex-wrap">
-                      <CategoryBadge value={c.category} categories={categories} />
+                      <CategoryBadge value={c.category} />
                       {c.recoverable_type === 'recoverable'
                         ? <span className="text-xs bg-green-100 text-green-700 px-1.5 py-0.5 rounded-full font-medium">Locataire</span>
                         : c.recoverable_type === 'deductible'
@@ -606,14 +599,14 @@ export default function Charges() {
                 <label className="label">Catégorie *</label>
                 <select className="input" value={form.category}
                   onChange={e => setForm(f => ({ ...f, category: e.target.value }))}>
-                  {categories.map(c => <option key={c.value} value={c.value}>{c.icon} {c.label}</option>)}
+                  {CATEGORIES.map(c => <option key={c.value} value={c.value}>{c.label}</option>)}
                 </select>
               </div>
               <div>
                 <label className="label">Année *</label>
                 <select className="input" value={form.year}
                   onChange={e => setForm(f => ({ ...f, year: e.target.value }))}>
-                  {availableYears.map(y => <option key={y} value={y}>{y}</option>)}
+                  {YEARS.map(y => <option key={y} value={y}>{y}</option>)}
                 </select>
               </div>
             </div>
@@ -742,11 +735,11 @@ export default function Charges() {
                 <h3 className="text-sm font-semibold text-gray-700 mb-2">Répartition par catégorie</h3>
                 <div className="space-y-1">
                   {bilan.charges_by_category.map(c => {
-                    const cat = categories.find(x => x.value === c.category)
+                    const cat = CATEGORIES.find(x => x.value === c.category)
                     const pct = bilan.total_charges_reelles > 0 ? (c.total / bilan.total_charges_reelles * 100).toFixed(1) : 0
                     return (
                       <div key={c.category} className="flex items-center justify-between text-sm py-1">
-                        <span className="text-gray-600">{cat ? `${cat.icon} ${cat.label}` : c.category}</span>
+                        <span className="text-gray-600">{cat?.label || c.category}</span>
                         <div className="flex items-center gap-3">
                           <div className="w-24 bg-gray-100 rounded-full h-1.5">
                             <div className="bg-blue-500 h-1.5 rounded-full" style={{ width: `${pct}%` }}></div>