TorbatYar/frontend/modules/workspace/features/reports.tsx
Mortezakoohjani a483b47369 feat(workspace): complete production workspace and content operations
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-12 11:54:17 +03:30

74 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useQuery } from "@tanstack/react-query";
import { Card, CardContent, PageHeader, StatCard } from "@/components/ds";
import { useCurrentHub } from "@/modules/workspace/hooks/useCurrentHub";
import { workspaceApi } from "@/modules/workspace/services/workspace-api";
import { useTenantMembers } from "@/modules/workspace/hooks/useTenantMembers";
import { CONTENT_STATUS, labelOf, personLabel } from "@/modules/workspace/labels";
import { WorkspaceEmptyState, WorkspacePageError, WorkspacePageLoader } from "@/modules/workspace/pages/shared";
export const WorkspaceReports = function WorkspaceReportsPage() {
const { tenantId, hubId, loading } = useCurrentHub();
const people = useTenantMembers();
const directory = Object.fromEntries((people.data ?? []).map((person) => [person.id, person.label]));
const dash = useQuery({
queryKey: ["workspace", tenantId, "dashboard", hubId],
queryFn: () => workspaceApi.hubs.dashboard(tenantId!, hubId!),
enabled: !!tenantId && !!hubId,
});
if (!tenantId || loading || dash.isLoading) return <WorkspacePageLoader />;
if (!hubId) return <WorkspaceEmptyState title="مرکز کار لازم است" description="ابتدا مرکز کار را انتخاب کنید." />;
if (dash.error) return <WorkspacePageError error={dash.error} onRetry={() => dash.refetch()} />;
const data = dash.data!;
return (
<div className="space-y-6">
<PageHeader title="گزارش‌ها" description="اعداد از پایگاه داده فضای کاری خوانده می‌شوند؛ مقدار ثابت وجود ندارد." />
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
<StatCard label="پروژه‌های فعال" value={data.overview.active_projects} />
<StatCard label="وظایف باز" value={data.overview.open_tasks} />
<StatCard label="عقب‌افتاده" value={data.overview.overdue_tasks} />
<StatCard label="صف تأیید" value={data.overview.pending_approvals} />
<StatCard label="در انتظار بررسی" value={data.overview.content_awaiting_review} />
<StatCard label="زمان‌بندی‌شده" value={data.overview.scheduled_content} />
<StatCard label="اعضای تیم" value={data.overview.team_members} />
<StatCard label="مهلت نزدیک" value={data.overview.upcoming_deadlines} />
</div>
<div className="grid gap-4 lg:grid-cols-2">
<Card>
<CardContent className="space-y-2 p-5">
<h2 className="font-semibold text-secondary">وضعیت تولید</h2>
{Object.entries(data.content).map(([status, count]) => (
<div key={status} className="flex justify-between text-sm">
<span>{labelOf(CONTENT_STATUS, status)}</span>
<span>{count}</span>
</div>
))}
</CardContent>
</Card>
<Card>
<CardContent className="space-y-2 p-5">
<h2 className="font-semibold text-secondary">بار کاری</h2>
{data.workload.length === 0 ? (
<p className="text-sm text-[var(--muted)]">تخصیصی ثبت نشده است.</p>
) : (
data.workload.map((row) => (
<div key={row.user_id} className="flex justify-between text-sm">
<span>{personLabel(row.user_id, directory)}</span>
<span>
{row.tasks} وظیفه / {row.content} محتوا
</span>
</div>
))
)}
</CardContent>
</Card>
</div>
</div>
);
};
export default WorkspaceReports;