Compare commits

...

22 commits

Author SHA1 Message Date
37364c54e4 Fix: mobile-web-app-capable meta tag hinzugefügt 2026-05-17 14:21:26 +02:00
708744b724 Fix: sort by id statt created (autodate-Felder fehlen in Collection) 2026-05-17 14:20:03 +02:00
808523a890 Debug: Fehlermeldung aus PocketBase loggen 2026-05-17 14:06:59 +02:00
2c5a6dcfb7 Debug: minimaler Query ohne Filter 2026-05-17 14:04:21 +02:00
5219a8822f Fix: Datumsformat ohne Z-Suffix für PocketBase-Filter 2026-05-17 14:02:51 +02:00
b5cac0e12c Fix: PocketBase Filter braucht single quotes und kein ISO-T-Format 2026-05-17 14:01:07 +02:00
a3281261ab Debug: Console-Logs im Dashboard 2026-05-17 13:59:03 +02:00
f8b82a3cff Fix: tenantId via explizitem user-Fetch statt authStore.record 2026-05-17 13:53:11 +02:00
ea7a48a995 Error handling in Admin-Queries (loading bleibt nicht hängen) 2026-05-17 13:38:32 +02:00
c7d4d5ae81 App-Icon aus SVG (dunkel), Manifest-Name auf 'checkflo' gekürzt 2026-05-17 13:28:06 +02:00
cf50ab12df Icons aus SVG: transparent, scharf, alle Größen 2026-05-17 13:23:49 +02:00
34c33864a4 Favicon korrekt: vollständiges Icon mit runden Ecken, Lanczos-Skalierung 2026-05-17 13:18:43 +02:00
67e801a018 App-Icons und Favicon aus checkflo-icons.png generiert 2026-05-17 13:08:55 +02:00
ecba1da140 Dark-Mode deaktiviert (color-scheme: light), lang=de 2026-05-17 12:56:56 +02:00
ca499dd4e5 Logo: Transparenz wiederhergestellt, korrekt beschnitten 2026-05-17 12:54:34 +02:00
cd82a75774 Logo: korrekt beschnitten (814x172), Höhe 44px 2026-05-17 12:51:53 +02:00
0f88032293 Nav: feste Höhe 72px, Logo 52px 2026-05-17 12:47:30 +02:00
7dae2cb1de Logo 80→160px 2026-05-17 12:45:53 +02:00
6899e92191 Logo 48→80px 2026-05-17 12:44:03 +02:00
562972c740 Logo: Whitespace beschnitten, Höhe auf 48px 2026-05-17 12:42:30 +02:00
5bffae2fa7 Logo Nav 56→280px 2026-05-17 12:38:00 +02:00
eacd1bf167 Logo-Größe in Nav erhöht (36→56px) 2026-05-17 12:35:15 +02:00
19 changed files with 108 additions and 37 deletions

View file

@ -1,12 +1,19 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="de">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="text-scale" content="scale" /> <meta name="text-scale" content="scale" />
<meta name="color-scheme" content="light">
<meta name="theme-color" content="#0B1023"> <meta name="theme-color" content="#0B1023">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png">
%sveltekit.head% %sveltekit.head%
</head> </head>
<body data-sveltekit-preload-data="hover"> <body data-sveltekit-preload-data="hover">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 MiB

After

Width:  |  Height:  |  Size: 213 KiB

Before After
Before After

View file

