feat(mobile-fixes-phase3): Complete US-305 - Tab-uri Clienți/Furnizori în Scadențe
Implemented by Ralph autonomous loop. Iteration: 2 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -96,8 +96,8 @@
|
||||
"MobileBottomNav activ",
|
||||
"npm run build passes"
|
||||
],
|
||||
"passes": false,
|
||||
"notes": ""
|
||||
"passes": true,
|
||||
"notes": "Completed in iteration 2"
|
||||
},
|
||||
{
|
||||
"id": "US-301",
|
||||
|
||||
@@ -1026,3 +1026,9 @@ User Stories: 11 (US-301 to US-311)
|
||||
[2026-01-12 16:34:08] Working on story: US-304
|
||||
[2026-01-12 16:34:08] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_1_US-304.log)
|
||||
[2026-01-12 16:36:25] SUCCESS: Story US-304 passed!
|
||||
[2026-01-12 16:36:26] Changes committed
|
||||
[2026-01-12 16:36:26] Progress: 3/11 stories completed
|
||||
[2026-01-12 16:36:28] === Iteration 2/100 ===
|
||||
[2026-01-12 16:36:28] Working on story: US-305
|
||||
[2026-01-12 16:36:28] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_2_US-305.log)
|
||||
[2026-01-12 16:39:00] SUCCESS: Story US-305 passed!
|
||||
|
||||
@@ -45,9 +45,10 @@
|
||||
<!-- Main Content -->
|
||||
<div v-else class="card-content">
|
||||
<!-- Nivel 1: Comparație Grafică -->
|
||||
<div class="comparison-section">
|
||||
<!-- Clienți Side -->
|
||||
<div class="comparison-side clients">
|
||||
<!-- US-305: On mobile, show only the active tab's content -->
|
||||
<div class="comparison-section" :class="{ 'mobile-single-view': props.isMobile }">
|
||||
<!-- Clienți Side - Hidden on mobile when suppliers tab active -->
|
||||
<div class="comparison-side clients" v-if="!props.isMobile || props.activeTab === 'clients'">
|
||||
<div class="side-header">
|
||||
<span class="side-label">Clienți - De încasat</span>
|
||||
<span class="side-total">{{ formatCurrency(clientsTotal) }}</span>
|
||||
@@ -86,11 +87,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Divider -->
|
||||
<div class="comparison-divider"></div>
|
||||
<!-- Divider - Hidden on mobile -->
|
||||
<div v-if="!props.isMobile" class="comparison-divider"></div>
|
||||
|
||||
<!-- Furnizori Side -->
|
||||
<div class="comparison-side suppliers">
|
||||
<!-- Furnizori Side - Hidden on mobile when clients tab active -->
|
||||
<div class="comparison-side suppliers" v-if="!props.isMobile || props.activeTab === 'suppliers'">
|
||||
<div class="side-header">
|
||||
<span class="side-label">Furnizori - De plătit</span>
|
||||
<span class="side-total">{{ formatCurrency(suppliersTotal) }}</span>
|
||||
@@ -512,6 +513,17 @@ const props = defineProps({
|
||||
type: [Number, String],
|
||||
required: true,
|
||||
},
|
||||
// US-305: Active tab for mobile view (clients/suppliers)
|
||||
activeTab: {
|
||||
type: String,
|
||||
default: 'clients',
|
||||
validator: (value) => ['clients', 'suppliers'].includes(value),
|
||||
},
|
||||
// US-305: Is mobile view
|
||||
isMobile: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
// Emits
|
||||
@@ -1689,14 +1701,24 @@ onMounted(() => {
|
||||
display: table;
|
||||
}
|
||||
|
||||
/* US-305: Mobile single view - show only active tab */
|
||||
.comparison-section.mobile-single-view {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.comparison-section.mobile-single-view .comparison-side {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Responsive - Tablet */
|
||||
@media (max-width: 1024px) {
|
||||
.comparison-section {
|
||||
.comparison-section:not(.mobile-single-view) {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.comparison-divider {
|
||||
.comparison-section:not(.mobile-single-view) .comparison-divider {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,32 @@
|
||||
<!-- Mobile Top Bar -->
|
||||
<MobileTopBar
|
||||
v-if="isMobile"
|
||||
title="Analiză Scadențe"
|
||||
title="Scadențe"
|
||||
:show-back="true"
|
||||
@back-click="goBack"
|
||||
/>
|
||||
|
||||
<main class="main-content" :class="{ 'mobile-layout': isMobile }">
|
||||
<!-- US-305: Mobile Tabs for Clienți/Furnizori -->
|
||||
<div v-if="isMobile" class="mobile-tabs-container">
|
||||
<div class="mobile-tabs">
|
||||
<button
|
||||
class="mobile-tab"
|
||||
:class="{ active: activeTab === 'clients' }"
|
||||
@click="switchTab('clients')"
|
||||
>
|
||||
<span class="tab-label">Clienți</span>
|
||||
</button>
|
||||
<button
|
||||
class="mobile-tab"
|
||||
:class="{ active: activeTab === 'suppliers' }"
|
||||
@click="switchTab('suppliers')"
|
||||
>
|
||||
<span class="tab-label">Furnizori</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="main-content" :class="{ 'mobile-layout': isMobile, 'has-tabs': isMobile }">
|
||||
<div class="app-container">
|
||||
<!-- Page Header - only on desktop -->
|
||||
<div v-if="!isMobile" class="page-header">
|
||||
@@ -34,6 +54,8 @@
|
||||
<div v-else class="maturity-container">
|
||||
<MaturityAndDetailsCard
|
||||
:companyId="companyStore.selectedCompany?.id_firma"
|
||||
:activeTab="activeTab"
|
||||
:isMobile="isMobile"
|
||||
@periodChanged="handlePeriodChange"
|
||||
/>
|
||||
</div>
|
||||
@@ -46,7 +68,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import Button from 'primevue/button'
|
||||
import MobileTopBar from '@shared/components/mobile/MobileTopBar.vue'
|
||||
import MobileBottomNav from '@shared/components/mobile/MobileBottomNav.vue'
|
||||
@@ -54,8 +76,12 @@ import MaturityAndDetailsCard from '@reports/components/dashboard/cards/Maturity
|
||||
import { useCompanyStore } from '@reports/stores/sharedStores'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const companyStore = useCompanyStore()
|
||||
|
||||
// US-305: Tab state synced with URL query params
|
||||
const activeTab = ref(route.query.tab === 'suppliers' ? 'suppliers' : 'clients')
|
||||
|
||||
// Detectare mobile - reactive with resize listener
|
||||
const windowWidth = ref(window.innerWidth)
|
||||
const isMobile = computed(() => windowWidth.value < 768)
|
||||
@@ -70,6 +96,22 @@ const goBack = () => {
|
||||
router.push('/reports/dashboard')
|
||||
}
|
||||
|
||||
// US-305: Switch between Clienți/Furnizori tabs
|
||||
// Updates URL query param without full navigation, preserves filters
|
||||
const switchTab = (tab) => {
|
||||
if (tab === activeTab.value) return
|
||||
|
||||
activeTab.value = tab
|
||||
|
||||
// Update URL query param without full navigation
|
||||
router.replace({
|
||||
query: {
|
||||
...route.query,
|
||||
tab: tab === 'suppliers' ? 'suppliers' : undefined // Remove param if 'clients' (default)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Handle period change from MaturityAndDetailsCard
|
||||
const handlePeriodChange = (period) => {
|
||||
console.log('Maturity period changed:', period)
|
||||
@@ -95,6 +137,63 @@ onUnmounted(() => {
|
||||
padding-bottom: 56px;
|
||||
}
|
||||
|
||||
/* Mobile layout with tabs - extra padding for tab bar */
|
||||
.main-content.mobile-layout.has-tabs {
|
||||
padding-top: calc(56px + 48px); /* MobileTopBar + tabs height */
|
||||
}
|
||||
|
||||
/* ================================================
|
||||
US-305: Mobile Tabs (Clienți/Furnizori)
|
||||
Material Design 3 inspired full-width tabs
|
||||
================================================ */
|
||||
|
||||
.mobile-tabs-container {
|
||||
position: fixed;
|
||||
top: 56px; /* Below MobileTopBar */
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: var(--z-sticky);
|
||||
background: var(--surface-card);
|
||||
border-bottom: 1px solid var(--surface-border);
|
||||
}
|
||||
|
||||
.mobile-tabs {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mobile-tab {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--space-md);
|
||||
min-height: 48px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
color: var(--text-color-secondary);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: var(--font-medium);
|
||||
}
|
||||
|
||||
.mobile-tab:active {
|
||||
background: var(--surface-hover);
|
||||
}
|
||||
|
||||
.mobile-tab.active {
|
||||
color: var(--color-primary);
|
||||
border-bottom-color: var(--color-primary);
|
||||
font-weight: var(--font-semibold);
|
||||
}
|
||||
|
||||
.tab-label {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* App container */
|
||||
.app-container {
|
||||
max-width: 1400px;
|
||||
|
||||
Reference in New Issue
Block a user