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:
@@ -1,25 +1,65 @@
|
||||
<template>
|
||||
<!-- US-501: Mobile Top Bar -->
|
||||
<!-- US-510: Dynamic title based on route type -->
|
||||
<!-- US-603: Title is now "Facturi Detaliate" with tabs below -->
|
||||
<MobileTopBar
|
||||
v-if="isMobile"
|
||||
:title="pageTitle"
|
||||
title="Facturi Detaliate"
|
||||
:show-back="true"
|
||||
:actions="topBarActions"
|
||||
@back-click="goBack"
|
||||
@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) -->
|
||||
<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">
|
||||
<!-- 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">
|
||||
<h1 class="page-title">{{ pageTitle }}</h1>
|
||||
<p class="page-subtitle">{{ pageSubtitle }}</p>
|
||||
<h1 class="page-title">Facturi Detaliate</h1>
|
||||
<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>
|
||||
|
||||
<!-- Loading state when no company selected -->
|
||||
@@ -474,19 +514,31 @@ const dashboardStore = useDashboardStore()
|
||||
const companyStore = useCompanyStore()
|
||||
const periodStore = useAccountingPeriodStore()
|
||||
|
||||
// US-510: Get invoice type from route meta (clients or suppliers)
|
||||
const invoiceType = computed(() => route.meta.invoiceType || 'clients')
|
||||
// US-603: Tab state - initialized from route meta or query param
|
||||
const activeTab = ref(route.query.tab === 'suppliers' ? 'suppliers' : (route.meta.invoiceType || 'clients'))
|
||||
|
||||
// US-510: Dynamic page title and subtitle based on invoice type
|
||||
const pageTitle = computed(() => {
|
||||
return invoiceType.value === 'clients' ? 'Facturi Clienți' : 'Facturi Furnizori'
|
||||
})
|
||||
// US-603: invoiceType is now derived from activeTab (not route meta)
|
||||
const invoiceType = computed(() => activeTab.value)
|
||||
|
||||
const pageSubtitle = computed(() => {
|
||||
return invoiceType.value === 'clients'
|
||||
? 'Vizualizare detaliată a facturilor clienți'
|
||||
: 'Vizualizare detaliată a facturilor furnizori'
|
||||
})
|
||||
// US-603: Switch between Clienți/Furnizori tabs
|
||||
const switchTab = async (tab) => {
|
||||
if (tab === activeTab.value) return
|
||||
|
||||
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
|
||||
const windowWidth = ref(window.innerWidth)
|
||||
@@ -880,6 +932,104 @@ onUnmounted(() => {
|
||||
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 {
|
||||
max-width: 1400px;
|
||||
|
||||
@@ -74,21 +74,11 @@ const routes = [
|
||||
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',
|
||||
redirect: '/reports/detailed-invoices/clients'
|
||||
},
|
||||
{
|
||||
path: 'detailed-invoices/clients',
|
||||
name: 'DetailedInvoicesClients',
|
||||
name: 'DetailedInvoices',
|
||||
component: () => import('@reports/views/DetailedInvoicesView.vue'),
|
||||
meta: { requiresAuth: true, title: 'Facturi Clienți - ROA2WEB', invoiceType: 'clients' }
|
||||
},
|
||||
{
|
||||
path: 'detailed-invoices/suppliers',
|
||||
name: 'DetailedInvoicesSuppliers',
|
||||
component: () => import('@reports/views/DetailedInvoicesView.vue'),
|
||||
meta: { requiresAuth: true, title: 'Facturi Furnizori - ROA2WEB', invoiceType: 'suppliers' }
|
||||
meta: { requiresAuth: true, title: 'Facturi Detaliate - ROA2WEB' }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user