Move business logic out of App Router into module packages, add boundary validation scripts, and keep all routes as thin re-exports without changing URLs or API behavior. Co-authored-by: Cursor <cursoragent@cursor.com>
363 lines
14 KiB
TypeScript
363 lines
14 KiB
TypeScript
import type { LucideIcon } from "lucide-react";
|
|
import {
|
|
LayoutDashboard,
|
|
Users,
|
|
CreditCard,
|
|
Calendar,
|
|
Dumbbell,
|
|
Trophy,
|
|
Building2,
|
|
Shield,
|
|
ClipboardList,
|
|
QrCode,
|
|
BarChart3,
|
|
Settings,
|
|
Activity,
|
|
UserCircle,
|
|
Stethoscope,
|
|
Lock,
|
|
Plug,
|
|
Bell,
|
|
Sparkles,
|
|
Target,
|
|
MessageSquare,
|
|
Wallet,
|
|
ScanLine,
|
|
Heart,
|
|
} from "lucide-react";
|
|
|
|
export type SportsCenterPortalId =
|
|
| "owner"
|
|
| "reception"
|
|
| "coach"
|
|
| "athlete"
|
|
| "parent"
|
|
| "cashier"
|
|
| "support"
|
|
| "admin";
|
|
|
|
export type PortalNavItem = { href: string; label: string; feature?: string | null };
|
|
export type PortalNavGroup = {
|
|
id: string;
|
|
label: string;
|
|
icon: LucideIcon;
|
|
href?: string;
|
|
feature?: string | null;
|
|
items?: PortalNavItem[];
|
|
};
|
|
|
|
export const SPORTS_CENTER_PORTALS: {
|
|
id: SportsCenterPortalId;
|
|
label: string;
|
|
description: string;
|
|
basePath: string;
|
|
icon: LucideIcon;
|
|
}[] = [
|
|
{
|
|
id: "owner",
|
|
label: "مدیریت اجرایی",
|
|
description: "داشبورد، درآمد، آنالیتیکس",
|
|
basePath: "/sports-center/owner",
|
|
icon: LayoutDashboard,
|
|
},
|
|
{
|
|
id: "reception",
|
|
label: "پذیرش",
|
|
description: "چکاین، جستجو، QR",
|
|
basePath: "/sports-center/reception",
|
|
icon: ClipboardList,
|
|
},
|
|
{
|
|
id: "coach",
|
|
label: "مربی",
|
|
description: "کلاسها، تمرین، پیشرفت",
|
|
basePath: "/sports-center/coach",
|
|
icon: Dumbbell,
|
|
},
|
|
{
|
|
id: "athlete",
|
|
label: "ورزشکار",
|
|
description: "تمرین امروز، پیشرفت، عضویت",
|
|
basePath: "/sports-center/athlete",
|
|
icon: UserCircle,
|
|
},
|
|
{
|
|
id: "parent",
|
|
label: "والدین",
|
|
description: "خانواده، پرداختها",
|
|
basePath: "/sports-center/parent",
|
|
icon: Heart,
|
|
},
|
|
{
|
|
id: "cashier",
|
|
label: "صندوق",
|
|
description: "پرداختها و عضویت",
|
|
basePath: "/sports-center/cashier",
|
|
icon: Wallet,
|
|
},
|
|
{
|
|
id: "support",
|
|
label: "پشتیبانی",
|
|
description: "اعلانها و پشتیبانی",
|
|
basePath: "/sports-center/support",
|
|
icon: MessageSquare,
|
|
},
|
|
{
|
|
id: "admin",
|
|
label: "مدیر سیستم",
|
|
description: "تنظیمات، نقشها، دسترسی",
|
|
basePath: "/sports-center/admin",
|
|
icon: Shield,
|
|
},
|
|
];
|
|
|
|
export const OWNER_NAV: PortalNavGroup[] = [
|
|
{ id: "dash", label: "داشبورد", icon: LayoutDashboard, href: "/sports-center/owner" },
|
|
{
|
|
id: "members",
|
|
label: "اعضا",
|
|
icon: Users,
|
|
items: [
|
|
{ href: "/sports-center/members", label: "اعضا" },
|
|
{ href: "/sports-center/families", label: "خانوادهها" },
|
|
{ href: "/sports-center/medical-records", label: "سوابق پزشکی" },
|
|
{ href: "/sports-center/membership-cards", label: "کارت عضویت" },
|
|
{ href: "/sports-center/digital-membership", label: "عضویت دیجیتال" },
|
|
],
|
|
},
|
|
{
|
|
id: "membership",
|
|
label: "عضویت",
|
|
icon: CreditCard,
|
|
feature: "membership_catalog",
|
|
items: [
|
|
{ href: "/sports-center/memberships", label: "عضویتها" },
|
|
{ href: "/sports-center/membership-types", label: "انواع عضویت" },
|
|
{ href: "/sports-center/catalog/packages", label: "پکیجها" },
|
|
{ href: "/sports-center/catalog/plans", label: "طرحها" },
|
|
{ href: "/sports-center/catalog/sport-categories", label: "دسته رشته" },
|
|
{ href: "/sports-center/catalog/age-groups", label: "گروه سنی" },
|
|
{ href: "/sports-center/catalog/pricing-models", label: "قیمتگذاری" },
|
|
{ href: "/sports-center/catalog/rules", label: "قوانین" },
|
|
{ href: "/sports-center/catalog/renewal-policies", label: "تمدید" },
|
|
{ href: "/sports-center/catalog/freezing-rules", label: "فریز" },
|
|
{ href: "/sports-center/catalog/expiration-policies", label: "انقضا" },
|
|
],
|
|
},
|
|
{
|
|
id: "staff",
|
|
label: "مربی و پرسنل",
|
|
icon: Target,
|
|
feature: "coach_staff_management",
|
|
items: [
|
|
{ href: "/sports-center/coaches", label: "مربیان" },
|
|
{ href: "/sports-center/staff/certificates", label: "گواهینامه" },
|
|
{ href: "/sports-center/staff/skills", label: "مهارتها" },
|
|
{ href: "/sports-center/staff/working-hours", label: "ساعات کاری" },
|
|
{ href: "/sports-center/staff/availability", label: "دسترسی" },
|
|
{ href: "/sports-center/staff/assignments", label: "انتساب" },
|
|
],
|
|
},
|
|
{
|
|
id: "ops",
|
|
label: "عملیات",
|
|
icon: Calendar,
|
|
items: [
|
|
{ href: "/sports-center/sessions", label: "جلسات", feature: "booking_engine" },
|
|
{ href: "/sports-center/bookings", label: "رزروها", feature: "booking_engine" },
|
|
{ href: "/sports-center/attendance", label: "حضور", feature: "attendance_engine" },
|
|
{ href: "/sports-center/access-logs", label: "لاگ دسترسی", feature: "attendance_engine" },
|
|
{ href: "/sports-center/events", label: "رویدادها" },
|
|
],
|
|
},
|
|
{
|
|
id: "training",
|
|
label: "تمرین",
|
|
icon: Dumbbell,
|
|
feature: "training_management",
|
|
items: [
|
|
{ href: "/sports-center/training/programs", label: "برنامهها" },
|
|
{ href: "/sports-center/training/exercises", label: "تمرینات" },
|
|
{ href: "/sports-center/training/workout-plans", label: "برنامه تمرین" },
|
|
{ href: "/sports-center/training/measurements", label: "اندازهگیری" },
|
|
{ href: "/sports-center/training/progress", label: "پیشرفت" },
|
|
{ href: "/sports-center/training/nutrition", label: "تغذیه" },
|
|
],
|
|
},
|
|
{
|
|
id: "competitions",
|
|
label: "مسابقات",
|
|
icon: Trophy,
|
|
feature: "competition_management",
|
|
items: [
|
|
{ href: "/sports-center/competitions", label: "مسابقات" },
|
|
{ href: "/sports-center/competitions/teams", label: "تیمها" },
|
|
{ href: "/sports-center/competitions/results", label: "نتایج" },
|
|
],
|
|
},
|
|
{
|
|
id: "facilities",
|
|
label: "امکانات",
|
|
icon: Building2,
|
|
items: [
|
|
{ href: "/sports-center/sports-centers", label: "مراکز" },
|
|
{ href: "/sports-center/branches", label: "شعب" },
|
|
{ href: "/sports-center/sports", label: "رشتهها" },
|
|
{ href: "/sports-center/facilities", label: "امکانات" },
|
|
{ href: "/sports-center/courts", label: "زمینها" },
|
|
{ href: "/sports-center/rooms", label: "اتاقها" },
|
|
{ href: "/sports-center/lockers", label: "کمدها" },
|
|
{ href: "/sports-center/equipment", label: "تجهیزات", feature: "booking_engine" },
|
|
],
|
|
},
|
|
{
|
|
id: "analytics",
|
|
label: "گزارشها",
|
|
icon: BarChart3,
|
|
items: [
|
|
{ href: "/sports-center/analytics", label: "آنالیتیکس" },
|
|
{ href: "/sports-center/reports", label: "گزارشها" },
|
|
],
|
|
},
|
|
{
|
|
id: "integrations",
|
|
label: "یکپارچهسازی",
|
|
icon: Plug,
|
|
items: [
|
|
{ href: "/sports-center/integrations/crm", label: "CRM" },
|
|
{ href: "/sports-center/integrations/accounting", label: "حسابداری" },
|
|
{ href: "/sports-center/integrations/loyalty", label: "وفاداری" },
|
|
{ href: "/sports-center/integrations/communication", label: "ارتباطات" },
|
|
{ href: "/sports-center/integrations/ai", label: "هوش مصنوعی" },
|
|
],
|
|
},
|
|
];
|
|
|
|
export const RECEPTION_NAV: PortalNavGroup[] = [
|
|
{ id: "dash", label: "پذیرش", icon: ClipboardList, href: "/sports-center/reception" },
|
|
{ id: "checkin", label: "چکاین سریع", icon: ScanLine, href: "/sports-center/reception/check-in" },
|
|
{ id: "search", label: "جستجوی عضو", icon: Users, href: "/sports-center/members" },
|
|
{ id: "qr", label: "QR", icon: QrCode, href: "/sports-center/reception/qr-scanner" },
|
|
{ id: "attendance", label: "حضور", icon: Activity, href: "/sports-center/attendance", feature: "attendance_engine" },
|
|
{ id: "bookings", label: "رزرو", icon: Calendar, href: "/sports-center/bookings", feature: "booking_engine" },
|
|
{ id: "schedule", label: "برنامه امروز", icon: Calendar, href: "/sports-center/sessions", feature: "booking_engine" },
|
|
];
|
|
|
|
export const COACH_NAV: PortalNavGroup[] = [
|
|
{ id: "dash", label: "داشبورد", icon: LayoutDashboard, href: "/sports-center/coach" },
|
|
{ id: "classes", label: "کلاسهای امروز", icon: Calendar, href: "/sports-center/sessions", feature: "booking_engine" },
|
|
{ id: "attendance", label: "حضور", icon: ClipboardList, href: "/sports-center/attendance", feature: "attendance_engine" },
|
|
{
|
|
id: "training",
|
|
label: "تمرین",
|
|
icon: Dumbbell,
|
|
feature: "training_management",
|
|
items: [
|
|
{ href: "/sports-center/training/programs", label: "برنامهها" },
|
|
{ href: "/sports-center/training/exercises", label: "کتابخانه تمرین" },
|
|
{ href: "/sports-center/training/workout-plans", label: "سازنده تمرین" },
|
|
{ href: "/sports-center/training/measurements", label: "اندازهگیری" },
|
|
{ href: "/sports-center/training/progress", label: "پیشرفت" },
|
|
{ href: "/sports-center/training/nutrition", label: "تغذیه" },
|
|
],
|
|
},
|
|
{ id: "messages", label: "پیامها", icon: MessageSquare, href: "/sports-center/coach/messages" },
|
|
{ id: "schedule", label: "برنامه", icon: Calendar, href: "/sports-center/coach/schedule" },
|
|
];
|
|
|
|
export const ATHLETE_NAV: PortalNavGroup[] = [
|
|
{ id: "today", label: "تمرین امروز", icon: Dumbbell, href: "/sports-center/athlete" },
|
|
{ id: "workouts", label: "جزئیات تمرین", icon: Target, href: "/sports-center/athlete/workout" },
|
|
{ id: "progress", label: "پیشرفت", icon: BarChart3, href: "/sports-center/athlete/progress", feature: "training_management" },
|
|
{ id: "measurements", label: "اندازهگیری", icon: Activity, href: "/sports-center/athlete/measurements", feature: "training_management" },
|
|
{ id: "attendance", label: "حضور", icon: ClipboardList, href: "/sports-center/athlete/attendance", feature: "attendance_engine" },
|
|
{ id: "membership", label: "عضویت", icon: CreditCard, href: "/sports-center/athlete/membership" },
|
|
{ id: "qr", label: "QR عضویت", icon: QrCode, href: "/sports-center/athlete/qr" },
|
|
{ id: "nutrition", label: "تغذیه", icon: Heart, href: "/sports-center/athlete/nutrition", feature: "training_management" },
|
|
{ id: "bookings", label: "رزروها", icon: Calendar, href: "/sports-center/athlete/bookings", feature: "booking_engine" },
|
|
{ id: "achievements", label: "دستاوردها", icon: Trophy, href: "/sports-center/athlete/achievements", feature: "competition_management" },
|
|
{ id: "profile", label: "پروفایل", icon: UserCircle, href: "/sports-center/athlete/profile" },
|
|
];
|
|
|
|
export const ADMIN_NAV: PortalNavGroup[] = [
|
|
{ id: "settings", label: "تنظیمات", icon: Settings, href: "/sports-center/settings" },
|
|
{ id: "roles", label: "نقشها", icon: Shield, href: "/sports-center/roles" },
|
|
{ id: "permissions", label: "مجوزها", icon: Lock, href: "/sports-center/permissions" },
|
|
{ id: "devices", label: "دستگاهها", icon: ScanLine, href: "/sports-center/devices" },
|
|
{ id: "gateways", label: "گیتوی", icon: Plug, href: "/sports-center/attendance-gateways" },
|
|
{ id: "health", label: "سلامت سرویس", icon: Activity, href: "/sports-center/health" },
|
|
{ id: "capabilities", label: "قابلیتها", icon: Sparkles, href: "/sports-center/capabilities" },
|
|
{ id: "notifications", label: "اعلانها", icon: Bell, href: "/sports-center/notifications" },
|
|
];
|
|
|
|
export const PARENT_NAV: PortalNavGroup[] = [
|
|
{ id: "dash", label: "خانواده", icon: Heart, href: "/sports-center/parent" },
|
|
{ id: "family", label: "اعضای خانواده", icon: Users, href: "/sports-center/families" },
|
|
{ id: "membership", label: "عضویت", icon: CreditCard, href: "/sports-center/memberships" },
|
|
];
|
|
|
|
export const CASHIER_NAV: PortalNavGroup[] = [
|
|
{ id: "dash", label: "صندوق", icon: Wallet, href: "/sports-center/cashier" },
|
|
{ id: "membership", label: "عضویت", icon: CreditCard, href: "/sports-center/memberships" },
|
|
{ id: "members", label: "اعضا", icon: Users, href: "/sports-center/members" },
|
|
];
|
|
|
|
export const SUPPORT_NAV: PortalNavGroup[] = [
|
|
{ id: "dash", label: "پشتیبانی", icon: MessageSquare, href: "/sports-center/support" },
|
|
{ id: "notifications", label: "اعلانها", icon: Bell, href: "/sports-center/notifications" },
|
|
];
|
|
|
|
export function navForPortal(portalId: SportsCenterPortalId): PortalNavGroup[] {
|
|
switch (portalId) {
|
|
case "owner":
|
|
return OWNER_NAV;
|
|
case "reception":
|
|
return RECEPTION_NAV;
|
|
case "coach":
|
|
return COACH_NAV;
|
|
case "athlete":
|
|
return ATHLETE_NAV;
|
|
case "parent":
|
|
return PARENT_NAV;
|
|
case "cashier":
|
|
return CASHIER_NAV;
|
|
case "support":
|
|
return SUPPORT_NAV;
|
|
case "admin":
|
|
return ADMIN_NAV;
|
|
default:
|
|
return OWNER_NAV;
|
|
}
|
|
}
|
|
|
|
export function detectPortal(pathname: string): SportsCenterPortalId {
|
|
if (pathname.startsWith("/sports-center/reception")) return "reception";
|
|
if (pathname.startsWith("/sports-center/coach")) return "coach";
|
|
if (pathname.startsWith("/sports-center/athlete")) return "athlete";
|
|
if (pathname.startsWith("/sports-center/parent")) return "parent";
|
|
if (pathname.startsWith("/sports-center/cashier")) return "cashier";
|
|
if (pathname.startsWith("/sports-center/support")) return "support";
|
|
if (pathname.startsWith("/sports-center/admin")) return "admin";
|
|
return "owner";
|
|
}
|
|
|
|
export function filterNavByCapabilities(
|
|
nav: PortalNavGroup[],
|
|
features?: Record<string, boolean>
|
|
): PortalNavGroup[] {
|
|
if (!features) return nav;
|
|
return nav
|
|
.map((group) => {
|
|
if (group.feature && features[group.feature] === false) return null;
|
|
if (!group.items) return group;
|
|
const items = group.items.filter((i) => !i.feature || features[i.feature] !== false);
|
|
if (items.length === 0 && !group.href) return null;
|
|
return { ...group, items };
|
|
})
|
|
.filter(Boolean) as PortalNavGroup[];
|
|
}
|
|
|
|
export function portalMeta(id: SportsCenterPortalId) {
|
|
return SPORTS_CENTER_PORTALS.find((p) => p.id === id)!;
|
|
}
|