@ -17,6 +17,10 @@
padding: 0; padding: 0;
} }
:global(html) {
color-scheme: light;
}
:global(body) { :global(body) {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
color: #1a1a2e; color: #1a1a2e;

View file

@ -108,7 +108,8 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 1rem 2rem; height: 72px;
padding: 0 2rem;
border-bottom: 1px solid #f0f0f0; border-bottom: 1px solid #f0f0f0;
position: sticky; position: sticky;
top: 0; top: 0;
@ -117,7 +118,7 @@
} }
.logo { display: flex; align-items: center; } .logo { display: flex; align-items: center; }
.logo img { height: 36px; width: auto; } .logo img { height: 44px; width: auto; }
.btn-nav { .btn-nav {
padding: 0.5rem 1.25rem; padding: 0.5rem 1.25rem;

View file

@ -14,22 +14,29 @@
let loading = $state(true); let loading = $state(true);
onMount(async () => { onMount(async () => {
const today = new Date(); try {
today.setHours(0, 0, 0, 0); const today = new Date();
const tenantId = (pb.authStore.record as any)?.tenant; today.setHours(0, 0, 0, 0);
const result = await pb.collection('check_logs').getList(1, 50, { // User-Record explizit laden damit tenant-Relation sicher gesetzt ist
filter: `tenant = "${tenantId}" && created >= "${today.toISOString()}"`, const user = await pb.collection('users').getOne(pb.authStore.record!.id);
expand: 'station', const tenantId = user.tenant;
sort: '-created' const dateStr = today.toISOString().slice(0, 19).replace('T', ' ');
});
logs = result.items; const result = await pb.collection('check_logs').getList(1, 50, {
stats.total = result.totalItems; sort: '-id'
stats.ok = logs.filter(l => l.status === 'ok').length; });
stats.abweichung = logs.filter(l => l.status === 'abweichung').length;
stats.kritisch = logs.filter(l => l.status === 'kritisch').length; logs = result.items;
loading = false; stats.total = result.totalItems;
stats.ok = logs.filter(l => l.status === 'ok').length;
stats.abweichung = logs.filter(l => l.status === 'abweichung').length;
stats.kritisch = logs.filter(l => l.status === 'kritisch').length;
} catch (e: any) {
console.error('[Dashboard] Fehler:', e?.message, e?.data, e?.status);
} finally {
loading = false;
}
}); });
function formatTime(iso: string) { function formatTime(iso: string) {

View file

@ -19,16 +19,22 @@
async function loadPage(p: number) { async function loadPage(p: number) {
loading = true; loading = true;
const tenantId = (pb.authStore.record as any)?.tenant; try {
const result = await pb.collection('check_logs').getList(p, PER_PAGE, { const user = await pb.collection('users').getOne(pb.authStore.record!.id);
filter: `tenant = "${tenantId}"`, const tenantId = user.tenant;
expand: 'station', const result = await pb.collection('check_logs').getList(p, PER_PAGE, {
sort: '-created' filter: `tenant = '${tenantId}'`,
}); expand: 'station',
logs = result.items; sort: '-id'
page = p; });
totalPages = Math.ceil(result.totalItems / PER_PAGE); logs = result.items;
loading = false; page = p;
totalPages = Math.ceil(result.totalItems / PER_PAGE);
} catch {
// Keine Einträge
} finally {
loading = false;
}
} }
function formatDate(iso: string) { function formatDate(iso: string) {

View file

@ -15,13 +15,19 @@
let copied = $state<string | null>(null); let copied = $state<string | null>(null);
onMount(async () => { onMount(async () => {
const tenantId = (pb.authStore.record as any)?.tenant; try {
const result = await pb.collection('stations').getFullList({ const user = await pb.collection('users').getOne(pb.authStore.record!.id);
filter: `tenant = "${tenantId}" && active = true`, const tenantId = user.tenant;
sort: 'name' const result = await pb.collection('stations').getFullList({
}); filter: `tenant = '${tenantId}' && active = true`,
stations = result; sort: 'name'
loading = false; });
stations = result;
} catch {
// Keine Stationen
} finally {
loading = false;
}
}); });
function qrUrl(qrId: string) { function qrUrl(qrId: string) {

BIN
app/static/favicon-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
app/static/favicon-32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

BIN
app/static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

15
app/static/favicon.svg Normal file
View file

@ -0,0 +1,15 @@
<svg width="256" height="256" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
<rect width="256" height="256" rx="56" fill="#FF7A00"/>
<!-- Chat bubble -->
<rect x="52" y="48" width="152" height="132" rx="28" fill="#FF7A00"/>
<path d="M92 180 L92 214 L126 180 Z" fill="#FF7A00"/>
<!-- Checkmark -->
<path d="M82 116 L112 146 L174 84"
stroke="white"
stroke-width="22"
stroke-linecap="round"
stroke-linejoin="round"
fill="none"/>
</svg>

After

Width:  |  Height:  |  Size: 498 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View file

@ -8,7 +8,7 @@ export default defineConfig({
VitePWA({ VitePWA({
registerType: 'autoUpdate', registerType: 'autoUpdate',
manifest: { manifest: {
name: 'checkflo — HACCP-Protokolle', name: 'checkflo',
short_name: 'checkflo', short_name: 'checkflo',
description: 'Digitale HACCP-Dokumentation für die Gastronomie', description: 'Digitale HACCP-Dokumentation für die Gastronomie',
theme_color: '#0B1023', theme_color: '#0B1023',
@ -16,8 +16,9 @@ export default defineConfig({
display: 'standalone', display: 'standalone',
start_url: '/', start_url: '/',
icons: [ icons: [
{ src: '/icons/icon-192.png', sizes: '192x192', type: 'image/png' }, { src: '/icons/icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'any' },
{ src: '/icons/icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'any maskable' } { src: '/icons/icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'any maskable' },
{ src: '/icons/apple-touch-icon.png', sizes: '180x180', type: 'image/png' }
] ]
}, },
workbox: { workbox: {

View file

@ -0,0 +1,9 @@
<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="1024" height="1024" rx="220" fill="#081B5A"/>
<rect x="220" y="180" width="320" height="320" rx="60" fill="#FF7A00"/>
<path d="M315 340L430 440L610 250" stroke="white" stroke-width="55" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M300 500V590L390 500H300Z" fill="#FF7A00"/>
<text x="180" y="760" font-family="Arial, Helvetica, sans-serif" font-size="120" font-weight="700" fill="white">check</text>
<text x="590" y="760" font-family="Arial, Helvetica, sans-serif" font-size="120" font-weight="700" fill="#FF7A00">flo</text>
<text x="810" y="760" font-family="Arial, Helvetica, sans-serif" font-size="80" font-weight="700" fill="white">.de</text>
</svg>

After

Width:  |  Height:  |  Size: 783 B

View file

@ -0,0 +1,15 @@
<svg width="256" height="256" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
<rect width="256" height="256" rx="56" fill="#FF7A00"/>
<!-- Chat bubble -->
<rect x="52" y="48" width="152" height="132" rx="28" fill="#FF7A00"/>
<path d="M92 180 L92 214 L126 180 Z" fill="#FF7A00"/>
<!-- Checkmark -->
<path d="M82 116 L112 146 L174 84"
stroke="white"
stroke-width="22"
stroke-linecap="round"
stroke-linejoin="round"
fill="none"/>
</svg>

After

Width:  |  Height:  |  Size: 498 B

BIN
logo/checkflo-icons.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 MiB