feat(mobile-fixes-phase4): Complete US-401 - Fix Layout Principal - Ascundere Header Desktop pe Mobil

Implemented by Ralph autonomous loop.
Iteration: 1

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-01-12 18:45:30 +00:00
parent ac2966c629
commit 65eff42312
4 changed files with 311 additions and 1226 deletions

View File

@@ -1,7 +1,7 @@
{ {
"projectName": "mobile-fixes-phase3", "projectName": "mobile-fixes-phase4",
"branchName": "ralph/unified-mobile-md", "branchName": "ralph/unified-mobile-md",
"description": "Corectări navigare mobilă: footer restructurat, tab-uri Clienți/Furnizori, FAB pe Bonuri, hamburger grupat", "description": "Fix layout mobil: ascundere header desktop, butoane filter/export vizibile, MobileDrawerMenu cu ANALIZE, persistență bonuri cu eroare",
"cssRules": { "cssRules": {
"documentation": [ "documentation": [
"docs/ONBOARDING_CSS.md", "docs/ONBOARDING_CSS.md",
@@ -16,7 +16,8 @@
"NICIODATĂ :deep() în componente (PrimeVue → vendor/)", "NICIODATĂ :deep() în componente (PrimeVue → vendor/)",
"Mobile: toate paginile folosesc MobileTopBar + MobileBottomNav", "Mobile: toate paginile folosesc MobileTopBar + MobileBottomNav",
"Mobile: filtrele se pun în BottomSheet, NU inline", "Mobile: filtrele se pun în BottomSheet, NU inline",
"Mobile: tab-uri pentru switch Clienți/Furnizori" "Mobile: v-if='isMobile' pentru componente mobile-only",
"Desktop: v-if='!isMobile' pentru componente desktop-only"
], ],
"mobileLayoutTokens": { "mobileLayoutTokens": {
"topBarHeight": "56px", "topBarHeight": "56px",
@@ -28,189 +29,133 @@
}, },
"userStories": [ "userStories": [
{ {
"id": "US-307", "id": "US-401",
"title": "Restructurare Footer Nav (4 butoane noi)", "title": "Fix Layout Principal - Ascundere Header Desktop pe Mobil",
"description": "Ca utilizator mobil vreau footer navigation cu: Dashboard | Bonuri | Facturi | Setări", "description": "Ca utilizator mobil vreau să văd doar MobileTopBar și MobileBottomNav, nu header-ul desktop",
"priority": 1, "priority": 1,
"acceptanceCriteria": [ "acceptanceCriteria": [
"MobileBottomNav cu 4 butoane: Dashboard, Bonuri, Facturi, Setări", "AppHeader.vue sau componenta părinte are v-if='!isMobile' pentru a se ascunde pe mobil",
"Dashboard: icon pi-home, route /dashboard", "Sidebar-ul desktop (navigation cu Rapoarte/Introduceri Date/Sistem) este ascuns pe mobil cu v-if='!isMobile'",
"Bonuri: icon pi-receipt, route /data-entry", "MobileTopBar este singurul header vizibil pe viewport < 768px",
"Facturi: icon pi-file-edit, route /reports/invoices", "Nu există suprapunere între header desktop și MobileTopBar",
"Setări: icon pi-cog, route /settings", "isMobile computed folosește window.innerWidth < 768 și este reactiv la resize",
"Active state corect pe fiecare pagină", "npm run build passes",
"Ștergere link Upload din footer (mutat în FAB)", "Verify in browser (375x667): Header desktop cu 'Selectare perioada' și 'AXN' NU este vizibil"
"npm run build passes"
], ],
"passes": true, "passes": true,
"notes": "Completed in iteration 1" "notes": "Completed in iteration 1"
}, },
{ {
"id": "US-308", "id": "US-402",
"title": "Actualizare Hamburger Menu - Grupat pe Categorii", "title": "Fix MobileTopBar - Butoane Filter/Export Vizibile",
"description": "Ca utilizator mobil vreau meniul hamburger organizat pe categorii clare", "description": "Ca utilizator mobil pe pagina Facturi/Bonuri vreau să văd butoanele de filtrare și export în header",
"priority": 2, "priority": 2,
"acceptanceCriteria": [ "acceptanceCriteria": [
"MobileDrawerMenu.vue restructurat cu secțiuni vizuale", "După US-401, pe InvoicesView.vue butoanele Filter/Refresh/Export sunt vizibile în MobileTopBar",
"Secțiune PRINCIPALE: Dashboard → /dashboard, Bonuri → /data-entry", "Pe ReceiptsListView.vue butoanele Filter/Export/More sunt vizibile în MobileTopBar",
"Secțiune RAPOARTE: Facturi → /reports/invoices, Balanță → /reports/trial-balance, Casa și Banca → /reports/bank-cash", "Butoanele au dimensiune touch target minim 48px",
"Secțiune ANALIZE: Scadențe → /reports/maturity-analysis, Facturi Detaliate → /reports/detailed-invoices", "npm run build passes",
"Secțiune ADMINISTRARE: Setări → /settings", "Verify in browser (375x667): Butoanele sunt vizibile și clickable pe pagina Facturi"
"Separatori vizuali între secțiuni",
"Header cu logo, Footer cu profil utilizator și logout",
"npm run build passes"
], ],
"passes": true, "passes": false,
"notes": "Completed in iteration 2" "notes": "Depinde de US-401 - butoanele există dar sunt acoperite de header-ul desktop"
}, },
{ {
"id": "US-304", "id": "US-403",
"title": "Tab-uri Clienți/Furnizori în Facturi", "title": "Fix MobileDrawerMenu - Secțiunea ANALIZE Vizibilă",
"description": "Ca utilizator vreau pagina Facturi să aibă tab-uri pentru Clienți și Furnizori", "description": "Ca utilizator mobil vreau să văd secțiunea ANALIZE în hamburger menu",
"priority": 3, "priority": 3,
"acceptanceCriteria": [ "acceptanceCriteria": [
"InvoicesView.vue modificat cu tab-uri: Clienți | Furnizori", "Click pe butonul Meniu din MobileTopBar deschide MobileDrawerMenu (nu sidebar desktop)",
"Tab-uri sub MobileTopBar (design Material, full-width)", "MobileDrawerMenu afișează secțiunile: PRINCIPALE, RAPOARTE, ANALIZE, ADMINISTRARE",
"Switch între tab-uri păstrează filtrele active", "Secțiunea ANALIZE conține: Scadențe (/reports/maturity-analysis), Facturi Detaliate (/reports/detailed-invoices)",
"Default: primul tab activ (Clienți)", "Link-urile din ANALIZE navighează corect și închid drawer-ul",
"URL query param pentru tab activ (?tab=suppliers)", "npm run build passes",
"MobileTopBar cu title Facturi", "Verify in browser (375x667): Click pe Meniu → apare MobileDrawerMenu cu secțiunea ANALIZE vizibilă"
"MobileBottomNav activ (Facturi highlighted)",
"npm run build passes"
], ],
"passes": true, "passes": false,
"notes": "Completed in iteration 1" "notes": "Depinde de US-401 - hamburger-ul deschidea sidebar-ul desktop"
}, },
{ {
"id": "US-305", "id": "US-404",
"title": "Tab-uri Clienți/Furnizori în Scadențe", "title": "Fix Spațiu Blank - Padding Corect pentru Mobile",
"description": "Ca utilizator vreau pagina Scadențe să aibă tab-uri pentru Clienți și Furnizori", "description": "Ca utilizator mobil vreau ca paginile să nu aibă spațiu blank excesiv în partea de sus",
"priority": 4, "priority": 4,
"acceptanceCriteria": [ "acceptanceCriteria": [
"MaturityAnalysisView.vue modificat cu tab-uri: Clienți | Furnizori", "Paginile de rapoarte au padding-top: 56px (doar MobileTopBar height) pe mobil",
"Tab-uri sub MobileTopBar (design Material, full-width)", "Nu există spațiu blank între MobileTopBar și conținut",
"Switch între tab-uri păstrează filtrele active", "Tab-urile Clienți/Furnizori sunt imediat sub MobileTopBar pe InvoicesView",
"Default: primul tab activ (Clienți)", "Status chips sunt imediat sub MobileTopBar pe ReceiptsListView",
"URL query param pentru tab activ (?tab=suppliers)", "npm run build passes",
"MobileTopBar cu title Scadențe și buton ← Înapoi", "Verify in browser (375x667): Conținutul începe imediat sub MobileTopBar, fără gap de ~120px"
"MobileBottomNav activ",
"npm run build passes"
], ],
"passes": true, "passes": false,
"notes": "Completed in iteration 2" "notes": "Depinde de US-401 - spațiul era ocupat de header-ul desktop ascuns incorect"
}, },
{ {
"id": "US-301", "id": "US-405",
"title": "Buton Înapoi în Creare/Editare/Vizualizare Bon", "title": "Fix batchProgressStore - Restaurare Joburi Failed",
"description": "Ca utilizator mobil vreau buton ← Înapoi în MobileTopBar pe pagina de bon", "description": "Ca utilizator care a uploadat bonuri cu erori OCR vreau ca acestea să rămână vizibile după refresh",
"priority": 5, "priority": 5,
"acceptanceCriteria": [ "acceptanceCriteria": [
"ReceiptCreateUnifiedView.vue are MobileTopBar cu showBack=true", "În batchProgressStore.js, funcția restoreJobsFromBatch() include joburi cu status 'failed' (nu doar pending/processing)",
"Click pe ← navighează la /data-entry (lista bonuri)", "Batch-ul NU este șters din localStorage dacă are joburi failed nerezolvate",
"Funcționează în toate modurile: create, edit, view", "După refresh, bonurile cu eroare sunt afișate în listă",
"Verify in browser: butonul apare și funcționează", "unifiedItems computed include joburile failed pentru afișare",
"npm run build passes" "npm run build passes"
], ],
"passes": true, "passes": false,
"notes": "Completed in iteration 3" "notes": ""
}, },
{ {
"id": "US-302", "id": "US-406",
"title": "Footer Nav pe toate Paginile de Setări", "title": "Fix UI Bonuri cu Eroare - Afișare Corectă pe Mobil",
"description": "Ca utilizator mobil vreau MobileBottomNav pe toate paginile din secțiunea Setări", "description": "Ca utilizator mobil vreau să văd clar că un bon are eroare, nu 'în procesare'",
"priority": 6, "priority": 6,
"acceptanceCriteria": [ "acceptanceCriteria": [
"OCRMetricsView.vue include MobileBottomNav cu Setări activ", "Bonurile cu status 'failed' afișează chip/badge 'Eroare' cu culoare roșie (var(--red-500))",
"CacheStatsView.vue include MobileBottomNav cu Setări activ", "NU afișează 'În procesare' sau spinner pentru bonuri failed",
"ServerLogsView.vue include MobileBottomNav cu Setări activ", "Mesajul de eroare este vizibil (truncat cu ellipsis dacă e prea lung)",
"TelegramAdminView.vue include MobileBottomNav cu Setări activ (dacă există)", "Utilizatorul poate vedea eroarea completă la click/hover",
"SettingsHubView.vue include MobileBottomNav cu Setări activ", "npm run build passes",
"npm run build passes" "Verify in browser (375x667): Bon cu eroare arată 'Eroare' nu 'În procesare'"
], ],
"passes": true, "passes": false,
"notes": "Completed in iteration 4" "notes": "Depinde de US-405 - bonurile failed trebuie să fie în listă mai întâi"
}, },
{ {
"id": "US-303", "id": "US-407",
"title": "FAB pe Pagina Bonuri (Mutare Upload)", "title": "Fix Editare Bonuri cu Eroare",
"description": "Ca utilizator mobil vreau funcția Upload să fie în butonul FAB (+) pe pagina Bonuri", "description": "Ca utilizator care are un bon cu eroare OCR vreau să pot edita bonul pentru a corecta erorile manual",
"priority": 7, "priority": 7,
"acceptanceCriteria": [ "acceptanceCriteria": [
"ReceiptsListView.vue are buton FAB (+) în colțul dreapta-jos", "Click pe bon cu eroare deschide formularul de editare (ReceiptCreateUnifiedView)",
"Click pe FAB deschide meniu popup: Bon Nou | Upload Bulk", "La salvare, processing_status este resetat la NULL în baza de date",
"FAB poziționat deasupra MobileBottomNav (bottom: 72px)", "După salvare, bonul poate fi trimis pe workflow (Submit for Approval)",
"Bon Nou navighează la /data-entry/receipts/new", "Backend endpoint PATCH /receipts/{id} resetează processing_status la NULL când se salvează modificări",
"Upload Bulk navighează la /data-entry/bulk-upload", "npm run build passes",
"FAB vizibil doar pe mobil (isMobile)", "Verify in browser: Editează bon cu eroare → Salvează → Statusul nu mai arată eroare"
"npm run build passes"
], ],
"passes": true, "passes": false,
"notes": "Completed in iteration 5" "notes": ""
}, },
{ {
"id": "US-306", "id": "US-408",
"title": "Restaurare Butoane Export și Filtrare pe Rapoarte", "title": "Verificare Finală - Toate Fix-urile Funcționează",
"description": "Ca utilizator mobil vreau butoane de export și filtrare pe toate rapoartele", "description": "Ca developer vreau să confirm că toate fix-urile din Phase 4 funcționează corect",
"priority": 8, "priority": 8,
"acceptanceCriteria": [ "acceptanceCriteria": [
"InvoicesView.vue: buton Export (pi-download) și Filtrare (pi-filter) în MobileTopBar actions", "Viewport 375x667: Header desktop (Selectare perioada, AXN) NU este vizibil",
"TrialBalanceView.vue: buton Export și Filtrare în MobileTopBar actions", "Viewport 375x667: MobileTopBar cu butoane Filter/Export este vizibil",
"BankCashRegisterView.vue: buton Export și Filtrare în MobileTopBar actions", "Click pe Meniu deschide MobileDrawerMenu cu secțiunea ANALIZE",
"ReceiptsListView.vue: buton Export și Filtrare în MobileTopBar actions", "Pagina Facturi: Tab-uri Clienți/Furnizori imediat sub header, fără spațiu blank",
"MaturityAnalysisView.vue: buton Export și Filtrare în MobileTopBar actions", "Pagina Bonuri: Status chips imediat sub header, fără spațiu blank",
"Click pe Filtrare deschide BottomSheet cu filtrele paginii", "Upload bon cu eroare: Afișează 'Eroare' nu 'În procesare'",
"Refresh după upload cu eroare: Bonul cu eroare rămâne vizibil în listă",
"npm run build passes" "npm run build passes"
], ],
"passes": true, "passes": false,
"notes": "Completed in iteration 6" "notes": ""
},
{
"id": "US-309",
"title": "Cleanup Dashboard Mobile",
"description": "Ca utilizator mobil vreau Dashboard-ul să afișeze doar KPIs fără quick-links",
"priority": 9,
"acceptanceCriteria": [
"DashboardView.vue pe mobil: ștergere quick-link cards dacă există",
"Doar SwipeableCards cu KPIs pe mobil",
"Desktop rămâne neschimbat",
"MobileTopBar cu title Dashboard",
"MobileBottomNav cu Dashboard activ",
"npm run build passes"
],
"passes": true,
"notes": "Completed in iteration 7"
},
{
"id": "US-310",
"title": "Actualizare Router cu Modificările",
"description": "Ca developer vreau router-ul actualizat pentru a funcționa cu noile pagini",
"priority": 10,
"acceptanceCriteria": [
"Rută /reports/invoices → InvoicesView funcțională",
"Rută /reports/maturity-analysis → MaturityAnalysisView funcțională",
"Rutele existente păstrate: /reports/trial-balance, /reports/bank-cash, /reports/detailed-invoices",
"Cleanup rute nefolosite dacă există",
"Toate rutele lazy loaded",
"npm run build passes"
],
"passes": true,
"notes": "Completed in iteration 8"
},
{
"id": "US-311",
"title": "Actualizare Documentație MOBILE_PATTERNS.md",
"description": "Ca developer viitor vreau documentația actualizată cu modificările din Phase 3",
"priority": 11,
"acceptanceCriteria": [
"Secțiune actualizată: Footer Navigation (Dashboard, Bonuri, Facturi, Setări)",
"Secțiune nouă: FAB Pattern pentru acțiuni contextuale",
"Secțiune nouă: Tab Pattern pentru switch Clienți/Furnizori",
"Secțiune actualizată: Hamburger Menu grupat pe categorii",
"Diagrame ASCII actualizate cu noua structură navigare",
"npm run build passes"
],
"passes": true,
"notes": "Completed in iteration 9"
} }
] ]
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
<template> <template>
<div id="app"> <div id="app">
<!-- Header --> <!-- Desktop Header - hidden on mobile (viewport < 768px) -->
<AppHeader <AppHeader
v-if="authStore.isAuthenticated" v-if="authStore.isAuthenticated && !isMobile"
title="ROA2WEB" title="ROA2WEB"
brand-link="/reports/dashboard" brand-link="/reports/dashboard"
:menu-open="menuOpen" :menu-open="menuOpen"
@@ -15,9 +15,9 @@
@period-changed="handlePeriodChanged" @period-changed="handlePeriodChanged"
/> />
<!-- Slide Menu --> <!-- Desktop Slide Menu - hidden on mobile (viewport < 768px) -->
<SlideMenu <SlideMenu
v-if="authStore.isAuthenticated" v-if="authStore.isAuthenticated && !isMobile"
:is-open="menuOpen" :is-open="menuOpen"
:menu-items="enabledMenuItems" :menu-items="enabledMenuItems"
:current-user="authStore.currentUser" :current-user="authStore.currentUser"
@@ -25,8 +25,8 @@
@logout="handleLogout" @logout="handleLogout"
/> />
<!-- Main Content --> <!-- Main Content - with-navbar only on desktop when authenticated -->
<main class="main-content" :class="{ 'with-navbar': authStore.isAuthenticated }"> <main class="main-content" :class="{ 'with-navbar': authStore.isAuthenticated && !isMobile }">
<router-view /> <router-view />
</main> </main>
@@ -37,7 +37,7 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, onMounted, watch } from 'vue' import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import AppHeader from '@shared/components/layout/AppHeader.vue' import AppHeader from '@shared/components/layout/AppHeader.vue'
import SlideMenu from '@shared/components/layout/SlideMenu.vue' import SlideMenu from '@shared/components/layout/SlideMenu.vue'
@@ -52,6 +52,14 @@ import axios from 'axios'
const router = useRouter() const router = useRouter()
// Mobile detection - reactive with resize listener
const windowWidth = ref(typeof window !== 'undefined' ? window.innerWidth : 1024)
const isMobile = computed(() => windowWidth.value < 768)
const handleResize = () => {
windowWidth.value = window.innerWidth
}
// API service for auth and shared endpoints (unified backend) // API service for auth and shared endpoints (unified backend)
const authApi = axios.create({ const authApi = axios.create({
baseURL: import.meta.env.BASE_URL + 'api', baseURL: import.meta.env.BASE_URL + 'api',
@@ -101,6 +109,9 @@ watch(
// Initialize auth and load companies on mount // Initialize auth and load companies on mount
onMounted(async () => { onMounted(async () => {
// Add resize listener for mobile detection
window.addEventListener('resize', handleResize)
console.log('[App] Mounted - initializing auth...') console.log('[App] Mounted - initializing auth...')
await authStore.initializeAuth() await authStore.initializeAuth()
console.log('[App] Auth initialized, isAuthenticated:', authStore.isAuthenticated) console.log('[App] Auth initialized, isAuthenticated:', authStore.isAuthenticated)
@@ -116,6 +127,11 @@ onMounted(async () => {
} }
}) })
// Cleanup resize listener
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
})
// Event handlers // Event handlers
const handleCompanyChanged = async (company) => { const handleCompanyChanged = async (company) => {
console.log('[App] Company changed:', company) console.log('[App] Company changed:', company)

View File

@@ -0,0 +1,188 @@
# PRD: Mobile Fixes Phase 4 - Layout & State Issues
## 1. Introducere
După completarea Phase 3 (11/11 stories), au fost identificate probleme critice în modul mobil prin testare Playwright. Cauza principală este că layout-ul desktop (AppHeader + sidebar) rămâne vizibil pe viewport mobil, acoperind componentele mobile (MobileTopBar, MobileDrawerMenu). În plus, există probleme cu persistența bonurilor cu eroare la upload.
## 2. Obiective
### Obiectiv Principal
- Corectarea layout-ului mobil pentru a afișa DOAR componentele mobile pe viewport < 768px
### Obiective Secundare
- Restaurarea corectă a bonurilor cu eroare după refresh
- Permiterea editării bonurilor cu eroare pentru corectare
### Metrici de Succes
- Playwright test: Header desktop ASCUNS pe viewport 375px
- Playwright test: MobileTopBar cu butoane filter/export VIZIBILE
- Playwright test: MobileDrawerMenu afișează secțiunea ANALIZE
- Playwright test: Bonuri cu eroare rămân vizibile după refresh
## 3. User Stories
### US-401: Fix Layout Principal - Ascundere Header Desktop pe Mobil
**Ca** utilizator mobil
**Vreau** văd doar MobileTopBar și MobileBottomNav
**Pentru că** header-ul desktop ocupă spațiu și acoperă butoanele mobile
**Acceptance Criteria:**
- [ ] AppHeader.vue are `v-if="!isMobile"` pentru a se ascunde pe mobil
- [ ] Sidebar-ul desktop (navigation cu Rapoarte/Introduceri Date/Sistem) este ascuns pe mobil
- [ ] MobileTopBar este singurul header vizibil pe viewport < 768px
- [ ] Nu există suprapunere între header desktop și MobileTopBar
- [ ] npm run build passes
- [ ] Verify in browser (375x667): Header desktop NU este vizibil
### US-402: Fix MobileTopBar - Butoane Filter/Export Vizibile
**Ca** utilizator mobil pe pagina Facturi/Bonuri
**Vreau** văd butoanele de filtrare și export în header
**Pentru că** acum sunt ascunse/acoperite de header-ul desktop
**Acceptance Criteria:**
- [ ] Pe InvoicesView.vue, butoanele Filter/Refresh/Export sunt vizibile în MobileTopBar
- [ ] Pe ReceiptsListView.vue, butoanele Filter/Export/More sunt vizibile în MobileTopBar
- [ ] Click pe butonul Filter deschide BottomSheet cu filtre
- [ ] Click pe butonul Export declanșează descărcarea
- [ ] npm run build passes
- [ ] Verify in browser (375x667): Butoanele sunt vizibile și funcționale pe pagina Facturi
### US-403: Fix MobileDrawerMenu - Secțiunea ANALIZE Vizibilă
**Ca** utilizator mobil
**Vreau** văd secțiunea ANALIZE în hamburger menu
**Pentru că** acum se deschide sidebar-ul desktop în loc de MobileDrawerMenu
**Acceptance Criteria:**
- [ ] Click pe butonul Meniu din MobileTopBar deschide MobileDrawerMenu (nu sidebar desktop)
- [ ] MobileDrawerMenu afișează secțiunile: PRINCIPALE, RAPOARTE, ANALIZE, ADMINISTRARE
- [ ] Secțiunea ANALIZE conține: Scadențe, Facturi Detaliate
- [ ] Link-urile din ANALIZE navighează corect
- [ ] npm run build passes
- [ ] Verify in browser (375x667): Click pe Meniu apare drawer cu secțiunea ANALIZE
### US-404: Fix Spațiu Blank - Padding Corect pentru Mobile
**Ca** utilizator mobil
**Vreau** ca paginile nu aibă spațiu blank excesiv în partea de sus
**Pentru că** acum există ~120px spațiu gol unde ar fi header-ul desktop
**Acceptance Criteria:**
- [ ] Paginile de rapoarte au padding-top corect pentru MobileTopBar (56px)
- [ ] Nu există spațiu blank între MobileTopBar și conținut
- [ ] Tab-urile Clienți/Furnizori sunt imediat sub MobileTopBar
- [ ] npm run build passes
- [ ] Verify in browser (375x667): Nu există spațiu blank excesiv pe pagina Facturi
### US-405: Fix batchProgressStore - Restaurare Joburi Failed
**Ca** utilizator care a uploadat bonuri cu erori OCR
**Vreau** ca bonurile cu eroare rămână vizibile după refresh
**Pentru că** acum dispar și nu pot fi editate
**Acceptance Criteria:**
- [ ] `restoreJobsFromBatch()` în batchProgressStore.js include joburi cu status 'failed'
- [ ] Batch-ul NU este șters din localStorage dacă are joburi failed
- [ ] După refresh, bonurile cu eroare sunt afișate cu status vizual "Eroare"
- [ ] `unifiedItems` computed include joburile failed pentru afișare
- [ ] npm run build passes
- [ ] Verify in browser: Upload bon cu eroare Refresh Bonul cu eroare rămâne vizibil
### US-406: Fix UI Bonuri cu Eroare - Afișare Corectă pe Mobil
**Ca** utilizator mobil
**Vreau** văd clar un bon are eroare (nu "în procesare")
**Pentru că** acum bonurile failed arată ca și cum ar fi încă în procesare
**Acceptance Criteria:**
- [ ] Bonurile cu status 'failed' afișează chip/badge "Eroare" (roșu)
- [ ] NU afișează "În procesare" pentru bonuri failed
- [ ] Mesajul de eroare este vizibil (truncat dacă e prea lung)
- [ ] npm run build passes
- [ ] Verify in browser (375x667): Bon cu eroare arată "Eroare" nu "În procesare"
### US-407: Fix Editare Bonuri cu Eroare
**Ca** utilizator care are un bon cu eroare OCR
**Vreau** pot edita bonul pentru a corecta erorile manual
**Pentru că** acum nu pot salva modificările sau re-trimite pe workflow
**Acceptance Criteria:**
- [ ] Click pe bon cu eroare deschide formularul de editare
- [ ] La salvare, `processing_status` este resetat la NULL
- [ ] După salvare, bonul poate fi trimis pe workflow (Submit for Approval)
- [ ] Backend endpoint PATCH /receipts/{id} resetează processing_status
- [ ] npm run build passes
- [ ] Verify in browser: Editează bon cu eroare Salvează Poate fi trimis pe workflow
### US-408: Verificare Finală cu Playwright
**Ca** developer
**Vreau** verificare automată a tuturor fix-urilor
**Pentru că** trebuie confirmate toate scenariile înainte de merge
**Acceptance Criteria:**
- [ ] Test 1: Viewport 375x667 Header desktop ASCUNS
- [ ] Test 2: Viewport 375x667 MobileTopBar cu butoane VIZIBILE
- [ ] Test 3: Click Meniu MobileDrawerMenu cu ANALIZE
- [ ] Test 4: Pagina Facturi Tab-uri + butoane imediat vizibile (fără blank)
- [ ] Test 5: Upload bon cu eroare Arată "Eroare" nu "În procesare"
- [ ] Test 6: Refresh Bonul cu eroare rămâne
- [ ] npm run build passes
## 4. Cerințe Funcționale
1. [REQ-001] Pe viewport < 768px, AppHeader și sidebar desktop trebuie ascunse complet
2. [REQ-002] MobileTopBar trebuie fie singurul header vizibil pe mobil
3. [REQ-003] MobileDrawerMenu trebuie se deschidă la click pe butonul Meniu din MobileTopBar
4. [REQ-004] Butoanele actions din MobileTopBar trebuie fie vizibile și funcționale
5. [REQ-005] batchProgressStore trebuie restaureze și afișeze joburi cu status 'failed'
6. [REQ-006] Editarea unui bon cu eroare trebuie reseteze processing_status pentru re-workflow
## 5. Non-Goals (Ce NU facem)
- NU modificăm layout-ul desktop (rămâne neschimbat)
- NU adăugăm funcționalități noi (doar fix-uri)
- NU modificăm stilurile cardurilor de bonuri
- NU schimbăm structura hamburger menu (doar ne asigurăm se deschide corect)
## 6. Considerații Tehnice
### Stack/Tehnologii
- Vue 3 Composition API
- PrimeVue components
- Pinia stores (batchProgressStore)
- CSS media queries / v-if cu isMobile computed
### Patterns de Urmat
- `isMobile` computed bazat pe `window.innerWidth < 768`
- `v-if="!isMobile"` pentru componente desktop-only
- `v-if="isMobile"` pentru componente mobile-only
### Fișiere Cheie de Modificat
| Fișier | Modificare |
|--------|------------|
| `src/App.vue` sau layout component | v-if pentru AppHeader/sidebar |
| `src/shared/components/layout/AppHeader.vue` | Verificare isMobile |
| `src/modules/reports/views/InvoicesView.vue` | CSS padding-top |
| `src/modules/data-entry/views/ReceiptsListView.vue` | CSS padding-top |
| `src/stores/batchProgressStore.js` | Include 'failed' în restore |
| `backend/modules/data_entry/routers/receipts.py` | Reset processing_status |
### Riscuri Tehnice
- Modificarea layout-ului principal poate afecta toate paginile - testare completă necesară
- isMobile computed trebuie fie reactiv la resize
## 7. Considerații UI/UX
- Mobile layout trebuie fie curat, fără suprapuneri
- Butoanele touch target minim 48px
- Feedback vizual clar pentru starea bonurilor (Eroare vs În procesare)
- Tranziție smooth pentru MobileDrawerMenu
## 8. Success Metrics
- 100% teste Playwright trec
- 0 suprapuneri vizuale pe viewport mobil
- Bonuri cu eroare persistent după refresh
- Timp de încărcare pagină neschimbat
## 9. Open Questions
- [x] Cauza exactă a problemei? Header desktop nu este ascuns pe mobil (confirmat prin Playwright)
- [x] isMobile computed există? Trebuie verificat în layout principal
- [ ] Există alte pagini afectate de layout? De verificat după fix