feat(unified-mobile-material-design): Complete US-108 - TrialBalanceView Mobile Material Design

Implemented by Ralph autonomous loop.
Iteration: 12

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-01-12 10:13:33 +00:00
parent fb0334e270
commit 1584d7ae61
3 changed files with 347 additions and 50 deletions

View File

@@ -200,8 +200,8 @@
"Filtre existente mutate în BottomSheet pe mobil",
"npm run build passes"
],
"passes": false,
"notes": ""
"passes": true,
"notes": "Completed in iteration 12"
},
{
"id": "US-109",

View File

@@ -72,3 +72,9 @@ Mon Jan 12 09:44:54 AM UTC 2026
[2026-01-12 10:07:40] Working on story: US-107
[2026-01-12 10:07:40] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_11_US-107.log)
[2026-01-12 10:11:07] SUCCESS: Story US-107 passed!
[2026-01-12 10:11:08] Changes committed
[2026-01-12 10:11:08] Progress: 10/20 stories completed
[2026-01-12 10:11:10] === Iteration 12/100 ===
[2026-01-12 10:11:10] Working on story: US-108
[2026-01-12 10:11:10] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_12_US-108.log)
[2026-01-12 10:13:33] SUCCESS: Story US-108 passed!

View File

@@ -1,8 +1,88 @@
<template>
<div class="app-container">
<div class="app-container" :class="{ 'mobile-layout': isMobile }">
<!-- US-108: Mobile Material Design Top Bar -->
<MobileTopBar
v-if="isMobile"
title="Balanță de Verificare"
:show-menu="true"
:actions="mobileTopBarActions"
@menu-click="toggleMobileMenu"
@action-click="handleTopBarAction"
/>
<!-- US-108: Mobile Hamburger Menu -->
<Sidebar v-model:visible="mobileMenuVisible" position="left" class="mobile-sidebar">
<template #header>
<div class="sidebar-header">
<span class="sidebar-title">ROA2WEB</span>
</div>
</template>
<div class="sidebar-menu">
<router-link to="/data-entry" class="sidebar-item">
<i class="pi pi-receipt"></i>
<span>Bonuri</span>
</router-link>
<router-link to="/reports/trial-balance" class="sidebar-item active">
<i class="pi pi-calculator"></i>
<span>Balanță</span>
</router-link>
<router-link to="/reports/dashboard" class="sidebar-item">
<i class="pi pi-chart-bar"></i>
<span>Rapoarte</span>
</router-link>
<router-link to="/data-entry/ocr-metrics" class="sidebar-item">
<i class="pi pi-cog"></i>
<span>Setări</span>
</router-link>
</div>
</Sidebar>
<!-- US-108: Filter BottomSheet for mobile -->
<BottomSheet v-model="showFilters">
<h3 class="bottom-sheet-title">Filtre</h3>
<div class="bottom-sheet-filters">
<!-- Cont Filter -->
<div class="form-group">
<label class="form-label">Număr Cont</label>
<InputText
v-model="localFilters.cont"
placeholder="Ex: 512, 4111"
class="w-full"
@input="handleFilterChange"
/>
</div>
<!-- Denumire Filter -->
<div class="form-group">
<label class="form-label">Denumire Cont</label>
<InputText
v-model="localFilters.denumire"
placeholder="Căutare după denumire..."
class="w-full"
@input="handleSearchChange"
/>
</div>
<!-- Bottom sheet actions -->
<div class="bottom-sheet-actions">
<Button
icon="pi pi-filter-slash"
label="Resetează"
class="p-button-outlined p-button-secondary"
@click="clearFilters(); showFilters = false"
/>
<Button
icon="pi pi-check"
label="Aplică"
@click="showFilters = false"
/>
</div>
</div>
</BottomSheet>
<div class="trial-balance">
<!-- Page Header -->
<div class="page-header">
<!-- Page Header - Desktop only -->
<div class="page-header" v-if="!isMobile">
<h1 class="page-title">
<i class="pi pi-calculator"></i>
Balanță de Verificare
@@ -29,48 +109,9 @@
</template>
</Card>
<!-- Mobile: Two-row toolbar -->
<div v-if="isMobile && companyStore.selectedCompany" class="mobile-toolbar-container">
<!-- Row 1: Icon-only action buttons -->
<div class="mobile-toolbar-buttons">
<Button
icon="pi pi-filter"
:class="{ 'filter-active': hasActiveFilters }"
class="p-button-text"
@click="showFilters = !showFilters"
v-tooltip.bottom="'Filtre'"
/>
<Button
icon="pi pi-filter-slash"
class="p-button-text"
@click="clearFilters"
v-tooltip.bottom="'Resetează'"
/>
<Button
icon="pi pi-file-excel"
class="p-button-text p-button-success"
@click="exportExcel"
:disabled="!trialBalanceStore.hasData"
v-tooltip.bottom="'Excel'"
/>
<Button
icon="pi pi-file-pdf"
class="p-button-text p-button-danger"
@click="exportPDF"
:disabled="!trialBalanceStore.hasData"
v-tooltip.bottom="'PDF'"
/>
<Button
icon="pi pi-refresh"
class="p-button-text"
:loading="trialBalanceStore.isLoading"
@click="refreshData"
v-tooltip.bottom="'Actualizează'"
/>
</div>
<!-- Row 2: Totals (unified grid format) -->
<div class="mobile-toolbar-totals">
<!-- US-108: Mobile Totals Bar -->
<div v-if="isMobile && companyStore.selectedCompany && trialBalanceStore.hasData" class="mobile-totals-bar">
<div class="mobile-totals-content">
<div class="mobile-totals-grid two-totals">
<div class="total-item">
<span class="total-label">Sold D:</span>
@@ -84,8 +125,8 @@
</div>
</div>
<!-- Filters Section -->
<Card v-if="companyStore.selectedCompany && (!isMobile || showFilters)" class="filters-card">
<!-- Filters Section - Desktop only (mobile uses BottomSheet) -->
<Card v-if="companyStore.selectedCompany && !isMobile" class="filters-card">
<template #content>
<div class="form">
<div class="form-row">
@@ -338,6 +379,12 @@
</template>
</Card>
</div>
<!-- US-108: Mobile Bottom Navigation -->
<MobileBottomNav
v-if="isMobile"
:items="mobileBottomNavItems"
/>
</div>
</template>
@@ -349,6 +396,12 @@ import { useTrialBalanceStore } from "@reports/stores/trialBalance";
import { useAccountingPeriodStore } from "@reports/stores/sharedStores";
import { exportToExcel, exportToPDF } from "@reports/utils/exportUtils";
// US-108: Mobile Material Design components
import MobileTopBar from "@shared/components/mobile/MobileTopBar.vue";
import MobileBottomNav from "@shared/components/mobile/MobileBottomNav.vue";
import BottomSheet from "@shared/components/mobile/BottomSheet.vue";
import Sidebar from "primevue/sidebar";
const toast = useToast();
const companyStore = useCompanyStore();
const trialBalanceStore = useTrialBalanceStore();
@@ -360,8 +413,46 @@ const selectedCompanyId = ref(companyStore.selectedCompany?.id_firma || null);
// Mobile state
const isMobile = ref(window.innerWidth < 768);
const showFilters = ref(false);
const mobileMenuVisible = ref(false);
const actionsMenu = ref(null);
// US-108: Toggle mobile hamburger menu
const toggleMobileMenu = () => {
mobileMenuVisible.value = !mobileMenuVisible.value;
};
// US-108: Mobile TopBar actions (filter + export)
const mobileTopBarActions = computed(() => [
{
icon: "pi pi-filter",
label: "Filtre",
tooltip: "Filtre",
active: hasActiveFilters.value
},
{
icon: "pi pi-download",
label: "Export",
tooltip: "Export Excel"
}
]);
// US-108: Handle top bar action clicks
const handleTopBarAction = (action) => {
if (action.icon === "pi pi-filter") {
showFilters.value = !showFilters.value;
} else if (action.icon === "pi pi-download") {
exportExcel();
}
};
// US-108: Bottom nav items for MobileBottomNav component
const mobileBottomNavItems = computed(() => [
{ to: "/data-entry", icon: "pi pi-receipt", label: "Bonuri" },
{ to: "/reports/trial-balance", icon: "pi pi-calculator", label: "Balanță", active: true },
{ to: "/reports/dashboard", icon: "pi pi-chart-bar", label: "Rapoarte" },
{ to: "/data-entry/ocr-metrics", icon: "pi pi-cog", label: "Setări" }
]);
// Handle window resize
const handleResize = () => {
isMobile.value = window.innerWidth < 768;
@@ -911,6 +1002,10 @@ watch(
</script>
<style scoped>
/* ================================================
US-108: TrialBalanceView Mobile Material Design Styles
================================================ */
/* ===== Page-Specific Styles Only ===== */
/* Uses shared CSS: dashboard.css (.page-header, .page-title, .page-subtitle) */
/* Uses shared CSS: forms.css (.form-actions) */
@@ -924,6 +1019,14 @@ watch(
padding: var(--space-xl);
}
/* Mobile layout adjustments for top/bottom bars */
.mobile-layout .trial-balance {
padding-top: calc(56px + var(--space-md)); /* Account for fixed MobileTopBar */
padding-bottom: calc(56px + var(--space-md)); /* Account for fixed MobileBottomNav */
padding-left: var(--space-md);
padding-right: var(--space-md);
}
/* Card Spacing */
.company-selection-card,
.filters-card,
@@ -943,7 +1046,195 @@ watch(
/* Uses shared CSS: stats.css (.summary-stats-inline, .stat-item, .stat-label, .stat-value) */
/* Responsive */
/* ================================================
US-108: Mobile Totals Bar
================================================ */
.mobile-totals-bar {
background: var(--surface-card);
border-bottom: 1px solid var(--surface-border);
padding: var(--space-sm) var(--space-md);
margin-bottom: var(--space-md);
border-radius: var(--radius-md);
}
.mobile-totals-content {
display: flex;
justify-content: center;
align-items: center;
}
.mobile-totals-grid {
display: flex;
gap: var(--space-lg);
}
.mobile-totals-grid.two-totals {
justify-content: space-around;
width: 100%;
}
.mobile-totals-bar .total-item {
display: flex;
align-items: center;
gap: var(--space-xs);
}
.mobile-totals-bar .total-label {
font-size: var(--text-sm);
color: var(--text-color-secondary);
font-weight: var(--font-medium);
}
.mobile-totals-bar .total-value {
font-size: var(--text-lg);
font-weight: var(--font-bold);
color: var(--text-color);
}
/* ================================================
US-108: Mobile Card List (Account Cards)
================================================ */
.mobile-card-list {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.mobile-data-card {
background: var(--surface-card);
border: 1px solid var(--surface-border);
border-radius: var(--radius-md);
padding: var(--space-md);
}
.mobile-data-card .card-header {
font-weight: var(--font-semibold);
color: var(--text-color);
margin-bottom: var(--space-xs);
font-size: var(--text-base);
}
.mobile-data-card .card-row {
display: flex;
justify-content: space-between;
align-items: center;
font-size: var(--text-sm);
color: var(--text-color-secondary);
}
.mobile-data-card .card-amount {
font-weight: var(--font-semibold);
color: var(--text-color);
}
.mobile-empty {
text-align: center;
padding: var(--space-xl);
color: var(--text-color-secondary);
}
.mobile-empty i {
font-size: var(--text-3xl);
margin-bottom: var(--space-sm);
display: block;
}
/* ================================================
US-108: Bottom Sheet Styles
================================================ */
.bottom-sheet-title {
font-size: var(--text-lg);
font-weight: var(--font-semibold);
color: var(--text-color);
margin: 0 0 var(--space-md) 0;
}
.bottom-sheet-filters {
display: flex;
flex-direction: column;
gap: var(--space-md);
}
.bottom-sheet-actions {
display: flex;
gap: var(--space-sm);
justify-content: flex-end;
margin-top: var(--space-md);
padding-top: var(--space-md);
border-top: 1px solid var(--surface-border);
}
/* ================================================
US-108: Mobile Sidebar Menu Styles
================================================ */
.sidebar-header {
padding: var(--space-md);
}
.sidebar-title {
font-size: var(--text-xl);
font-weight: var(--font-bold);
color: var(--text-color);
}
.sidebar-menu {
display: flex;
flex-direction: column;
padding: var(--space-sm);
}
.sidebar-item {
display: flex;
align-items: center;
gap: var(--space-md);
padding: var(--space-md);
color: var(--text-color);
text-decoration: none;
border-radius: var(--radius-md);
font-weight: var(--font-medium);
transition: background var(--transition-fast);
}
.sidebar-item:hover {
background: var(--surface-hover);
}
.sidebar-item.active {
background: var(--blue-50);
color: var(--color-primary);
}
.sidebar-item i {
font-size: var(--text-xl);
width: 24px;
text-align: center;
}
/* ================================================
Dark Mode Support
================================================ */
[data-theme="dark"] .sidebar-item.active {
background: var(--blue-900);
color: var(--blue-400);
}
/* Auto dark mode */
@media (prefers-color-scheme: dark) {
:root:not([data-theme]) .sidebar-item.active {
background: var(--blue-900);
color: var(--blue-400);
}
}
/* ================================================
Responsive Design
================================================ */
@media (max-width: 768px) {
.trial-balance {
padding: var(--space-md);