Build a Smart Receipt Scanner & Expense Tracker — mobile-first web app. IMPORTANT: Zero third-party watermarks, branding, attribution links, or "Built with" badges anywhere. The UI must be completely clean. TECH STACK React + Tailwind CSS Recharts (Bar, Line, Pie, Donut charts) Google Gemini 1.5 Flash API for receipt scanning (free tier — user supplies their own key in Settings) 100% localStorage — no backend, no accounts, works offline Mobile-first, max-width 480px centered on desktop Dark default theme: #060a08 background, #0d1510 cards, #22c55e accent. Full light mode via CSS variables toggled in Settings Smooth fade/slide transitions between pages Every page must have a proper empty state HOW SCANNING WORKS User takes photo or uploads receipt image Image is converted to base64 in the browser Sent to Gemini 1.5 Flash vision API with the parsing prompt below Gemini returns structured JSON JSON pre-fills an editable review form — user corrects any errors before saving If no API key is set, the scan button is replaced with a "Enter manually" button that opens the same form blank Gemini API call: const response = await fetch( `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=${apiKey}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ contents: [{ parts: [ { inline_data: { mime_type: imageMimeType, data: base64Image } }, { text: RECEIPT_PROMPT } ] }] }) } ); RECEIPT_PROMPT (used in the Gemini call): You are a receipt OCR parser. Analyze this receipt image and return ONLY a valid JSON object — no markdown, no explanation, nothing outside the JSON. { "store": "store name", "address": "full address or null", "date": "YYYY-MM-DD or null", "time": "HH:MM or null", "currency": "₪ or $ or £ or € or ¥", "items": [ { "name": "English name (original language in parentheses)", "qty": 1, "unit_price": 0.00, "discount": 0.00, "final_price": 0.00 } ], "subtotal": 0.00, "total_discount": 0.00, "tax": 0.00, "total": 0.00, "payment_method": "Cash|Credit Card|Debit Card|Apple Pay|Google Pay|Other", "cash_given": null, "change_given": null, "notes": null, "category": "Groceries|Dining|Gas|Shopping|Health|Transport|Entertainment|Utilities|Other" } Rules: - Per-item discounts appear as negative numbers directly below a product line — match them to the item above. discount = positive amount saved, final_price = unit_price - discount. - Hebrew: מזומן = cash paid, עודף = change returned, סך הכל/סה״כ = total - total_discount = sum of all item-level discounts (positive number) - Translate all item names to English, keep original in parentheses - All numeric fields must be numbers, never strings - Use null for any field not visible on the receipt - Detect currency symbol from the receipt itself PAGES — 5 total, fixed bottom nav 1. Dashboard Top bar: greeting ("Good morning / afternoon / evening") + current month + year Hero spend card: big total spent this month, subtext showing receipt count and "saved X from sales" in green, budget progress bar if budget is set in Settings 6-month bar chart — current month in accent green, others in dark green Pie chart — category breakdown for current month with colored legend Category list — icon, name, amount, progress bar showing % of month's total Recent receipts — last 5 cards: category icon, store name, date, total, payment method, green "saved X" badge if discounts exist 2. Scan (center FAB +) Two buttons: "📷 Camera" (opens device camera via capture="environment") and "🖼 Gallery" (file picker) After image selected: full-width preview image "Scan Receipt" button (green, full width) → shows a progress spinner with message "Reading receipt…" If no API key: show a yellow banner "Add your free Gemini API key in Settings to enable scanning" with a "Enter manually instead" button After scan OR manual entry: editable review form containing: Store name (text), Address (text, optional), Date (date picker), Time (time picker), Category (icon grid selector) Items table: each row has [Item name] [Qty] [Unit price] [Discount] → auto-shows final price. "+ Add item" button below. Each row has a delete button. Below items: Subtotal (auto-calculated, locked), Discount total (auto-calculated, locked), Tax (manual, optional), Total (auto-calculated but editable) Payment method: horizontal chip selector (Cash / Credit Card / Debit Card / Apple Pay / Google Pay / Other) Cash given + Change back fields — only visible when Cash is selected, change auto-calculates as cash_given - total Notes (textarea, optional) Save (green) and Discard (red outline) buttons 3. History Search bar at top — filters by store name in real time Receipts grouped by month, newest first Month group header: month name + year, receipt count, total spent, total saved (green) if any Each receipt card: category icon (colored background), store name, date + address snippet, total amount, payment method, "saved X" badge Tap any card → bottom sheet modal slides up showing: Store + address + category tag + date + time + payment method pills Green savings banner if total_discount > 0 Full items table: name, qty, original price (struck through if discounted), discount badge, final price Totals section: subtotal → discounts → tax → TOTAL PAID → cash given → change back Edit button (re-opens review form pre-filled) and Delete button (with confirm dialog) 4. Analytics Month selector dropdown at top (defaults to current month) 12-month spending trend — line chart Category breakdown — pie/donut chart for selected month Payment method split — donut chart Top 5 stores — ranked list with bar for each showing relative spend Stats grid (2×2 cards): Average per receipt · Biggest single purchase · Total saved all-time · Total receipts logged 5. Settings Gemini API Key — password-type input field, stored in localStorage. "Test connection" button that sends a short test request and shows ✅ or ❌. Helper text: "Free at aistudio.google.com — no credit card needed" Default currency — dropdown: $ · ₪ · £ · € · ¥ Default payment method — dropdown Default category — dropdown (used when AI can't classify) Monthly budget — number input. If set, dashboard shows a progress bar Theme — Dark / Light toggle Export — "Download JSON" and "Download CSV" buttons Import — File picker that accepts a previously exported JSON and merges/replaces data (with a choice dialog: Merge or Replace) Clear all data — opens a confirmation dialog requiring the user to type DELETE before proceeding DATA MODEL (localStorage array key: expense-tracker-v1) { "id": "unique string", "savedAt": "ISO timestamp", "store": "string", "address": "string or null", "date": "YYYY-MM-DD", "time": "HH:MM or null", "currency": "$", "category": "Groceries", "items": [ { "name": "string", "qty": 1, "unit_price": 0.00, "discount": 0.00, "final_price": 0.00 } ], "subtotal": 0.00, "total_discount": 0.00, "tax": 0.00, "total": 0.00, "payment_method": "Cash", "cash_given": null, "change_given": null, "notes": null } Settings localStorage key: expense-tracker-settings { "geminiApiKey": "", "currency": "$", "defaultPayment": "Cash", "defaultCategory": "Other", "monthlyBudget": null, "theme": "dark" } CATEGORY ICON + COLOR MAP Groceries 🛒 #4ade80 Dining 🍽️ #fb923c Gas ⛽ #38bdf8 Shopping 🛍️ #a78bfa Health 💊 #f472b6 Transport 🚌 #2dd4bf Entertainment 🎬 #fbbf24 Utilities 💡 #f97316 Other 📄 #94a3b8
Sign in to leave a comment
No comments yet. Be the first!