185 lines
5.4 KiB
TypeScript
185 lines
5.4 KiB
TypeScript
"use client";
|
|
|
|
import React, { useState, useEffect } from 'react';
|
|
import {
|
|
BarChart3,
|
|
MessageSquare,
|
|
Users,
|
|
ShoppingCart,
|
|
Package,
|
|
Settings,
|
|
Search,
|
|
Grid,
|
|
Bell,
|
|
Calendar,
|
|
LayoutDashboard,
|
|
Wallet,
|
|
Building2,
|
|
Cpu,
|
|
Utensils,
|
|
LogOut
|
|
} from 'lucide-react';
|
|
import Link from 'next/link';
|
|
import { useRouter } from 'next/navigation';
|
|
import { deleteCookie, getCookie } from 'cookies-next';
|
|
import styles from './page.module.css';
|
|
|
|
// Restaurant-focused modules only
|
|
const apps = [
|
|
{ id: 'restaurant', name: 'Restaurant', icon: <Utensils size={32} />, color: '#F1C40F' },
|
|
{ id: 'pos', name: 'POS', icon: <ShoppingCart size={32} />, color: '#27AE60' },
|
|
{ id: 'inventory', name: 'Inventory', icon: <Package size={32} />, color: '#786FA6' },
|
|
{ id: 'accounting', name: 'Accounting', icon: <Wallet size={32} />, color: '#546DE5' },
|
|
{ id: 'calendar', name: 'Calendar', icon: <Calendar size={32} />, color: '#017E84' },
|
|
{ id: 'settings', name: 'Settings', icon: <Settings size={32} />, color: '#7F8C8D' },
|
|
];
|
|
|
|
export default function Home() {
|
|
const [search, setSearch] = useState('');
|
|
const [user, setUser] = useState<{ id: string; name: string; role: string; email: string } | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const router = useRouter();
|
|
|
|
useEffect(() => {
|
|
const checkAuth = async () => {
|
|
const token = getCookie('auth_token');
|
|
if (!token) {
|
|
setUser(null);
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const res = await fetch('http://localhost:5000/api/auth/me', {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
const data = await res.json();
|
|
if (res.ok) {
|
|
setUser(data);
|
|
} else {
|
|
deleteCookie('auth_token');
|
|
setUser(null);
|
|
}
|
|
} catch (err) {
|
|
setUser(null);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
checkAuth();
|
|
}, []);
|
|
|
|
const handleLogout = () => {
|
|
deleteCookie('auth_token');
|
|
localStorage.removeItem('user');
|
|
setUser(null);
|
|
router.push('/auth/login');
|
|
};
|
|
|
|
const filteredApps = apps.filter(app => {
|
|
const matchesSearch = app.name.toLowerCase().includes(search.toLowerCase());
|
|
if (!matchesSearch) return false;
|
|
if (loading) return true;
|
|
if (!user) return true; // Show all for guests (landing page feel)
|
|
if (user.role === 'admin') return true;
|
|
|
|
const rolePermissions: Record<string, string[]> = {
|
|
'waiter': ['POS', 'Restaurant', 'Calendar'],
|
|
'cashier': ['POS', 'Accounting', 'Calendar'],
|
|
'manager': ['Restaurant', 'POS', 'Inventory', 'Accounting', 'Calendar', 'Settings'],
|
|
};
|
|
|
|
const allowedApps = rolePermissions[user.role as keyof typeof rolePermissions] || [];
|
|
return allowedApps.includes(app.name);
|
|
});
|
|
|
|
return (
|
|
<div className={styles.container}>
|
|
<div className={styles.bgGlow1} />
|
|
<div className={styles.bgGlow2} />
|
|
|
|
<header className={styles.header}>
|
|
<div className={styles.logoArea}>
|
|
{/* <div className={styles.logoIcon}>O</div> */}
|
|
<h1 className={styles.logoTitle}>Dine360</h1>
|
|
</div>
|
|
|
|
<div className={styles.searchWrapper}>
|
|
<Search className={styles.searchIcon} />
|
|
<input
|
|
type="text"
|
|
placeholder="Search your apps..."
|
|
className={styles.searchInput}
|
|
value={search}
|
|
onChange={(e) => setSearch(e.target.value)}
|
|
/>
|
|
</div>
|
|
|
|
<div className={styles.actions}>
|
|
<button className={styles.iconBtn}>
|
|
<Bell size={20} />
|
|
<div className={styles.badge} />
|
|
</button>
|
|
{user ? (
|
|
<div className={styles.userSection}>
|
|
<div className={styles.userAvatar} title={user.name}>
|
|
{user.name.substring(0, 2).toUpperCase()}
|
|
</div>
|
|
<button className={styles.logoutBtn} onClick={handleLogout} title="Logout">
|
|
<LogOut size={18} />
|
|
</button>
|
|
</div>
|
|
) : (
|
|
<Link href="/auth/login" className={styles.loginBtn}>Login</Link>
|
|
)}
|
|
</div>
|
|
</header>
|
|
|
|
<main className={styles.mainGrid}>
|
|
{filteredApps.map((app, index) => {
|
|
const content = (
|
|
<div
|
|
key={app.id}
|
|
className={styles.appItem}
|
|
style={{ animationDelay: `${index * 0.05}s` }}
|
|
>
|
|
<div
|
|
className={styles.appIconWrapper}
|
|
style={{
|
|
backgroundColor: app.color,
|
|
boxShadow: `0 12px 24px -8px ${app.color}60`
|
|
}}
|
|
>
|
|
{app.icon}
|
|
</div>
|
|
<span className={styles.appName}>{app.name}</span>
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<Link
|
|
key={app.id}
|
|
href={`/${app.id === 'employees' ? 'payroll' : app.id === 'discuss' ? 'dashboard' : app.id}`}
|
|
style={{ textDecoration: 'none' }}
|
|
>
|
|
{content}
|
|
</Link>
|
|
);
|
|
})}
|
|
</main>
|
|
|
|
<div className={styles.footerActions}>
|
|
<button className={styles.footerBtn} title="App Switcher">
|
|
<Grid size={24} />
|
|
</button>
|
|
<button className={styles.footerBtn} title="Home Dashboard">
|
|
<LayoutDashboard size={24} />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|