Merge version_2 into main #3
332
src/app/admin/page.tsx
Normal file
332
src/app/admin/page.tsx
Normal file
@@ -0,0 +1,332 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
import NavbarStyleCentered from '@/components/navbar/NavbarStyleCentered/NavbarStyleCentered';
|
||||
import FooterLogoEmphasis from '@/components/sections/footer/FooterLogoEmphasis';
|
||||
import HeroBillboardDashboard from '@/components/sections/hero/HeroBillboardDashboard';
|
||||
import { Settings, Clock, DollarSign, UtensilsCrossed, LogOut } from 'lucide-react';
|
||||
|
||||
export default function AdminPage() {
|
||||
const [activeTab, setActiveTab] = useState<'hours' | 'prices' | 'menu'>('hours');
|
||||
const [hours, setHours] = useState({
|
||||
monday: { open: 'Closed', close: '' },
|
||||
tuesday: { open: '11:00 AM', close: '9:00 PM' },
|
||||
wednesday: { open: '11:00 AM', close: '9:00 PM' },
|
||||
thursday: { open: '11:00 AM', close: '9:00 PM' },
|
||||
friday: { open: '11:00 AM', close: '9:30 PM' },
|
||||
saturday: { open: '9:00 AM', close: '9:00 PM' },
|
||||
sunday: { open: '11:00 AM', close: '9:00 PM' },
|
||||
});
|
||||
|
||||
const [prices, setPrices] = useState([
|
||||
{ id: 'camarones-diabla', name: 'Camarones a la Diabla', price: '24.00' },
|
||||
{ id: 'ceviche-pina', name: 'Ceviche en su Piña', price: '28.00' },
|
||||
{ id: 'molcajete-mixto', name: 'Molcajete Mixto', price: '38.99' },
|
||||
{ id: 'tacos-camarones', name: 'Tacos de Camarón', price: '20.00' },
|
||||
]);
|
||||
|
||||
const [menuItems, setMenuItems] = useState([
|
||||
{ id: '1', name: 'Camarones a la Diabla', description: 'Spicy deviled shrimp', available: true },
|
||||
{ id: '2', name: 'Ceviche en su Piña', description: 'Ceviche served in pineapple', available: true },
|
||||
{ id: '3', name: 'Molcajete Mixto', description: 'Mixed molcajete stone bowl', available: true },
|
||||
{ id: '4', name: 'Tacos de Camarón', description: 'Fresh shrimp tacos', available: true },
|
||||
]);
|
||||
|
||||
const [newItem, setNewItem] = useState({ name: '', description: '' });
|
||||
|
||||
const handleHourChange = (day: string, field: 'open' | 'close', value: string) => {
|
||||
setHours(prev => ({
|
||||
...prev,
|
||||
[day]: { ...prev[day as keyof typeof hours], [field]: value }
|
||||
}));
|
||||
};
|
||||
|
||||
const handlePriceChange = (id: string, price: string) => {
|
||||
setPrices(prev => prev.map(p => p.id === id ? { ...p, price } : p));
|
||||
};
|
||||
|
||||
const handleToggleMenuItem = (id: string) => {
|
||||
setMenuItems(prev => prev.map(item => item.id === id ? { ...item, available: !item.available } : item));
|
||||
};
|
||||
|
||||
const handleAddMenuItem = () => {
|
||||
if (newItem.name && newItem.description) {
|
||||
setMenuItems(prev => [...prev, { id: Date.now().toString(), name: newItem.name, description: newItem.description, available: true }]);
|
||||
setNewItem({ name: '', description: '' });
|
||||
}
|
||||
};
|
||||
|
||||
const dashboardData = {
|
||||
title: 'Admin Dashboard',
|
||||
stats: [
|
||||
{ label: 'Active Orders', value: '12', icon: Settings },
|
||||
{ label: 'Menu Items', value: String(menuItems.length), icon: UtensilsCrossed },
|
||||
{ label: 'Today\'s Revenue', value: '$1,240', icon: DollarSign }
|
||||
],
|
||||
logoIcon: Settings,
|
||||
sidebarItems: [
|
||||
{ label: 'Hours', icon: Clock, active: activeTab === 'hours' },
|
||||
{ label: 'Prices', icon: DollarSign, active: activeTab === 'prices' },
|
||||
{ label: 'Menu', icon: UtensilsCrossed, active: activeTab === 'menu' }
|
||||
],
|
||||
buttons: [
|
||||
{ text: 'Save Changes', onClick: () => alert('Changes saved!') },
|
||||
{ text: 'Preview', onClick: () => alert('Preview mode') }
|
||||
],
|
||||
listItems: [
|
||||
{ label: 'Settings', icon: Settings },
|
||||
{ label: 'Logout', icon: LogOut }
|
||||
],
|
||||
imageSrc: 'https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3Am2LJhLLWUokyhthLvKyFV0QpK/uploaded-1773512918447-hg7wldhe.png',
|
||||
searchPlaceholder: 'Search orders...',
|
||||
chartTitle: 'Weekly Revenue',
|
||||
chartData: [
|
||||
{ day: 'Mon', value: 450 },
|
||||
{ day: 'Tue', value: 520 },
|
||||
{ day: 'Wed', value: 480 },
|
||||
{ day: 'Thu', value: 610 },
|
||||
{ day: 'Fri', value: 890 },
|
||||
{ day: 'Sat', value: 1200 },
|
||||
{ day: 'Sun', value: 950 }
|
||||
],
|
||||
listTitle: 'Quick Actions'
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="elastic-effect"
|
||||
defaultTextAnimation="entrance-slide"
|
||||
borderRadius="pill"
|
||||
contentWidth="small"
|
||||
sizing="largeSizeMediumTitles"
|
||||
background="none"
|
||||
cardStyle="gradient-mesh"
|
||||
primaryButtonStyle="flat"
|
||||
secondaryButtonStyle="solid"
|
||||
headingFontWeight="extrabold"
|
||||
>
|
||||
<div id="nav" data-section="nav">
|
||||
<NavbarStyleCentered
|
||||
brandName="Mariscos Mi Tierra - Admin"
|
||||
navItems={[
|
||||
{ name: "Dashboard", id: "dashboard" },
|
||||
{ name: "Hours", id: "admin-hours" },
|
||||
{ name: "Menu", id: "admin" },
|
||||
{ name: "Prices", id: "admin-prices" }
|
||||
]}
|
||||
button={{ text: "Logout", href: "/" }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="hero" data-section="hero">
|
||||
<HeroBillboardDashboard
|
||||
title="Restaurant Management"
|
||||
description="Manage your restaurant's hours, prices, and menu items from one centralized dashboard."
|
||||
background={{ variant: "plain" }}
|
||||
dashboard={dashboardData}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="max-w-6xl mx-auto px-4 py-16">
|
||||
<div className="flex gap-8">
|
||||
{/* Sidebar Navigation */}
|
||||
<div className="w-48 flex flex-col gap-4">
|
||||
<button
|
||||
onClick={() => setActiveTab('hours')}
|
||||
className={`px-6 py-3 rounded-lg font-semibold transition-all ${
|
||||
activeTab === 'hours'
|
||||
? 'bg-primary-cta text-white'
|
||||
: 'bg-card text-foreground hover:bg-card/80'
|
||||
}`}
|
||||
>
|
||||
<Clock className="inline mr-2 w-4 h-4" />
|
||||
Operating Hours
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab('prices')}
|
||||
className={`px-6 py-3 rounded-lg font-semibold transition-all ${
|
||||
activeTab === 'prices'
|
||||
? 'bg-primary-cta text-white'
|
||||
: 'bg-card text-foreground hover:bg-card/80'
|
||||
}`}
|
||||
>
|
||||
<DollarSign className="inline mr-2 w-4 h-4" />
|
||||
Prices
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab('menu')}
|
||||
className={`px-6 py-3 rounded-lg font-semibold transition-all ${
|
||||
activeTab === 'menu'
|
||||
? 'bg-primary-cta text-white'
|
||||
: 'bg-card text-foreground hover:bg-card/80'
|
||||
}`}
|
||||
>
|
||||
<UtensilsCrossed className="inline mr-2 w-4 h-4" />
|
||||
Menu Items
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Main Content */}
|
||||
<div className="flex-1">
|
||||
{/* Operating Hours Tab */}
|
||||
{activeTab === 'hours' && (
|
||||
<div className="bg-card p-8 rounded-xl">
|
||||
<h2 className="text-3xl font-extrabold text-foreground mb-6">Operating Hours</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{Object.entries(hours).map(([day, times]) => (
|
||||
<div key={day} className="flex flex-col gap-3">
|
||||
<label className="text-lg font-semibold text-foreground capitalize">{day}</label>
|
||||
{day === 'monday' && times.open === 'Closed' ? (
|
||||
<div className="text-foreground/70 font-semibold">Closed</div>
|
||||
) : (
|
||||
<div className="flex gap-3">
|
||||
<input
|
||||
type="text"
|
||||
value={times.open}
|
||||
onChange={(e) => handleHourChange(day, 'open', e.target.value)}
|
||||
placeholder="Opening time"
|
||||
className="flex-1 px-4 py-2 bg-background border border-foreground/20 rounded-lg text-foreground"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={times.close}
|
||||
onChange={(e) => handleHourChange(day, 'close', e.target.value)}
|
||||
placeholder="Closing time"
|
||||
className="flex-1 px-4 py-2 bg-background border border-foreground/20 rounded-lg text-foreground"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button className="mt-8 px-8 py-3 bg-primary-cta text-white font-semibold rounded-lg hover:opacity-90 transition-all">
|
||||
Save Hours
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Prices Tab */}
|
||||
{activeTab === 'prices' && (
|
||||
<div className="bg-card p-8 rounded-xl">
|
||||
<h2 className="text-3xl font-extrabold text-foreground mb-6">Menu Prices</h2>
|
||||
<div className="space-y-4">
|
||||
{prices.map((item) => (
|
||||
<div key={item.id} className="flex items-center gap-4 p-4 bg-background rounded-lg">
|
||||
<div className="flex-1">
|
||||
<p className="font-semibold text-foreground">{item.name}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-foreground/70">$</span>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
value={item.price}
|
||||
onChange={(e) => handlePriceChange(item.id, e.target.value)}
|
||||
className="w-24 px-3 py-2 bg-card border border-foreground/20 rounded-lg text-foreground"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button className="mt-8 px-8 py-3 bg-primary-cta text-white font-semibold rounded-lg hover:opacity-90 transition-all">
|
||||
Save Prices
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Menu Items Tab */}
|
||||
{activeTab === 'menu' && (
|
||||
<div className="bg-card p-8 rounded-xl">
|
||||
<h2 className="text-3xl font-extrabold text-foreground mb-6">Menu Management</h2>
|
||||
|
||||
{/* Add New Item */}
|
||||
<div className="mb-8 p-6 bg-background rounded-lg border border-foreground/10">
|
||||
<h3 className="text-xl font-semibold text-foreground mb-4">Add New Item</h3>
|
||||
<div className="flex flex-col gap-4">
|
||||
<input
|
||||
type="text"
|
||||
value={newItem.name}
|
||||
onChange={(e) => setNewItem({ ...newItem, name: e.target.value })}
|
||||
placeholder="Item name"
|
||||
className="px-4 py-2 bg-card border border-foreground/20 rounded-lg text-foreground"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={newItem.description}
|
||||
onChange={(e) => setNewItem({ ...newItem, description: e.target.value })}
|
||||
placeholder="Item description"
|
||||
className="px-4 py-2 bg-card border border-foreground/20 rounded-lg text-foreground"
|
||||
/>
|
||||
<button
|
||||
onClick={handleAddMenuItem}
|
||||
className="px-6 py-2 bg-primary-cta text-white font-semibold rounded-lg hover:opacity-90 transition-all"
|
||||
>
|
||||
Add Item
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Menu Items List */}
|
||||
<div className="space-y-3">
|
||||
{menuItems.map((item) => (
|
||||
<div key={item.id} className="flex items-center justify-between p-4 bg-background rounded-lg">
|
||||
<div>
|
||||
<p className="font-semibold text-foreground">{item.name}</p>
|
||||
<p className="text-sm text-foreground/70">{item.description}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleToggleMenuItem(item.id)}
|
||||
className={`px-4 py-2 rounded-lg font-semibold transition-all ${
|
||||
item.available
|
||||
? 'bg-green-500/20 text-green-600 hover:bg-green-500/30'
|
||||
: 'bg-red-500/20 text-red-600 hover:bg-red-500/30'
|
||||
}`}
|
||||
>
|
||||
{item.available ? 'Available' : 'Unavailable'}
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button className="mt-8 px-8 py-3 bg-primary-cta text-white font-semibold rounded-lg hover:opacity-90 transition-all">
|
||||
Save Menu Changes
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer" data-section="footer">
|
||||
<FooterLogoEmphasis
|
||||
logoText="Mariscos Mi Tierra Admin"
|
||||
columns={[
|
||||
{
|
||||
items: [
|
||||
{ label: "Dashboard", href: "/admin" },
|
||||
{ label: "Settings", href: "#" },
|
||||
]
|
||||
},
|
||||
{
|
||||
items: [
|
||||
{ label: "Back to Main", href: "/" },
|
||||
{ label: "Help", href: "#" },
|
||||
]
|
||||
},
|
||||
{
|
||||
items: [
|
||||
{ label: "Terms", href: "#" },
|
||||
{ label: "Privacy", href: "#" },
|
||||
]
|
||||
},
|
||||
{
|
||||
items: [
|
||||
{ label: "Logout", href: "/" },
|
||||
]
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
@@ -279,7 +279,7 @@ export default function LandingPage() {
|
||||
items: [
|
||||
{ label: "Privacy Policy", href: "#" },
|
||||
{ label: "Terms of Service", href: "#" },
|
||||
{ label: "Contact", href: "tel:(509) 928-0513" }
|
||||
{ label: "Admin", href: "/admin" }
|
||||
]
|
||||
}
|
||||
]}
|
||||
@@ -291,4 +291,4 @@ export default function LandingPage() {
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -10,15 +10,15 @@
|
||||
--accent: #ffffff;
|
||||
--background-accent: #ffffff; */
|
||||
|
||||
--background: #f7f6f7;
|
||||
--card: #ffffff;
|
||||
--foreground: #25190c;
|
||||
--primary-cta: #ff6207;
|
||||
--primary-cta-text: #f7f6f7;
|
||||
--secondary-cta: #ffffff;
|
||||
--secondary-cta-text: #25190c;
|
||||
--accent: #ffce93;
|
||||
--background-accent: #e8cfa8;
|
||||
--background: #e8dcc4;
|
||||
--card: #f5f0e6;
|
||||
--foreground: #3d2817;
|
||||
--primary-cta: #a67c52;
|
||||
--primary-cta-text: #ffffff;
|
||||
--secondary-cta: #f5f0e6;
|
||||
--secondary-cta-text: #3d2817;
|
||||
--accent: #d4b896;
|
||||
--background-accent: #c9a876;
|
||||
|
||||
/* text sizing - set by ThemeProvider */
|
||||
/* --text-2xs: clamp(0.465rem, 0.62vw, 0.62rem);
|
||||
|
||||
Reference in New Issue
Block a user