diff --git a/scripts/ralph/prd.json b/scripts/ralph/prd.json
index 05fe869..d37e950 100644
--- a/scripts/ralph/prd.json
+++ b/scripts/ralph/prd.json
@@ -144,8 +144,8 @@
"FAB vizibil doar pe mobil (isMobile)",
"npm run build passes"
],
- "passes": false,
- "notes": ""
+ "passes": true,
+ "notes": "Completed in iteration 5"
},
{
"id": "US-306",
diff --git a/scripts/ralph/progress.txt b/scripts/ralph/progress.txt
index 7382bb2..0f91015 100644
--- a/scripts/ralph/progress.txt
+++ b/scripts/ralph/progress.txt
@@ -1044,3 +1044,9 @@ User Stories: 11 (US-301 to US-311)
[2026-01-12 16:40:03] Working on story: US-302
[2026-01-12 16:40:03] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_4_US-302.log)
[2026-01-12 16:42:59] SUCCESS: Story US-302 passed!
+[2026-01-12 16:42:59] Changes committed
+[2026-01-12 16:42:59] Progress: 6/11 stories completed
+[2026-01-12 16:43:01] === Iteration 5/100 ===
+[2026-01-12 16:43:01] Working on story: US-303
+[2026-01-12 16:43:01] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_5_US-303.log)
+[2026-01-12 16:46:26] SUCCESS: Story US-303 passed!
diff --git a/src/modules/data-entry/views/receipts/ReceiptsListView.vue b/src/modules/data-entry/views/receipts/ReceiptsListView.vue
index 4fdf38e..052fdca 100644
--- a/src/modules/data-entry/views/receipts/ReceiptsListView.vue
+++ b/src/modules/data-entry/views/receipts/ReceiptsListView.vue
@@ -545,18 +545,30 @@
/>
-
+
+
+
+
@@ -1038,6 +1050,10 @@ const handleResize = () => {
const showDrawer = ref(false)
const moreMenuRef = ref(null)
const fabVisible = ref(true)
+
+// US-303: FAB Menu State
+const fabMenuRef = ref(null)
+const fabMenuOpen = ref(false)
let lastScrollY = 0
let scrollTimeout = null
@@ -1075,6 +1091,32 @@ const moreMenuItems = computed(() => [
}
])
+// US-303: FAB Menu Items (Bon Nou | Upload Bulk)
+const fabMenuItems = [
+ {
+ label: 'Bon Nou',
+ icon: 'pi pi-plus',
+ command: () => {
+ fabMenuOpen.value = false
+ goToCreate()
+ }
+ },
+ {
+ label: 'Upload Bulk',
+ icon: 'pi pi-cloud-upload',
+ command: () => {
+ fabMenuOpen.value = false
+ openBulkFileInput()
+ }
+ }
+]
+
+// US-303: Toggle FAB Menu
+const toggleFabMenu = (event) => {
+ fabMenuOpen.value = !fabMenuOpen.value
+ fabMenuRef.value?.toggle(event)
+}
+
// US-103: Top bar actions for MobileTopBar component
const mobileTopBarActions = computed(() => {
if (mobileSelectionMode.value) {
@@ -4398,6 +4440,50 @@ const cleanupCompletedBatches = (storedBatchIds) => {
.mobile-fab i {
font-size: var(--text-2xl);
+ transition: transform var(--transition-fast);
+}
+
+/* US-303: FAB active state when menu is open */
+.mobile-fab.fab-active {
+ background: var(--color-primary-dark);
+}
+
+.mobile-fab .fab-icon-rotate {
+ transform: rotate(45deg);
+}
+
+/* US-303: FAB Popup Menu positioning */
+.fab-popup-menu {
+ /* Position above FAB, aligned to right */
+ position: fixed !important;
+ bottom: 140px !important; /* 72px FAB position + 56px FAB height + 12px spacing */
+ right: var(--space-md) !important;
+ left: auto !important;
+ top: auto !important;
+ min-width: 180px;
+ z-index: 1000 !important;
+ border-radius: var(--radius-lg);
+ box-shadow: var(--shadow-xl);
+}
+
+.fab-popup-menu .p-menuitem {
+ padding: 0;
+}
+
+.fab-popup-menu .p-menuitem-link {
+ padding: var(--space-md) var(--space-lg);
+ gap: var(--space-sm);
+ font-size: var(--text-base);
+ min-height: 48px; /* Touch-friendly */
+}
+
+.fab-popup-menu .p-menuitem-icon {
+ font-size: var(--text-lg);
+ color: var(--color-primary);
+}
+
+.fab-popup-menu .p-menuitem-text {
+ font-weight: var(--font-medium);
}
/* FAB slide animation */
@@ -4523,6 +4609,19 @@ const cleanupCompletedBatches = (storedBatchIds) => {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
+[data-theme="dark"] .mobile-fab.fab-active {
+ background: var(--blue-700);
+}
+
+[data-theme="dark"] .fab-popup-menu {
+ background: var(--surface-card);
+ border: 1px solid var(--surface-border);
+}
+
+[data-theme="dark"] .fab-popup-menu .p-menuitem-icon {
+ color: var(--blue-400);
+}
+
[data-theme="dark"] .sidebar-item.active,
[data-theme="dark"] .sidebar-item.router-link-active {
color: var(--blue-400);
@@ -4568,6 +4667,19 @@ const cleanupCompletedBatches = (storedBatchIds) => {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
+ :root:not([data-theme]) .mobile-fab.fab-active {
+ background: var(--blue-700);
+ }
+
+ :root:not([data-theme]) .fab-popup-menu {
+ background: var(--surface-card);
+ border: 1px solid var(--surface-border);
+ }
+
+ :root:not([data-theme]) .fab-popup-menu .p-menuitem-icon {
+ color: var(--blue-400);
+ }
+
:root:not([data-theme]) .sidebar-item.active,
:root:not([data-theme]) .sidebar-item.router-link-active {
color: var(--blue-400);