Files
depenses_trello/templates/index.html
2026-02-27 09:24:51 +01:00

234 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>💸 Dépenses Trello</title>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;600;700&display=swap" rel="stylesheet">
<style>
:root { --bg-dark: #0d0d1a; --bg-card: #16162a; --bg-input: #1a1a35; --primary: #e94560; --secondary: #7b2cbf; --accent: #00d9ff; --text: #fff; --text-dim: #888; --success: #00ff88; --danger: #ff4757; }
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Outfit', sans-serif; background: var(--bg-dark); color: var(--text); padding: 15px; min-height: 100vh; }
h1 { text-align: center; font-size: 1.6em; background: linear-gradient(135deg, var(--primary), var(--secondary)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
.nav { display: flex; gap: 10px; margin: 15px 0; }
.nav a { flex: 1; padding: 12px; background: var(--bg-card); border-radius: 10px; text-align: center; color: var(--text-dim); text-decoration: none; }
.nav a.active { background: linear-gradient(135deg, var(--primary), var(--secondary)); color: #fff; }
.card { background: var(--bg-card); border-radius: 15px; padding: 15px; margin-bottom: 15px; }
h2 { font-size: 1em; margin-bottom: 12px; }
.form-group { margin-bottom: 10px; }
.form-group label { display: block; color: var(--text-dim); font-size: 0.85em; margin-bottom: 4px; }
.form-group input, .form-group select { width: 100%; padding: 12px; background: var(--bg-input); border: 2px solid transparent; border-radius: 10px; color: var(--text); font-size: 1em; }
.form-group input:focus { border-color: var(--accent); outline: none; }
.btn { width: 100%; padding: 14px; border: none; border-radius: 10px; font-weight: 600; cursor: pointer; margin-top: 10px; }
.btn-primary { background: linear-gradient(135deg, var(--accent), #0099cc); color: var(--bg-dark); }
.btn-success { background: linear-gradient(135deg, var(--success), #00cc66); color: var(--bg-dark); }
.btn-danger { background: var(--danger); color: #fff; }
.prenom-tags { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0; }
.prenom-tag { display: flex; align-items: center; gap: 5px; background: linear-gradient(135deg, var(--primary), var(--secondary)); padding: 8px 12px; border-radius: 20px; font-size: 0.85em; }
.expense-item { display: flex; justify-content: space-between; align-items: center; padding: 12px; background: var(--bg-input); border-radius: 10px; margin-bottom: 8px; flex-wrap: wrap; gap: 5px; }
.expense-prenom { background: linear-gradient(135deg, var(--primary), var(--secondary)); padding: 4px 10px; border-radius: 15px; font-size: 0.75em; white-space: nowrap; }
.expense-montant { font-weight: 700; color: var(--accent); }
.total { text-align: right; font-size: 1.2em; margin: 10px 0; padding: 12px; background: rgba(0,217,255,0.1); border-radius: 10px; }
.total span { font-weight: 700; color: var(--accent); }
.preview { background: var(--bg-input); padding: 12px; border-radius: 10px; white-space: pre-wrap; color: var(--success); font-family: monospace; margin-top: 10px; }
.actions { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
</style>
</head>
<body>
<h1>💸 Dépenses Trello</h1>
<div class="nav">
<a href="?page=saisie" id="nav-saisie">✏️ Saisie</a>
<a href="?page=config" id="nav-config">⚙️ Config</a>
</div>
<div id="saisie" style="display:none">
<div class="card">
<h2> Nouvelle dépense</h2>
<form method="POST" action="/api/add" id="form-add">
<div class="form-group"><label>👤 Prénom</label><select name="prenom" id="prenom-select" required></select></div>
<div class="form-group"><label>📅 Date</label><input type="date" name="date" id="depense-date" required></div>
<div class="form-group"><label>📝 Libellé</label><input type="text" name="libelle" placeholder="Courses, Essence..." required></div>
<div class="form-group"><label>💰 Montant (€)</label><input type="number" name="montant" placeholder="0.00" step="0.01" required></div>
<button type="submit" class="btn btn-primary"> Ajouter</button>
</form>
</div>
<div class="card">
<h2>📋 Dépenses (<span id="count">0</span>)</h2>
<div id="expenses"></div>
<div class="total">Total: <span id="total">0.00€</span></div>
<div class="actions">
<button class="btn btn-primary" onclick="generate()">👁️ Aperçu</button>
<button class="btn btn-success" onclick="sendTrello()">🟦 Envoyer Trello</button>
<button class="btn btn-danger" onclick="clearAll()">🗑️ Tout effacer</button>
</div>
<div class="preview" id="preview" style="display:none"></div>
</div>
</div>
<div id="config" style="display:none">
<div class="card">
<h2>👥 Prénoms</h2>
<div id="prenom-tags"></div>
<form method="POST" action="/api/prenom/add" id="form-prenom">
<div style="display:flex;gap:10px;margin-top:10px">
<input type="text" name="prenom" placeholder="Nouveau prénom..." style="flex:1">
<button type="submit" class="btn btn-primary" style="width:auto"></button>
</div>
</form>
</div>
<div class="card">
<h2>📄 Format du texte</h2>
<form method="POST" action="/api/format" id="form-format">
<div class="form-group"><input type="text" name="format" id="format-input"></div>
<button type="submit" class="btn btn-primary">💾 Sauvegarder</button>
</form>
<div class="preview" id="format-preview"></div>
</div>
<div class="card">
<h2>🔗 Trello</h2>
<form method="POST" action="/api/trello/save" id="form-trello">
<div class="form-group"><label>🔑 API Key</label><input type="text" name="api_key" id="trello-api_key"></div>
<div class="form-group"><label>🔐 Token</label><input type="password" name="token" id="trello-token"></div>
<div class="form-group"><label>📁 List ID</label><input type="text" name="list_id" id="trello-list_id"></div>
<button type="submit" class="btn btn-primary">💾 Sauvegarder</button>
</form>
</div>
</div>
<script>
var config = { prenoms: [], format: '', trello: {} };
var depenses = [];
function formatDate(d) { if(!d) return ""; return d.split("-").reverse().join("/"); }
async function load() {
var r = await fetch('/api/config');
config = await r.json();
r = await fetch('/api/depenses');
depenses = await r.json();
render();
checkPage();
}
function checkPage() {
var params = new URLSearchParams(window.location.search);
var page = params.get('page') || 'saisie';
showPage(page);
}
function showPage(page) {
document.getElementById('saisie').style.display = page === 'saisie' ? 'block' : 'none';
document.getElementById('config').style.display = page === 'config' ? 'block' : 'none';
document.getElementById('nav-saisie').className = page === 'saisie' ? 'nav a active' : 'nav a';
document.getElementById('nav-config').className = page === 'config' ? 'nav a active' : 'nav a';
}
function render() {
// Prenoms
document.getElementById('prenom-select').innerHTML = '<option value="">Choisir...</option>' + config.prenoms.map(function(p) { return '<option value="' + p + '">' + p + '</option>'; }).join('');
document.getElementById('prenom-tags').innerHTML = config.prenoms.map(function(p, i) { return '<span class="prenom-tag">' + p + '<a href="/api/prenom/del/' + i + '" style="color:#fff;text-decoration:none;margin-left:5px">×</a></span>'; }).join('');
// Format
document.getElementById('format-input').value = config.format || '{prenom} - {date} - {libelle} - {montant}€';
var fmt = config.format || '{prenom} - {date} - {libelle} - {montant}€';
fmt = fmt.replace('{prenom}', 'Papa').replace('{date}', '27/02/2026').replace('{libelle}', 'Courses').replace('{montant}', '45.50');
document.getElementById('format-preview').textContent = fmt;
// Trello
if (config.trello) {
document.getElementById('trello-api_key').value = config.trello.api_key || '';
document.getElementById('trello-token').value = config.trello.token || '';
document.getElementById('trello-list_id').value = config.trello.list_id || '';
}
// Expenses
document.getElementById('count').textContent = depenses.length;
var total = depenses.reduce(function(s, d) { return s + (parseFloat(d.montant) || 0); }, 0);
document.getElementById('total').textContent = total.toFixed(2) + '€';
var html = '';
for (var i = 0; i < depenses.length; i++) {
var d = depenses[i];
html += '<div class="expense-item">';
html += '<div style="display:flex;align-items:center;gap:10px">';
html += '<span class="expense-prenom">' + d.prenom + '</span>';
html += '<span>' + formatDate(d.date) + ' - ' + d.libelle + '</span>';
html += '</div>';
html += '<div style="display:flex;align-items:center;gap:10px">';
html += '<span class="expense-montant">' + parseFloat(d.montant).toFixed(2) + '€</span>';
html += '<a href="/api/del/' + d.id + '" style="color:var(--danger);text-decoration:none;font-size:1.2em">🗑️</a>';
html += '</div></div>';
}
document.getElementById('expenses').innerHTML = html;
document.getElementById('depense-date').value = new Date().toISOString().split('T')[0];
}
document.getElementById('form-add').onsubmit = function(e) {
e.preventDefault();
var fd = new FormData(e.target);
fetch('/api/add', { method: 'POST', body: fd }).then(function() {
e.target.reset();
load();
});
};
document.getElementById('form-prenom').onsubmit = function(e) {
e.preventDefault();
var fd = new FormData(e.target);
fetch('/api/prenom/add', { method: 'POST', body: fd }).then(function() {
e.target.reset();
load();
});
};
document.getElementById('form-format').onsubmit = function(e) {
e.preventDefault();
var fd = new FormData(e.target);
fetch('/api/format', { method: 'POST', body: fd }).then(function() {
alert('Format sauvegardé!');
load();
});
};
document.getElementById('form-trello').onsubmit = function(e) {
e.preventDefault();
var fd = new FormData(e.target);
fetch('/api/trello/save', { method: 'POST', body: fd }).then(function() {
alert('Config Trello sauvegardée!');
load();
});
};
async function generate() {
var r = await fetch('/api/generate', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({depenses: depenses}) });
var d = await r.json();
document.getElementById('preview').textContent = d.text;
document.getElementById('preview').style.display = 'block';
}
async function sendTrello() {
if (!config.trello || !config.trello.api_key) { alert('Configure Trello!'); showPage('config'); return; }
await generate();
var text = document.getElementById('preview').textContent;
var r = await fetch('/api/trello/send', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({title: 'Dépenses ' + new Date().toLocaleDateString('fr'), text: text}) });
if (r.ok) { alert('Envoyé sur Trello!'); clearAll(); }
else { var e = await r.json(); alert('Erreur: ' + e.error); }
}
async function clearAll() {
if (confirm('Tout effacer?')) {
await fetch('/api/clear', { method: 'POST' });
load();
}
}
load();
</script>
</body>
</html>