feat(unified-mobile-material-design): Complete US-105 - Adăugare buton Înapoi în editare bon
Implemented by Ralph autonomous loop. Iteration: 8 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -136,8 +136,8 @@
|
|||||||
"Verify in browser că butonul funcționează",
|
"Verify in browser că butonul funcționează",
|
||||||
"npm run build passes"
|
"npm run build passes"
|
||||||
],
|
],
|
||||||
"passes": false,
|
"passes": true,
|
||||||
"notes": ""
|
"notes": "Completed in iteration 8"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "US-112",
|
"id": "US-112",
|
||||||
|
|||||||
@@ -48,3 +48,9 @@ Mon Jan 12 09:44:54 AM UTC 2026
|
|||||||
[2026-01-12 09:58:25] Working on story: US-104
|
[2026-01-12 09:58:25] Working on story: US-104
|
||||||
[2026-01-12 09:58:25] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_7_US-104.log)
|
[2026-01-12 09:58:25] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_7_US-104.log)
|
||||||
[2026-01-12 10:00:17] SUCCESS: Story US-104 passed!
|
[2026-01-12 10:00:17] SUCCESS: Story US-104 passed!
|
||||||
|
[2026-01-12 10:00:18] Changes committed
|
||||||
|
[2026-01-12 10:00:18] Progress: 6/20 stories completed
|
||||||
|
[2026-01-12 10:00:20] === Iteration 8/100 ===
|
||||||
|
[2026-01-12 10:00:20] Working on story: US-105
|
||||||
|
[2026-01-12 10:00:20] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_8_US-105.log)
|
||||||
|
[2026-01-12 10:03:01] SUCCESS: Story US-105 passed!
|
||||||
|
|||||||
@@ -1,77 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="receipt-unified-view" :class="{ 'mobile-compose-layout': isMobile }">
|
<div class="receipt-unified-view" :class="{ 'mobile-compose-layout': isMobile }">
|
||||||
<!-- US-041/US-042: Mobile Top Bar - Gmail Style -->
|
<!-- US-105: Mobile Top Bar using shared MobileTopBar component -->
|
||||||
<header v-if="isMobile" class="mobile-compose-top-bar">
|
<MobileTopBar
|
||||||
<div class="top-bar-left">
|
v-if="isMobile"
|
||||||
<Button
|
:title="mobileTitle"
|
||||||
:icon="isViewMode ? 'pi pi-arrow-left' : 'pi pi-times'"
|
:show-back="true"
|
||||||
text
|
:actions="mobileTopBarActions"
|
||||||
rounded
|
@back-click="goBack"
|
||||||
class="top-bar-btn"
|
@action-click="handleTopBarAction"
|
||||||
@click="goBack"
|
|
||||||
aria-label="Înapoi"
|
|
||||||
/>
|
|
||||||
<span class="top-bar-title">{{ mobileTitle }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="top-bar-right">
|
|
||||||
<!-- Create/Edit mode icons -->
|
|
||||||
<Button
|
|
||||||
v-if="!isViewMode"
|
|
||||||
icon="pi pi-paperclip"
|
|
||||||
text
|
|
||||||
rounded
|
|
||||||
class="top-bar-btn"
|
|
||||||
@click="triggerFileAttach"
|
|
||||||
aria-label="Atașează fișier"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
v-if="!isViewMode"
|
|
||||||
icon="pi pi-save"
|
|
||||||
text
|
|
||||||
rounded
|
|
||||||
class="top-bar-btn"
|
|
||||||
:loading="saving"
|
|
||||||
@click="saveReceipt"
|
|
||||||
aria-label="Salvează"
|
|
||||||
/>
|
|
||||||
<!-- US-042: View mode icons - edit, delete, more menu -->
|
|
||||||
<Button
|
|
||||||
v-if="isViewMode && (receipt?.status === 'draft' || receipt?.status === 'rejected')"
|
|
||||||
icon="pi pi-pencil"
|
|
||||||
text
|
|
||||||
rounded
|
|
||||||
class="top-bar-btn"
|
|
||||||
@click="goToEdit"
|
|
||||||
aria-label="Editează"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
v-if="isViewMode && canDelete"
|
|
||||||
icon="pi pi-trash"
|
|
||||||
text
|
|
||||||
rounded
|
|
||||||
class="top-bar-btn top-bar-btn-danger"
|
|
||||||
@click="confirmDelete"
|
|
||||||
aria-label="Șterge"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
v-if="isViewMode"
|
|
||||||
icon="pi pi-ellipsis-v"
|
|
||||||
text
|
|
||||||
rounded
|
|
||||||
class="top-bar-btn"
|
|
||||||
@click="toggleMoreMenu"
|
|
||||||
aria-label="Mai multe opțiuni"
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-controls="more_menu"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- US-042: More Menu for view mode (used by MobileTopBar action) -->
|
||||||
<Menu
|
<Menu
|
||||||
|
v-if="isMobile"
|
||||||
ref="moreMenuRef"
|
ref="moreMenuRef"
|
||||||
id="more_menu"
|
id="more_menu"
|
||||||
:model="moreMenuItems"
|
:model="moreMenuItems"
|
||||||
:popup="true"
|
:popup="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<!-- Desktop Header -->
|
<!-- Desktop Header -->
|
||||||
<div v-if="!isMobile" class="view-header">
|
<div v-if="!isMobile" class="view-header">
|
||||||
@@ -358,6 +304,7 @@ import { useReceiptsStore } from '@data-entry/stores/receiptsStore'
|
|||||||
import { useCompanyStore } from '@data-entry/stores/sharedStores'
|
import { useCompanyStore } from '@data-entry/stores/sharedStores'
|
||||||
|
|
||||||
import UnifiedReceiptForm from '@data-entry/components/receipts/UnifiedReceiptForm.vue'
|
import UnifiedReceiptForm from '@data-entry/components/receipts/UnifiedReceiptForm.vue'
|
||||||
|
import MobileTopBar from '@shared/components/mobile/MobileTopBar.vue'
|
||||||
import {
|
import {
|
||||||
getDefaultUnifiedFormState,
|
getDefaultUnifiedFormState,
|
||||||
legacyToUnifiedForm,
|
legacyToUnifiedForm,
|
||||||
@@ -468,6 +415,75 @@ const moreMenuItems = computed(() => {
|
|||||||
return items
|
return items
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// US-105: Mobile top bar actions - contextual based on mode
|
||||||
|
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'
|
||||||
|
})
|
||||||
|
actions.push({
|
||||||
|
id: 'save',
|
||||||
|
icon: 'pi pi-save',
|
||||||
|
label: 'Salvează',
|
||||||
|
tooltip: 'Salvează'
|
||||||
|
})
|
||||||
|
} 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'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
actions.push({
|
||||||
|
id: 'more',
|
||||||
|
icon: 'pi pi-ellipsis-v',
|
||||||
|
label: 'Mai multe',
|
||||||
|
tooltip: 'Mai multe opțiuni'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return actions
|
||||||
|
})
|
||||||
|
|
||||||
|
// US-105: Handle top bar action clicks
|
||||||
|
const handleTopBarAction = (action) => {
|
||||||
|
switch (action.id) {
|
||||||
|
case 'attach':
|
||||||
|
triggerFileAttach()
|
||||||
|
break
|
||||||
|
case 'save':
|
||||||
|
saveReceipt()
|
||||||
|
break
|
||||||
|
case 'edit':
|
||||||
|
goToEdit()
|
||||||
|
break
|
||||||
|
case 'delete':
|
||||||
|
confirmDelete()
|
||||||
|
break
|
||||||
|
case 'more':
|
||||||
|
// Toggle more menu - need to pass event
|
||||||
|
moreMenuRef.value?.toggle({ currentTarget: document.querySelector('[aria-label="Mai multe opțiuni"]') })
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Form state
|
// Form state
|
||||||
const form = ref(getDefaultUnifiedFormState())
|
const form = ref(getDefaultUnifiedFormState())
|
||||||
const receipt = ref(null)
|
const receipt = ref(null)
|
||||||
@@ -1339,8 +1355,8 @@ const cancelApproval = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ========================================
|
/* ========================================
|
||||||
* US-041: Mobile Gmail Compose Layout
|
* US-041/US-105: Mobile Layout
|
||||||
* Similar to Gmail's email compose interface
|
* Uses shared MobileTopBar component
|
||||||
* PRD Mobile Layout Tokens:
|
* PRD Mobile Layout Tokens:
|
||||||
* - topBarHeight: 56px
|
* - topBarHeight: 56px
|
||||||
* - bottomNavHeight: 56px
|
* - bottomNavHeight: 56px
|
||||||
@@ -1350,7 +1366,7 @@ const cancelApproval = async () => {
|
|||||||
/* Mobile compose layout container */
|
/* Mobile compose layout container */
|
||||||
.receipt-unified-view.mobile-compose-layout {
|
.receipt-unified-view.mobile-compose-layout {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
padding-top: 56px; /* Space for fixed top bar */
|
padding-top: 56px; /* Space for fixed MobileTopBar */
|
||||||
padding-bottom: 80px; /* Space for fixed bottom action bar */
|
padding-bottom: 80px; /* Space for fixed bottom action bar */
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
@@ -1362,60 +1378,6 @@ const cancelApproval = async () => {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mobile Top Bar - Gmail Compose Style */
|
|
||||||
.mobile-compose-top-bar {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
height: 56px;
|
|
||||||
background: var(--surface-card);
|
|
||||||
border-bottom: 1px solid var(--surface-border);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 0 var(--space-xs);
|
|
||||||
z-index: 1000;
|
|
||||||
box-shadow: var(--shadow-sm);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-compose-top-bar .top-bar-left,
|
|
||||||
.mobile-compose-top-bar .top-bar-right {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: var(--space-xs);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-compose-top-bar .top-bar-title {
|
|
||||||
font-size: var(--text-lg);
|
|
||||||
font-weight: var(--font-semibold);
|
|
||||||
color: var(--text-color);
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
max-width: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-compose-top-bar .top-bar-btn {
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
min-width: 48px; /* Touch target minimum */
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
color: var(--text-color);
|
|
||||||
transition: all var(--transition-fast);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-compose-top-bar .top-bar-btn:active {
|
|
||||||
background: var(--surface-hover);
|
|
||||||
border-radius: var(--radius-full);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobile-compose-top-bar .top-bar-btn-danger {
|
|
||||||
color: var(--red-500);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mobile Bottom Action Bar - Gmail Compose Style */
|
/* Mobile Bottom Action Bar - Gmail Compose Style */
|
||||||
.mobile-form-bottom-bar {
|
.mobile-form-bottom-bar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -1486,25 +1448,9 @@ const cancelApproval = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ========================================
|
/* ========================================
|
||||||
* Dark Mode Support for Mobile Layout
|
* Dark Mode Support for Mobile Bottom Bar
|
||||||
|
* (MobileTopBar handles its own dark mode)
|
||||||
* ======================================== */
|
* ======================================== */
|
||||||
[data-theme="dark"] .mobile-compose-top-bar {
|
|
||||||
background: var(--surface-card);
|
|
||||||
border-bottom-color: var(--surface-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="dark"] .mobile-compose-top-bar .top-bar-btn {
|
|
||||||
color: var(--text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="dark"] .mobile-compose-top-bar .top-bar-btn:active {
|
|
||||||
background: var(--surface-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="dark"] .mobile-compose-top-bar .top-bar-btn-danger {
|
|
||||||
color: var(--red-400);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="dark"] .mobile-form-bottom-bar {
|
[data-theme="dark"] .mobile-form-bottom-bar {
|
||||||
background: var(--surface-card);
|
background: var(--surface-card);
|
||||||
border-top-color: var(--surface-border);
|
border-top-color: var(--surface-border);
|
||||||
@@ -1515,23 +1461,6 @@ const cancelApproval = async () => {
|
|||||||
* System Preference Dark Mode Support
|
* System Preference Dark Mode Support
|
||||||
* ======================================== */
|
* ======================================== */
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
:root:not([data-theme="light"]) .mobile-compose-top-bar {
|
|
||||||
background: var(--surface-card);
|
|
||||||
border-bottom-color: var(--surface-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
:root:not([data-theme="light"]) .mobile-compose-top-bar .top-bar-btn {
|
|
||||||
color: var(--text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
:root:not([data-theme="light"]) .mobile-compose-top-bar .top-bar-btn:active {
|
|
||||||
background: var(--surface-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
:root:not([data-theme="light"]) .mobile-compose-top-bar .top-bar-btn-danger {
|
|
||||||
color: var(--red-400);
|
|
||||||
}
|
|
||||||
|
|
||||||
:root:not([data-theme="light"]) .mobile-form-bottom-bar {
|
:root:not([data-theme="light"]) .mobile-form-bottom-bar {
|
||||||
background: var(--surface-card);
|
background: var(--surface-card);
|
||||||
border-top-color: var(--surface-border);
|
border-top-color: var(--surface-border);
|
||||||
|
|||||||
Reference in New Issue
Block a user