feat(frontend): Vue 3 + wa-sqlite + sync engine + auth + layouts

- package.json with Vue 3, Pinia, vue-router, wa-sqlite, Tailwind CSS 4, Vite
- wa-sqlite database layer with IDBBatchAtomicVFS (offline-first)
- Full schema mirroring backend tables (vehicles, orders, invoices, etc.)
- SyncEngine: fullSync, incrementalSync, pushQueue for offline queue
- Auth store with JWT parsing, login/register, plan tier detection
- Router with all routes and auth navigation guards
- AppLayout (sidebar desktop / bottom nav mobile) + AuthLayout
- Login/Register views connected to API contract
- SyncIndicator component (online/offline status)
- Reactive SQL query composable (useSqlQuery)
- Placeholder views for dashboard, orders, vehicles, appointments, catalog, settings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 17:22:50 +02:00
parent a16d01a669
commit c3482bba8d
27 changed files with 7614 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
<template>
<div class="min-h-screen bg-gray-50">
<!-- Desktop sidebar -->
<aside class="hidden md:fixed md:inset-y-0 md:flex md:w-56 md:flex-col">
<div class="flex flex-col flex-grow bg-gray-900 overflow-y-auto">
<div class="px-4 py-5">
<h1 class="text-xl font-bold text-white">ROA AUTO</h1>
</div>
<nav class="flex-1 px-2 space-y-1">
<router-link
v-for="item in navItems"
:key="item.path"
:to="item.path"
class="flex items-center px-3 py-2 text-sm font-medium rounded-md text-gray-300 hover:bg-gray-800 hover:text-white"
active-class="!bg-gray-800 !text-white"
>
{{ item.label }}
</router-link>
</nav>
<div class="px-4 py-3 border-t border-gray-700">
<SyncIndicator />
<button
@click="logout"
class="mt-2 w-full text-left text-sm text-gray-400 hover:text-white"
>
Deconectare
</button>
</div>
</div>
</aside>
<!-- Main content -->
<div class="md:pl-56">
<!-- Mobile header -->
<header class="md:hidden bg-white border-b border-gray-200 px-4 py-3 flex items-center justify-between">
<h1 class="text-lg font-bold text-gray-900">ROA AUTO</h1>
<SyncIndicator />
</header>
<main class="p-4 md:p-6">
<slot />
</main>
<!-- Mobile bottom nav -->
<nav class="md:hidden fixed bottom-0 inset-x-0 bg-white border-t border-gray-200 flex">
<router-link
v-for="item in mobileNavItems"
:key="item.path"
:to="item.path"
class="flex-1 flex flex-col items-center py-2 text-xs text-gray-500"
active-class="!text-blue-600"
>
{{ item.label }}
</router-link>
</nav>
</div>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
import { useAuthStore } from '../stores/auth.js'
import SyncIndicator from '../components/common/SyncIndicator.vue'
const router = useRouter()
const auth = useAuthStore()
const navItems = [
{ path: '/dashboard', label: 'Dashboard' },
{ path: '/orders', label: 'Comenzi' },
{ path: '/vehicles', label: 'Vehicule' },
{ path: '/appointments', label: 'Programari' },
{ path: '/catalog', label: 'Catalog' },
{ path: '/settings', label: 'Setari' },
]
const mobileNavItems = [
{ path: '/dashboard', label: 'Acasa' },
{ path: '/orders', label: 'Comenzi' },
{ path: '/vehicles', label: 'Vehicule' },
{ path: '/appointments', label: 'Programari' },
{ path: '/settings', label: 'Setari' },
]
function logout() {
auth.logout()
router.push('/login')
}
</script>