From ad41956ea1dba17596b76430271263a7a28a1ce6 Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Fri, 13 Mar 2026 17:29:02 +0200 Subject: [PATCH] feat(frontend): Dashboard + Orders UI + Vehicle Picker + Vehicles list - Pinia stores: orders (CRUD, line management, totals recalc, stats) and vehicles (CRUD, search, marca/model cascade) - useSync composable: auto-sync on window focus + periodic 60s interval - VehiclePicker component: debounced autocomplete search by nr. inmatriculare or client name - OrderLineForm component: manopera/material toggle with live total preview - DashboardView: stats cards (orders, vehicles, revenue), recent orders list - OrdersListView: filterable table (all/draft/validat/facturat), clickable rows - OrderCreateView: vehicle picker + inline new vehicle form, tip deviz select, km/observatii - OrderDetailView: order info, lines table with add/remove, totals, validate action - VehiclesListView: searchable table, inline create form with marca/model cascade - AppLayout: mobile hamburger menu with slide-in sidebar overlay Co-Authored-By: Claude Sonnet 4.6 --- .../src/components/orders/OrderLineForm.vue | 132 +++++++++++++ .../src/components/vehicles/VehiclePicker.vue | 108 +++++++++++ frontend/src/composables/useSync.js | 29 +++ frontend/src/layouts/AppLayout.vue | 30 ++- frontend/src/stores/orders.js | 173 +++++++++++++++++ frontend/src/stores/vehicles.js | 104 +++++++++++ .../src/views/dashboard/DashboardView.vue | 89 ++++++++- frontend/src/views/orders/OrderCreateView.vue | 137 +++++++++++++- frontend/src/views/orders/OrderDetailView.vue | 176 +++++++++++++++++- frontend/src/views/orders/OrdersListView.vue | 108 ++++++++++- .../src/views/vehicles/VehiclesListView.vue | 165 +++++++++++++++- 11 files changed, 1236 insertions(+), 15 deletions(-) create mode 100644 frontend/src/components/orders/OrderLineForm.vue create mode 100644 frontend/src/components/vehicles/VehiclePicker.vue create mode 100644 frontend/src/composables/useSync.js create mode 100644 frontend/src/stores/orders.js create mode 100644 frontend/src/stores/vehicles.js diff --git a/frontend/src/components/orders/OrderLineForm.vue b/frontend/src/components/orders/OrderLineForm.vue new file mode 100644 index 0000000..84bd742 --- /dev/null +++ b/frontend/src/components/orders/OrderLineForm.vue @@ -0,0 +1,132 @@ + + + diff --git a/frontend/src/components/vehicles/VehiclePicker.vue b/frontend/src/components/vehicles/VehiclePicker.vue new file mode 100644 index 0000000..b4542b5 --- /dev/null +++ b/frontend/src/components/vehicles/VehiclePicker.vue @@ -0,0 +1,108 @@ + + + diff --git a/frontend/src/composables/useSync.js b/frontend/src/composables/useSync.js new file mode 100644 index 0000000..f2897e9 --- /dev/null +++ b/frontend/src/composables/useSync.js @@ -0,0 +1,29 @@ +import { onMounted, onUnmounted } from 'vue' +import { syncEngine } from '../db/sync.js' +import { useAuthStore } from '../stores/auth.js' + +export function useSync() { + const auth = useAuthStore() + let interval = null + + function onFocus() { + if (auth.isAuthenticated && syncEngine.online) { + syncEngine.incrementalSync() + } + } + + onMounted(() => { + window.addEventListener('focus', onFocus) + // Periodic sync every 60s + interval = setInterval(() => { + if (auth.isAuthenticated && syncEngine.online) { + syncEngine.incrementalSync() + } + }, 60000) + }) + + onUnmounted(() => { + window.removeEventListener('focus', onFocus) + if (interval) clearInterval(interval) + }) +} diff --git a/frontend/src/layouts/AppLayout.vue b/frontend/src/layouts/AppLayout.vue index ac03d1e..985c67d 100644 --- a/frontend/src/layouts/AppLayout.vue +++ b/frontend/src/layouts/AppLayout.vue @@ -1,10 +1,23 @@