"use client"; import { useMemo, useState } from "react"; import Link from "next/link"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import dayjs from "dayjs"; import { toast } from "sonner"; import { Button, Card, CardContent, PageHeader, Select } from "@/components/ds"; import { useCurrentHub } from "@/modules/workspace/hooks/useCurrentHub"; import { workspaceApi } from "@/modules/workspace/services/workspace-api"; import { CHANNEL, CONTENT_STATUS, CONTENT_TYPE, displayPerson, formatWhen, labelOf } from "@/modules/workspace/labels"; import { StatusChip } from "@/modules/workspace/components/StatusChip"; import { WorkspaceEmptyState, WorkspacePageError, WorkspacePageLoader } from "@/modules/workspace/pages/shared"; import type { WorkspaceRecord } from "@/modules/workspace/types"; type View = "month" | "week" | "list"; function startOfWeek(date: dayjs.Dayjs) { const weekday = date.day(); return date.subtract((weekday + 1) % 7, "day").startOf("day"); } export const WorkspaceContentCalendar = function WorkspaceContentCalendarPage() { const queryClient = useQueryClient(); const { tenantId, hubId, loading } = useCurrentHub(); const [view, setView] = useState("month"); const [cursor, setCursor] = useState(dayjs()); const [channel, setChannel] = useState(""); const [status, setStatus] = useState(""); const [contentType, setContentType] = useState(""); const projects = useQuery({ queryKey: ["workspace", tenantId, "projects", hubId], queryFn: () => workspaceApi.projects.list(tenantId!, { work_hub_id: hubId! }), enabled: !!tenantId && !!hubId, }); const projectNames = Object.fromEntries( (projects.data ?? []).map((project) => [String(project.id), String(project.name || "پروژه")]), ); const items = useQuery({ queryKey: ["workspace", tenantId, "calendar", hubId, channel, status, contentType], queryFn: () => workspaceApi.content.calendar(tenantId!, { work_hub_id: hubId!, channel: channel || undefined, status: status || undefined, content_type: contentType || undefined, }), enabled: !!tenantId && !!hubId, }); const reschedule = useMutation({ mutationFn: ({ id, scheduled_at }: { id: string; scheduled_at: string }) => workspaceApi.content.update(tenantId!, id, { scheduled_at }), onSuccess: () => { toast.success("زمان‌بندی ذخیره شد"); void queryClient.invalidateQueries({ queryKey: ["workspace", tenantId, "calendar"] }); }, onError: (err) => toast.error(err instanceof Error ? err.message : "تغییر زمان‌بندی ناموفق بود"), }); const days = useMemo(() => { if (view === "week") { const start = startOfWeek(cursor); return Array.from({ length: 7 }, (_, index) => start.add(index, "day")); } const start = cursor.startOf("month"); const gridStart = startOfWeek(start); return Array.from({ length: 42 }, (_, index) => gridStart.add(index, "day")); }, [cursor, view]); const byDay = useMemo(() => { const map = new Map(); for (const item of items.data ?? []) { const key = item.scheduled_at ? dayjs(String(item.scheduled_at)).format("YYYY-MM-DD") : ""; if (!key) continue; map.set(key, [...(map.get(key) ?? []), item]); } return map; }, [items.data]); if (!tenantId || loading || items.isLoading) return ; if (!hubId) return ; if (items.error) return items.refetch()} />; return (
} />
{(["month", "week", "list"] as View[]).map((mode) => ( ))}
{view === "list" ? (
{(items.data ?? []).length === 0 ? ( ) : ( (items.data ?? []).map((item) => (
{String(item.title || "محتوا")}

{labelOf(CONTENT_TYPE, String(item.content_type || ""))} · {labelOf(CHANNEL, String(item.channel || ""))} ·{" "} {projectNames[String(item.project_id || "")] || "بدون پروژه"} ·{" "} {displayPerson(String(item.owner_user_id || ""))}

{formatWhen(String(item.scheduled_at || ""))}
)) )}
) : (
{days.map((day) => { const key = day.format("YYYY-MM-DD"); return (
event.preventDefault()} onDrop={(event) => { const id = event.dataTransfer.getData("text/content-id"); if (id) reschedule.mutate({ id, scheduled_at: `${key}T10:00:00` }); }} >

{day.format("D MMM")}

{(byDay.get(key) ?? []).map((item) => ( ))}
); })}
)} ); }; export default WorkspaceContentCalendar;