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:
@@ -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",
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user