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>
86 lines
3.5 KiB
TypeScript
86 lines
3.5 KiB
TypeScript
"use client";
|
||
|
||
import { useQuery } from "@tanstack/react-query";
|
||
import Link from "next/link";
|
||
import { useTenantId } from "@/hooks/useTenantId";
|
||
import { sportsCenterApi } from "@/modules/sports-center/services/sports-center-api";
|
||
import { SportsCenterPageLoader, SportsCenterPageError } from "@/modules/sports-center/pages/shared";
|
||
import { PageHeader, StatCard, Card, CardContent, Button } from "@/components/ds";
|
||
import { SportsCenterBreadcrumbs } from "@/modules/sports-center/components/SportsCenterBreadcrumbs";
|
||
|
||
export function AnalyticsPage() {
|
||
const { tenantId } = useTenantId();
|
||
const q = useQuery({
|
||
queryKey: ["sports-center", tenantId, "analytics"],
|
||
queryFn: async () => {
|
||
const [members, memberships, coaches] = await Promise.all([
|
||
sportsCenterApi.members.list(tenantId!, { page: 1, page_size: 500 }),
|
||
sportsCenterApi.memberships.list(tenantId!, { page: 1, page_size: 500 }),
|
||
sportsCenterApi.coaches.list(tenantId!, { page: 1, page_size: 500 }),
|
||
]);
|
||
return { members: members.length, memberships: memberships.length, coaches: coaches.length };
|
||
},
|
||
enabled: !!tenantId,
|
||
});
|
||
|
||
if (!tenantId || q.isLoading) return <SportsCenterPageLoader />;
|
||
if (q.error) return <SportsCenterPageError error={q.error} onRetry={() => q.refetch()} />;
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
<SportsCenterBreadcrumbs current="آنالیتیکس" />
|
||
<PageHeader title="آنالیتیکس" description="شاخصهای کلیدی عملکرد مرکز ورزشی" />
|
||
<div className="grid gap-4 sm:grid-cols-3">
|
||
<StatCard label="اعضا" value={String(q.data!.members)} />
|
||
<StatCard label="عضویت" value={String(q.data!.memberships)} />
|
||
<StatCard label="مربی" value={String(q.data!.coaches)} />
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export function ReportsPage() {
|
||
const { tenantId } = useTenantId();
|
||
const q = useQuery({
|
||
queryKey: ["sports-center", tenantId, "reports"],
|
||
queryFn: () => sportsCenterApi.members.list(tenantId!, { page: 1, page_size: 500 }),
|
||
enabled: !!tenantId,
|
||
});
|
||
|
||
if (!tenantId || q.isLoading) return <SportsCenterPageLoader />;
|
||
if (q.error) return <SportsCenterPageError error={q.error} onRetry={() => q.refetch()} />;
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
<SportsCenterBreadcrumbs current="گزارشها" />
|
||
<PageHeader title="گزارشهای عملیاتی" description="گزارش اعضا و عضویت از API واقعی" />
|
||
<Card>
|
||
<CardContent className="p-4 text-sm text-[var(--muted)]">
|
||
{q.data!.length} عضو ثبتشده — گزارشهای تفصیلی از دادههای live.
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export function NotificationsPage() {
|
||
return (
|
||
<div className="space-y-6">
|
||
<SportsCenterBreadcrumbs current="اعلانها" />
|
||
<PageHeader title="اعلانها" description="یکپارچه با Communication Platform" />
|
||
<Card>
|
||
<CardContent className="space-y-3 p-6">
|
||
<p className="text-sm text-[var(--muted)]">
|
||
ارسال اعلان از طریق سرویس Communication — بدون mock.
|
||
</p>
|
||
<Link href="/sports-center/integrations/communication">
|
||
<Button variant="outline">تنظیمات یکپارچهسازی</Button>
|
||
</Link>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default AnalyticsPage;
|