feat(unified-mobile-desktop-ui): Complete US-502 - Header Actions Bar Unificat - Lista Bonuri

Implemented by Ralph autonomous loop.
Iteration: 2

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-01-12 22:20:46 +00:00
parent 94d215d6ae
commit c74fe4b221
3 changed files with 163 additions and 17 deletions

View File

@@ -81,8 +81,8 @@
"npm run build passes",
"Verify in browser: butoanele au același aspect ca pe pagina Facturi"
],
"passes": false,
"notes": ""
"passes": true,
"notes": "Completed in iteration 2"
},
{
"id": "US-503",

View File

@@ -76,3 +76,9 @@ Design Reference: src/modules/reports/views/InvoicesView.vue
[2026-01-12 22:09:40] Working on story: US-501
[2026-01-12 22:09:40] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_1_US-501.log)
[2026-01-12 22:16:53] SUCCESS: Story US-501 passed!
[2026-01-12 22:16:53] Changes committed
[2026-01-12 22:16:53] Progress: 1/19 stories completed
[2026-01-12 22:16:55] === Iteration 2/100 ===
[2026-01-12 22:16:55] Working on story: US-502
[2026-01-12 22:16:55] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_2_US-502.log)
[2026-01-12 22:20:46] SUCCESS: Story US-502 passed!

View File

