web: start: add dynamique menu

Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
This commit is contained in:
GnomeZworc 2026-06-04 00:06:51 +02:00
commit c805169747
Signed by: nicolas.boufideline
GPG key ID: 4406BBBF8845D632
9 changed files with 343 additions and 8 deletions

View file

@ -0,0 +1,121 @@
#account-page {
width: 100%;
display: flex;
flex-direction: column;
gap: 24px;
}
/* ── Header ────────────────────────────────────────────────────────────── */
#account-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
background: #1e1e2e;
border: 1px solid #313244;
border-radius: 10px;
padding: 20px 24px;
}
#account-name {
font-size: 20px;
font-weight: 600;
color: #cdd6f4;
margin: 0 0 4px;
}
#account-id {
font-size: 12px;
color: #6c7086;
font-family: monospace;
}
#account-balance-block {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
}
.balance-label {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.08em;
color: #6c7086;
}
#account-balance {
font-size: 24px;
font-weight: 700;
color: #a6e3a1;
font-variant-numeric: tabular-nums;
}
#account-balance.negative { color: #f38ba8; }
/* ── Transactions ───────────────────────────────────────────────────────── */
#account-transactions {
background: #1e1e2e;
border: 1px solid #313244;
border-radius: 10px;
padding: 20px 24px;
}
#account-transactions h3 {
font-size: 13px;
font-weight: 600;
color: #a6adc8;
text-transform: uppercase;
letter-spacing: 0.08em;
margin: 0 0 16px;
}
#tx-table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
#tx-table th {
text-align: left;
color: #6c7086;
font-weight: 500;
font-size: 12px;
padding: 0 12px 10px;
border-bottom: 1px solid #313244;
}
#tx-table td {
padding: 10px 12px;
color: #a6adc8;
border-bottom: 1px solid #1e1e2e;
}
#tx-table tbody tr:last-child td { border-bottom: none; }
#tx-table tbody tr:hover td { background: #313244; }
.amount-col { text-align: right; }
td.amount { text-align: right; font-variant-numeric: tabular-nums; font-weight: 500; }
td.amount.positive { color: #a6e3a1; }
td.amount.negative { color: #f38ba8; }
td.date { color: #6c7086; font-size: 13px; white-space: nowrap; }
/* ── States ─────────────────────────────────────────────────────────────── */
#account-loading {
color: #6c7086;
font-size: 14px;
}
#account-error {
background: #313244;
border: 1px solid #f38ba8;
border-radius: 8px;
padding: 12px 16px;
color: #f38ba8;
font-size: 13px;
}

View file

@ -0,0 +1,117 @@
// Account page.
// Reads ?id=<account-id> from the URL hash and renders account details.
// Replace fetchAccount() with a real api-client call when backend is ready.
// ── Mock data ────────────────────────────────────────────────────────────────
const MOCK_DB = {
tresorerie: {
name: 'Trésorerie',
balance: 48_230.50,
currency: 'EUR',
transactions: [
{ date: '2026-06-03', label: 'Virement client Martin SA', amount: +12_000.00 },
{ date: '2026-06-01', label: 'Virement client Dupont SARL', amount: +5_000.00 },
{ date: '2026-05-30', label: 'Loyer bureau juin', amount: -2_500.00 },
{ date: '2026-05-28', label: 'Facture EDF', amount: -340.20 },
{ date: '2026-05-25', label: 'Abonnement SaaS infra', amount: -189.00 },
],
},
charges: {
name: 'Charges',
balance: 12_890.00,
currency: 'EUR',
transactions: [
{ date: '2026-06-01', label: 'Salaires mai', amount: -8_500.00 },
{ date: '2026-05-28', label: 'Assurance professionnelle', amount: -420.00 },
{ date: '2026-05-20', label: 'Formation équipe', amount: -1_200.00 },
],
},
produits: {
name: 'Produits',
balance: 67_450.00,
currency: 'EUR',
transactions: [
{ date: '2026-06-02', label: 'Facture client #2024-089', amount: +18_000.00 },
{ date: '2026-05-29', label: 'Facture client #2024-088', amount: +9_500.00 },
{ date: '2026-05-22', label: 'Avoir client Dupont', amount: -500.00 },
],
},
fournisseurs: {
name: 'Fournisseurs',
balance: -8_340.00,
currency: 'EUR',
transactions: [
{ date: '2026-06-01', label: 'Facture Tech Components SAS', amount: -3_200.00 },
{ date: '2026-05-27', label: 'Règlement fournisseur Leroy', amount: +2_000.00 },
{ date: '2026-05-20', label: 'Facture Bureau & Co', amount: -640.00 },
],
},
}
async function fetchAccount(id) {
// TODO: replace with real call
// const api = document.querySelector('api-client')
// return await api.finance.get(`/accounts/${id}`)
await new Promise(r => setTimeout(r, 300))
const data = MOCK_DB[id]
if (!data) throw new Error(`Compte introuvable : ${id}`)
return data
}
// ── Helpers ──────────────────────────────────────────────────────────────────
function formatAmount(amount, currency) {
return new Intl.NumberFormat('fr-FR', { style: 'currency', currency }).format(amount)
}
function formatDate(iso) {
return new Intl.DateTimeFormat('fr-FR', { day: '2-digit', month: 'short', year: 'numeric' }).format(new Date(iso))
}
// ── Init ─────────────────────────────────────────────────────────────────────
export function init(main) {
const params = new URLSearchParams(window.location.hash.split('?')[1])
const id = params.get('id')
const loading = main.querySelector('#account-loading')
const error = main.querySelector('#account-error')
if (!id) {
loading.style.display = 'none'
error.style.display = 'block'
error.textContent = 'Aucun compte sélectionné.'
return
}
fetchAccount(id)
.then(data => render(main, id, data))
.catch(err => {
loading.style.display = 'none'
error.style.display = 'block'
error.textContent = err.message
})
}
function render(main, id, data) {
main.querySelector('#account-loading').style.display = 'none'
main.querySelector('#account-name').textContent = data.name
main.querySelector('#account-id').textContent = id
const balanceEl = main.querySelector('#account-balance')
balanceEl.textContent = formatAmount(data.balance, data.currency)
balanceEl.classList.toggle('negative', data.balance < 0)
const tbody = main.querySelector('#tx-body')
tbody.innerHTML = data.transactions.map(tx => `
<tr>
<td class="date">${formatDate(tx.date)}</td>
<td>${tx.label}</td>
<td class="amount ${tx.amount >= 0 ? 'positive' : 'negative'}">
${formatAmount(tx.amount, data.currency)}
</td>
</tr>
`).join('')
}

View file

@ -0,0 +1,29 @@
<div id="account-page">
<div id="account-header">
<div id="account-title">
<h2 id="account-name"></h2>
<span id="account-id"></span>
</div>
<div id="account-balance-block">
<span class="balance-label">Solde</span>
<span id="account-balance"></span>
</div>
</div>
<section id="account-transactions">
<h3>Transactions récentes</h3>
<table id="tx-table">
<thead>
<tr>
<th>Date</th>
<th>Libellé</th>
<th class="amount-col">Montant</th>
</tr>
</thead>
<tbody id="tx-body"></tbody>
</table>
</section>
<div id="account-error" style="display:none"></div>
<div id="account-loading">Chargement…</div>
</div>

View file

@ -0,0 +1,5 @@
{
"route": "account",
"label": "Compte",
"icon": "account"
}