fix(reports): neutralize totals color and fix dark mode button contrast

- Remove green/red/blue coloring from summary totals on all report pages
  (Facturi, Facturi pe Parteneri, Casă, Bancă) — mobile and desktop,
  light and dark mode; totals now use --text-color like TrialBalance
- Fix SplitButton (Export) dark mode: was blue (--color-primary), now
  matches secondary outlined style (--text-color / --surface-border)
- Update button syntax: severity="secondary" outlined instead of legacy
  class="p-button-outlined p-button-secondary"
- DetailedInvoices: partner-meta (8 facturi) inline with partner name
  via flex-direction row instead of column
- TrialBalance: mobile flat-row list layout replacing card layout
- Dashboard mobile title: shows company name + period instead of static "Dashboard"
- Navigation: move Facturi pe Parteneri to RAPOARTE section;
  update MobileBottomNav default items (Detalii replaces Facturi)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-02-26 08:40:59 +00:00
parent 1839285ac3
commit 0459b3feaf
10 changed files with 654 additions and 646 deletions

View File

@@ -184,6 +184,11 @@
cursor: pointer; cursor: pointer;
} }
/* DataTable body text - override saga-blue hardcoded #495057 */
.p-datatable .p-datatable-tbody > tr {
color: var(--text-color) !important;
}
/* Compact DataTable variant (p-datatable-sm) */ /* Compact DataTable variant (p-datatable-sm) */
.p-datatable-sm .p-datatable-thead > tr > th { .p-datatable-sm .p-datatable-thead > tr > th {
padding: 0.5rem 0.75rem !important; padding: 0.5rem 0.75rem !important;
@@ -683,9 +688,121 @@
} }
} }
/* ===== Menu (popup/SplitButton dropdown) ===== */
.p-menu {
background: var(--surface-card);
border-color: var(--surface-border);
color: var(--text-color);
}
.p-menu .p-menuitem > .p-menuitem-content .p-menuitem-link {
color: var(--text-color);
padding: var(--space-sm) var(--space-md);
gap: var(--space-sm);
}
.p-menu .p-menuitem > .p-menuitem-content .p-menuitem-link .p-menuitem-text {
color: var(--text-color);
}
.p-menu .p-menuitem > .p-menuitem-content .p-menuitem-link .p-menuitem-icon {
color: var(--text-color-secondary);
margin-right: 0;
}
.p-menu .p-menuitem > .p-menuitem-content:hover,
.p-menu .p-menuitem > .p-menuitem-content:not(.p-highlight):not(.p-disabled).p-focus {
background: var(--surface-hover);
}
[data-theme="dark"] .p-menu {
background: var(--surface-card);
border-color: var(--surface-border);
}
[data-theme="dark"] .p-menu .p-menuitem > .p-menuitem-content .p-menuitem-link {
color: var(--text-color);
}
[data-theme="dark"] .p-menu .p-menuitem > .p-menuitem-content:hover {
background: var(--surface-hover);
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme]) .p-menu {
background: var(--surface-card);
border-color: var(--surface-border);
}
:root:not([data-theme]) .p-menu .p-menuitem > .p-menuitem-content .p-menuitem-link {
color: var(--text-color);
}
:root:not([data-theme]) .p-menu .p-menuitem > .p-menuitem-content:hover {
background: var(--surface-hover);
}
}
/* Server dropdown in login form uses default styling (inherits from global rules above) */ /* Server dropdown in login form uses default styling (inherits from global rules above) */
/* Server dropdown in header is styled in header.css to match CompanySelector */ /* Server dropdown in header is styled in header.css to match CompanySelector */
/* ===== Dark Mode Outlined Button Contrast Fix ===== */
/* PrimeVue saga-blue (light) theme doesn't adapt outlined buttons for dark mode.
Secondary outlined buttons become invisible (grey on dark bg).
SplitButton outlined also needs explicit dark-mode color. */
[data-theme="dark"] .p-button.p-button-outlined.p-button-secondary {
color: var(--text-color) !important;
border-color: var(--surface-border) !important;
background: transparent !important;
}
[data-theme="dark"] .p-button.p-button-outlined.p-button-secondary:hover {
background: var(--surface-hover) !important;
color: var(--text-color) !important;
border-color: var(--text-color-secondary) !important;
}
[data-theme="dark"] .p-splitbutton .p-splitbutton-defaultbutton.p-button-outlined,
[data-theme="dark"] .p-splitbutton .p-splitbutton-menubutton.p-button-outlined {
color: var(--text-color) !important;
border-color: var(--surface-border) !important;
background: transparent !important;
}
[data-theme="dark"] .p-splitbutton .p-splitbutton-defaultbutton.p-button-outlined:hover,
[data-theme="dark"] .p-splitbutton .p-splitbutton-menubutton.p-button-outlined:hover {
background: var(--surface-hover) !important;
color: var(--text-color) !important;
border-color: var(--text-color-secondary) !important;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme]) .p-button.p-button-outlined.p-button-secondary {
color: var(--text-color) !important;
border-color: var(--surface-border) !important;
background: transparent !important;
}
:root:not([data-theme]) .p-button.p-button-outlined.p-button-secondary:hover {
background: var(--surface-hover) !important;
color: var(--text-color) !important;
border-color: var(--text-color-secondary) !important;
}
:root:not([data-theme]) .p-splitbutton .p-splitbutton-defaultbutton.p-button-outlined,
:root:not([data-theme]) .p-splitbutton .p-splitbutton-menubutton.p-button-outlined {
color: var(--text-color) !important;
border-color: var(--surface-border) !important;
background: transparent !important;
}
:root:not([data-theme]) .p-splitbutton .p-splitbutton-defaultbutton.p-button-outlined:hover,
:root:not([data-theme]) .p-splitbutton .p-splitbutton-menubutton.p-button-outlined:hover {
background: var(--surface-hover) !important;
color: var(--text-color) !important;
border-color: var(--text-color-secondary) !important;
}
}
/* ===== All Dialogs - Dark Mode ===== */ /* ===== All Dialogs - Dark Mode ===== */
/* Dialog background + content folosesc design tokens */ /* Dialog background + content folosesc design tokens */

View File

