import { useCallback, useEffect, useState } from 'react'; import { Link, Navigate, useNavigate, useParams } from 'react-router-dom'; import { useAuth } from '@/hooks/useAuth'; import { AssignmentFormFields } from '@/components/assignments/AssignmentFormFields'; import { assignmentDayStatusLabel, assignmentStatusLabel, assignmentTypeLabel, createAssignmentEntry, fetchAssignment, isMultiDayAssignment, saveAssignmentDraft, startAssignment, submitAssignmentReport, updateAssignmentEntry, type AssignmentDayStatus, type AssignmentFormField, type AssignmentReportStatus, type UserAssignment, } from '@/services/assignmentService'; import { useToast } from '@/components/ui/use-toast'; import { getFetchErrorMessage } from '@/lib/fetchError'; import { PageSkeleton } from '@/components/skeletons'; import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; import { ArrowRight, Check, Loader2 } from 'lucide-react'; function emptyDraftFromSchema(schema: AssignmentFormField[] | null): Record { if (!schema) return { text: '' }; const draft: Record = {}; for (const field of schema) { if (field.type === 'list') { draft[field.key] = [{}]; } else if (field.type === 'checkbox') { draft[field.key] = false; } else { draft[field.key] = ''; } } return draft; } function progressLabel(assignment: UserAssignment): string | null { const target = assignment.definition.expectedDurationDays; if (!target) return `${assignment.doneDayCount} روز انجام‌شده`; return `${assignment.doneDayCount} روز از ${target} روز هدف`; } /** * Assignment detail — one-time vs multi-day flows diverge deliberately. * Status is system-driven; experience notes are optional and soft. */ export default function AssignmentDetailPage() { const { id } = useParams<{ id: string }>(); const { effectiveUserId, guestSessionHydrated, isGuest } = useAuth(); const navigate = useNavigate(); const { toast } = useToast(); const [assignment, setAssignment] = useState(null); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [draft, setDraft] = useState>({}); const [entryData, setEntryData] = useState>({}); const [entryNote, setEntryNote] = useState(''); const [dayStatus, setDayStatus] = useState('done'); const [editingEntryId, setEditingEntryId] = useState(null); const [experienceNote, setExperienceNote] = useState(''); const [experienceStatus, setExperienceStatus] = useState('difficult'); const load = useCallback(async () => { if (!id) return; setLoading(true); try { const row = await fetchAssignment(id); setAssignment(row); const schema = row.definition.formSchema; setDraft( (row.draftData as Record | null) ?? emptyDraftFromSchema(schema), ); const today = row.serverToday; const todayEntry = row.dailyEntries?.find((e) => e.entryDate === today); if (todayEntry) { setEditingEntryId(todayEntry.id); setEntryData(todayEntry.responseData); setEntryNote(todayEntry.note ?? ''); setDayStatus(todayEntry.dayStatus); } else { setEditingEntryId(null); setEntryData(emptyDraftFromSchema(schema)); setEntryNote(''); setDayStatus('done'); } } catch (err) { toast({ title: 'خطا', description: getFetchErrorMessage(err, 'بارگذاری تکلیف ناموفق بود'), variant: 'destructive', }); navigate('/assignments', { replace: true }); } finally { setLoading(false); } }, [id, navigate, toast]); useEffect(() => { if (!effectiveUserId || isGuest) return; void load(); }, [effectiveUserId, isGuest, load]); if (!guestSessionHydrated || loading) { return ; } if (!effectiveUserId) { return ; } if (isGuest || !assignment) { return ; } const isMultiDay = isMultiDayAssignment(assignment.definition.assignmentType); const isOneTime = assignment.definition.assignmentType === 'ONE_TIME'; const schema = assignment.definition.formSchema; const completed = assignment.status === 'COMPLETED'; const serverToday = assignment.serverToday; const updateDraftField = (key: string, value: unknown) => { setDraft((prev) => ({ ...prev, [key]: value })); }; const updateEntryField = (key: string, value: unknown) => { setEntryData((prev) => ({ ...prev, [key]: value })); }; const handleSaveDraft = async (completeIfValid: boolean) => { setSaving(true); try { await startAssignment(assignment.id); const updated = await saveAssignmentDraft(assignment.id, draft, { completeIfValid }); setAssignment(updated); toast({ title: updated.status === 'COMPLETED' ? 'پاسخ ثبت و تکلیف تکمیل شد' : 'پیش‌نویس ذخیره شد', description: updated.status === 'COMPLETED' ? undefined : completeIfValid ? undefined : 'برای تکمیل، فیلدهای الزامی را پر کن و «ثبت پاسخ» را بزن.', }); } catch (err) { toast({ title: 'خطا', description: getFetchErrorMessage(err, 'ذخیره پاسخ ناموفق بود'), variant: 'destructive', }); } finally { setSaving(false); } }; const handleSaveEntry = async () => { setSaving(true); try { await startAssignment(assignment.id); const payload = { dayStatus, responseData: dayStatus === 'done' ? entryData : {}, note: entryNote || null, }; if (editingEntryId) { await updateAssignmentEntry(assignment.id, editingEntryId, payload); } else { await createAssignmentEntry(assignment.id, { ...payload, entryDate: serverToday, }); } await load(); toast({ title: 'ثبت امروز ذخیره شد' }); } catch (err) { toast({ title: 'خطا', description: getFetchErrorMessage(err, 'ثبت روزانه ناموفق بود'), variant: 'destructive', }); } finally { setSaving(false); } }; const handleExperienceNote = async () => { const text = experienceNote.trim(); if (text.length < 3) { toast({ title: 'یادداشت کوتاه است', description: 'اگر می‌خواهی مانعی را ثبت کنی، چند کلمه بنویس.', variant: 'destructive', }); return; } setSaving(true); try { const result = await submitAssignmentReport(assignment.id, text, experienceStatus); setAssignment(result.assignment); setExperienceNote(''); toast({ title: 'یادداشت تجربه ثبت شد' }); } catch (err) { toast({ title: 'خطا', description: getFetchErrorMessage(err, 'ثبت یادداشت ناموفق بود'), variant: 'destructive', }); } finally { setSaving(false); } }; const dayOptions: Array<{ value: AssignmentDayStatus; label: string }> = [ { value: 'done', label: 'بله، انجام دادم' }, { value: 'skipped', label: 'امروز انجام ندادم' }, { value: 'difficult', label: 'امروز برایم دشوار بود' }, ]; return (
بازگشت به تکالیف

جلسه {assignment.definition.sessionOrder}

{assignment.definition.title}

{assignmentTypeLabel(assignment.definition.assignmentType)} {assignmentStatusLabel(assignment.status)} {isMultiDay && {progressLabel(assignment)}}

راهنمای تمرین

{assignment.definition.instructions}

{completed && isOneTime && (

پاسخ ثبت‌شده

{}} disabled />
)} {isOneTime && !completed && (

پاسخ تمرین

فیلدهای ستاره‌دار لازم‌اند. می‌توانی پیش‌نویس ذخیره کنی و بعداً ادامه بدهی.

)} {isMultiDay && (

پیشرفت کلی

{progressLabel(assignment)}

{assignment.definition.minValidDays != null ? (

تکمیل پس از {assignment.definition.minValidDays} روز انجام‌شده

) : (

تکمیل خودکار فعلاً فعال نیست

)}
{assignment.completionBlockReason && !completed ? (

{assignment.completionBlockReason}

) : null} {completed ? (

این تمرین تکمیل شده است.

) : null}
)} {isMultiDay && !completed && (

ثبت امروز ({serverToday}) {editingEntryId ? ' — ویرایش' : ''}

آیا امروز این تمرین را انجام دادی؟

{dayOptions.map((opt) => ( ))}
{dayStatus === 'done' ? ( <>