Upload app/webui/app.html
This commit is contained in:
@@ -0,0 +1,145 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>CRM – Dashboard</title>
|
||||||
|
|
||||||
|
<!-- Tailwind CSS via CDN (Dev) -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<link rel="stylesheet" href="/css/app.css" />
|
||||||
|
|
||||||
|
<!-- Alpine.js -->
|
||||||
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.1/dist/cdn.min.js"></script>
|
||||||
|
|
||||||
|
<!-- App stores + dashboard component -->
|
||||||
|
<script type="module" src="/js/store.js"></script>
|
||||||
|
<script type="module" src="/js/components/notifications.js"></script>
|
||||||
|
<script type="module" src="/components/app-shell.js"></script>
|
||||||
|
<script type="module" src="/components/dashboard-kpis.js"></script>
|
||||||
|
</head>
|
||||||
|
<body class="min-h-screen bg-slate-50">
|
||||||
|
|
||||||
|
<!-- === TOAST CONTAINER === -->
|
||||||
|
<div x-data="toastContainer()" class="crm-toast-container" x-cloak>
|
||||||
|
<template x-for="n in items" :key="n.id">
|
||||||
|
<div class="crm-toast" :class="'toast-' + n.type"
|
||||||
|
@click="dismiss(n.id)" x-text="n.message"></div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- === LAYOUT SHELL === -->
|
||||||
|
<!-- Auth-Gate + appShell: store.js's init() redirects to /index.html when no JWT. -->
|
||||||
|
<div x-data="{ init: () => Alpine.store('auth').init() }" x-init="init()" class="flex min-h-screen">
|
||||||
|
<div x-data="appShell('dashboard')" x-cloak class="flex min-h-screen flex-1">
|
||||||
|
|
||||||
|
<!-- === SIDEBAR === -->
|
||||||
|
<aside class="crm-sidebar">
|
||||||
|
<div class="px-6 py-4 text-white text-lg font-bold border-b border-slate-700">
|
||||||
|
<a href="/app.html" class="!text-white !border-0">CRM</a>
|
||||||
|
</div>
|
||||||
|
<nav class="mt-2">
|
||||||
|
<a href="/app.html" :class="{ active: active === 'dashboard' }">Dashboard</a>
|
||||||
|
<a href="/accounts.html" :class="{ active: active === 'accounts' }">Accounts</a>
|
||||||
|
<a href="/contacts.html" :class="{ active: active === 'contacts' }">Contacts</a>
|
||||||
|
<a href="/pipeline.html" :class="{ active: active === 'pipeline' }">Pipeline</a>
|
||||||
|
<a href="/activities.html" :class="{ active: active === 'activities' }">Activities</a>
|
||||||
|
<a href="/settings-profile.html":class="{ active: active === 'settings-profile' }">Profil</a>
|
||||||
|
<a href="/settings-users.html" :class="{ active: active === 'settings-users' }"
|
||||||
|
x-show="$store.auth.isAdmin">Users (Admin)</a>
|
||||||
|
<a href="/settings-org.html" :class="{ active: active === 'settings-org' }"
|
||||||
|
x-show="$store.auth.isAdmin">Org (Admin)</a>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- === MAIN AREA === -->
|
||||||
|
<div class="flex-1 flex flex-col">
|
||||||
|
|
||||||
|
<!-- Top navigation -->
|
||||||
|
<header class="bg-white border-b border-slate-200 px-6 py-3 flex items-center justify-between">
|
||||||
|
<h1 class="text-xl font-semibold text-slate-800" x-text="title"></h1>
|
||||||
|
<div class="flex items-center gap-3 text-sm">
|
||||||
|
<span class="text-slate-600">
|
||||||
|
Angemeldet als
|
||||||
|
<strong class="text-slate-900"
|
||||||
|
x-text="$store.auth.user ? $store.auth.user.name : '…'"></strong>
|
||||||
|
</span>
|
||||||
|
<button class="btn-secondary" @click="logout()">Logout</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- === DASHBOARD CONTENT (default landing) === -->
|
||||||
|
<main class="flex-1 p-6" x-data="dashboardKpis()" x-init="init()">
|
||||||
|
|
||||||
|
<!-- Loading -->
|
||||||
|
<div x-show="loading" class="crm-card text-center py-8">
|
||||||
|
<div class="crm-spinner mx-auto"></div>
|
||||||
|
<p class="text-slate-500 mt-2 text-sm">Lade Dashboard …</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Error -->
|
||||||
|
<div x-show="error" class="crm-card text-red-700 bg-red-50">
|
||||||
|
<span x-text="error"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div x-show="!loading && !error">
|
||||||
|
|
||||||
|
<!-- KPI Grid -->
|
||||||
|
<h2 class="text-lg font-semibold mb-3">Kennzahlen</h2>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
||||||
|
<div class="crm-card">
|
||||||
|
<p class="text-xs text-slate-500">Open Deals</p>
|
||||||
|
<p class="text-2xl font-bold text-slate-900" x-text="kpis.open_deals ?? '–'"></p>
|
||||||
|
</div>
|
||||||
|
<div class="crm-card">
|
||||||
|
<p class="text-xs text-slate-500">Pipeline Value</p>
|
||||||
|
<p class="text-2xl font-bold text-slate-900"
|
||||||
|
x-text="formatCurrency(kpis.pipeline_value)"></p>
|
||||||
|
</div>
|
||||||
|
<div class="crm-card">
|
||||||
|
<p class="text-xs text-slate-500">Won this Month</p>
|
||||||
|
<p class="text-2xl font-bold text-slate-900" x-text="kpis.won_this_month ?? '–'"></p>
|
||||||
|
</div>
|
||||||
|
<div class="crm-card">
|
||||||
|
<p class="text-xs text-slate-500">Conversion Rate</p>
|
||||||
|
<p class="text-2xl font-bold text-slate-900"
|
||||||
|
x-text="formatPercent(kpis.conversion_rate)"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Quick actions -->
|
||||||
|
<h2 class="text-lg font-semibold mb-3">Schnellaktionen</h2>
|
||||||
|
<div class="flex gap-2 mb-6">
|
||||||
|
<a href="/accounts.html" class="btn-primary">+ New Account</a>
|
||||||
|
<a href="/contacts.html" class="btn-primary">+ New Contact</a>
|
||||||
|
<a href="/pipeline.html" class="btn-primary">+ New Deal</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Activity feed -->
|
||||||
|
<h2 class="text-lg font-semibold mb-3">Letzte Aktivitäten</h2>
|
||||||
|
<div class="crm-card">
|
||||||
|
<template x-for="a in feed" :key="a.id">
|
||||||
|
<div class="py-2 border-b border-slate-100 last:border-0">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<p class="text-sm">
|
||||||
|
<span class="crm-badge" :class="badgeColor(a.type)" x-text="a.type"></span>
|
||||||
|
<span class="ml-2 font-medium text-slate-800" x-text="a.subject"></span>
|
||||||
|
</p>
|
||||||
|
<span class="text-xs text-slate-400" x-text="formatRelative(a.created_at)"></span>
|
||||||
|
</div>
|
||||||
|
<p class="text-xs text-slate-500 mt-1" x-text="a.body || ''"></p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<p x-show="feed.length === 0" class="text-sm text-slate-500 text-center py-4">
|
||||||
|
Keine Aktivitäten.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user