@@ -4,6 +4,7 @@ export const menuSections = [
items: [ items: [
{ to: '/reports/dashboard', icon: 'pi pi-home', label: 'Dashboard' }, { to: '/reports/dashboard', icon: 'pi pi-home', label: 'Dashboard' },
{ to: '/reports/invoices', icon: 'pi pi-file', label: 'Facturi' }, { to: '/reports/invoices', icon: 'pi pi-file', label: 'Facturi' },
{ to: '/reports/detailed-invoices', icon: 'pi pi-list', label: 'Facturi pe Parteneri' },
{ to: '/reports/cash', icon: 'pi pi-wallet', label: 'Casă' }, { to: '/reports/cash', icon: 'pi pi-wallet', label: 'Casă' },
{ to: '/reports/bank', icon: 'pi pi-building', label: 'Bancă' }, { to: '/reports/bank', icon: 'pi pi-building', label: 'Bancă' },
{ to: '/reports/trial-balance', icon: 'pi pi-calculator', label: 'Balanță de Verificare' } { to: '/reports/trial-balance', icon: 'pi pi-calculator', label: 'Balanță de Verificare' }
@@ -12,8 +13,7 @@ export const menuSections = [
{ {
title: 'Analize', title: 'Analize',
items: [ items: [
{ to: '/reports/maturity-analysis', icon: 'pi pi-clock', label: 'Scadențe' }, { to: '/reports/maturity-analysis', icon: 'pi pi-clock', label: 'Scadențe' }
{ to: '/reports/detailed-invoices', icon: 'pi pi-list', label: 'Facturi Detaliate' }
] ]
}, },
{ {

View File

@@ -74,7 +74,8 @@
<Button <Button
icon="pi pi-filter-slash" icon="pi pi-filter-slash"
label="Resetează" label="Resetează"
class="p-button-outlined p-button-secondary" severity="secondary"
outlined
@click="resetFilters(); showFilters = false" @click="resetFilters(); showFilters = false"
/> />
<Button <Button
@@ -124,11 +125,11 @@
</div> </div>
<div class="total-item"> <div class="total-item">
<span class="total-label">Încasări:</span> <span class="total-label">Încasări:</span>
<span class="total-value incasari">{{ formatCompact(treasuryStore.totals.total_incasari_all) }}</span> <span class="total-value">{{ formatCompact(treasuryStore.totals.total_incasari_all) }}</span>
</div> </div>
<div class="total-item"> <div class="total-item">
<span class="total-label">Plăți:</span> <span class="total-label">Plăți:</span>
<span class="total-value plati">{{ formatCompact(treasuryStore.totals.total_plati_all) }}</span> <span class="total-value">{{ formatCompact(treasuryStore.totals.total_plati_all) }}</span>
</div> </div>
<div class="total-item"> <div class="total-item">
<span class="total-label">Sold Final:</span> <span class="total-label">Sold Final:</span>
@@ -190,7 +191,8 @@
<Button <Button
icon="pi pi-filter-slash" icon="pi pi-filter-slash"
label="Resetează Filtre" label="Resetează Filtre"
class="p-button-outlined p-button-secondary" severity="secondary"
outlined
@click="resetFilters" @click="resetFilters"
/> />
<SplitButton <SplitButton
@@ -198,7 +200,7 @@
icon="pi pi-download" icon="pi pi-download"
:model="desktopExportItems" :model="desktopExportItems"
@click="exportPDF" @click="exportPDF"
class="p-button-outlined" outlined
:disabled="!hasData" :disabled="!hasData"
/> />
<Button <Button
@@ -216,55 +218,49 @@
<div v-if="!isMobile && companyStore.selectedCompany" class="summary-stats-inline"> <div v-if="!isMobile && companyStore.selectedCompany" class="summary-stats-inline">
<div class="stat-item"> <div class="stat-item">
<span class="stat-label">Sold Precedent:</span> <span class="stat-label">Sold Precedent:</span>
<span <span class="stat-value">{{ formatCurrency(treasuryStore.totals.sold_precedent_all) }}</span>
class="stat-value"
:class="treasuryStore.totals.sold_precedent_all >= 0 ? 'incasari' : 'plati'"
>{{ formatCurrency(treasuryStore.totals.sold_precedent_all) }}</span
>
</div> </div>
<div class="stat-item"> <div class="stat-item">
<span class="stat-label">Încasări:</span> <span class="stat-label">Încasări:</span>
<span class="stat-value incasari">{{ <span class="stat-value">{{ formatCurrency(treasuryStore.totals.total_incasari_all) }}</span>
formatCurrency(treasuryStore.totals.total_incasari_all)
}}</span>
</div> </div>
<div class="stat-item"> <div class="stat-item">
<span class="stat-label">Plăți:</span> <span class="stat-label">Plăți:</span>
<span class="stat-value plati">{{ <span class="stat-value">{{ formatCurrency(treasuryStore.totals.total_plati_all) }}</span>
formatCurrency(treasuryStore.totals.total_plati_all)
}}</span>
</div> </div>
<div class="stat-item"> <div class="stat-item">
<span class="stat-label">Sold Final:</span> <span class="stat-label">Sold Final:</span>
<span <span class="stat-value">{{ formatCurrency(treasuryStore.totals.sold_final_all) }}</span>
class="stat-value"
:class="treasuryStore.totals.sold_final_all >= 0 ? 'incasari' : 'plati'"
>{{ formatCurrency(treasuryStore.totals.sold_final_all) }}</span
>
</div> </div>
</div> </div>
<!-- Data Table --> <!-- Data Table -->
<Card v-if="companyStore.selectedCompany" class="data-card"> <Card v-if="companyStore.selectedCompany" class="data-card">
<template #content> <template #content>
<!-- Mobile: Card Layout --> <!-- Mobile: Compact Rows with Collapsible Meta -->
<div v-if="isMobile" class="mobile-card-list"> <div v-if="isMobile" class="mobile-card-list">
<div <div
v-for="reg in treasuryStore.registers" v-for="(reg, index) in treasuryStore.registers"
:key="`${reg.dataact}-${reg.nract}`" :key="`${reg.dataact}-${reg.nract}`"
class="mobile-data-card" class="mobile-compact-row"
> >
<div class="card-header">{{ reg.nume || 'Fără partener' }}</div> <div class="compact-main" @click="toggleMeta(index)">
<div class="card-row"> <span class="compact-date">{{ formatDateShort(reg.dataact) }}</span>
<span class="card-meta">{{ formatDateShort(reg.dataact) }} · {{ reg.nume_cont_bancar }}</span> <span class="compact-partner">{{ reg.nume || 'Fără partener' }}</span>
<span <span
class="card-amount" class="compact-amount"
:class="reg.incasari > 0 ? 'positive' : (reg.plati > 0 ? 'negative' : '')" :class="reg.incasari > 0 ? 'positive' : (reg.plati > 0 ? 'negative' : '')"
> >
<template v-if="reg.incasari > 0">+{{ formatNumber(reg.incasari) }}</template> <template v-if="reg.incasari > 0">+{{ formatNumber(reg.incasari) }}</template>
<template v-else-if="reg.plati > 0">-{{ formatNumber(reg.plati) }}</template> <template v-else-if="reg.plati > 0">-{{ formatNumber(reg.plati) }}</template>
<template v-else>{{ formatNumber(0) }}</template> <template v-else>0</template>
</span> </span>
<i :class="expandedMeta.has(index) ? 'pi pi-chevron-up' : 'pi pi-chevron-down'" class="meta-chevron"></i>
</div>
<div v-if="expandedMeta.has(index)" class="compact-meta">
<span v-if="reg.nume_cont_bancar" class="meta-item">{{ reg.nume_cont_bancar }}</span>
<span v-if="reg.nract" class="meta-item">Nr: {{ reg.nract }}</span>
<span v-if="reg.explicatia" class="meta-item">{{ truncateText(reg.explicatia, 80) }}</span>
</div> </div>
</div> </div>
<div v-if="treasuryStore.registers.length === 0" class="mobile-empty"> <div v-if="treasuryStore.registers.length === 0" class="mobile-empty">
@@ -419,6 +415,14 @@ const selectedCompanyId = ref(companyStore.selectedCompany?.id_firma || null);
const isMobile = ref(window.innerWidth < 768); const isMobile = ref(window.innerWidth < 768);
const showFilters = ref(false); const showFilters = ref(false);
const showDrawer = ref(false); const showDrawer = ref(false);
const expandedMeta = ref(new Set());
const toggleMeta = (index) => {
const s = new Set(expandedMeta.value);
if (s.has(index)) s.delete(index);
else s.add(index);
expandedMeta.value = s;
};
// Handle logout from drawer menu // Handle logout from drawer menu
const handleLogout = async () => { const handleLogout = async () => {
@@ -527,11 +531,11 @@ const pagination = ref({
rows: 50, rows: 50,
}); });
const formatCurrency = (amount, currency = "RON") => { const formatCurrency = (amount) => {
if (!amount) return "0,00 " + currency; if (!amount || amount === 0) return "0,00";
return new Intl.NumberFormat("ro-RO", { return new Intl.NumberFormat("ro-RO", {
style: "currency", minimumFractionDigits: 2,
currency: currency, maximumFractionDigits: 2,
}).format(amount); }).format(amount);
}; };
@@ -943,6 +947,12 @@ watch(
}, },
{ immediate: true }, { immediate: true },
); );
// Reset expanded meta when data changes
watch(
() => treasuryStore.registers,
() => { expandedMeta.value = new Set(); }
);
</script> </script>
<style scoped> <style scoped>
@@ -1025,63 +1035,83 @@ watch(
color: var(--text-color); color: var(--text-color);
} }
.mobile-totals-bar .total-value.incasari { /* Colors removed - totals use neutral --text-color like TrialBalance */
color: var(--green-600);
}
.mobile-totals-bar .total-value.plati {
color: var(--red-600);
}
/* ================================================ /* ================================================
Mobile Card List Mobile Compact Rows with Collapsible Meta
================================================ */ ================================================ */
.mobile-card-list { .mobile-card-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: var(--space-sm);
} }
.mobile-data-card { .mobile-compact-row {
background: var(--surface-card); border-bottom: 1px solid var(--surface-border);
border: 1px solid var(--surface-border);
border-radius: var(--radius-md);
padding: var(--space-md);
} }
.mobile-data-card .card-header { .compact-main {
font-weight: var(--font-semibold);
color: var(--text-color);
margin-bottom: var(--space-xs);
font-size: var(--text-base);
}
.mobile-data-card .card-row {
display: flex; display: flex;
justify-content: space-between;
align-items: center; align-items: center;
font-size: var(--text-sm); min-height: 44px;
color: var(--text-color-secondary); padding: var(--space-sm) var(--space-md);
gap: var(--space-sm);
cursor: pointer;
} }
.mobile-data-card .card-meta { .compact-main:active {
background: var(--surface-hover);
}
.compact-date {
font-size: var(--text-xs);
color: var(--text-color-secondary);
min-width: 40px;
flex-shrink: 0;
}
.compact-partner {
flex: 1;
font-size: var(--text-sm);
color: var(--text-color);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.compact-amount {
font-weight: var(--font-semibold);
font-variant-numeric: tabular-nums;
font-size: var(--text-sm);
flex-shrink: 0;
}
.compact-amount.positive {
color: var(--green-600);
}
.compact-amount.negative {
color: var(--red-600);
}
.meta-chevron {
font-size: var(--text-xs);
color: var(--text-color-secondary);
flex-shrink: 0;
}
.compact-meta {
display: flex;
flex-direction: column;
gap: var(--space-xs);
padding: var(--space-xs) var(--space-md) var(--space-sm) calc(40px + var(--space-md) + var(--space-sm));
background: var(--surface-hover);
font-size: var(--text-xs); font-size: var(--text-xs);
color: var(--text-color-secondary); color: var(--text-color-secondary);
} }
.mobile-data-card .card-amount { .meta-item {
font-weight: var(--font-semibold); display: block;
color: var(--text-color);
font-variant-numeric: tabular-nums;
}
.mobile-data-card .card-amount.positive {
color: var(--green-600);
}
.mobile-data-card .card-amount.negative {
color: var(--red-600);
} }
.mobile-empty { .mobile-empty {
@@ -1126,41 +1156,33 @@ watch(
Dark Mode Support Dark Mode Support
================================================ */ ================================================ */
[data-theme="dark"] .mobile-totals-bar .total-value.incasari { [data-theme="dark"] .compact-amount.positive {
color: var(--green-400); color: var(--green-400);
} }
[data-theme="dark"] .mobile-totals-bar .total-value.plati { [data-theme="dark"] .compact-amount.negative {
color: var(--red-400);
}
[data-theme="dark"] .mobile-data-card .card-amount.positive {
color: var(--green-400);
}
[data-theme="dark"] .mobile-data-card .card-amount.negative {
color: var(--red-400); color: var(--red-400);
} }
/* Auto dark mode */ /* Auto dark mode */
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root:not([data-theme]) .mobile-totals-bar .total-value.incasari { :root:not([data-theme]) .compact-amount.positive {
color: var(--green-400); color: var(--green-400);
} }
:root:not([data-theme]) .mobile-totals-bar .total-value.plati { :root:not([data-theme]) .compact-amount.negative {
color: var(--red-400); color: var(--red-400);
} }
:root:not([data-theme]) .mobile-data-card .card-amount.positive { :root:not([data-theme]) .numeric-value.negative {
color: var(--green-400);
}
:root:not([data-theme]) .mobile-data-card .card-amount.negative {
color: var(--red-400); color: var(--red-400);
} }
} }
[data-theme="dark"] .numeric-value.negative {
color: var(--red-400);
}
/* ================================================ /* ================================================
Responsive Design Responsive Design
================================================ */ ================================================ */

View File

@@ -74,7 +74,8 @@
<Button <Button
icon="pi pi-filter-slash" icon="pi pi-filter-slash"
label="Resetează" label="Resetează"
class="p-button-outlined p-button-secondary" severity="secondary"
outlined
@click="resetFilters(); showFilters = false" @click="resetFilters(); showFilters = false"
/> />
<Button <Button
@@ -124,11 +125,11 @@
</div> </div>
<div class="total-item"> <div class="total-item">
<span class="total-label">Încasări:</span> <span class="total-label">Încasări:</span>
<span class="total-value incasari">{{ formatCompact(treasuryStore.totals.total_incasari_all) }}</span> <span class="total-value">{{ formatCompact(treasuryStore.totals.total_incasari_all) }}</span>
</div> </div>
<div class="total-item"> <div class="total-item">
<span class="total-label">Plăți:</span> <span class="total-label">Plăți:</span>
<span class="total-value plati">{{ formatCompact(treasuryStore.totals.total_plati_all) }}</span> <span class="total-value">{{ formatCompact(treasuryStore.totals.total_plati_all) }}</span>
</div> </div>
<div class="total-item"> <div class="total-item">
<span class="total-label">Sold Final:</span> <span class="total-label">Sold Final:</span>
@@ -190,7 +191,8 @@
<Button <Button
icon="pi pi-filter-slash" icon="pi pi-filter-slash"
label="Resetează Filtre" label="Resetează Filtre"
class="p-button-outlined p-button-secondary" severity="secondary"
outlined
@click="resetFilters" @click="resetFilters"
/> />
<SplitButton <SplitButton
@@ -198,7 +200,7 @@
icon="pi pi-download" icon="pi pi-download"
:model="desktopExportItems" :model="desktopExportItems"
@click="exportPDF" @click="exportPDF"
class="p-button-outlined" outlined
:disabled="!hasData" :disabled="!hasData"
/> />
<Button <Button
@@ -216,55 +218,49 @@
<div v-if="!isMobile && companyStore.selectedCompany" class="summary-stats-inline"> <div v-if="!isMobile && companyStore.selectedCompany" class="summary-stats-inline">
<div class="stat-item"> <div class="stat-item">
<span class="stat-label">Sold Precedent:</span> <span class="stat-label">Sold Precedent:</span>
<span <span class="stat-value">{{ formatCurrency(treasuryStore.totals.sold_precedent_all) }}</span>
class="stat-value"
:class="treasuryStore.totals.sold_precedent_all >= 0 ? 'incasari' : 'plati'"
>{{ formatCurrency(treasuryStore.totals.sold_precedent_all) }}</span
>
</div> </div>
<div class="stat-item"> <div class="stat-item">
<span class="stat-label">Încasări:</span> <span class="stat-label">Încasări:</span>
<span class="stat-value incasari">{{ <span class="stat-value">{{ formatCurrency(treasuryStore.totals.total_incasari_all) }}</span>
formatCurrency(treasuryStore.totals.total_incasari_all)
}}</span>
</div> </div>
<div class="stat-item"> <div class="stat-item">
<span class="stat-label">Plăți:</span> <span class="stat-label">Plăți:</span>
<span class="stat-value plati">{{ <span class="stat-value">{{ formatCurrency(treasuryStore.totals.total_plati_all) }}</span>
formatCurrency(treasuryStore.totals.total_plati_all)
}}</span>
</div> </div>
<div class="stat-item"> <div class="stat-item">
<span class="stat-label">Sold Final:</span> <span class="stat-label">Sold Final:</span>
<span <span class="stat-value">{{ formatCurrency(treasuryStore.totals.sold_final_all) }}</span>
class="stat-value"
:class="treasuryStore.totals.sold_final_all >= 0 ? 'incasari' : 'plati'"
>{{ formatCurrency(treasuryStore.totals.sold_final_all) }}</span
>
</div> </div>
</div> </div>
<!-- Data Table --> <!-- Data Table -->
<Card v-if="companyStore.selectedCompany" class="data-card"> <Card v-if="companyStore.selectedCompany" class="data-card">
<template #content> <template #content>
<!-- Mobile: Card Layout --> <!-- Mobile: Compact Rows with Collapsible Meta -->
<div v-if="isMobile" class="mobile-card-list"> <div v-if="isMobile" class="mobile-card-list">
<div <div
v-for="reg in treasuryStore.registers" v-for="(reg, index) in treasuryStore.registers"
:key="`${reg.dataact}-${reg.nract}`" :key="`${reg.dataact}-${reg.nract}`"
class="mobile-data-card" class="mobile-compact-row"
> >
<div class="card-header">{{ reg.nume || 'Fără partener' }}</div> <div class="compact-main" @click="toggleMeta(index)">
<div class="card-row"> <span class="compact-date">{{ formatDateShort(reg.dataact) }}</span>
<span class="card-meta">{{ formatDateShort(reg.dataact) }} · {{ reg.nume_cont_bancar }}</span> <span class="compact-partner">{{ reg.nume || 'Fără partener' }}</span>
<span <span
class="card-amount" class="compact-amount"
:class="reg.incasari > 0 ? 'positive' : (reg.plati > 0 ? 'negative' : '')" :class="reg.incasari > 0 ? 'positive' : (reg.plati > 0 ? 'negative' : '')"
> >
<template v-if="reg.incasari > 0">+{{ formatNumber(reg.incasari) }}</template> <template v-if="reg.incasari > 0">+{{ formatNumber(reg.incasari) }}</template>
<template v-else-if="reg.plati > 0">-{{ formatNumber(reg.plati) }}</template> <template v-else-if="reg.plati > 0">-{{ formatNumber(reg.plati) }}</template>
<template v-else>{{ formatNumber(0) }}</template> <template v-else>0</template>
</span> </span>
<i :class="expandedMeta.has(index) ? 'pi pi-chevron-up' : 'pi pi-chevron-down'" class="meta-chevron"></i>
</div>
<div v-if="expandedMeta.has(index)" class="compact-meta">
<span v-if="reg.nume_cont_bancar" class="meta-item">{{ reg.nume_cont_bancar }}</span>
<span v-if="reg.nract" class="meta-item">Nr: {{ reg.nract }}</span>
<span v-if="reg.explicatia" class="meta-item">{{ truncateText(reg.explicatia, 80) }}</span>
</div> </div>
</div> </div>
<div v-if="treasuryStore.registers.length === 0" class="mobile-empty"> <div v-if="treasuryStore.registers.length === 0" class="mobile-empty">
@@ -419,6 +415,14 @@ const selectedCompanyId = ref(companyStore.selectedCompany?.id_firma || null);
const isMobile = ref(window.innerWidth < 768); const isMobile = ref(window.innerWidth < 768);
const showFilters = ref(false); const showFilters = ref(false);
const showDrawer = ref(false); const showDrawer = ref(false);
const expandedMeta = ref(new Set());
const toggleMeta = (index) => {
const s = new Set(expandedMeta.value);
if (s.has(index)) s.delete(index);
else s.add(index);
expandedMeta.value = s;
};
// Handle logout from drawer menu // Handle logout from drawer menu
const handleLogout = async () => { const handleLogout = async () => {
@@ -527,11 +531,11 @@ const pagination = ref({
rows: 50, rows: 50,
}); });
const formatCurrency = (amount, currency = "RON") => { const formatCurrency = (amount) => {
if (!amount) return "0,00 " + currency; if (!amount || amount === 0) return "0,00";
return new Intl.NumberFormat("ro-RO", { return new Intl.NumberFormat("ro-RO", {
style: "currency", minimumFractionDigits: 2,
currency: currency, maximumFractionDigits: 2,
}).format(amount); }).format(amount);
}; };
@@ -943,6 +947,12 @@ watch(
}, },
{ immediate: true }, { immediate: true },
); );
// Reset expanded meta when data changes
watch(
() => treasuryStore.registers,
() => { expandedMeta.value = new Set(); }
);
</script> </script>
<style scoped> <style scoped>
@@ -1025,63 +1035,83 @@ watch(
color: var(--text-color); color: var(--text-color);
} }
.mobile-totals-bar .total-value.incasari { /* Colors removed - totals use neutral --text-color like TrialBalance */
color: var(--green-600);
}
.mobile-totals-bar .total-value.plati {
color: var(--red-600);
}
/* ================================================ /* ================================================
Mobile Card List Mobile Compact Rows with Collapsible Meta
================================================ */ ================================================ */
.mobile-card-list { .mobile-card-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: var(--space-sm);
} }
.mobile-data-card { .mobile-compact-row {
background: var(--surface-card); border-bottom: 1px solid var(--surface-border);
border: 1px solid var(--surface-border);
border-radius: var(--radius-md);
padding: var(--space-md);
} }
.mobile-data-card .card-header { .compact-main {
font-weight: var(--font-semibold);
color: var(--text-color);
margin-bottom: var(--space-xs);
font-size: var(--text-base);
}
.mobile-data-card .card-row {
display: flex; display: flex;
justify-content: space-between;
align-items: center; align-items: center;
font-size: var(--text-sm); min-height: 44px;
color: var(--text-color-secondary); padding: var(--space-sm) var(--space-md);
gap: var(--space-sm);
cursor: pointer;
} }
.mobile-data-card .card-meta { .compact-main:active {
background: var(--surface-hover);
}
.compact-date {
font-size: var(--text-xs);
color: var(--text-color-secondary);
min-width: 40px;
flex-shrink: 0;
}
.compact-partner {
flex: 1;
font-size: var(--text-sm);
color: var(--text-color);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.compact-amount {
font-weight: var(--font-semibold);
font-variant-numeric: tabular-nums;
font-size: var(--text-sm);
flex-shrink: 0;
}
.compact-amount.positive {
color: var(--green-600);
}
.compact-amount.negative {
color: var(--red-600);
}
.meta-chevron {
font-size: var(--text-xs);
color: var(--text-color-secondary);
flex-shrink: 0;
}
.compact-meta {
display: flex;
flex-direction: column;
gap: var(--space-xs);
padding: var(--space-xs) var(--space-md) var(--space-sm) calc(40px + var(--space-md) + var(--space-sm));
background: var(--surface-hover);
font-size: var(--text-xs); font-size: var(--text-xs);
color: var(--text-color-secondary); color: var(--text-color-secondary);
} }
.mobile-data-card .card-amount { .meta-item {
font-weight: var(--font-semibold); display: block;
color: var(--text-color);
font-variant-numeric: tabular-nums;
}
.mobile-data-card .card-amount.positive {
color: var(--green-600);
}
.mobile-data-card .card-amount.negative {
color: var(--red-600);
} }
.mobile-empty { .mobile-empty {
@@ -1126,41 +1156,33 @@ watch(
Dark Mode Support Dark Mode Support
================================================ */ ================================================ */
[data-theme="dark"] .mobile-totals-bar .total-value.incasari { [data-theme="dark"] .compact-amount.positive {
color: var(--green-400); color: var(--green-400);
} }
[data-theme="dark"] .mobile-totals-bar .total-value.plati { [data-theme="dark"] .compact-amount.negative {
color: var(--red-400);
}
[data-theme="dark"] .mobile-data-card .card-amount.positive {
color: var(--green-400);
}
[data-theme="dark"] .mobile-data-card .card-amount.negative {
color: var(--red-400); color: var(--red-400);
} }
/* Auto dark mode */ /* Auto dark mode */
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root:not([data-theme]) .mobile-totals-bar .total-value.incasari { :root:not([data-theme]) .compact-amount.positive {
color: var(--green-400); color: var(--green-400);
} }
:root:not([data-theme]) .mobile-totals-bar .total-value.plati { :root:not([data-theme]) .compact-amount.negative {
color: var(--red-400); color: var(--red-400);
} }
:root:not([data-theme]) .mobile-data-card .card-amount.positive { :root:not([data-theme]) .numeric-value.negative {
color: var(--green-400);
}
:root:not([data-theme]) .mobile-data-card .card-amount.negative {
color: var(--red-400); color: var(--red-400);
} }
} }
[data-theme="dark"] .numeric-value.negative {
color: var(--red-400);
}
/* ================================================ /* ================================================
Responsive Design Responsive Design
================================================ */ ================================================ */

View File

@@ -2,7 +2,7 @@
<!-- Mobile Top Bar --> <!-- Mobile Top Bar -->
<MobileTopBar <MobileTopBar
v-if="isMobile" v-if="isMobile"
title="Dashboard" :title="dashboardTitle"
:show-menu="true" :show-menu="true"
:actions="mobileTopBarActions" :actions="mobileTopBarActions"
@menu-click="showDrawer = true" @menu-click="showDrawer = true"
@@ -775,6 +775,17 @@ const bancaPreviousSparkline = computed(() => {
const windowWidth = ref(window.innerWidth); const windowWidth = ref(window.innerWidth);
const isMobile = computed(() => windowWidth.value < 768); const isMobile = computed(() => windowWidth.value < 768);
const dashboardTitle = computed(() => {
const company = companyStore.selectedCompany?.name;
const period = periodStore.selectedPeriod;
if (!company) return 'Dashboard';
if (period) {
const lunaStr = String(period.luna).padStart(2, '0');
return `${company} · ${lunaStr}/${period.an}`;
}
return company;
});
// Handle window resize for mobile detection // Handle window resize for mobile detection
const handleResize = () => { const handleResize = () => {
windowWidth.value = window.innerWidth; windowWidth.value = window.innerWidth;

View File

@@ -2,7 +2,7 @@
<!-- US-703: Mobile Top Bar with Hamburger Menu (not back button) --> <!-- US-703: Mobile Top Bar with Hamburger Menu (not back button) -->
<MobileTopBar <MobileTopBar
v-if="isMobile" v-if="isMobile"
title="Facturi Detaliate" title="Facturi pe Parteneri"
:show-menu="true" :show-menu="true"
:actions="topBarActions" :actions="topBarActions"
@menu-click="showDrawer = true" @menu-click="showDrawer = true"
@@ -52,8 +52,8 @@
<!-- Page Header - only on desktop --> <!-- Page Header - only on desktop -->
<!-- US-603: Desktop header with tabs --> <!-- US-603: Desktop header with tabs -->
<div v-if="!isMobile" class="page-header"> <div v-if="!isMobile" class="page-header">
<h1 class="page-title">Facturi Detaliate</h1> <h1 class="page-title">Facturi pe Parteneri</h1>
<p class="page-subtitle">Vizualizare detaliată a facturilor clienți și furnizori</p> <p class="page-subtitle">Vizualizare facturi grupate pe clienți și furnizori</p>
<!-- US-603: Desktop Tabs for Clienți/Furnizori --> <!-- US-603: Desktop Tabs for Clienți/Furnizori -->
<div class="desktop-tabs"> <div class="desktop-tabs">
@@ -106,18 +106,6 @@
@input="handleSearch" @input="handleSearch"
/> />
</div> </div>
<div class="filter-group">
<label class="form-label">Perioadă</label>
<Dropdown
v-model="selectedPeriod"
:options="periodOptions"
optionLabel="label"
optionValue="value"
placeholder="Selectați perioada"
class="w-full"
@change="loadDetailedData"
/>
</div>
</div> </div>
<!-- US-501: Desktop Action buttons with Export dropdown --> <!-- US-501: Desktop Action buttons with Export dropdown -->
<div class="filters-actions"> <div class="filters-actions">
@@ -152,11 +140,6 @@
<span>{{ searchTerm }}</span> <span>{{ searchTerm }}</span>
<i class="pi pi-times" @click="clearSearch"></i> <i class="pi pi-times" @click="clearSearch"></i>
</div> </div>
<div v-if="selectedPeriod !== 'all'" class="filter-chip active">
<i class="pi pi-calendar"></i>
<span>{{ getPeriodLabel(selectedPeriod) }}</span>
<i class="pi pi-times" @click="clearPeriod"></i>
</div>
</div> </div>
<!-- Loading State --> <!-- Loading State -->
@@ -174,6 +157,26 @@
<!-- Data Table / Cards --> <!-- Data Table / Cards -->
<div v-else class="data-section"> <div v-else class="data-section">
<!-- Desktop Totals - above table -->
<div v-if="!isMobile && filteredData.length > 0" class="summary-stats-inline">
<div class="stat-item">
<span class="stat-label">Total Sold:</span>
<span class="stat-value">{{ formatCurrency(calculateTotal('sold')) }}</span>
</div>
<div v-if="invoiceType !== 'treasury'" class="stat-item">
<span class="stat-label">Total Facturat:</span>
<span class="stat-value">{{ formatCurrency(calculateTotal('facturat')) }}</span>
</div>
</div>
<!-- Mobile Totals - above cards -->
<div v-if="isMobile && filteredData.length > 0" class="mobile-totals-bar">
<div class="mobile-totals-content">
<span class="total-label">Sold Total:</span>
<span class="total-value">{{ formatCurrency(calculateTotal('sold')) }}</span>
</div>
</div>
<!-- Desktop Table --> <!-- Desktop Table -->
<div v-if="!isMobile" class="table-wrapper"> <div v-if="!isMobile" class="table-wrapper">
<!-- Treasury DataTable (no expansion needed) --> <!-- Treasury DataTable (no expansion needed) -->
@@ -314,103 +317,56 @@
</div> </div>
</div> </div>
<!-- Mobile Cards --> <!-- Mobile: Collapsible Rows -->
<div v-if="isMobile" class="mobile-cards"> <div v-if="isMobile" class="mobile-partner-list">
<!-- Treasury Cards --> <!-- Treasury: simple flat rows -->
<template v-if="invoiceType === 'treasury'"> <template v-if="invoiceType === 'treasury'">
<div <div
v-for="row in paginatedData" v-for="row in paginatedData"
:key="row.id" :key="row.id"
class="invoice-card" class="mobile-partner-row treasury-row"
> >
<div class="card-header-row"> <div class="partner-header">
<strong>{{ row.cont }}</strong> <div class="partner-info">
<span class="card-badge">{{ row.valuta }}</span> <span class="partner-name">{{ row.cont }}</span>
</div> <span class="partner-meta">{{ row.nume_cont }}</span>
<div class="card-body">
<div class="card-field">
<span class="field-label">Nume Cont</span>
<span class="field-value">{{ row.nume_cont }}</span>
</div>
<div class="card-field highlight">
<span class="field-label">Sold</span>
<span class="field-value sold-value">{{ formatCurrency(row.sold) }}</span>
</div> </div>
<span class="partner-sold">{{ formatCurrency(row.sold) }}</span>
</div> </div>
</div> </div>
</template> </template>
<!-- Client/Supplier Cards --> <!-- Clients/Suppliers: collapsible partner rows -->
<template v-else> <template v-else>
<div <div
v-for="group in paginatedGroups" v-for="group in paginatedGroups"
:key="group.name" :key="group.name"
class="invoice-card" class="mobile-partner-row"
:class="{ 'has-multiple': group.facturi.length > 1 }"
@click="group.facturi.length > 1 && toggleGroup(group.name)"
> >
<div class="card-header-row"> <div class="partner-header" @click="toggleGroup(group.name)">
<div class="header-left"> <div class="partner-info">
<strong>{{ group.name }}</strong> <span class="partner-name">{{ group.name }}</span>
<span v-if="group.facturi.length > 1" class="count-badge"> <span class="partner-meta">({{ group.facturi.length }})</span>
({{ group.facturi.length }})
</span>
</div> </div>
<div class="header-right"> <div class="partner-total">
<span <span class="partner-sold" :class="{ overdue: group.hasRestant }">
class="sold-value"
:class="{ 'sold-restant': group.hasRestant }"
>
{{ formatCurrency(group.totalSold) }} {{ formatCurrency(group.totalSold) }}
</span> </span>
<i <i :class="isGroupExpanded(group.name) ? 'pi pi-chevron-up' : 'pi pi-chevron-down'" class="partner-chevron"></i>
v-if="group.facturi.length > 1"
:class="['pi', isGroupExpanded(group.name) ? 'pi-chevron-up' : 'pi-chevron-down']"
></i>
</div> </div>
</div> </div>
<div v-if="isGroupExpanded(group.name)" class="partner-invoices">
<!-- Single invoice details -->
<div v-if="group.facturi.length === 1" class="card-body">
<div class="card-field">
<span class="field-label">Nr. Document</span>
<span class="field-value">{{ group.facturi[0].numar_document }}</span>
</div>
<div class="card-row-inline">
<div class="card-field">
<span class="field-label">Data Doc.</span>
<span class="field-value">{{ formatDate(group.facturi[0].data_document) }}</span>
</div>
<div class="card-field">
<span class="field-label">Scadență</span>
<span class="field-value">{{ formatDate(group.facturi[0].data_scadenta) }}</span>
</div>
</div>
<div class="card-status" :class="getStatusClass(group.facturi[0].status)">
{{ group.facturi[0].status }}
</div>
</div>
<!-- Multiple invoices expanded -->
<div v-if="group.facturi.length > 1 && isGroupExpanded(group.name)" class="card-sub-items">
<div <div
v-for="(factura, idx) in group.facturi" v-for="(factura, idx) in group.facturi"
:key="`${group.name}-${idx}`" :key="`${group.name}-${idx}`"
class="sub-item" class="invoice-line"
> >
<div class="sub-item-header"> <span class="invoice-ref">
<span>{{ factura.numar_document }}</span> {{ factura.numar_document }} · {{ formatDate(factura.data_document) }} · sc:{{ formatDate(factura.data_scadenta) }}
<span </span>
class="sub-item-sold" <span class="invoice-sold" :class="{ overdue: factura.status === 'Restant' }">
:class="{ 'sold-restant': factura.status === 'Restant' }" {{ formatCurrency(factura.sold) }}
> </span>
{{ formatCurrency(factura.sold) }}
</span>
</div>
<div class="sub-item-dates">
<span>{{ formatDate(factura.data_scadenta) }}</span>
<span :class="getStatusClass(factura.status)">{{ factura.status }}</span>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -434,17 +390,6 @@
/> />
</div> </div>
<!-- Totals Summary -->
<div v-if="filteredData.length > 0" class="totals-summary">
<div class="total-item">
<span class="total-label">Total Sold:</span>
<span class="total-value">{{ formatCurrency(calculateTotal('sold')) }}</span>
</div>
<div v-if="invoiceType !== 'treasury'" class="total-item">
<span class="total-label">Total Facturat:</span>
<span class="total-value">{{ formatCurrency(calculateTotal('facturat')) }}</span>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -468,18 +413,6 @@
/> />
</div> </div>
<div class="filter-sheet-group">
<label class="form-label">Perioadă</label>
<Dropdown
v-model="selectedPeriod"
:options="periodOptions"
optionLabel="label"
optionValue="value"
placeholder="Selectați perioada"
class="w-full"
/>
</div>
<div class="filter-sheet-actions"> <div class="filter-sheet-actions">
<Button <Button
label="Resetează" label="Resetează"
@@ -504,7 +437,6 @@
import { ref, computed, onMounted, onUnmounted, watch, Transition } from 'vue' import { ref, computed, onMounted, onUnmounted, watch, Transition } from 'vue'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import Button from 'primevue/button' import Button from 'primevue/button'
import Dropdown from 'primevue/dropdown'
import InputText from 'primevue/inputtext' import InputText from 'primevue/inputtext'
import DataTable from 'primevue/datatable' import DataTable from 'primevue/datatable'
import Column from 'primevue/column' import Column from 'primevue/column'
@@ -519,8 +451,8 @@ import SplitButton from 'primevue/splitbutton'
import { useDashboardStore } from '@reports/stores/dashboard' import { useDashboardStore } from '@reports/stores/dashboard'
import { useCompanyStore, useAccountingPeriodStore, useAuthStore } from '@reports/stores/sharedStores' import { useCompanyStore, useAccountingPeriodStore, useAuthStore } from '@reports/stores/sharedStores'
import * as XLSX from 'xlsx' import * as XLSX from 'xlsx'
import jsPDF from 'jspdf' import { jsPDF } from 'jspdf'
import 'jspdf-autotable' import autoTable from 'jspdf-autotable'
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
@@ -572,7 +504,6 @@ const isLoading = ref(false)
const error = ref(null) const error = ref(null)
// US-510: Removed selectedType - now using invoiceType from route // US-510: Removed selectedType - now using invoiceType from route
const searchTerm = ref('') const searchTerm = ref('')
const selectedPeriod = ref('all')
const detailedData = ref([]) const detailedData = ref([])
const firstRow = ref(0) const firstRow = ref(0)
const rowsPerPage = ref(25) const rowsPerPage = ref(25)
@@ -582,20 +513,10 @@ const isFilterSheetOpen = ref(false)
// Options // Options
// US-510: Removed typeOptions - type is now determined by route // US-510: Removed typeOptions - type is now determined by route
const periodOptions = [
{ label: 'Toate', value: 'all' },
{ label: '7 zile', value: '7d' },
{ label: '1 lună', value: '1m' },
{ label: '3 luni', value: '3m' },
{ label: '6 luni', value: '6m' },
{ label: '12 luni', value: '12m' }
]
// US-501: Check if filters have non-default values // US-501: Check if filters have non-default values
// US-510: Removed selectedType check - type is now route-based // US-510: Removed selectedType check - type is now route-based
const hasActiveFilters = computed(() => { const hasActiveFilters = computed(() => {
return searchTerm.value !== '' || return searchTerm.value !== ''
selectedPeriod.value !== 'all'
}) })
// US-501: Mobile TopBar actions (filter, reset, export dropdown) // US-501: Mobile TopBar actions (filter, reset, export dropdown)
@@ -729,16 +650,6 @@ const totalRecords = computed(() => {
// Helper functions // Helper functions
// US-510: Removed getTypeLabel - no longer needed // US-510: Removed getTypeLabel - no longer needed
const getPeriodLabel = (period) => {
const option = periodOptions.find(o => o.value === period)
return option?.label || period
}
const getStatusClass = (status) => {
if (status === 'Restant') return 'status-restant'
return 'status-ok'
}
const toggleGroup = (groupName) => { const toggleGroup = (groupName) => {
if (expandedGroups.value.has(groupName)) { if (expandedGroups.value.has(groupName)) {
expandedGroups.value.delete(groupName) expandedGroups.value.delete(groupName)
@@ -811,12 +722,6 @@ const clearSearch = () => {
handleSearch() handleSearch()
} }
// US-511: Clear period filter from chip
const clearPeriod = () => {
selectedPeriod.value = 'all'
loadDetailedData()
}
const handleSearch = () => { const handleSearch = () => {
firstRow.value = 0 firstRow.value = 0
expandedGroups.value.clear() expandedGroups.value.clear()
@@ -825,7 +730,6 @@ const handleSearch = () => {
const resetFilters = () => { const resetFilters = () => {
// US-510: Removed type reset - type is now determined by route // US-510: Removed type reset - type is now determined by route
searchTerm.value = '' searchTerm.value = ''
selectedPeriod.value = 'all'
firstRow.value = 0 firstRow.value = 0
expandedGroups.value.clear() expandedGroups.value.clear()
loadDetailedData() loadDetailedData()
@@ -923,7 +827,7 @@ const exportPDF = () => {
] ]
}) })
doc.autoTable({ autoTable(doc, {
head: [columns], head: [columns],
body: rows, body: rows,
theme: 'grid', theme: 'grid',
@@ -1537,154 +1441,125 @@ onUnmounted(() => {
color: var(--color-error) !important; color: var(--color-error) !important;
} }
/* Mobile Cards */ [data-theme="dark"] .sold-restant {
.mobile-cards { color: var(--red-400) !important;
display: flex;
flex-direction: column;
gap: var(--space-md);
} }
.invoice-card { @media (prefers-color-scheme: dark) {
:root:not([data-theme]) .sold-restant {
color: var(--red-400) !important;
}
}
/* Mobile Partner List */
.mobile-partner-list {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.mobile-partner-row {
background: var(--surface-card); background: var(--surface-card);
border: 1px solid var(--surface-border); border: 1px solid var(--surface-border);
border-radius: var(--radius-md); border-radius: var(--radius-md);
overflow: hidden; overflow: hidden;
} }
.invoice-card.has-multiple { .partner-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--space-sm) var(--space-md);
cursor: pointer; cursor: pointer;
}
.card-header-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--space-md);
background: var(--surface-hover);
border-bottom: 1px solid var(--surface-border);
}
.header-left {
display: flex;
align-items: center;
gap: var(--space-sm); gap: var(--space-sm);
min-height: 44px;
} }
.header-right { .treasury-row .partner-header {
cursor: default;
}
.partner-info {
display: flex; display: flex;
flex-direction: row;
align-items: center; align-items: center;
gap: var(--space-sm); gap: var(--space-xs);
}
.card-badge {
font-size: var(--text-xs);
padding: 2px var(--space-xs);
background: var(--primary-100);
color: var(--color-primary);
border-radius: var(--radius-sm);
}
.card-body {
padding: var(--space-md);
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.card-field {
display: flex;
justify-content: space-between;
align-items: center;
}
.card-field.highlight {
padding-top: var(--space-sm);
border-top: 1px solid var(--surface-border);
margin-top: var(--space-xs);
}
.card-row-inline {
display: flex;
gap: var(--space-md);
}
.card-row-inline .card-field {
flex: 1; flex: 1;
flex-direction: column; min-width: 0;
align-items: flex-start;
gap: 2px;
} }
.field-label { .partner-name {
font-size: var(--text-sm);
font-weight: var(--font-semibold);
color: var(--text-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.partner-meta {
font-size: var(--text-xs); font-size: var(--text-xs);
color: var(--text-color-secondary); color: var(--text-color-secondary);
} }
.field-value { .partner-total {
font-size: var(--text-sm); display: flex;
color: var(--text-color); align-items: center;
font-weight: var(--font-medium); gap: var(--space-xs);
flex-shrink: 0;
} }
.sold-value { .partner-sold {
font-family: var(--font-mono); font-family: var(--font-mono);
font-size: var(--text-sm);
font-weight: var(--font-bold); font-weight: var(--font-bold);
color: var(--text-color); color: var(--text-color);
} }
.card-status { .partner-sold.overdue {
display: inline-flex;
align-self: flex-start;
font-size: var(--text-xs);
padding: 2px var(--space-sm);
border-radius: var(--radius-full);
font-weight: var(--font-medium);
}
.status-ok {
background: var(--green-100);
color: var(--green-600);
}
.status-restant {
background: var(--red-100);
color: var(--red-600); color: var(--red-600);
} }
/* Sub items for expanded groups */ .partner-chevron {
.card-sub-items { font-size: 12px;
color: var(--text-color-secondary);
}
.partner-invoices {
border-top: 1px solid var(--surface-border); border-top: 1px solid var(--surface-border);
padding: var(--space-sm) var(--space-md) var(--space-md);
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.sub-item {
padding: var(--space-sm);
background: var(--surface-hover); background: var(--surface-hover);
border-radius: var(--radius-sm);
} }
.sub-item-header { .invoice-line {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
font-size: var(--text-sm); padding: var(--space-xs) var(--space-md);
font-weight: var(--font-medium); border-bottom: 1px solid var(--surface-border);
margin-bottom: 4px; gap: var(--space-sm);
} }
.sub-item-sold { .invoice-line:last-child {
font-family: var(--font-mono); border-bottom: none;
font-weight: var(--font-bold);
} }
.sub-item-dates { .invoice-ref {
display: flex;
justify-content: space-between;
font-size: var(--text-xs); font-size: var(--text-xs);
color: var(--text-color-secondary); color: var(--text-color-secondary);
flex: 1;
min-width: 0;
}
.invoice-sold {
font-family: var(--font-mono);
font-size: var(--text-xs);
font-weight: var(--font-semibold);
color: var(--text-color);
flex-shrink: 0;
}
.invoice-sold.overdue {
color: var(--red-600);
} }
/* Empty data state */ /* Empty data state */
@@ -1710,39 +1585,34 @@ onUnmounted(() => {
justify-content: center; justify-content: center;
} }
/* Totals Summary */ /* Desktop Totals - uses global stats.css (src/assets/css/components/stats.css) */
.totals-summary {
display: flex; /* Mobile Totals Bar */
gap: var(--space-lg); .mobile-totals-bar {
padding: var(--space-md);
background: var(--surface-card); background: var(--surface-card);
border: 1px solid var(--surface-border); border: 1px solid var(--surface-border);
padding: var(--space-sm) var(--space-md);
margin-bottom: var(--space-md);
border-radius: var(--radius-md); border-radius: var(--radius-md);
} }
@media (max-width: 768px) { .mobile-totals-content {
.totals-summary {
flex-direction: column;
gap: var(--space-sm);
}
}
.total-item {
display: flex; display: flex;
justify-content: space-between;
align-items: center; align-items: center;
gap: var(--space-sm);
} }
.total-label { .mobile-totals-bar .total-label {
font-size: var(--text-sm); font-size: var(--text-sm);
color: var(--text-color-secondary); color: var(--text-color-secondary);
font-weight: var(--font-medium);
} }
.total-value { .mobile-totals-bar .total-value {
font-size: var(--text-lg); font-size: var(--text-lg);
font-weight: var(--font-bold); font-weight: var(--font-bold);
font-family: var(--font-mono); font-family: var(--font-mono);
color: var(--color-primary); color: var(--text-color);
} }
/* Filter Sheet Content */ /* Filter Sheet Content */
@@ -1787,18 +1657,9 @@ onUnmounted(() => {
background: var(--primary-800); background: var(--primary-800);
} }
[data-theme="dark"] .card-badge { [data-theme="dark"] .partner-sold.overdue,
background: var(--primary-800); [data-theme="dark"] .invoice-sold.overdue {
} color: var(--red-400);
[data-theme="dark"] .status-ok {
background: var(--green-900);
color: var(--green-300);
}
[data-theme="dark"] .status-restant {
background: var(--red-900);
color: var(--red-300);
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
@@ -1810,18 +1671,9 @@ onUnmounted(() => {
background: var(--primary-800); background: var(--primary-800);
} }
:root:not([data-theme]) .card-badge { :root:not([data-theme]) .partner-sold.overdue,
background: var(--primary-800); :root:not([data-theme]) .invoice-sold.overdue {
} color: var(--red-400);
:root:not([data-theme]) .status-ok {
background: var(--green-900);
color: var(--green-300);
}
:root:not([data-theme]) .status-restant {
background: var(--red-900);
color: var(--red-300);
} }
} }
</style> </style>

View File

@@ -104,7 +104,8 @@
<Button <Button
icon="pi pi-filter-slash" icon="pi pi-filter-slash"
label="Resetează" label="Resetează"
class="p-button-outlined p-button-secondary" severity="secondary"
outlined
@click="clearFilters(); showFilters = false" @click="clearFilters(); showFilters = false"
/> />
<Button <Button
@@ -149,7 +150,7 @@
<div v-if="isMobile && companyStore.selectedCompany && invoicesStore.hasInvoices" class="mobile-totals-bar"> <div v-if="isMobile && companyStore.selectedCompany && invoicesStore.hasInvoices" class="mobile-totals-bar">
<div class="mobile-totals-content"> <div class="mobile-totals-content">
<span class="total-label">Sold Total:</span> <span class="total-label">Sold Total:</span>
<span class="total-value" :class="invoicesStore.totalSoldAll > 0 ? 'positive' : 'negative'"> <span class="total-value">
{{ formatCompact(invoicesStore.totalSoldAll) }} {{ formatCompact(invoicesStore.totalSoldAll) }}
</span> </span>
</div> </div>
@@ -224,21 +225,16 @@
<Button <Button
icon="pi pi-filter-slash" icon="pi pi-filter-slash"
label="Resetează Filtre" label="Resetează Filtre"
class="p-button-outlined p-button-secondary" severity="secondary"
outlined
@click="clearFilters" @click="clearFilters"
/> />
<Button <SplitButton
icon="pi pi-file-excel" label="Export"
label="Export Excel" icon="pi pi-download"
class="p-button-outlined p-button-success" :model="desktopExportItems"
@click="exportExcel" @click="exportExcel"
:disabled="!invoicesStore.hasInvoices" outlined
/>
<Button
icon="pi pi-file-pdf"
label="Export PDF"
class="p-button-outlined p-button-danger"
@click="exportPDF"
:disabled="!invoicesStore.hasInvoices" :disabled="!invoicesStore.hasInvoices"
/> />
<Button <Button
@@ -257,7 +253,7 @@
<div v-if="!isMobile && companyStore.selectedCompany && invoicesStore.hasInvoices" class="summary-stats-inline"> <div v-if="!isMobile && companyStore.selectedCompany && invoicesStore.hasInvoices" class="summary-stats-inline">
<div class="stat-item"> <div class="stat-item">
<span class="stat-label">Total Sold:</span> <span class="stat-label">Total Sold:</span>
<span class="stat-value" :class="invoicesStore.totalSoldAll > 0 ? 'plati' : 'incasari'"> <span class="stat-value">
{{ formatCurrency(invoicesStore.totalSoldAll) }} {{ formatCurrency(invoicesStore.totalSoldAll) }}
</span> </span>
</div> </div>
@@ -266,23 +262,19 @@
<!-- Invoices Table --> <!-- Invoices Table -->
<Card v-if="companyStore.selectedCompany" class="table-card"> <Card v-if="companyStore.selectedCompany" class="table-card">
<template #content> <template #content>
<!-- Mobile: Card Layout --> <!-- Mobile: Flat List (compact, table-like) -->
<div v-if="isMobile" class="mobile-card-list"> <div v-if="isMobile" class="mobile-flat-list">
<div <div
v-for="invoice in invoicesStore.invoiceList" v-for="invoice in invoicesStore.invoiceList"
:key="invoice.nract" :key="invoice.nract"
class="mobile-data-card" class="flat-row"
> >
<div class="card-header">{{ invoice.nume }}</div> <div class="flat-row-left">
<div class="card-row"> <span class="flat-cont">{{ invoice.nract }}</span>
<span>{{ formatDate(invoice.dataact) }} · {{ invoice.nract }}</span> <span class="flat-date">{{ formatDateShort(invoice.dataact) }}</span>
<span <span class="flat-denumire">{{ invoice.nume || '' }}</span>
class="card-amount"
:class="{ positive: invoice.soldfinal > 0 }"
>
{{ formatNumber(invoice.soldfinal) }}
</span>
</div> </div>
<span class="flat-sold">{{ formatNumber(invoice.soldfinal) }}</span>
</div> </div>
<div v-if="invoicesStore.invoiceList.length === 0" class="mobile-empty"> <div v-if="invoicesStore.invoiceList.length === 0" class="mobile-empty">
<i class="pi pi-info-circle"></i> <i class="pi pi-info-circle"></i>
@@ -412,6 +404,7 @@ import MobileTopBar from "@shared/components/mobile/MobileTopBar.vue";
import MobileBottomNav from "@shared/components/mobile/MobileBottomNav.vue"; import MobileBottomNav from "@shared/components/mobile/MobileBottomNav.vue";
import BottomSheet from "@shared/components/mobile/BottomSheet.vue"; import BottomSheet from "@shared/components/mobile/BottomSheet.vue";
import MobileDrawerMenu from "@shared/components/mobile/MobileDrawerMenu.vue"; import MobileDrawerMenu from "@shared/components/mobile/MobileDrawerMenu.vue";
import SplitButton from "primevue/splitbutton";
import { useRouter, useRoute } from "vue-router"; import { useRouter, useRoute } from "vue-router";
const toast = useToast(); const toast = useToast();
@@ -591,12 +584,26 @@ const paymentStatusOptions = [
{ label: "Toate", value: "toate" }, { label: "Toate", value: "toate" },
]; ];
// Desktop export dropdown items (SplitButton)
const desktopExportItems = [
{
label: "Export Excel",
icon: "pi pi-file-excel",
command: () => exportExcel(),
},
{
label: "Export PDF",
icon: "pi pi-file-pdf",
command: () => exportPDF(),
},
];
// Methods // Methods
const formatCurrency = (amount) => { const formatCurrency = (amount) => {
if (!amount) return "0,00 RON"; if (!amount || amount === 0) return "0,00";
return new Intl.NumberFormat("ro-RO", { return new Intl.NumberFormat("ro-RO", {
style: "currency", minimumFractionDigits: 2,
currency: "RON", maximumFractionDigits: 2,
}).format(amount); }).format(amount);
}; };
@@ -631,6 +638,16 @@ const formatDate = (dateString) => {
} }
}; };
// Short date format for mobile (DD/MM only)
const formatDateShort = (dateString) => {
if (!dateString) return "";
try {
return format(new Date(dateString), "dd/MM", { locale: ro });
} catch (error) {
return "";
}
};
const handleCompanyChange = async () => { const handleCompanyChange = async () => {
if (!selectedCompanyId.value) return; if (!selectedCompanyId.value) return;
@@ -1157,55 +1174,66 @@ watch(
.mobile-totals-bar .total-value { .mobile-totals-bar .total-value {
font-size: var(--text-lg); font-size: var(--text-lg);
font-weight: var(--font-bold); font-weight: var(--font-bold);
color: var(--text-color);
} }
/* Colors removed - totals use neutral --text-color like TrialBalance */
.mobile-totals-bar .total-value.positive {
color: var(--green-600);
}
.mobile-totals-bar .total-value.negative {
color: var(--red-600);
}
/* ================================================ /* ================================================
US-107: Mobile Card List (Invoice Cards) Mobile Flat List (Compact Invoice Rows - like TrialBalance)
================================================ */ ================================================ */
.mobile-card-list { .mobile-flat-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: var(--space-sm);
} }
.mobile-data-card { .flat-row {
background: var(--surface-card);
border: 1px solid var(--surface-border);
border-radius: var(--radius-md);
padding: var(--space-md);
}
.mobile-data-card .card-header {
font-weight: var(--font-semibold);
color: var(--text-color);
margin-bottom: var(--space-xs);
font-size: var(--text-base);
}
.mobile-data-card .card-row {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
font-size: var(--text-sm); border-bottom: 1px solid var(--surface-border);
color: var(--text-color-secondary); min-height: 44px;
padding: var(--space-sm) var(--space-md);
gap: var(--space-sm);
} }
.mobile-data-card .card-amount { .flat-row-left {
font-weight: var(--font-semibold); display: flex;
align-items: center;
gap: var(--space-sm);
flex: 1;
min-width: 0;
}
.flat-cont {
font-weight: var(--font-bold);
color: var(--text-color); color: var(--text-color);
font-size: var(--text-sm);
min-width: 48px;
flex-shrink: 0;
} }
.mobile-data-card .card-amount.positive { .flat-date {
color: var(--green-600); font-size: var(--text-xs);
color: var(--text-color-secondary);
flex-shrink: 0;
}
.flat-denumire {
color: var(--text-color-secondary);
font-size: var(--text-sm);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.flat-sold {
font-weight: var(--font-semibold);
font-variant-numeric: tabular-nums;
font-size: var(--text-sm);
color: var(--text-color);
text-align: right;
flex-shrink: 0;
} }
.mobile-empty { .mobile-empty {
@@ -1293,83 +1321,19 @@ watch(
text-align: center; text-align: center;
} }
/* ================================================ /* Summary Stats - uses global stats.css (src/assets/css/components/stats.css) */
Summary Stats
================================================ */
.summary-stats-inline {
display: flex;
justify-content: flex-end;
margin-bottom: var(--space-md);
}
.stat-item {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.stat-label {
font-size: var(--text-sm);
color: var(--text-color-secondary);
}
.stat-value {
font-size: var(--text-lg);
font-weight: var(--font-bold);
}
.stat-value.plati {
color: var(--red-600);
}
.stat-value.incasari {
color: var(--green-600);
}
/* ================================================ /* ================================================
Dark Mode Support Dark Mode Support
================================================ */ ================================================ */
[data-theme="dark"] .mobile-totals-bar .total-value.positive {
color: var(--green-400);
}
[data-theme="dark"] .mobile-totals-bar .total-value.negative {
color: var(--red-400);
}
[data-theme="dark"] .mobile-data-card .card-amount.positive {
color: var(--green-400);
}
[data-theme="dark"] .sidebar-item.active { [data-theme="dark"] .sidebar-item.active {
background: var(--blue-900); background: var(--blue-900);
color: var(--blue-400); color: var(--blue-400);
} }
[data-theme="dark"] .stat-value.plati {
color: var(--red-400);
}
[data-theme="dark"] .stat-value.incasari {
color: var(--green-400);
}
/* Auto dark mode */ /* Auto dark mode */
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root:not([data-theme]) .mobile-totals-bar .total-value.positive {
color: var(--green-400);
}
:root:not([data-theme]) .mobile-totals-bar .total-value.negative {
color: var(--red-400);
}
:root:not([data-theme]) .mobile-data-card .card-amount.positive {
color: var(--green-400);
}
:root:not([data-theme]) .sidebar-item.active { :root:not([data-theme]) .sidebar-item.active {
background: var(--blue-900); background: var(--blue-900);
color: var(--blue-400); color: var(--blue-400);

View File

@@ -57,7 +57,8 @@
<Button <Button
icon="pi pi-filter-slash" icon="pi pi-filter-slash"
label="Resetează" label="Resetează"
class="p-button-outlined p-button-secondary" severity="secondary"
outlined
@click="clearFilters(); showFilters = false" @click="clearFilters(); showFilters = false"
/> />
<Button <Button
@@ -151,7 +152,8 @@
<Button <Button
icon="pi pi-filter-slash" icon="pi pi-filter-slash"
label="Resetează Filtre" label="Resetează Filtre"
class="p-button-outlined p-button-secondary" severity="secondary"
outlined
@click="clearFilters" @click="clearFilters"
/> />
<SplitButton <SplitButton
@@ -159,7 +161,7 @@
icon="pi pi-download" icon="pi pi-download"
:model="desktopExportItems" :model="desktopExportItems"
@click="exportPDF" @click="exportPDF"
class="p-button-outlined" outlined
:disabled="!trialBalanceStore.hasData" :disabled="!trialBalanceStore.hasData"
/> />
<Button <Button
@@ -205,26 +207,24 @@
<!-- Trial Balance Table --> <!-- Trial Balance Table -->
<Card v-if="companyStore.selectedCompany" class="table-card"> <Card v-if="companyStore.selectedCompany" class="table-card">
<template #content> <template #content>
<!-- Mobile: Card Layout --> <!-- Mobile: Flat Single-Row List -->
<div v-if="isMobile" class="mobile-card-list"> <div v-if="isMobile" class="mobile-flat-list">
<div <div
v-for="account in trialBalanceStore.trialBalanceData.filter(a => a.sold_final_debit > 0 || a.sold_final_credit > 0)" v-for="account in filteredMobileAccounts"
:key="account.cont" :key="account.cont"
class="mobile-data-card" class="flat-row"
> >
<div class="card-header"> <div class="flat-row-left">
<strong>{{ account.cont }}</strong>&nbsp;&nbsp;{{ truncate(account.denumire, 30) }} <span class="flat-cont">{{ account.cont }}</span>
</div> <span class="flat-denumire">{{ account.denumire }}</span>
<div class="card-row">
<span></span>
<span class="card-amount">
{{ account.sold_final_debit > 0
? formatCurrency(account.sold_final_debit) + ' D'
: formatCurrency(account.sold_final_credit) + ' C' }}
</span>
</div> </div>
<span class="flat-sold">
{{ account.sold_final_debit > 0
? formatCompact(account.sold_final_debit) + ' D'
: formatCompact(account.sold_final_credit) + ' C' }}
</span>
</div> </div>
<div v-if="trialBalanceStore.trialBalanceData.filter(a => a.sold_final_debit > 0 || a.sold_final_credit > 0).length === 0" class="mobile-empty"> <div v-if="filteredMobileAccounts.length === 0" class="mobile-empty">
<i class="pi pi-info-circle"></i> <i class="pi pi-info-circle"></i>
<p>Nu au fost găsite date</p> <p>Nu au fost găsite date</p>
</div> </div>
@@ -506,6 +506,11 @@ const hasActiveFilters = computed(() => {
return localFilters.value.cont !== "" || localFilters.value.denumire !== ""; return localFilters.value.cont !== "" || localFilters.value.denumire !== "";
}); });
// Mobile: Accounts with non-zero final balance (avoids inline .filter() in template)
const filteredMobileAccounts = computed(() =>
trialBalanceStore.trialBalanceData.filter(a => a.sold_final_debit > 0 || a.sold_final_credit > 0)
);
// Mobile: Actions menu items // Mobile: Actions menu items
const actionMenuItems = computed(() => [ const actionMenuItems = computed(() => [
{ {
@@ -1123,40 +1128,55 @@ watch(
} }
/* ================================================ /* ================================================
US-108: Mobile Card List (Account Cards) Mobile Flat List (Account Rows)
================================================ */ ================================================ */
.mobile-card-list { .mobile-flat-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: var(--space-sm);
} }
.mobile-data-card { .flat-row {
background: var(--surface-card);
border: 1px solid var(--surface-border);
border-radius: var(--radius-md);
padding: var(--space-md);
}
.mobile-data-card .card-header {
font-weight: var(--font-semibold);
color: var(--text-color);
margin-bottom: var(--space-xs);
font-size: var(--text-base);
}
.mobile-data-card .card-row {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
font-size: var(--text-sm); border-bottom: 1px solid var(--surface-border);
color: var(--text-color-secondary); min-height: 44px;
padding: var(--space-sm) var(--space-md);
gap: var(--space-sm);
} }
.mobile-data-card .card-amount { .flat-row-left {
font-weight: var(--font-semibold); display: flex;
align-items: center;
gap: var(--space-sm);
flex: 1;
min-width: 0;
}
.flat-cont {
font-weight: var(--font-bold);
color: var(--text-color); color: var(--text-color);
font-size: var(--text-sm);
min-width: 48px;
flex-shrink: 0;
}
.flat-denumire {
color: var(--text-color-secondary);
font-size: var(--text-sm);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.flat-sold {
font-weight: var(--font-semibold);
font-variant-numeric: tabular-nums;
font-size: var(--text-sm);
color: var(--text-color);
text-align: right;
flex-shrink: 0;
} }
.mobile-empty { .mobile-empty {

View File

@@ -44,7 +44,7 @@
* Default items (4 links): * Default items (4 links):
* - Dashboard (/dashboard) * - Dashboard (/dashboard)
* - Bonuri (/data-entry) * - Bonuri (/data-entry)
* - Facturi (/reports/invoices) * - Detalii (/reports/detailed-invoices)
* - Setări (/settings) * - Setări (/settings)
*/ */
@@ -58,7 +58,7 @@ defineProps({
default: () => [ default: () => [
{ to: '/dashboard', icon: 'pi pi-home', label: 'Dashboard' }, { to: '/dashboard', icon: 'pi pi-home', label: 'Dashboard' },
{ to: '/data-entry', icon: 'pi pi-shopping-bag', label: 'Bonuri' }, { to: '/data-entry', icon: 'pi pi-shopping-bag', label: 'Bonuri' },
{ to: '/reports/invoices', icon: 'pi pi-file-edit', label: 'Facturi' }, { to: '/reports/detailed-invoices', icon: 'pi pi-file-edit', label: 'Detalii' },
{ to: '/settings', icon: 'pi pi-cog', label: 'Setări' } { to: '/settings', icon: 'pi pi-cog', label: 'Setări' }
], ],
validator: (items) => { validator: (items) => {

View File

@@ -715,18 +715,18 @@ const principaleItems = [
{ to: '/data-entry', icon: 'pi pi-shopping-bag', label: 'Bonuri', exactMatch: false } { to: '/data-entry', icon: 'pi pi-shopping-bag', label: 'Bonuri', exactMatch: false }
] ]
// RAPOARTE: Facturi, Balanță, Casă, Bancă (US-519: separate pages) // RAPOARTE: Facturi, Facturi Detaliate, Balanță, Casă, Bancă (US-519: separate pages)
const rapoarteItems = [ const rapoarteItems = [
{ to: '/reports/invoices', icon: 'pi pi-file', label: 'Facturi', exactMatch: true }, { to: '/reports/invoices', icon: 'pi pi-file', label: 'Facturi', exactMatch: true },
{ to: '/reports/detailed-invoices', icon: 'pi pi-list', label: 'Facturi Detaliate', exactMatch: true },
{ to: '/reports/trial-balance', icon: 'pi pi-calculator', label: 'Balanță', exactMatch: true }, { to: '/reports/trial-balance', icon: 'pi pi-calculator', label: 'Balanță', exactMatch: true },
{ to: '/reports/cash', icon: 'pi pi-wallet', label: 'Casă', exactMatch: true }, { to: '/reports/cash', icon: 'pi pi-wallet', label: 'Casă', exactMatch: true },
{ to: '/reports/bank', icon: 'pi pi-building', label: 'Bancă', exactMatch: true } { to: '/reports/bank', icon: 'pi pi-building', label: 'Bancă', exactMatch: true }
] ]
// ANALIZE: Scadențe, Facturi Detaliate // ANALIZE: Scadențe
const analizeItems = [ const analizeItems = [
{ to: '/reports/maturity-analysis', icon: 'pi pi-clock', label: 'Scadențe', exactMatch: true }, { to: '/reports/maturity-analysis', icon: 'pi pi-clock', label: 'Scadențe', exactMatch: true }
{ to: '/reports/detailed-invoices', icon: 'pi pi-list', label: 'Facturi Detaliate', exactMatch: true }
] ]
// ADMINISTRARE: Setări // ADMINISTRARE: Setări