Family Budget Planner: Gestionare Financiară Inteligentă

Explorați soluția noastră în categoria: JavaScript

Detalii Tehnice

Preia controlul total asupra banilor tăi cu Family Budget Master, un instrument digital inteligent creat pentru a-ți simplifica viața. Indiferent dacă vrei să monitorizezi veniturile (Cash, Card sau Bonuri) sau să detaliezi cheltuielile pe utilități și rate, această aplicație îți oferă claritate instantanee. Nu necesită cont și se poate utiliza direct pe Rtec-Design, salvând datele în siguranță pe dispozitivul tău.

Gestionarea banilor nu ar trebui să fie o corvoadă plină de tabele complicate. Am creat acest SaaS utilitar plecând de la o nevoie umană reală: dorința de a ști exact unde se duc banii familiei la final de lună.

Spre deosebire de alte aplicații care îți cer datele pe servere externe, soluția noastră pune intimitatea pe primul loc. Totul se întâmplă în browserul tău. Am integrat o logică de selectare ierarhică: alegi o categorie mare (ca "Utilități") și poți specifica imediat dacă e vorba de Gaz, Curent sau Internet. Astfel, la finalul lunii, graficul tău interactiv îți va arăta nu doar că ai cheltuit, ci pe ce ai cheltuit cel mai mult.

Beneficii cheie pentru tine:

  • Organizare pe surse: Știi exact câți bani ai în portofel (Cash), câți pe card și câți în tichete de masă.
  • Detaliere pentru Credite: Monitorizează separat ratele la bancă sau creditele externe pentru o planificare riguroasă.
  • Interfață Prietenoasă: Design modern, intuitiv, optimizat pentru a fi folosit de oricine, de la tineri la bunici.
  • Analiză Vizuală: Graficele tip "pie chart" îți transformă cifrele seci în imagini clare și ușor de înțeles.
🎨 1. Partea de Stil (CSS)

Designul este unul curat, de tip "Dark Dashboard", care nu obosește ochii și oferă un aer profesional proiectului tău.


🧠 2. Logica Inteligentă (JavaScript)

Nucleul aplicației care se ocupă de calcule și de salvarea sigură a datelor în browser.


🚀 3. Interfața SaaS (HTML)

Structura este concepută pentru a fi inserată într-un singur bloc, fără a necesita fișiere externe.

HTML