@@ -315,24 +315,41 @@
@date-select="onFilterChange"
/>
<!-- Desktop filter action buttons -->
<div v-if="!isMobile" class="filter-actions">
<!-- US-502: Desktop header actions bar (Filter, Reset, Export dropdown) -->
<div v-if="!isMobile" class="header-actions-bar">
<Button
icon="pi pi-search"
label="Filtrează"
severity="primary"
outlined
size="small"
@click="onFilterChange"
/>
<Button
icon="pi pi-times"
label="Resetează"
icon="pi pi-filter"
:class="{ 'filter-active': hasActiveFilters }"
severity="secondary"
outlined
size="small"
v-tooltip.bottom="'Filtrează'"
@click="onFilterChange"
/>
<Button
icon="pi pi-filter-slash"
severity="secondary"
outlined
size="small"
v-tooltip.bottom="'Resetează filtrele'"
@click="clearFilters"
/>
<Button
icon="pi pi-download"
severity="secondary"
outlined
size="small"
v-tooltip.bottom="'Export'"
@click="toggleExportMenu"
aria-haspopup="true"
aria-controls="export_menu"
/>
<Menu
ref="exportMenuRef"
id="export_menu"
:model="exportMenuItems"
:popup="true"
/>
</div>
</div>
@@ -1005,7 +1022,7 @@ import DragDropOverlay from '@data-entry/components/bulk/DragDropOverlay.vue'
import MobileTopBar from '@shared/components/mobile/MobileTopBar.vue'
import MobileBottomNav from '@shared/components/mobile/MobileBottomNav.vue'
import MobileSelectionFooter from '@shared/components/mobile/MobileSelectionFooter.vue'
import { exportToExcel } from '@reports/utils/exportUtils'
import { exportToExcel, exportToPDF } from '@reports/utils/exportUtils'
import BatchGroupHeader from '@data-entry/components/bulk/BatchGroupHeader.vue'
import ProcessingStatusCell from '@data-entry/components/bulk/ProcessingStatusCell.vue'
import Paginator from 'primevue/paginator'
@@ -1079,6 +1096,9 @@ const showDrawer = ref(false)
const moreMenuRef = ref(null)
const fabVisible = ref(true)
// US-502: Export Menu ref and items for desktop header actions
const exportMenuRef = ref(null)
// US-303: FAB Menu State
const fabMenuRef = ref(null)
const fabMenuOpen = ref(false)
@@ -1119,6 +1139,25 @@ const moreMenuItems = computed(() => [
}
])
// US-502: Toggle export menu
const toggleExportMenu = (event) => {
exportMenuRef.value?.toggle(event)
}
// US-502: Export menu items (PDF and XLSX)
const exportMenuItems = computed(() => [
{
label: 'Export PDF',
icon: 'pi pi-file-pdf',
command: () => exportAllReceiptsPDF()
},
{
label: 'Export XLSX',
icon: 'pi pi-file-excel',
command: () => exportAllReceipts()
}
])
// US-303: FAB Menu Items (Bon Nou | Upload Bulk)
const fabMenuItems = [
{
@@ -1171,8 +1210,13 @@ const handleTopBarAction = (action) => {
showFilters.value = !showFilters.value
break
case 'export':
// US-306: Export all current receipts
exportAllReceipts()
// US-502: Show export menu (PDF/XLSX dropdown) on mobile too
if (exportMenuRef.value) {
const btn = document.querySelector('.mobile-top-bar .top-bar-btn:nth-child(2)')
if (btn) {
exportMenuRef.value.toggle({ currentTarget: btn })
}
}
break
case 'more':
// The more menu needs to be toggled with the event, but we don't have the event here
@@ -2508,6 +2552,78 @@ const exportAllReceipts = () => {
}
}
/**
* US-502: Export all currently visible receipts to PDF.
* Exports all receipts from the current filtered list (excludes job items).
*/
const exportAllReceiptsPDF = () => {
// Filter out job items - only export actual receipts
const receiptsList = unifiedItems.value.filter(item => !isJobItem(item))
if (receiptsList.length === 0) {
toast.add({
severity: 'warn',
summary: 'Atenție',
detail: 'Nu există bonuri de exportat',
life: 3000,
})
return
}
// Map receipt data to export format for PDF
const exportData = receiptsList.map(r => ({
store_name: r.store_name || r.partner_name || '-',
cui: r.cui || '-',
receipt_date: r.receipt_date ? formatDate(r.receipt_date) : '-',
receipt_number: r.receipt_number || '-',
receipt_type: r.receipt_type === 'receipt' ? 'Bon' : r.receipt_type === 'invoice' ? 'Factură' : r.receipt_type || '-',
direction: r.direction === 'expense' ? 'Cheltuială' : r.direction === 'income' ? 'Venit' : r.direction || '-',
amount: r.amount || 0,
tva_total: r.tva_total || 0,
status: getStatusLabel(r.status) || '-',
}))
// Define columns for PDF with proportional widths
const columns = [
{ field: 'store_name', header: 'Magazin', type: 'text', width: 0.22 },
{ field: 'cui', header: 'CUI', type: 'text', width: 0.10 },
{ field: 'receipt_date', header: 'Data', type: 'text', width: 0.10 },
{ field: 'receipt_number', header: 'Nr. Bon', type: 'text', width: 0.10 },
{ field: 'receipt_type', header: 'Tip', type: 'text', width: 0.08 },
{ field: 'direction', header: 'Direcție', type: 'text', width: 0.10 },
{ field: 'amount', header: 'Suma', type: 'number', width: 0.10 },
{ field: 'tva_total', header: 'TVA', type: 'number', width: 0.10 },
{ field: 'status', header: 'Status', type: 'text', width: 0.10 },
]
const result = exportToPDF(
exportData,
columns,
`bonuri_export_${receiptsList.length}`,
{
companyName: companyStore.selectedCompany?.name || '',
title: 'Lista Bonuri Fiscale',
period: '',
}
)
if (result.success) {
toast.add({
severity: 'success',
summary: 'Export reușit',
detail: `${receiptsList.length} bonuri exportate cu succes (PDF)`,
life: 3000,
})
} else {
toast.add({
severity: 'error',
summary: 'Eroare',
detail: 'Nu s-a putut exporta lista de bonuri în format PDF',
life: 5000,
})
}
}
/**
* US-026: Confirmation dialog for bulk delete.
* Uses PrimeVue ConfirmDialog to ask user before deleting multiple receipts.
@@ -3359,6 +3475,30 @@ const cleanupCompletedBatches = (storedBatchIds) => {
margin-left: auto;
}
/* US-502: Header actions bar for unified Filter/Reset/Export buttons */
.header-actions-bar {
display: flex;
gap: var(--space-xs);
margin-left: auto;
align-items: center;
}
.header-actions-bar .p-button {
min-width: auto;
padding: var(--space-sm);
}
.header-actions-bar .filter-active {
background: var(--color-primary);
border-color: var(--color-primary);
color: var(--surface-ground);
}
.header-actions-bar .filter-active:hover {
background: var(--color-primary-dark);
border-color: var(--color-primary-dark);
}
/* Compact DataTable - styles moved to vendor/primevue-overrides.css */
/* Action buttons - always on same line */