diff --git a/frontend/src/components/Dashboard.jsx b/frontend/src/components/Dashboard.jsx index 947c23f..fd56e94 100644 --- a/frontend/src/components/Dashboard.jsx +++ b/frontend/src/components/Dashboard.jsx @@ -3,6 +3,17 @@ import { useState, useEffect } from 'react' const KSUITE_PRICE = 6.58 const SITE_PRICE = 69 +function getCosts(d) { + const team = JSON.parse(d.team_members || '[]') + const nbUsers = d.has_team ? team.length : 0 + const doms = JSON.parse(d.domains_list || '[]') + const ksuite = nbUsers * KSUITE_PRICE + const site = d.has_website ? SITE_PRICE / 12 : 0 + const extra = (d.extra_email_count || 0) * (d.extra_email_cost || 0) + const domCost = doms.reduce((s, dm) => s + (dm.cost_per_year || 0) / 12, 0) + return { nbUsers, doms, ksuite, site, extra, domCost, total: ksuite + site + extra + domCost } +} + export default function Dashboard({ token, user }) { const [domains, setDomains] = useState([]) const [activeTab, setActiveTab] = useState(-1) @@ -35,8 +46,8 @@ export default function Dashboard({ token, user }) { const update = (id, field, val) => { setDomains(prev => prev.map(d => d.id === id ? { ...d, [field]: val } : d)) - const timeout = setTimeout(() => saveDomain(id), 1200) - return () => clearTimeout(timeout) + const t = setTimeout(() => saveDomain(id), 1200) + return () => clearTimeout(t) } const addToList = (id, field) => { @@ -73,8 +84,10 @@ export default function Dashboard({ token, user }) { doms.forEach(dm => allDomains.push({ ...dm, society: d.company_name })) }) + const grandTotal = domains.reduce((s, d) => s + getCosts(d).total, 0) + const getColor = (expiry) => { - if (!expiry) return '' + if (!expiry) return 'text-slate-500' const diff = (new Date(expiry) - new Date()) / (1000 * 60 * 60 * 24) if (diff < 0) return 'text-red-400' if (diff < 30) return 'text-amber-400' @@ -82,86 +95,91 @@ export default function Dashboard({ token, user }) { return 'text-emerald-400' } - const hosterColors = { - 'OVH': 'bg-sky-500/20 text-sky-300', - 'Infomaniak': 'bg-emerald-500/20 text-emerald-300', - 'Other': 'bg-slate-500/20 text-slate-300' + const hosterBadge = (h) => { + const m = { 'OVH': 'bg-sky-500/20 text-sky-300', 'Infomaniak': 'bg-emerald-500/20 text-emerald-300' } + return m[h] || 'bg-slate-500/20 text-slate-300' } return (
-

Tableau de bord

-
- - - - - - - - - - - {allDomains.length === 0 && ( - - )} - {allDomains.map((dm, i) => ( - - - - - - - ))} - -
SocieteDomaineHebergeurExpiration
Aucun domaine declare
{dm.society}{dm.name || '—'} - - {dm.hoster || '—'} - - - {dm.expiry || '—'} -
+ {/* Recap par societe */} +
+ {domains.map((d, i) => { + const c = getCosts(d) + return ( + + ) + })}
+ + {/* Grand total */} + {isAdmin && ( +
+

Total general

+

{grandTotal.toFixed(2)}EUR/mois HT

+
+ )} + + {/* Tableau domaines */} + {allDomains.length > 0 && ( +
+

Domaines

+
+ + + + + + + + + + + {allDomains.map((dm, i) => ( + + + + + + + ))} + +
SocieteDomaineHebergeurExpiration
{dm.society}{dm.name || '—'}{dm.hoster || '—'}{dm.expiry || '—'}
+
+
+ )}
) } - // DOMAIN FORM VIEW + // DOMAIN FORM const DomainForm = ({ d }) => { - const team = JSON.parse(d.team_members || '[]') - const nbUsers = d.has_team ? team.length : 0 - const doms = JSON.parse(d.domains_list || '[]') - - const ksuiteCost = nbUsers * KSUITE_PRICE - const siteCost = d.has_website ? SITE_PRICE / 12 : 0 - const extraCost = (d.extra_email_count || 0) * (d.extra_email_cost || 0) - const domsCost = doms.reduce((s, dm) => s + (dm.cost_per_year || 0) / 12, 0) - const total = ksuiteCost + siteCost + extraCost + domsCost - - const Row = ({ label, children }) => ( -
- {label} -
{children}
-
- ) + const c = getCosts(d) const Txt = ({ value, onChange, placeholder }) => ( onChange(e.target.value)} placeholder={placeholder} className="w-full px-3 py-2 bg-slate-900/40 border border-slate-700/50 rounded-lg text-white text-sm placeholder-slate-600 focus:outline-none focus:ring-1 focus:ring-blue-500/50" /> ) - const Num = ({ value, onChange, placeholder, step }) => ( onChange(parseFloat(e.target.value) || 0)} placeholder={placeholder} className="w-28 px-3 py-2 bg-slate-900/40 border border-slate-700/50 rounded-lg text-white text-sm text-right placeholder-slate-600 focus:outline-none focus:ring-1 focus:ring-blue-500/50 font-mono" /> ) - - const Toggle = ({ checked, onChange, activeText, inactiveText, color }) => ( + const Toggle = ({ checked, onChange }) => ( ) - const Select = ({ value, onChange, options }) => ( updateInList(d.id, 'team_members', i, 'first_name', e.target.value)} placeholder="Prenom" className="flex-1 px-3 py-2 bg-slate-900/40 border border-slate-700/50 rounded-lg text-white text-sm placeholder-slate-600 focus:outline-none focus:ring-1 focus:ring-blue-500/50" /> updateInList(d.id, 'team_members', i, 'last_name', e.target.value)} placeholder="Nom" className="flex-1 px-3 py-2 bg-slate-900/40 border border-slate-700/50 rounded-lg text-white text-sm placeholder-slate-600 focus:outline-none focus:ring-1 focus:ring-blue-500/50" /> - +
))} - + )} - - -
+ {/* Site internet */} -
-
- Site internet 69 EUR/an - +
+
+ Site actif + update(d.id, 'has_website', v)} />
{d.has_website && ( -
+
WordPress - - Gere par + update(d.id, 'website_wordpress', v)} /> + Gere par updateInList(d.id, 'domains_list', i, 'name', e.target.value)} placeholder="domaine.fr" className="flex-1 px-3 py-2 bg-slate-900/40 border border-slate-700/50 rounded-lg text-white text-sm placeholder-slate-600 focus:outline-none focus:ring-1 focus:ring-blue-500/50" /> @@ -282,37 +273,31 @@ export default function Dashboard({ token, user }) { className="w-28 px-3 py-2 bg-slate-900/40 border border-slate-700/50 rounded-lg text-white text-sm focus:outline-none focus:ring-1 focus:ring-blue-500/50" /> updateInList(d.id, 'domains_list', i, 'hoster', e.target.value)} placeholder="Hebergeur" className="w-24 px-3 py-2 bg-slate-900/40 border border-slate-700/50 rounded-lg text-white text-sm placeholder-slate-600 focus:outline-none focus:ring-1 focus:ring-blue-500/50" /> - +
))}
)} -
- -
+
{/* Notes */} -
- Notes +