<style>
:root { --primary: #00ff88; --danger: #ff4757; --card: #161b22; --bg: #0d1117; }
.budget-v4-container { max-width: 1200px; margin: 20px auto; font-family: 'Segoe UI', sans-serif; background: var(--bg); color: #c9d1d9; padding: 30px; border-radius: 20px; border: 1px solid #30363d; }
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 30px; }
.stat-box { background: var(--card); padding: 20px; border-radius: 12px; border-left: 4px solid var(--primary); }
.stat-box small { color: #8b949e; font-size: 0.8rem; }
.stat-box div { font-size: 1.4rem; font-weight: bold; margin-top: 5px; }
.app-layout { display: grid; grid-template-columns: 350px 1fr; gap: 30px; }
.form-card { background: var(--card); padding: 25px; border-radius: 15px; height: fit-content; }
select, input { width: 100%; padding: 12px; margin: 8px 0 15px; background: #0d1117; border: 1px solid #30363d; color: #fff; border-radius: 8px; box-sizing: border-box; }
.btn-submit { background: var(--primary); color: #0d1117; font-weight: bold; border: none; padding: 15px; border-radius: 8px; cursor: pointer; width: 100%; transition: 0.3s; }
.btn-submit:hover { filter: brightness(1.1); transform: scale(1.01); }
.history-item { padding: 12px; border-bottom: 1px solid #30363d; display: flex; justify-content: space-between; align-items: center; animation: fadeIn 0.3s; }
.delete-btn { background: #ff4757; color: white; border: none; cursor: pointer; padding: 6px 12px; border-radius: 6px; font-weight: bold; font-size: 0.7rem; }
.delete-btn:hover { background: #b91c1c; }
.badge-income { color: var(--primary); }
.badge-expense { color: var(--danger); }
@keyframes fadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } }
@media (max-width: 900px) { .app-layout { grid-template-columns: 1fr; } }
</style>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
const FamilyBudget = (() => {
    const KEY = 'rtec_v4_audit_data';
    
    let storage = { transactions: [] };
    try {
        const saved = localStorage.getItem(KEY);
        if(saved) storage = JSON.parse(saved);
        if(!Array.isArray(storage.transactions)) storage.transactions = [];
    } catch(e) { storage = { transactions: [] }; }


    let chart = null;
    const subs = {
        'Utilități': ['Apă', 'Curent', 'Gaz', 'Internet/TV'],
        'Credite': ['Rată Bancă', 'Credit Extern', 'Card Credit'],
        'Mâncare': ['Supermarket', 'Restaurant/Delivery'],
        'Altele': ['Divertisment', 'Sănătate', 'Haine', 'Transport']
    };


    const saveAndRefresh = () => {
        localStorage.setItem(KEY, JSON.stringify(storage));
        updateInterface();
    };


    const updateInterface = () => {
        let t = { cash: 0, card: 0, bonuri: 0, exp: 0 };
        storage.transactions.forEach(i => {
            if(i.type === 'income') {
                if(t.hasOwnProperty(i.category)) t[i.category] += i.amount;
            } else {
                t.exp += i.amount;
            }
        });


        document.getElementById('stat-cash').innerText = t.cash.toFixed(2) + ' RON';
        document.getElementById('stat-card').innerText = t.card.toFixed(2) + ' RON';
        document.getElementById('stat-bonuri').innerText = t.bonuri.toFixed(2) + ' RON';
        document.getElementById('stat-total-exp').innerText = t.exp.toFixed(2) + ' RON';
        document.getElementById('stat-balance').innerText = ((t.cash + t.card + t.bonuri) - t.exp).toFixed(2) + ' RON';


        renderHistory();
        renderChart();
    };


    const renderChart = () => {
        const ctx = document.getElementById('budgetChartV4');
        if(!ctx) return;


        const exps = storage.transactions.filter(i => i.type === 'expense');
        const catData = {};
        exps.forEach(i => catData[i.category] = (catData[i.category] || 0) + i.amount);


        if(chart) chart.destroy();
        if(Object.keys(catData).length === 0) return;


        chart = new Chart(ctx, {
            type: 'pie',
            data: {
                labels: Object.keys(catData),
                datasets: [{ data: Object.values(catData), backgroundColor: ['#00ff88','#38bdf8','#fbbf24','#ff4757','#a78bfa'] }]
            },
            options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: '#fff' } } } }
        });
    };


    const renderHistory = () => {
        const div = document.getElementById('history-v4');
        if(!div) return;


        if(storage.transactions.length === 0) {
            div.innerHTML = '<p style="text-align:center; color:#8b949e">Niciun istoric.</p>';
            return;
        }


        let html = '';
        // Iterăm invers pentru a vedea ultimele 15 tranzacții
        const start = Math.max(0, storage.transactions.length - 15);
        for(let i = storage.transactions.length - 1; i >= start; i--) {
            const item = storage.transactions[i];
            html += `
            <div class="history-item">
                <div>
                    <span class="${item.type === 'income' ? 'badge-income' : 'badge-expense'}" style="font-weight:bold">
                        ${item.type === 'income' ? '↑' : '↓'} ${item.amount.toFixed(2)}
                    </span><br>
                    <small style="color:#8b949e">${item.sub || item.category} | ${item.date}</small>
                </div>
                <button class="delete-btn" onclick="FamilyBudget.deleteEntry(${i})">ȘTERGE</button>
            </div>`;
        }
        div.innerHTML = html;
    };


    return {
        init: () => {
            document.getElementById('main-cat').onchange = (e) => {
                const s = document.getElementById('sub-cat');
                const list = subs[e.target.value] || [];
                s.innerHTML = list.map(x => `<option value="${x}">${x}</option>`).join('') || '<option value="">Alege...</option>';
            };
            updateInterface();
        },
        addEntry: (type) => {
            const amtEl = document.getElementById(type === 'income' ? 'inc-amount' : 'exp-amount');
            const amt = parseFloat(amtEl.value);
            
            if(!amt || amt <= 0) return;


            const entry = {
                type: type,
                amount: amt,
                category: document.getElementById(type === 'income' ? 'inc-type' : 'main-cat').value,
                sub: type === 'expense' ? document.getElementById('sub-cat').value : null,
                date: new Date().toLocaleTimeString('ro-RO', {hour:'2-digit', minute:'2-digit'}) + ' - ' + new Date().toLocaleDateString('ro-RO', {day:'2-digit', month:'2-digit'})
            };


            if(type === 'expense' && !entry.category) return;


            storage.transactions.push(entry);
            amtEl.value = '';
            saveAndRefresh();
        },
        deleteEntry: (index) => {
            // Am eliminat confirm() pentru a evita blocarea sandbox
            storage.transactions.splice(index, 1);
            saveAndRefresh();
        },
        resetData: () => {
            // Am eliminat confirm() pentru a evita blocarea sandbox
            storage.transactions = [];
            saveAndRefresh();
        }
    };
})();


document.addEventListener('DOMContentLoaded', FamilyBudget.init);
</script>

<div class="budget-v4-container">
    <h2 style="text-align:center; color:var(--primary); margin-bottom:30px;">Sistem Audit Financiar Rtec-Design</h2>
    
    <div class="stats-grid">
        <div class="stat-box" style="border-left-color: #fbbf24;"><small>Cash</small><div id="stat-cash">0.00</div></div>
        <div class="stat-box" style="border-left-color: #38bdf8;"><small>Card</small><div id="stat-card">0.00</div></div>
        <div class="stat-box" style="border-left-color: #a78bfa;"><small>Bonuri</small><div id="stat-bonuri">0.00</div></div>
        <div class="stat-box" style="border-left-color: #ff4757;"><small>Cheltuieli</small><div id="stat-total-exp">0.00</div></div>
        <div class="stat-box"><small>Balanță</small><div id="stat-balance">0.00</div></div>
    </div>


    <div class="app-layout">
        <div class="form-card">
            <h4>💰 Venituri</h4>
            <select id="inc-type">
                <option value="cash">Bani Cash</option>
                <option value="card">Card / Salariu</option>
                <option value="bonuri">Bonuri Masă</option>
            </select>
            <input type="number" id="inc-amount" placeholder="Sumă RON" step="0.01">
            <button class="btn-submit" onclick="FamilyBudget.addEntry('income')">ADĂUGA VENIT</button>


            <h4 style="margin-top:25px">💸 Cheltuieli</h4>
            <select id="main-cat">
                <option value="">Alege Categoria...</option>
                <option value="Utilități">Utilități</option>
                <option value="Credite">Credite / Rate</option>
                <option value="Mâncare">Mâncare</option>
                <option value="Altele">Altele</option>
            </select>
            <select id="sub-cat"><option value="">Alege sub-categoria...</option></select>
            <input type="number" id="exp-amount" placeholder="Sumă RON" step="0.01">
            <button class="btn-submit" onclick="FamilyBudget.addEntry('expense')" style="background:#38bdf8">ÎNREGISTREAZĂ</button>
            
            <div style="margin-top:40px; border-top: 1px solid #30363d; padding-top:20px;">
                <button onclick="FamilyBudget.resetData()" style="color:#8b949e; background:none; border:1px solid #30363d; padding:8px; border-radius:8px; cursor:pointer; width:100%; font-size: 0.7rem;">
                    RESET TOTAL DATE
                </button>
            </div>
        </div>


        <div>
            <div style="background:var(--card); padding:20px; border-radius:15px; height:300px; margin-bottom:20px;">
                <canvas id="budgetChartV4"></canvas>
            </div>
            <div style="background:var(--card); padding:20px; border-radius:15px; min-height: 100px;">
                <h4 style="margin-top:0">Istoric Recent (Venituri & Cheltuieli)</h4>
                <div id="history-v4"></div>
            </div>
        </div>
    </div>
</div>

Ai Nevoie de Cod Personalizat?

Contactează-ne pentru soluții de cod personalizate pentru proiectul tău. Putem dezvolta componente, module și funcționalități specifice nevoilor tale.

Contactează-ne
RTEC
Suport RTEC DESIGN Nexa este online