From 8e74b3291fd8cda8ea8c6fdd86032d490713ad42 Mon Sep 17 00:00:00 2001 From: Claude Agent Date: Mon, 12 Jan 2026 23:39:17 +0000 Subject: [PATCH] feat(unified-mobile-desktop-ui): Complete US-518 - Creare/Vizualizare/Editare Bon - Butoane Doar Sus Implemented by Ralph autonomous loop. Iteration: 20 Co-Authored-By: Claude --- scripts/ralph/prd.json | 4 +- scripts/ralph/progress.txt | 6 + .../receipts/ReceiptCreateUnifiedView.vue | 306 +++++++++--------- 3 files changed, 152 insertions(+), 164 deletions(-) diff --git a/scripts/ralph/prd.json b/scripts/ralph/prd.json index 6c3c1dc..d2d02b4 100644 --- a/scripts/ralph/prd.json +++ b/scripts/ralph/prd.json @@ -378,8 +378,8 @@ "npm run build passes", "Verify in browser: butoane doar în header pe toate cele 3 pagini" ], - "passes": false, - "notes": "" + "passes": true, + "notes": "Completed in iteration 20" }, { "id": "US-519", diff --git a/scripts/ralph/progress.txt b/scripts/ralph/progress.txt index d37f1e8..a954336 100644 --- a/scripts/ralph/progress.txt +++ b/scripts/ralph/progress.txt @@ -182,3 +182,9 @@ Design Reference: src/modules/reports/views/InvoicesView.vue [2026-01-12 23:33:06] Working on story: US-517 [2026-01-12 23:33:06] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_19_US-517.log) [2026-01-12 23:35:59] SUCCESS: Story US-517 passed! +[2026-01-12 23:35:59] Changes committed +[2026-01-12 23:35:59] Progress: 17/19 stories completed +[2026-01-12 23:36:01] === Iteration 20/100 === +[2026-01-12 23:36:01] Working on story: US-518 +[2026-01-12 23:36:01] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_20_US-518.log) +[2026-01-12 23:39:17] SUCCESS: Story US-518 passed! diff --git a/src/modules/data-entry/views/receipts/ReceiptCreateUnifiedView.vue b/src/modules/data-entry/views/receipts/ReceiptCreateUnifiedView.vue index 2e17808..4e55169 100644 --- a/src/modules/data-entry/views/receipts/ReceiptCreateUnifiedView.vue +++ b/src/modules/data-entry/views/receipts/ReceiptCreateUnifiedView.vue @@ -40,11 +40,17 @@ />
- + - +
@@ -203,11 +216,7 @@ - - + @@ -229,7 +238,7 @@ import { useCompanyStore } from '@data-entry/stores/sharedStores' import UnifiedReceiptForm from '@data-entry/components/receipts/UnifiedReceiptForm.vue' import MobileTopBar from '@shared/components/mobile/MobileTopBar.vue' -import MobileActionBar from '@shared/components/mobile/MobileActionBar.vue' +// US-518: MobileActionBar removed - buttons only in MobileTopBar now import { getDefaultUnifiedFormState, legacyToUnifiedForm, @@ -316,122 +325,7 @@ const canApproveReject = computed(() => { return true }) -// US-209: Mobile Action Bar actions based on receipt state -const mobileActionBarActions = computed(() => { - // Create/Edit mode buttons - if (!isViewMode.value) { - return [ - { - label: 'Salvează Ciornă', - icon: 'pi pi-save', - severity: 'secondary', - handler: saveReceipt, - disabled: saving.value - }, - { - label: 'Trimite', - icon: 'pi pi-send', - severity: 'success', - handler: submitForReviewMobile, - disabled: !canSubmit.value || submitting.value - } - ] - } - - // View mode - context-aware based on status - const status = receiptStatus.value - const actions = [] - - switch (status) { - case 'draft': - // Draft: Salvează | Submit pentru Aprobare | Șterge - actions.push({ - label: 'Editează', - icon: 'pi pi-pencil', - severity: 'secondary', - handler: goToEdit, - disabled: false - }) - actions.push({ - label: 'Trimite', - icon: 'pi pi-send', - severity: 'success', - handler: submitReceipt, - disabled: submitting.value - }) - break - - case 'pending_review': - // Pending: Salvează | Aprobă | Respinge (dacă are permisiuni) - if (canApproveReject.value) { - actions.push({ - label: 'Validează', - icon: 'pi pi-check', - severity: 'success', - handler: approveReceipt, - disabled: approving.value - }) - actions.push({ - label: 'Respinge', - icon: 'pi pi-times', - severity: 'danger', - handler: openRejectDialog, - disabled: rejecting.value - }) - } - break - - case 'approved': - // Approved: doar vizualizare (butoane disabled sau ascunse) - // Show cancel approval button for admin users - actions.push({ - label: 'Anulează Validarea', - icon: 'pi pi-replay', - severity: 'warning', - handler: confirmCancelApproval, - disabled: cancelling.value - }) - break - - case 'rejected': - // Rejected: Salvează (re-edit) | Re-submit - actions.push({ - label: 'Editează', - icon: 'pi pi-pencil', - severity: 'primary', - handler: goToEdit, - disabled: false - }) - actions.push({ - label: 'Re-trimite', - icon: 'pi pi-send', - severity: 'success', - handler: submitReceipt, - disabled: submitting.value - }) - break - } - - return actions -}) - -// US-209/US-211: Check if MobileActionBar should be visible -// Hide when dialogs/overlays are open for better UX -const showMobileActionBar = computed(() => { - if (!isMobile.value) return false - - // US-211: Hide action bar when overlays are open - if (showRejectDialog.value || showCreateSupplierDialog.value) return false - - // US-211: Hide action bar when virtual keyboard is visible (better form UX) - if (keyboardVisible.value) return false - - // In create/edit mode, always show (unless overlay open) - if (!isViewMode.value) return true - - // In view mode, show only if there are actions - return mobileActionBarActions.value.length > 0 -}) +// US-518: Removed mobileActionBarActions and showMobileActionBar - buttons now only in MobileTopBar // US-042: More menu items - contextual based on status const moreMenuItems = computed(() => { @@ -471,42 +365,118 @@ const moreMenuItems = computed(() => { return items }) -// US-105: Mobile top bar actions - contextual based on mode +// US-518: Mobile top bar actions - ALL buttons in header only (no bottom bar) +// Includes both icon actions and contextual workflow buttons const mobileTopBarActions = computed(() => { const actions = [] if (!isViewMode.value) { - // Create/Edit mode: attach file + save - actions.push({ - id: 'attach', - icon: 'pi pi-paperclip', - label: 'Atașează fișier', - tooltip: 'Atașează fișier' - }) + // Create/Edit mode: Salvează + Trimite buttons actions.push({ id: 'save', icon: 'pi pi-save', label: 'Salvează', - tooltip: 'Salvează' + tooltip: 'Salvează ciornă', + disabled: saving.value }) + // Show Trimite button for edit mode when status is draft + if (isEditMode.value && receipt.value?.status === 'draft') { + actions.push({ + id: 'submit', + icon: 'pi pi-send', + label: 'Trimite', + tooltip: 'Trimite spre aprobare', + severity: 'success', + disabled: !canSubmit.value || submitting.value + }) + } else if (isCreateMode.value) { + // For create mode, show Submit after save + actions.push({ + id: 'submit', + icon: 'pi pi-send', + label: 'Trimite', + tooltip: 'Salvează și trimite', + severity: 'success', + disabled: !canSubmit.value || submitting.value + }) + } } else { - // View mode: edit (if allowed), delete (if allowed), more menu - if (receipt.value?.status === 'draft' || receipt.value?.status === 'rejected') { - actions.push({ - id: 'edit', - icon: 'pi pi-pencil', - label: 'Editează', - tooltip: 'Editează' - }) - } - if (canDelete.value) { - actions.push({ - id: 'delete', - icon: 'pi pi-trash', - label: 'Șterge', - tooltip: 'Șterge' - }) + // View mode - context-aware based on receipt status + const status = receiptStatus.value + + switch (status) { + case 'draft': + // Draft: Editează + Trimite + actions.push({ + id: 'edit', + icon: 'pi pi-pencil', + label: 'Editează', + tooltip: 'Editează bonul' + }) + actions.push({ + id: 'submit-view', + icon: 'pi pi-send', + label: 'Trimite', + tooltip: 'Trimite spre aprobare', + severity: 'success', + disabled: submitting.value + }) + break + + case 'pending_review': + // Pending Review: Validează + Respinge + if (canApproveReject.value) { + actions.push({ + id: 'approve', + icon: 'pi pi-check', + label: 'Validează', + tooltip: 'Aprobă bonul', + severity: 'success', + disabled: approving.value + }) + actions.push({ + id: 'reject', + icon: 'pi pi-times', + label: 'Respinge', + tooltip: 'Respinge bonul', + severity: 'danger', + disabled: rejecting.value + }) + } + break + + case 'approved': + // Approved: Anulează Validarea + actions.push({ + id: 'cancel-approval', + icon: 'pi pi-replay', + label: 'Anulează', + tooltip: 'Anulează validarea', + severity: 'warning', + disabled: cancelling.value + }) + break + + case 'rejected': + // Rejected: Editează + Re-trimite + actions.push({ + id: 'edit', + icon: 'pi pi-pencil', + label: 'Editează', + tooltip: 'Editează bonul' + }) + actions.push({ + id: 'submit-view', + icon: 'pi pi-send', + label: 'Re-trimite', + tooltip: 'Trimite din nou', + severity: 'success', + disabled: submitting.value + }) + break } + + // Add more menu at the end for additional actions (delete, share, etc.) actions.push({ id: 'more', icon: 'pi pi-ellipsis-v', @@ -518,18 +488,32 @@ const mobileTopBarActions = computed(() => { return actions }) -// US-105: Handle top bar action clicks +// US-518: Handle top bar action clicks - all actions now in header const handleTopBarAction = (action) => { switch (action.id) { - case 'attach': - triggerFileAttach() - break case 'save': saveReceipt() break + case 'submit': + // Create/Edit mode: save and submit + submitForReviewMobile() + break + case 'submit-view': + // View mode: just submit (already saved) + submitReceipt() + break case 'edit': goToEdit() break + case 'approve': + approveReceipt() + break + case 'reject': + openRejectDialog() + break + case 'cancel-approval': + confirmCancelApproval() + break case 'delete': confirmDelete() break @@ -1411,12 +1395,11 @@ const cancelApproval = async () => { } /* ======================================== - * US-041/US-105/US-209: Mobile Layout - * Uses shared MobileTopBar + MobileActionBar components + * US-518: Mobile Layout - Buttons ONLY in MobileTopBar + * Removed MobileActionBar - all actions now in header * PRD Mobile Layout Tokens: * - topBarHeight: 56px * - bottomNavHeight: 56px - * - MobileActionBar: positioned at bottom: 56px (above MobileBottomNav) * - touchTargetMin: 48px * ======================================== */ @@ -1424,9 +1407,8 @@ const cancelApproval = async () => { .receipt-unified-view.mobile-compose-layout { padding: 0; padding-top: 56px; /* Space for fixed MobileTopBar */ - /* MobileActionBar sits at bottom: 56px, so we need: - 56px (action bar height ~56px) + 56px (bottom nav) = 112px */ - padding-bottom: 120px; /* Space for MobileActionBar + MobileBottomNav */ + /* US-518: Only need space for MobileBottomNav (no more MobileActionBar) */ + padding-bottom: 64px; /* Space for MobileBottomNav + small buffer */ max-width: 100%; min-height: 100vh; background: var(--surface-ground);