Compare commits

..

2 Commits

Author SHA1 Message Date
DanielS
1b4e998cf9 feat: add admin settings page with toggle switch for demo banner
All checks were successful
Staging Build / build (push) Successful in 2m16s
2026-06-23 23:43:22 +02:00
DanielS
a99adb88d6 feat: update navbar links, settings labels, dark mode text color, and banner toggle hook 2026-06-23 23:43:16 +02:00
4 changed files with 97 additions and 3 deletions

View File

@@ -0,0 +1,33 @@
'use client';
import { useState, useEffect } from 'react';
import { Switch } from '@/components/ui/switch';
export default function AdminSettings() {
const [demoActive, setDemoActive] = useState(true);
useEffect(() => {
const state = localStorage.getItem('demo_banner_disabled') !== 'true';
setDemoActive(state);
}, []);
const toggleDemo = (checked: boolean) => {
setDemoActive(checked);
localStorage.setItem('demo_banner_disabled', (!checked).toString());
// Event feuern, damit andere Tabs/Komponenten sofort updaten
window.dispatchEvent(new Event('storage_demo_changed'));
};
return (
<div className="p-6 max-w-xl mx-auto text-slate-900 dark:text-white">
<h1 className="text-2xl font-bold mb-6">Admin Einstellungen</h1>
<div className="flex items-center justify-between p-4 bg-slate-100 dark:bg-white/5 rounded-xl border border-slate-200 dark:border-white/10">
<div>
<p className="font-medium text-slate-900 dark:text-white">Demo-Warnmeldungen</p>
<p className="text-xs text-slate-500 dark:text-slate-400">Schaltet gelbe Banner ein oder aus.</p>
</div>
<Switch checked={demoActive} onCheckedChange={toggleDemo} />
</div>
</div>
);
}

View File

@@ -7,7 +7,7 @@ export default function Home() {
return ( return (
<div className="flex flex-col min-h-screen bg-slate-50 text-slate-900 dark:bg-[#020617] dark:text-white"> <div className="flex flex-col min-h-screen bg-slate-50 text-slate-900 dark:bg-[#020617] dark:text-white">
{/* Demo Banner */} {/* Demo Banner */}
<div className="bg-amber-500/10 border-b border-amber-500/20 py-2 px-4 text-center text-xs text-amber-600 dark:text-amber-400 font-medium tracking-wide z-50"> <div id="demo-banner" className="bg-amber-500/10 border-b border-amber-500/20 py-2 px-4 text-center text-xs text-amber-600 dark:text-amber-400 font-medium tracking-wide z-50">
Dies ist eine **Demo-Webseite (Dummy-Shop)**. Es werden keine echten Bestellungen verarbeitet oder Zahlungen abgewickelt. Dies ist eine **Demo-Webseite (Dummy-Shop)**. Es werden keine echten Bestellungen verarbeitet oder Zahlungen abgewickelt.
</div> </div>
@@ -24,7 +24,7 @@ export default function Home() {
CASPOS Lizenz-Management-Server CASPOS Lizenz-Management-Server
</div> </div>
<h1 className="text-3xl font-bold tracking-tighter sm:text-4xl md:text-5xl lg:text-7xl/none"> <h1 className="text-3xl font-bold tracking-tighter sm:text-4xl md:text-5xl lg:text-7xl/none">
POS Software <span className="text-blue-600 dark:text-blue-500">Lizenzen & Add-ons</span> POS Software <span className="text-blue-600 dark:text-blue-500">Lizenzen & Module</span>
</h1> </h1>
<p className="mx-auto max-w-[700px] text-slate-600 dark:text-slate-400 md:text-xl mt-6"> <p className="mx-auto max-w-[700px] text-slate-600 dark:text-slate-400 md:text-xl mt-6">
Erwerben und verwalten Sie digitale Lizenzen für CASPOS Kassensysteme. Sofortige Aktivierung und automatische Bereitstellung für Ihre Kunden. Erwerben und verwalten Sie digitale Lizenzen für CASPOS Kassensysteme. Sofortige Aktivierung und automatische Bereitstellung für Ihre Kunden.

View File

@@ -62,6 +62,18 @@ export function NavbarClient({ user }: NavbarClientProps) {
}; };
}, [supabase]); }, [supabase]);
useEffect(() => {
const checkBanner = () => {
const disabled = localStorage.getItem('demo_banner_disabled') === 'true';
const banner = document.getElementById('demo-banner');
if (banner) banner.style.display = disabled ? 'none' : 'block';
};
checkBanner();
window.addEventListener('storage_demo_changed', checkBanner);
return () => window.removeEventListener('storage_demo_changed', checkBanner);
}, []);
const handleSignOut = async () => { const handleSignOut = async () => {
await supabase.auth.signOut(); await supabase.auth.signOut();
setCurrentUser(null); setCurrentUser(null);
@@ -119,12 +131,19 @@ export function NavbarClient({ user }: NavbarClientProps) {
<div className="px-3 py-1.5 text-[11px] truncate border-b text-slate-400 border-slate-100 dark:border-white/5 mb-1"> <div className="px-3 py-1.5 text-[11px] truncate border-b text-slate-400 border-slate-100 dark:border-white/5 mb-1">
{currentUser.email} {currentUser.email}
</div> </div>
<Link
href="/account-kunden"
onClick={() => setOpen(false)}
className="block px-3 py-2 text-sm rounded-lg font-medium hover:bg-slate-100 dark:hover:bg-white/5"
>
Account Einstellungen
</Link>
<Link <Link
href="/my-customers" href="/my-customers"
onClick={() => setOpen(false)} onClick={() => setOpen(false)}
className="block px-3 py-2 text-sm rounded-lg font-medium hover:bg-slate-100 dark:hover:bg-white/5" className="block px-3 py-2 text-sm rounded-lg font-medium hover:bg-slate-100 dark:hover:bg-white/5"
> >
Account Kunden Kundenliste
</Link> </Link>
<hr className="my-1 border-slate-100 dark:border-white/5" /> <hr className="my-1 border-slate-100 dark:border-white/5" />
<button <button
@@ -135,6 +154,7 @@ export function NavbarClient({ user }: NavbarClientProps) {
</button> </button>
</div> </div>
)} )}
</div> </div>
) : ( ) : (
<Button asChild className="bg-primary hover:bg-primary/95 text-white dark:text-blue-500"> <Button asChild className="bg-primary hover:bg-primary/95 text-white dark:text-blue-500">

View File

@@ -0,0 +1,41 @@
"use client";
import * as React from "react";
import { cn } from "@/lib/utils";
interface SwitchProps extends React.InputHTMLAttributes<HTMLInputElement> {
checked?: boolean;
onCheckedChange?: (checked: boolean) => void;
}
const Switch = React.forwardRef<HTMLInputElement, SwitchProps>(
({ className, checked, onCheckedChange, ...props }, ref) => {
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
onCheckedChange?.(e.target.checked);
};
return (
<label className="relative inline-flex items-center cursor-pointer select-none">
<input
type="checkbox"
className="sr-only peer"
checked={checked}
onChange={handleChange}
ref={ref}
{...props}
/>
<div className={cn(
"w-11 h-6 bg-slate-200 rounded-full peer dark:bg-slate-700",
"peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-blue-500/50",
"peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white",
"after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-slate-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-slate-600",
"peer-checked:bg-blue-600"
)} />
</label>
);
}
);
Switch.displayName = "Switch";
export { Switch };