mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
task list working
This commit is contained in:
@@ -14,6 +14,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import DeadlinePicker from '@/components/generic/DeadlinePicker';
|
||||
import {
|
||||
AlertDialog, AlertDialogAction, AlertDialogCancel,
|
||||
AlertDialogContent, AlertDialogDescription,
|
||||
@@ -51,9 +52,7 @@ export default function EditTask() {
|
||||
setForm({
|
||||
name: data.name ?? '',
|
||||
description: data.description ?? '',
|
||||
deadline: data.deadline
|
||||
? new Date(data.deadline).toISOString().slice(0, 16)
|
||||
: '',
|
||||
deadline: data.deadline ?? '',
|
||||
status: data.status ?? 'pending',
|
||||
is_required: data.is_required ?? true,
|
||||
requirements: reqs,
|
||||
@@ -185,32 +184,30 @@ export default function EditTask() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="deadline">Deadline</Label>
|
||||
<Input
|
||||
id="deadline"
|
||||
type="datetime-local"
|
||||
value={form.deadline}
|
||||
onChange={(e) => setForm({ ...form, deadline: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label>Status</Label>
|
||||
<Select
|
||||
value={form.status}
|
||||
onValueChange={(v) => setForm({ ...form, status: v })}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{STATUS_OPTIONS.map((s) => (
|
||||
<SelectItem key={s.value} value={s.value}>{s.label}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<Label>Deadline</Label>
|
||||
<DeadlinePicker
|
||||
value={form.deadline}
|
||||
onChange={(iso) => setForm({ ...form, deadline: iso })}
|
||||
disabled={loading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<Label>Status</Label>
|
||||
<Select
|
||||
value={form.status}
|
||||
onValueChange={(v) => setForm({ ...form, status: v })}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{STATUS_OPTIONS.map((s) => (
|
||||
<SelectItem key={s.value} value={s.value}>{s.label}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between rounded-md border px-3 py-2.5">
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
ArrowLeft, Pencil, FileText, CalendarClock,
|
||||
Link2, Upload, BookOpen, BookMarked, FileCheck2,
|
||||
Info, GitPullRequest, Tag, Globe, Copy, File, Bookmark,
|
||||
ClipboardCheck,
|
||||
} from 'lucide-react';
|
||||
|
||||
// ─── Same config as ViewTaskList — label, icon only, all styling via shadcn tokens
|
||||
@@ -128,8 +129,8 @@ function TaskRequirementsSection({ requirements = [] }) {
|
||||
export default function ViewTask() {
|
||||
const navigate = useNavigate();
|
||||
const { taskListId, taskId } = useParams();
|
||||
const { fetchTask } = useAdminTask();
|
||||
const { fmtDate } = useDateFormat();
|
||||
const { fetchTask, fetchCompletions, completionPagination, completionLoading } = useAdminTask();
|
||||
const { fmtDateTime } = useDateFormat();
|
||||
|
||||
const [task, setTask] = useState(null);
|
||||
|
||||
@@ -138,6 +139,7 @@ export default function ViewTask() {
|
||||
if (!data) return;
|
||||
setTask(data);
|
||||
});
|
||||
fetchCompletions(taskListId, taskId, { page: 1, limit: 1 });
|
||||
}, [taskListId, taskId]);
|
||||
|
||||
if (!task) return (
|
||||
@@ -202,7 +204,7 @@ export default function ViewTask() {
|
||||
<span className="text-sm">
|
||||
Deadline:{' '}
|
||||
<span className="text-foreground font-medium">
|
||||
{fmtDate(task.deadline)}
|
||||
{fmtDateTime(task.deadline)}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@@ -224,6 +226,28 @@ export default function ViewTask() {
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Completions */}
|
||||
<Separator />
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<ClipboardCheck className="size-4" /> Completions
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-sm font-medium text-foreground">
|
||||
{completionLoading
|
||||
? '…'
|
||||
: `${completionPagination.totalRecords} submission${completionPagination.totalRecords === 1 ? '' : 's'}`}
|
||||
</span>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => navigate(`/admin/taskList/${taskListId}/tasks/${taskId}/completions`)}
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
{/* Requirements */}
|
||||
|
||||
@@ -16,7 +16,7 @@ function normalizeLinkUrl(url) {
|
||||
|
||||
export const requirementSchema = z.object({
|
||||
type: z.string(),
|
||||
reference_id: z.string().optional(),
|
||||
reference_id: z.string().nullable().optional(),
|
||||
duration_seconds: z.number().optional(),
|
||||
}).passthrough().superRefine((req, ctx) => {
|
||||
if (!READ_TYPES.includes(req.type)) return;
|
||||
|
||||
Reference in New Issue
Block a user