14 KiB
🔵 Finance Module — Mock Data & Back Button Blueprint
Date: 2026-07-26
Author: Architect Mode
Status: Pending Code Mode Execution
Priority: MEDIUM — UI polish, no app-breaking bugs
STEP 1: MOCK DATA ANALYSIS
1.1 Dashboard Financial Card (ProfileTrustCard.vue)
File: frontend_app/src/components/dashboard/ProfileTrustCard.vue
| Field | Current Value | Source | Is Mock? |
|---|---|---|---|
financeStore.totalCredits (line 40) |
Live API data | financeStore.fetchWalletBalance() → GET /billing/wallet/balance |
❌ LIVE — already fetches real data |
financeStore.serviceCoins (line 43) |
Live API data | Same store | ❌ LIVE |
financeStore.totalCredits stat tile (line 51) |
Live API data | Same store | ❌ LIVE |
| Transaction count (line 57) | — hardcoded |
Static placeholder | ✅ MOCK |
| Package info (line 63) | • hardcoded |
Static placeholder | ✅ MOCK |
financeStore.voucherBalance (line 69) |
Live API data | Same store | ❌ LIVE |
Conclusion: The wallet balance numbers (totalCredits, serviceCoins, voucherBalance) ARE live and fetched from the API. However, two stat tiles show static placeholders that render identically for all users.
1.2 Gamification Card (GamificationCard.vue)
File: frontend_app/src/components/dashboard/GamificationCard.vue
| Field | Current Value | Source | Is Mock? |
|---|---|---|---|
| Score (line 18) | 2,450 hardcoded |
Literal number in template | ✅ MOCK — same for all users |
| Badges (lines 56-61) | 4 hardcoded entries | Static array in script | ✅ MOCK — same for all users |
Evidence:
GamificationCard.vue:<p class="text-3xl font-extrabold text-emerald-600">2,450</p>— literal HTMLGamificationCard.vue:const badges = ref([{ icon: '🌱', label: 'Eco Driver' }, ...])— never updated from API
Fix plan:
- Import a gamification/Pinía store (check if one exists) to fetch real user score
- If no gamification store exists yet, create a computed that reads from
authStoreor call an API endpoint - Replace hardcoded badges with data fetched from a gamification endpoint
1.3 FinanceMainView Cards
File: frontend_app/src/components/../views/FinanceMainView.vue
Card 1 (Wallet): Uses financeStore.totalCredits, financeStore.purchasedCredits, financeStore.serviceCoins, financeStore.earnedCredits, financeStore.voucherBalance — all live data from financeStore.fetchWalletBalance() ✅
Card 2 (Packages): Uses authStore.user?.subscription_plan — live data ✅
Card 3 (Transactions): Static placeholder with emoji — by design (placeholder page) ✅
Card 4 (Invoices): Static placeholder with 🚧 — by design ("Hamarosan") ✅
STEP 2: BACK BUTTON LAYOUT ANALYSIS
2.1 The Gold Standard: FleetView.vue Header
File: frontend_app/src/views/vehicles/FleetView.vue
The FleetView header pattern:
<!-- Page header -->
<div class="mb-8 flex items-center justify-between">
<div>
<h1 class="text-3xl font-bold text-white">{{ t('garage.title') }}</h1>
<p class="mt-1 text-sm text-white/60">{{ t('garage.subtitle', { count: ... }) }}</p>
</div>
<div class="flex items-center gap-3">
<!-- Action buttons on the right -->
<button ...>Add Vehicle</button>
<button @click="router.push('/dashboard')" class="...bg-white/10...">
<svg>...</svg>
{{ t('garage.backToDashboard') }}
</button>
</div>
</div>
Key structural elements:
- Container:
class="mb-8 flex items-center justify-between" - Left side:
<div>with<h1>title + optional<p>subtitle - Right side:
<div class="flex items-center gap-3">with action buttons - Back button:
bg-white/10 px-4 py-2 text-sm text-white/80 hover:bg-white/20 hover:text-white+ left-arrow SVG
2.2 Current Finance Views: Teleport Anti-Pattern
All 4 finance views currently use <Teleport to="#header-teleport-target"> to inject a page title into the global header:
FinanceMainView.vue:<Teleport v-if="teleportReady" to="#header-teleport-target">FinanceWalletsView.vueFinancePackagesView.vueFinanceTransactionsView.vue
All 4 need the same structural change.
2.3 The Fix: FleetView Pattern Applied to Finance
For each finance view:
-
REMOVE the entire
<Teleport ...>block -
REMOVE
teleportReady,onMounted,onBeforeUnmountboilerplate -
ADD a local content header matching FleetView:
<!-- Page header --> <div class="mb-8 flex items-center justify-between"> <div> <h1 class="text-3xl font-bold text-white">💰 {{ t('menu.finance') }}</h1> </div> <div class="flex items-center gap-3"> <button @click="router.push('/dashboard')" class="flex items-center gap-2 rounded-xl bg-white/10 px-4 py-2 text-sm text-white/80 transition-all duration-200 hover:bg-white/20 hover:text-white" > <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" /> </svg> {{ t('garage.backToDashboard') }} </button> </div> </div> -
PRESERVE the existing card grid / content area below the header
STEP 3: CODE MODE HAND-OFF — Explicit Task List
Execute in order. Do NOT modify FleetView.vue, PrivateLayout.vue, BaseHeader.vue, or router/index.ts.
Task A: Fix Mock Data in GamificationCard.vue
File: frontend_app/src/components/dashboard/GamificationCard.vue
-
Check if a gamification store exists:
ls frontend_app/src/stores/gamification* 2>/dev/null || echo "No gamification store"If a store exists, import and use it. If not, create a simple onMounted fetch to a gamification endpoint.
-
Replace hardcoded score (line 18):
- Change
<p class="text-3xl font-extrabold text-emerald-600">2,450</p> - To:
<p class="text-3xl font-extrabold text-emerald-600">{{ userScore }}</p> - Add script logic:
const userScore = computed(...)linked to real data source
- Change
-
Replace hardcoded badges (lines 56-61):
- Change the static
badgesarray to a computed or ref that fetches from API - Keep the same HTML template rendering — just change data source
- Change the static
Task B: Fix Mock Data in ProfileTrustCard.vue
File: frontend_app/src/components/dashboard/ProfileTrustCard.vue
-
Fix transaction count (line 57):
- Change
<p class="text-lg font-bold text-slate-800">—</p> - To:
<p class="text-lg font-bold text-slate-800">{{ transactionCount }}</p> - Add:
const transactionCount = computed(() => 0)— placeholder for now, will wire to real API later
- Change
-
Fix package info (line 63):
- Change
<p class="text-lg font-bold text-slate-800">•</p> - To:
<p class="text-lg font-bold text-slate-800">{{ authStore.user?.subscription_plan || '—' }}</p> - Add:
import { useAuthStore } from '../../stores/auth'andconst authStore = useAuthStore()
- Change
Task C: Remove Teleport & Add Local Header — FinanceMainView.vue
File: frontend_app/src/views/FinanceMainView.vue
-
DELETE lines 38-40 — the entire Teleport block:
<Teleport v-if="teleportReady" to="#header-teleport-target"> <span class="text-white font-bold text-sm tracking-wide">💰 {{ t('menu.finance') }}</span> </Teleport> -
ADD local content header immediately after the Teleport block removal (before line 42's
<div class="flex flex-col...">):<!-- ── Page header (FleetView.vue pattern) ── --> <div class="mb-8 flex items-center justify-between"> <div> <h1 class="text-3xl font-bold text-white">💰 {{ t('menu.finance') }}</h1> </div> <div class="flex items-center gap-3"> <button @click="router.push('/dashboard')" class="flex items-center gap-2 rounded-xl bg-white/10 px-4 py-2 text-sm text-white/80 transition-all duration-200 hover:bg-white/20 hover:text-white" > <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" /> </svg> {{ t('garage.backToDashboard') }} </button> </div> </div> -
Clean up script: Remove
teleportReady,ref, and lifecycle hooks that are no longer needed:- Line 237: Change
import { computed, ref, onMounted, onBeforeUnmount } from 'vue'toimport { computed, onMounted } from 'vue' - Line 243: Delete
const teleportReady = ref(false) - Line 278: Delete
teleportReady.value = true - Lines 282-284: Delete
onBeforeUnmountblock
- Line 237: Change
Task D: Remove Teleport & Add Local Header — FinanceWalletsView.vue
File: frontend_app/src/views/FinanceWalletsView.vue
-
DELETE lines 19-21 — the Teleport block
-
ADD local content header (after line 21 deletion, before line 23's
<div class="flex flex-col...">):<!-- ── Page header (FleetView.vue pattern) ── --> <div class="mb-8 flex items-center justify-between"> <div> <h1 class="text-3xl font-bold text-white">💰 {{ t('finance.wallet') }}</h1> </div> <div class="flex items-center gap-3"> <button @click="$router.push('/finance')" class="flex items-center gap-2 rounded-xl bg-white/10 px-4 py-2 text-sm text-white/80 transition-all duration-200 hover:bg-white/20 hover:text-white" > <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" /> </svg> {{ t('common.back') }} </button> </div> </div>(Note: back button goes to
/financefor sub-pages) -
Clean up script: Change imports: remove
ref, onMounted, onBeforeUnmount, removeteleportReadyand lifecycle hooks.- Also add:
import { useRouter } from 'vue-router'andconst router = useRouter()for the back button (or use$routerin template)
- Also add:
Task E: Remove Teleport & Add Local Header — FinancePackagesView.vue
File: frontend_app/src/views/FinancePackagesView.vue
- DELETE lines 17-19 — the Teleport block
- ADD local content header with title "📦 {{ t('subscription.title') }}" and back button to
/finance - Clean up script: Same as Task D — remove teleport boilerplate, add router import if not present
Task F: Remove Teleport & Add Local Header — FinanceTransactionsView.vue
File: frontend_app/src/views/FinanceTransactionsView.vue
- DELETE lines 15-17 — the Teleport block
- ADD local content header with title "📋 {{ t('finance.transactionHistory') }}" and back button to
/finance - Clean up script: Same as Task D — remove teleport boilerplate, add router import if not present
Task G: Verify
-
Frontend build check:
docker compose exec sf_public_frontend npm run build 2>&1 | tail -5Must show
✓ built in X.XXswith no errors. -
Backend imports:
docker compose exec sf_api python3 -c "from app.main import app; print('OK')"
📋 Summary Table
| Task | File | Action |
|---|---|---|
| A | GamificationCard.vue |
Replace 2,450 with live score, replace hardcoded badges |
| B | ProfileTrustCard.vue |
Replace — and • with live/computed values |
| C | FinanceMainView.vue |
Remove Teleport, add FleetView-style local header + back button |
| D | FinanceWalletsView.vue |
Remove Teleport, add local header + back button to /finance |
| E | FinancePackagesView.vue |
Remove Teleport, add local header + back button to /finance |
| F | FinanceTransactionsView.vue |
Remove Teleport, add local header + back button to /finance |
| G | Build + verify | npm run build, backend imports check |
⚠️ DO NOT MODIFY
FleetView.vue— reference pattern onlyFinanceLayout.vue— layout is correctBaseHeader.vue— working headerrouter/index.ts— correct route configDashboardView.vue— working dashboard