feat(ui-fixes-phase6): Complete US-603 - Implementare Pagină Facturi Detaliate

Implemented by Ralph autonomous loop.
Iteration: 3

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-01-13 16:11:33 +00:00
parent ea82f61a74
commit 496fd8014e
4 changed files with 178 additions and 32 deletions

View File

@@ -84,8 +84,8 @@
"npm run typecheck passes", "npm run typecheck passes",
"Verify in browser: Page shows detailed invoices table with Clienți/Furnizori tabs" "Verify in browser: Page shows detailed invoices table with Clienți/Furnizori tabs"
], ],
"passes": false, "passes": true,
"notes": "Creează fișier nou, adaugă rută în src/modules/reports/router/reports.routes.js" "notes": "Completed in iteration 3"
}, },
{ {
"id": "US-604", "id": "US-604",

View File

@@ -255,3 +255,9 @@ PRD: tasks/prd-ui-fixes-phase6.md
[2026-01-13 16:02:34] Working on story: US-602 [2026-01-13 16:02:34] Working on story: US-602
[2026-01-13 16:02:34] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_2_US-602.log) [2026-01-13 16:02:34] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_2_US-602.log)
[2026-01-13 16:08:47] SUCCESS: Story US-602 passed! [2026-01-13 16:08:47] SUCCESS: Story US-602 passed!
[2026-01-13 16:08:47] Changes committed
[2026-01-13 16:08:47] Progress: 2/10 stories completed
[2026-01-13 16:08:49] === Iteration 3/30 ===
[2026-01-13 16:08:49] Working on story: US-603
[2026-01-13 16:08:49] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_3_US-603.log)
[2026-01-13 16:11:33] SUCCESS: Story US-603 passed!

View File

