698 lines
19 KiB
TypeScript
698 lines
19 KiB
TypeScript
import type {
|
||
Combo,
|
||
Department,
|
||
MenuCategory,
|
||
Product,
|
||
ProductSalesStats,
|
||
RevenueDataPoint,
|
||
ShiftSlot,
|
||
Shop,
|
||
ShopInfo,
|
||
SocialLinks,
|
||
User,
|
||
} from "./types";
|
||
|
||
// ===== SHOP INFORMATION =====
|
||
export const SHOP_INFO: ShopInfo = {
|
||
name: "Coffee Shop",
|
||
tagline: "Rich Flavors – Moments of Relaxation",
|
||
logo: "/imgs/logo.png",
|
||
address: "123 Nguyen Hue Street, District 1, Ho Chi Minh City",
|
||
phone: "0901 234 567",
|
||
managerPhone: "0912 345 678",
|
||
email: "contact@coffeeshop.vn",
|
||
wifi: {
|
||
name: "CoffeeShop_Free",
|
||
password: "coffee2024",
|
||
},
|
||
openHours: "07:00 – 22:00 (Monday – Sunday)",
|
||
};
|
||
|
||
// ===== SOCIAL LINKS =====
|
||
export const SOCIAL_LINKS: SocialLinks = {
|
||
facebook: "https://facebook.com/coffeeshop",
|
||
tiktok: "https://tiktok.com/@coffeeshop",
|
||
website: "/",
|
||
};
|
||
|
||
// ===== MENU CATEGORIES =====
|
||
// Each category has a unique FontAwesome icon representing the item type
|
||
export const MENU_CATEGORIES: MenuCategory[] = [
|
||
{ id: "all", name: "All", icon: "fa-solid fa-border-all" },
|
||
{ id: "cafe", name: "Coffee", icon: "fa-solid fa-mug-hot" },
|
||
{ id: "tra", name: "Tea", icon: "fa-solid fa-leaf" },
|
||
{ id: "sua-chua", name: "Yogurt", icon: "fa-solid fa-jar" },
|
||
{ id: "nuoc-ep", name: "Juice", icon: "fa-solid fa-blender" },
|
||
{ id: "latte", name: "Latte", icon: "fa-solid fa-mug-saucer" },
|
||
{
|
||
id: "giai-khat",
|
||
name: "Refreshments / Snacks",
|
||
icon: "fa-solid fa-ice-cream",
|
||
},
|
||
{ id: "topping", name: "Topping", icon: "fa-solid fa-layer-group" },
|
||
];
|
||
|
||
// ===== MOCK PRODUCTS =====
|
||
// Placeholder data – replace with real API calls when backend is ready
|
||
export const MOCK_PRODUCTS: Product[] = [
|
||
{
|
||
id: 1,
|
||
name: "Black Coffee",
|
||
category: "cafe",
|
||
price: 25000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Traditional Vietnamese black coffee, rich and bold, brewed by hand with a phin filter.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 2,
|
||
name: "Milk Coffee",
|
||
category: "cafe",
|
||
price: 30000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Aromatic condensed milk coffee, rich and creamy — a perfect blend of strong coffee and sweet condensed milk.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 3,
|
||
name: "White Coffee",
|
||
category: "cafe",
|
||
price: 32000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Light and mild, with less coffee and more milk — perfect for those just starting to enjoy coffee.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 4,
|
||
name: "Egg Coffee",
|
||
category: "cafe",
|
||
price: 45000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"A Hanoi specialty — smooth, velvety egg cream layered over a bold coffee base.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 5,
|
||
name: "Peach Orange Lemongrass Tea",
|
||
category: "tra",
|
||
price: 35000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Fragrant peach tea with fresh orange and lemongrass — refreshing and wonderfully cooling.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 6,
|
||
name: "Matcha Green Tea",
|
||
category: "tra",
|
||
price: 40000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Pure Japanese matcha with a signature light bitterness — aromatic, refreshing, and nutritious.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 7,
|
||
name: "Lychee Jasmine Tea",
|
||
category: "tra",
|
||
price: 38000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Sweet lychee tea delicately infused with jasmine blossom — a calming and soulful sip.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 8,
|
||
name: "Yogurt with Tapioca Pearls",
|
||
category: "sua-chua",
|
||
price: 38000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Smooth, creamy yogurt paired with chewy black tapioca pearls — a perfectly balanced sweet and tangy treat.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 9,
|
||
name: "Strawberry Yogurt",
|
||
category: "sua-chua",
|
||
price: 40000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Chilled yogurt with fresh sweet-tart strawberries, packed with vitamins and minerals.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 10,
|
||
name: "Fresh Orange Juice",
|
||
category: "nuoc-ep",
|
||
price: 35000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"100% freshly squeezed orange juice, rich in vitamin C and great for your health.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 11,
|
||
name: "Watermelon Juice",
|
||
category: "nuoc-ep",
|
||
price: 30000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Ice-cold watermelon juice — instantly refreshing on hot summer days.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 12,
|
||
name: "Caramel Latte",
|
||
category: "latte",
|
||
price: 45000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Sweet and indulgent caramel latte with a velvety milk foam topping and a drizzle of caramel sauce.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 13,
|
||
name: "Vanilla Latte",
|
||
category: "latte",
|
||
price: 45000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Smooth and gentle vanilla latte with a delicate natural vanilla fragrance.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 14,
|
||
name: "Toasted Butter Bread",
|
||
category: "giai-khat",
|
||
price: 20000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Crispy toasted bread spread with fragrant butter and strawberry jam — the perfect coffee companion.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 15,
|
||
name: "Caramel Flan",
|
||
category: "giai-khat",
|
||
price: 25000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Silky smooth flan with a golden caramel topping that melts in your mouth.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 16,
|
||
name: "Black Tapioca Pearls",
|
||
category: "topping",
|
||
price: 10000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Chewy black tapioca pearls — add them to any drink for extra flavor and texture.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 17,
|
||
name: "Coffee Jelly",
|
||
category: "topping",
|
||
price: 10000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Cool coffee jelly that adds a distinctive flavor boost to your drink.",
|
||
available: true,
|
||
},
|
||
{
|
||
id: 18,
|
||
name: "White Tapioca Pearls",
|
||
category: "topping",
|
||
price: 10000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
description:
|
||
"Chewy white tapioca pearls — add them to any drink for extra flavor and texture.",
|
||
available: true,
|
||
},
|
||
];
|
||
|
||
// ===== MOCK COMBOS =====
|
||
export const MOCK_COMBOS: Combo[] = [
|
||
{
|
||
id: 1,
|
||
name: "Double Coffee Combo",
|
||
description: "2 black coffees + 2 toasted butter breads, save 15%.",
|
||
price: 75000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
items: [
|
||
{ productId: 1, quantity: 2 },
|
||
{ productId: 14, quantity: 2 },
|
||
],
|
||
available: true,
|
||
},
|
||
{
|
||
id: 2,
|
||
name: "Group Tea Combo",
|
||
description:
|
||
"2 peach orange lemongrass teas + 2 matcha green teas, perfect for a group.",
|
||
price: 130000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
items: [
|
||
{ productId: 5, quantity: 2 },
|
||
{ productId: 6, quantity: 2 },
|
||
],
|
||
available: true,
|
||
},
|
||
{
|
||
id: 3,
|
||
name: "Morning Combo",
|
||
description:
|
||
"1 milk coffee + 1 caramel flan — start your day on a sweet note.",
|
||
price: 48000,
|
||
image: "/imgs/products/placeholder.jpg",
|
||
items: [
|
||
{ productId: 2, quantity: 1 },
|
||
{ productId: 15, quantity: 1 },
|
||
],
|
||
available: false,
|
||
},
|
||
];
|
||
|
||
// ===== MOCK SHOPS (for Feed page) =====
|
||
export const MOCK_SHOPS: Shop[] = [
|
||
{
|
||
id: 1,
|
||
name: "The Coffee House",
|
||
address: "86 Cao Thắng, Quận 3, TP. Hồ Chí Minh",
|
||
image:
|
||
"https://images.unsplash.com/photo-1554118811-1e0d58224f24?w=600&h=400&fit=crop",
|
||
},
|
||
{
|
||
id: 2,
|
||
name: "Highlands Coffee",
|
||
address: "123 Nguyễn Huệ, Quận 1, TP. Hồ Chí Minh",
|
||
image:
|
||
"https://images.unsplash.com/photo-1559305616-3f99cd43e353?w=600&h=400&fit=crop",
|
||
},
|
||
{
|
||
id: 3,
|
||
name: "Phúc Long Heritage",
|
||
address: "42 Lê Lợi, Quận 1, TP. Hồ Chí Minh",
|
||
image:
|
||
"https://images.unsplash.com/photo-1501339847302-ac426a4a7cbb?w=600&h=400&fit=crop",
|
||
},
|
||
{
|
||
id: 4,
|
||
name: "Katinat Saigon Kafe",
|
||
address: "26 Lý Tự Trọng, Quận 1, TP. Hồ Chí Minh",
|
||
image:
|
||
"https://images.unsplash.com/photo-1495474472287-4d71bcdd2085?w=600&h=400&fit=crop",
|
||
},
|
||
{
|
||
id: 5,
|
||
name: "Trung Nguyên E-Coffee",
|
||
address: "15 Hai Bà Trưng, Quận 1, TP. Hồ Chí Minh",
|
||
image:
|
||
"https://images.unsplash.com/photo-1453614512568-c4024d13c247?w=600&h=400&fit=crop",
|
||
},
|
||
];
|
||
|
||
// ===== MOCK FINANCIAL DATA =====
|
||
|
||
// Daily revenue for the last 30 days (current month)
|
||
export const MOCK_REVENUE_DAILY: RevenueDataPoint[] = [
|
||
{ label: "01/04", revenue: 1250000, orders: 42 },
|
||
{ label: "02/04", revenue: 980000, orders: 35 },
|
||
{ label: "03/04", revenue: 1540000, orders: 55 },
|
||
{ label: "04/04", revenue: 1120000, orders: 40 },
|
||
{ label: "05/04", revenue: 1890000, orders: 68 },
|
||
{ label: "06/04", revenue: 2100000, orders: 74 },
|
||
{ label: "07/04", revenue: 2350000, orders: 82 },
|
||
{ label: "08/04", revenue: 1680000, orders: 60 },
|
||
{ label: "09/04", revenue: 1430000, orders: 50 },
|
||
{ label: "10/04", revenue: 1750000, orders: 63 },
|
||
{ label: "11/04", revenue: 1560000, orders: 56 },
|
||
{ label: "12/04", revenue: 1920000, orders: 70 },
|
||
{ label: "13/04", revenue: 2230000, orders: 80 },
|
||
{ label: "14/04", revenue: 2480000, orders: 90 },
|
||
{ label: "15/04", revenue: 1870000, orders: 66 },
|
||
{ label: "16/04", revenue: 1340000, orders: 48 },
|
||
{ label: "17/04", revenue: 1610000, orders: 58 },
|
||
{ label: "18/04", revenue: 1490000, orders: 53 },
|
||
{ label: "19/04", revenue: 1970000, orders: 71 },
|
||
{ label: "20/04", revenue: 2140000, orders: 77 },
|
||
{ label: "21/04", revenue: 2560000, orders: 93 },
|
||
{ label: "22/04", revenue: 1780000, orders: 64 },
|
||
{ label: "23/04", revenue: 1520000, orders: 54 },
|
||
{ label: "24/04", revenue: 1840000, orders: 66 },
|
||
{ label: "25/04", revenue: 1660000, orders: 60 },
|
||
{ label: "26/04", revenue: 2050000, orders: 74 },
|
||
{ label: "27/04", revenue: 2280000, orders: 82 },
|
||
{ label: "28/04", revenue: 2490000, orders: 89 },
|
||
{ label: "29/04", revenue: 1950000, orders: 70 },
|
||
{ label: "30/04", revenue: 1720000, orders: 62 },
|
||
];
|
||
|
||
// Weekly revenue (last 12 weeks)
|
||
export const MOCK_REVENUE_WEEKLY: RevenueDataPoint[] = [
|
||
{ label: "Jan/W1", revenue: 8200000, orders: 295 },
|
||
{ label: "Jan/W2", revenue: 9450000, orders: 340 },
|
||
{ label: "Jan/W3", revenue: 10100000, orders: 362 },
|
||
{ label: "Jan/W4", revenue: 8750000, orders: 315 },
|
||
{ label: "Feb/W1", revenue: 9200000, orders: 330 },
|
||
{ label: "Feb/W2", revenue: 10500000, orders: 378 },
|
||
{ label: "Feb/W3", revenue: 11200000, orders: 400 },
|
||
{ label: "Feb/W4", revenue: 9800000, orders: 352 },
|
||
{ label: "Mar/W1", revenue: 10400000, orders: 374 },
|
||
{ label: "Mar/W2", revenue: 11800000, orders: 424 },
|
||
{ label: "Mar/W3", revenue: 12500000, orders: 448 },
|
||
{ label: "Mar/W4", revenue: 10900000, orders: 392 },
|
||
];
|
||
|
||
// Monthly revenue (last 12 months)
|
||
export const MOCK_REVENUE_MONTHLY: RevenueDataPoint[] = [
|
||
{ label: "Apr/2025", revenue: 42000000, orders: 1512 },
|
||
{ label: "May/2025", revenue: 45500000, orders: 1638 },
|
||
{ label: "Jun/2025", revenue: 48000000, orders: 1728 },
|
||
{ label: "Jul/2025", revenue: 52000000, orders: 1872 },
|
||
{ label: "Aug/2025", revenue: 49500000, orders: 1782 },
|
||
{ label: "Sep/2025", revenue: 46800000, orders: 1685 },
|
||
{ label: "Oct/2025", revenue: 51200000, orders: 1843 },
|
||
{ label: "Nov/2025", revenue: 55000000, orders: 1980 },
|
||
{ label: "Dec/2025", revenue: 62000000, orders: 2232 },
|
||
{ label: "Jan/2026", revenue: 44000000, orders: 1584 },
|
||
{ label: "Feb/2026", revenue: 47500000, orders: 1710 },
|
||
{ label: "Mar/2026", revenue: 53500000, orders: 1926 },
|
||
];
|
||
|
||
// Yearly revenue (last 5 years)
|
||
export const MOCK_REVENUE_YEARLY: RevenueDataPoint[] = [
|
||
{ label: "2022", revenue: 420000000, orders: 15120 },
|
||
{ label: "2023", revenue: 485000000, orders: 17460 },
|
||
{ label: "2024", revenue: 530000000, orders: 19080 },
|
||
{ label: "2025", revenue: 598000000, orders: 21528 },
|
||
{ label: "2026", revenue: 180000000, orders: 6480 },
|
||
];
|
||
|
||
// Product sales statistics (with cost price for profit analysis)
|
||
export const MOCK_PRODUCT_SALES: ProductSalesStats[] = [
|
||
{
|
||
productId: 12,
|
||
name: "Caramel Latte",
|
||
category: "latte",
|
||
unitsSold: 487,
|
||
revenue: 21915000,
|
||
costPrice: 18000,
|
||
sellingPrice: 45000,
|
||
profit: 13185000,
|
||
profitMargin: 60.2,
|
||
},
|
||
{
|
||
productId: 6,
|
||
name: "Matcha Green Tea",
|
||
category: "tra",
|
||
unitsSold: 412,
|
||
revenue: 16480000,
|
||
costPrice: 15000,
|
||
sellingPrice: 40000,
|
||
profit: 10300000,
|
||
profitMargin: 62.5,
|
||
},
|
||
{
|
||
productId: 5,
|
||
name: "Peach Orange Lemongrass Tea",
|
||
category: "tra",
|
||
unitsSold: 398,
|
||
revenue: 13930000,
|
||
costPrice: 12000,
|
||
sellingPrice: 35000,
|
||
profit: 9153000,
|
||
profitMargin: 65.7,
|
||
},
|
||
{
|
||
productId: 13,
|
||
name: "Vanilla Latte",
|
||
category: "latte",
|
||
unitsSold: 356,
|
||
revenue: 16020000,
|
||
costPrice: 18000,
|
||
sellingPrice: 45000,
|
||
profit: 9612000,
|
||
profitMargin: 60.0,
|
||
},
|
||
{
|
||
productId: 4,
|
||
name: "Egg Coffee",
|
||
category: "cafe",
|
||
unitsSold: 340,
|
||
revenue: 15300000,
|
||
costPrice: 16000,
|
||
sellingPrice: 45000,
|
||
profit: 9860000,
|
||
profitMargin: 64.4,
|
||
},
|
||
{
|
||
productId: 2,
|
||
name: "Milk Coffee",
|
||
category: "cafe",
|
||
unitsSold: 325,
|
||
revenue: 9750000,
|
||
costPrice: 10000,
|
||
sellingPrice: 30000,
|
||
profit: 6500000,
|
||
profitMargin: 66.7,
|
||
},
|
||
{
|
||
productId: 3,
|
||
name: "White Coffee",
|
||
category: "cafe",
|
||
unitsSold: 298,
|
||
revenue: 9536000,
|
||
costPrice: 11000,
|
||
sellingPrice: 32000,
|
||
profit: 6259000,
|
||
profitMargin: 65.6,
|
||
},
|
||
{
|
||
productId: 1,
|
||
name: "Black Coffee",
|
||
category: "cafe",
|
||
unitsSold: 285,
|
||
revenue: 7125000,
|
||
costPrice: 8000,
|
||
sellingPrice: 25000,
|
||
profit: 4845000,
|
||
profitMargin: 68.0,
|
||
},
|
||
{
|
||
productId: 9,
|
||
name: "Strawberry Yogurt",
|
||
category: "sua-chua",
|
||
unitsSold: 267,
|
||
revenue: 10680000,
|
||
costPrice: 15000,
|
||
sellingPrice: 40000,
|
||
profit: 6675000,
|
||
profitMargin: 62.5,
|
||
},
|
||
{
|
||
productId: 10,
|
||
name: "Fresh Orange Juice",
|
||
category: "nuoc-ep",
|
||
unitsSold: 241,
|
||
revenue: 8435000,
|
||
costPrice: 12000,
|
||
sellingPrice: 35000,
|
||
profit: 5543000,
|
||
profitMargin: 65.7,
|
||
},
|
||
{
|
||
productId: 8,
|
||
name: "Yogurt with Tapioca Pearls",
|
||
category: "sua-chua",
|
||
unitsSold: 228,
|
||
revenue: 8664000,
|
||
costPrice: 14000,
|
||
sellingPrice: 38000,
|
||
profit: 5472000,
|
||
profitMargin: 63.2,
|
||
},
|
||
{
|
||
productId: 7,
|
||
name: "Lychee Jasmine Tea",
|
||
category: "tra",
|
||
unitsSold: 215,
|
||
revenue: 8170000,
|
||
costPrice: 13000,
|
||
sellingPrice: 38000,
|
||
profit: 5375000,
|
||
profitMargin: 65.8,
|
||
},
|
||
{
|
||
productId: 15,
|
||
name: "Caramel Flan",
|
||
category: "giai-khat",
|
||
unitsSold: 198,
|
||
revenue: 4950000,
|
||
costPrice: 8000,
|
||
sellingPrice: 25000,
|
||
profit: 3366000,
|
||
profitMargin: 68.0,
|
||
},
|
||
{
|
||
productId: 11,
|
||
name: "Watermelon Juice",
|
||
category: "nuoc-ep",
|
||
unitsSold: 182,
|
||
revenue: 5460000,
|
||
costPrice: 10000,
|
||
sellingPrice: 30000,
|
||
profit: 3640000,
|
||
profitMargin: 66.7,
|
||
},
|
||
{
|
||
productId: 14,
|
||
name: "Toasted Butter Bread",
|
||
category: "giai-khat",
|
||
unitsSold: 175,
|
||
revenue: 3500000,
|
||
costPrice: 6000,
|
||
sellingPrice: 20000,
|
||
profit: 2450000,
|
||
profitMargin: 70.0,
|
||
},
|
||
{
|
||
productId: 16,
|
||
name: "Black Tapioca Pearls",
|
||
category: "topping",
|
||
unitsSold: 456,
|
||
revenue: 4560000,
|
||
costPrice: 2000,
|
||
sellingPrice: 10000,
|
||
profit: 3648000,
|
||
profitMargin: 80.0,
|
||
},
|
||
{
|
||
productId: 17,
|
||
name: "Coffee Jelly",
|
||
category: "topping",
|
||
unitsSold: 389,
|
||
revenue: 3890000,
|
||
costPrice: 2000,
|
||
sellingPrice: 10000,
|
||
profit: 3112000,
|
||
profitMargin: 80.0,
|
||
},
|
||
{
|
||
productId: 18,
|
||
name: "White Tapioca Pearls",
|
||
category: "topping",
|
||
unitsSold: 342,
|
||
revenue: 3420000,
|
||
costPrice: 2000,
|
||
sellingPrice: 10000,
|
||
profit: 2736000,
|
||
profitMargin: 80.0,
|
||
},
|
||
];
|
||
|
||
// ===== SHIFT / SCHEDULE DATA =====
|
||
|
||
export const DEPARTMENTS: Department[] = [
|
||
{ id: "bar", name: "Bar Staff", icon: "fa-solid fa-martini-glass-citrus" },
|
||
{ id: "kitchen", name: "Kitchen", icon: "fa-solid fa-kitchen-set" },
|
||
{ id: "cashier", name: "Cashier", icon: "fa-solid fa-cash-register" },
|
||
{ id: "janitor", name: "Janitor", icon: "fa-solid fa-broom" },
|
||
];
|
||
|
||
/**
|
||
* Generate mock shift slots for the weeks around today (April 2026).
|
||
* Covers Mon 6 Apr – Sun 26 Apr 2026.
|
||
*/
|
||
function generateMockShifts(): ShiftSlot[] {
|
||
const shifts: ShiftSlot[] = [];
|
||
const departments = ["bar", "kitchen", "cashier", "janitor"];
|
||
const timeSlots = [
|
||
{ start: "07:00", end: "11:00", hours: 4, wage: 120000 },
|
||
{ start: "11:00", end: "15:00", hours: 4, wage: 120000 },
|
||
{ start: "15:00", end: "19:00", hours: 4, wage: 120000 },
|
||
{ start: "19:00", end: "22:00", hours: 3, wage: 100000 },
|
||
];
|
||
|
||
const staffPool = [
|
||
{ id: 2, name: "Alex Nguyen" },
|
||
{ id: 3, name: "Binh Tran" },
|
||
{ id: 4, name: "Cuong Le" },
|
||
];
|
||
|
||
// Generate shifts from April 6 to April 26, 2026
|
||
let shiftCounter = 0;
|
||
for (let day = 6; day <= 26; day++) {
|
||
const dateStr = `2026-04-${day.toString().padStart(2, "0")}`;
|
||
|
||
for (const dept of departments) {
|
||
// Not every department has shifts every day
|
||
if (dept === "janitor" && day % 3 !== 0) continue;
|
||
|
||
for (const slot of timeSlots) {
|
||
// Skip some slots randomly for variety
|
||
if (dept === "kitchen" && slot.start === "19:00") continue;
|
||
if (dept === "cashier" && slot.start === "07:00" && day % 2 === 0)
|
||
continue;
|
||
|
||
shiftCounter++;
|
||
const shiftId = `shift_${shiftCounter.toString().padStart(3, "0")}`;
|
||
|
||
// Determine registration status
|
||
const registered: { id: number; name: string }[] = [];
|
||
let status: ShiftSlot["status"] = "available";
|
||
|
||
// Past shifts (before April 10) are mostly registered
|
||
if (day < 10) {
|
||
const staffIdx = shiftCounter % staffPool.length;
|
||
registered.push(staffPool[staffIdx]);
|
||
if (shiftCounter % 7 === 0) {
|
||
registered.push(staffPool[(staffIdx + 1) % staffPool.length]);
|
||
}
|
||
status = "registered";
|
||
// Some past shifts have leave/absent
|
||
if (shiftCounter % 11 === 0) status = "approved_leave";
|
||
if (shiftCounter % 13 === 0) status = "absent";
|
||
}
|
||
// Current week (April 6-12): mix of registered and available
|
||
else if (day >= 10 && day <= 12) {
|
||
if (shiftCounter % 3 === 0) {
|
||
registered.push(staffPool[shiftCounter % staffPool.length]);
|
||
status = "registered";
|
||
}
|
||
}
|
||
// Future shifts: mostly available, some registered
|
||
else {
|
||
if (shiftCounter % 5 === 0) {
|
||
registered.push(staffPool[shiftCounter % staffPool.length]);
|
||
status = "registered";
|
||
}
|
||
}
|
||
|
||
shifts.push({
|
||
id: shiftId,
|
||
date: dateStr,
|
||
startTime: slot.start,
|
||
endTime: slot.end,
|
||
durationHours: slot.hours,
|
||
wage: slot.wage,
|
||
department: dept,
|
||
maxStaff: dept === "bar" ? 3 : 2,
|
||
registeredStaff: registered,
|
||
status,
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
return shifts;
|
||
}
|
||
|
||
export const MOCK_SHIFT_SLOTS: ShiftSlot[] = generateMockShifts();
|