/** * Tasks Page (Challenges) * * Demonstrates: * - 'unclaimed-or-own' permission for claimable tasks * - writableFields for restricting which fields can be created or updated * - timestampTrigger for automatic timestamps * - Admin grading workflow */ import { useState, useMemo } from 'react' import { useUser } from 'deepspace' import { useUsers } from 'deepspace' import { useQuery } from 'deepspace' import { useMutations } from 'deepspace' import { Button, Modal, Badge, EmptyState } from '@/components/ui' import { ROLES, type Role } from 'deepspace' import { DIFFICULTY, DIFFICULTY_CONFIG, GRADE, GRADE_CONFIG, type Difficulty, type Grade, type BadgeVariant } from '../components/tasks/tasks-constants' // Tailwind color classes for buttons (semantic colors) const buttonColorClasses: Record, string> = { default: 'text-primary', success: 'text-success', warning: 'text-warning', destructive: 'text-destructive', info: 'text-info', secondary: 'text-muted-foreground', outline: 'text-foreground', } // ============================================================================ // Types // ============================================================================ interface Challenge { title: string description: string difficulty: string points: number claimedById?: string claimedAt?: string submitted: boolean submissionUrl?: string submissionNotes?: string submittedAt?: string grade?: string feedback?: string gradedById?: string gradedAt?: string createdById: string } interface TasksPageProps { className?: string } // ============================================================================ // Create Challenge Modal // ============================================================================ interface CreateChallengeModalProps { isOpen: boolean onClose: () => void onCreate: (title: string, description: string, difficulty: Difficulty) => void } function CreateChallengeModal({ isOpen, onClose, onCreate }: CreateChallengeModalProps) { const [title, setTitle] = useState('') const [description, setDescription] = useState('') const [difficulty, setDifficulty] = useState(DIFFICULTY.MEDIUM) const handleSubmit = () => { if (title.trim() && description.trim()) { onCreate(title.trim(), description.trim(), difficulty) setTitle('') setDescription('') setDifficulty(DIFFICULTY.MEDIUM) onClose() } } return ( Create Challenge
setTitle(e.target.value)} placeholder="Challenge title" className="w-full px-3 py-2 bg-transparent border border-border rounded-lg text-foreground placeholder-muted-foreground focus:outline-none focus:ring-ring" autoFocus />