@@ -1,25 +1,65 @@
<template> <template>
<!-- US-501: Mobile Top Bar --> <!-- US-501: Mobile Top Bar -->
<!-- US-510: Dynamic title based on route type --> <!-- US-603: Title is now "Facturi Detaliate" with tabs below -->
<MobileTopBar <MobileTopBar
v-if="isMobile" v-if="isMobile"
:title="pageTitle" title="Facturi Detaliate"
:show-back="true" :show-back="true"
:actions="topBarActions" :actions="topBarActions"
@back-click="goBack" @back-click="goBack"
@action-click="handleTopBarAction" @action-click="handleTopBarAction"
/> />
<!-- US-603: Mobile Tabs for Clienți/Furnizori -->
<div v-if="isMobile" class="mobile-tabs-container">
<div class="mobile-tabs">
<button
class="mobile-tab"
:class="{ active: activeTab === 'clients' }"
@click="switchTab('clients')"
>
<span class="tab-label">Clienți</span>
</button>
<button
class="mobile-tab"
:class="{ active: activeTab === 'suppliers' }"
@click="switchTab('suppliers')"
>
<span class="tab-label">Furnizori</span>
</button>
</div>
</div>
<!-- US-501: Export Menu (for mobile export dropdown) --> <!-- US-501: Export Menu (for mobile export dropdown) -->
<Menu ref="exportMenu" :model="exportMenuItems" :popup="true" /> <Menu ref="exportMenu" :model="exportMenuItems" :popup="true" />
<main class="main-content" :class="{ 'mobile-layout': isMobile }"> <main class="main-content" :class="{ 'mobile-layout': isMobile, 'has-tabs': isMobile }">
<div class="app-container"> <div class="app-container">
<!-- Page Header - only on desktop --> <!-- Page Header - only on desktop -->
<!-- US-510: Dynamic title based on route type --> <!-- US-603: Desktop header with tabs -->
<div v-if="!isMobile" class="page-header"> <div v-if="!isMobile" class="page-header">
<h1 class="page-title">{{ pageTitle }}</h1> <h1 class="page-title">Facturi Detaliate</h1>
<p class="page-subtitle">{{ pageSubtitle }}</p> <p class="page-subtitle">Vizualizare detaliată a facturilor clienți și furnizori</p>
<!-- US-603: Desktop Tabs for Clienți/Furnizori -->
<div class="desktop-tabs">
<button
class="desktop-tab"
:class="{ active: activeTab === 'clients' }"
@click="switchTab('clients')"
>
<i class="pi pi-users"></i>
<span>Clienți</span>
</button>
<button
class="desktop-tab"
:class="{ active: activeTab === 'suppliers' }"
@click="switchTab('suppliers')"
>
<i class="pi pi-truck"></i>
<span>Furnizori</span>
</button>
</div>
</div> </div>
<!-- Loading state when no company selected --> <!-- Loading state when no company selected -->
@@ -474,19 +514,31 @@ const dashboardStore = useDashboardStore()
const companyStore = useCompanyStore() const companyStore = useCompanyStore()
const periodStore = useAccountingPeriodStore() const periodStore = useAccountingPeriodStore()
// US-510: Get invoice type from route meta (clients or suppliers) // US-603: Tab state - initialized from route meta or query param
const invoiceType = computed(() => route.meta.invoiceType || 'clients') const activeTab = ref(route.query.tab === 'suppliers' ? 'suppliers' : (route.meta.invoiceType || 'clients'))
// US-510: Dynamic page title and subtitle based on invoice type // US-603: invoiceType is now derived from activeTab (not route meta)
const pageTitle = computed(() => { const invoiceType = computed(() => activeTab.value)
return invoiceType.value === 'clients' ? 'Facturi Clienți' : 'Facturi Furnizori'
})
const pageSubtitle = computed(() => { // US-603: Switch between Clienți/Furnizori tabs
return invoiceType.value === 'clients' const switchTab = async (tab) => {
? 'Vizualizare detaliată a facturilor clienți' if (tab === activeTab.value) return
: 'Vizualizare detaliată a facturilor furnizori'
}) activeTab.value = tab
// Update URL query param without full navigation
router.replace({
query: {
...route.query,
tab: tab === 'suppliers' ? 'suppliers' : undefined // Remove param if 'clients' (default)
}
})
// Reset pagination and reload data
firstRow.value = 0
expandedGroups.value.clear()
await loadDetailedData()
}
// Mobile detection // Mobile detection
const windowWidth = ref(window.innerWidth) const windowWidth = ref(window.innerWidth)
@@ -880,6 +932,104 @@ onUnmounted(() => {
padding-bottom: 56px; padding-bottom: 56px;
} }
/* US-603: Extra padding when tabs are visible on mobile */
.main-content.mobile-layout.has-tabs {
padding-top: calc(56px + 48px); /* MobileTopBar + tabs */
}
/* ================================================
US-603: Mobile Tabs (Clienți/Furnizori)
Material Design 3 inspired full-width tabs
================================================ */
.mobile-tabs-container {
position: fixed;
top: 56px; /* Below MobileTopBar */
left: 0;
right: 0;
z-index: var(--z-sticky);
background: var(--surface-card);
border-bottom: 1px solid var(--surface-border);
}
.mobile-tabs {
display: flex;
width: 100%;
}
.mobile-tab {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: var(--space-md);
min-height: 48px;
background: transparent;
border: none;
border-bottom: 2px solid transparent;
cursor: pointer;
transition: all var(--transition-fast);
color: var(--text-color-secondary);
font-size: var(--text-sm);
font-weight: var(--font-medium);
}
.mobile-tab:active {
background: var(--surface-hover);
}
.mobile-tab.active {
color: var(--color-primary);
border-bottom-color: var(--color-primary);
font-weight: var(--font-semibold);
}
.tab-label {
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* ================================================
US-603: Desktop Tabs (Clienți/Furnizori)
================================================ */
.desktop-tabs {
display: flex;
gap: var(--space-sm);
margin-top: var(--space-md);
}
.desktop-tab {
display: flex;
align-items: center;
gap: var(--space-sm);
padding: var(--space-sm) var(--space-lg);
background: var(--surface-hover);
border: 1px solid var(--surface-border);
border-radius: var(--radius-md);
cursor: pointer;
transition: all var(--transition-fast);
color: var(--text-color-secondary);
font-size: var(--text-sm);
font-weight: var(--font-medium);
}
.desktop-tab:hover {
background: var(--surface-card);
border-color: var(--color-primary);
color: var(--color-primary);
}
.desktop-tab.active {
background: var(--color-primary);
border-color: var(--color-primary);
color: var(--color-text-inverse);
}
.desktop-tab i {
font-size: var(--text-base);
}
/* App container */ /* App container */
.app-container { .app-container {
max-width: 1400px; max-width: 1400px;

View File

@@ -74,21 +74,11 @@ const routes = [
meta: { requiresAuth: true, title: 'Analiză Scadențe - ROA2WEB' } meta: { requiresAuth: true, title: 'Analiză Scadențe - ROA2WEB' }
}, },
{ {
// US-601: Redirect base detailed-invoices path to clients (default) // US-603: Single route for Detailed Invoices with tabs (Clienți/Furnizori)
path: 'detailed-invoices', path: 'detailed-invoices',
redirect: '/reports/detailed-invoices/clients' name: 'DetailedInvoices',
},
{
path: 'detailed-invoices/clients',
name: 'DetailedInvoicesClients',
component: () => import('@reports/views/DetailedInvoicesView.vue'), component: () => import('@reports/views/DetailedInvoicesView.vue'),
meta: { requiresAuth: true, title: 'Facturi Clienți - ROA2WEB', invoiceType: 'clients' } meta: { requiresAuth: true, title: 'Facturi Detaliate - ROA2WEB' }
},
{
path: 'detailed-invoices/suppliers',
name: 'DetailedInvoicesSuppliers',
component: () => import('@reports/views/DetailedInvoicesView.vue'),
meta: { requiresAuth: true, title: 'Facturi Furnizori - ROA2WEB', invoiceType: 'suppliers' }
} }
] ]
}, },