'use client'; import { useRouter } from 'next/navigation'; import { type ChangeEvent, useContext, useEffect, useMemo, useState } from 'react'; import { useForm } from 'react-hook-form'; import { useSWRConfig } from 'swr'; import AppLink from './AppLink'; import Button from './Button'; import Dialog from './Dialog'; import Icon from './Icon'; import Input from './Input'; import Select from './Select'; import { UserContext } from '@/context/user'; import { useGroups } from '@/lib/hooks/use-groups'; import { usePuzzles } from '@/lib/hooks/use-puzzles'; import type { Chapter, Puzzle } from '@/lib/puzzles'; import { cn } from '@/lib/utils'; import useLocalStorage from '@/lib/hooks/use-local-storage'; const difficulty = [ { value: 'easy', label: 'Facile' }, { value: 'medium', label: 'Moyen' }, { value: 'hard', label: 'Difficile' } ]; // TODO: REFACTOR FILTER TO AVOID WARNINGS export default function Puzzles({ token }: { token: string }) { const { data: me } = useContext(UserContext); const { data, isLoading } = usePuzzles({ token }); const [isOpen, setIsOpen] = useState([]); const [filterTags, setFilterTags] = useState(''); const [filterDifficulty, setFilterDifficulty] = useState(''); const [filterChapter, setFilterChapter] = useState(); function handleClick(index: number) { setIsOpen((prevState) => { const newState = [...prevState]; newState[index] = !newState[index]; return newState; }); } function isInEventGroup(chapter: Chapter) { return ( chapter.startDate && chapter.endDate && me?.groups?.some((group) => group.chapter && group.chapter === chapter.id) ); } function isBeforeStart(chapter: Chapter) { if (!chapter.startDate || !chapter.endDate) { return false; } const startDate = new Date(chapter.startDate); const now = new Date(); return now.getTime() < startDate.getTime() + 10 * 60 * 1000; } const filteredData = useMemo(() => { if ((filterTags || filterDifficulty) && filterChapter) { return data ?.find((chapter) => chapter.id === filterChapter) ?.puzzles.filter((puzzle) => { if (!puzzle?.tags) return false; if (filterDifficulty && filterTags) { if (filterTags === 'completed') { return puzzle!.tags!.some((tag) => tag.name === filterDifficulty) && puzzle!.score; } else if (filterTags === 'not-completed') { return puzzle!.tags!.some((tag) => tag.name === filterDifficulty) && !puzzle!.score; } return ( puzzle!.tags!.some((tag) => tag.name === filterTags) && puzzle!.tags!.some((tag) => tag.name === filterDifficulty) ); } if (filterDifficulty) { return puzzle!.tags!.some((tag) => tag.name === filterDifficulty); } if (filterTags) { if (filterTags === 'completed') { return puzzle!.score; } else if (filterTags === 'not-completed') { return !puzzle!.score; } return puzzle!.tags!.some((tag) => tag.name === filterTags); } return puzzle; }) .map((puzzle) => puzzle); } return data?.find((chapter) => chapter.id === filterChapter)?.puzzles; }, [data, filterTags, filterDifficulty, filterChapter]); return ( <> {(!isLoading && data?.map((chapter) => (

{chapter.name}

{!isInEventGroup(chapter) && isBeforeStart(chapter) && ( handleClick(chapter.id)} trigger={ } className="right-96 p-4" > )}
{chapter.startDate && chapter.endDate ? (
{new Date(chapter.startDate).toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric', hour: 'numeric', minute: 'numeric' })}{' '} -{' '} {new Date(chapter.endDate).toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric', hour: 'numeric', minute: 'numeric' })}
) : (
)}
{isInEventGroup(chapter) && ( <> )}
{isInEventGroup(chapter) && (
    {filteredData && filteredData .sort((a, b) => a.scoreMax - b.scoreMax) .map((puzzle) => ( ))}
)}
))) || (
{[...Array(3).keys()].map((i) => (
    {[...Array(6).keys()].map((j) => ( ))}
))}
)} ); } function PuzzleProp({ puzzle, chapter }: { puzzle: Puzzle; chapter: Chapter }) { function isStarted(chapter: Chapter) { if (!chapter.startDate || !chapter.endDate) { return false; } const startDate = new Date(chapter.startDate); const now = new Date(); return now > startDate; } return (
  • tag.name.toLowerCase() === 'easy'), 'border-yellow-600/30': puzzle.tags?.find((tag) => tag.name.toLowerCase() === 'medium'), 'border-red-600/30': puzzle.tags?.find((tag) => tag.name.toLowerCase() === 'hard'), 'border-highlight-primary': !puzzle.tags?.length, 'cursor-not-allowed': !isStarted(chapter) } )} > {isStarted(chapter) ? (
    {puzzle.name}{' '} ({puzzle.score ? `${puzzle.score}` : '?'}/{puzzle.scoreMax} points)
    {puzzle.tags?.length && (
    {puzzle.tags .filter((tag) => !['easy', 'medium', 'hard'].includes(tag.name)) .map((tag, i) => ( {tag.name} ))}
    )}
    ) : (
    {puzzle.name}{' '} ({puzzle.score ? `${puzzle.score}` : '?'}/{puzzle.scoreMax} points)
    {puzzle.tags?.length && (
    {puzzle.tags .filter((tag) => !['easy', 'medium', 'hard'].includes(tag.name)) .map((tag, i) => ( {tag.name} ))}
    )}
    )}
  • ); } function FilterDifficulty({ chapters, chapter, filter, setFilter, setFilterChapter }: { chapters: Chapter[]; chapter: Chapter; filter: string; setFilter: (filter: string) => void; setFilterChapter: (chapter: number) => void; }) { const [stored, setStored] = useLocalStorage({ key: 'filter-difficulty', initialValue: '' }); let options = [] as { title: string; value: string }[]; options = chapters .find((c) => c.id === chapter.id) ?.puzzles?.map((p) => p.tags) .flat() .filter((tag) => difficulty.some((d) => tag?.name === d.value)) .filter((tag, index, self) => self.findIndex((t) => t!.name === tag!.name) === index) .map((t) => { return { title: t!.name, value: t!.name }; }) as { title: string; value: string }[]; options?.unshift({ title: 'Toutes les difficultés', value: '' }); setFilterChapter(chapter.id); function handleChange(event: ChangeEvent) { setFilter(event.target.value); // TODO OPTI // @ts-ignore setStored(event.target.value); } useEffect(() => { if (stored) { // TODO OPTI // @ts-ignore setFilter(stored); } }, [stored]); return ( ); } type GroupData = { name?: string; chapter?: number; puzzle?: number; }; function GroupForm({ chapter, token }: { chapter: Chapter; token: string }) { const [isJoining, setIsJoining] = useState(false); const { data: groups } = useGroups({ token }); const { mutate } = useSWRConfig(); const router = useRouter(); const { register, handleSubmit, reset } = useForm({ defaultValues: { name: undefined, chapter: chapter.id, puzzle: undefined } }); async function onSubmit(data: GroupData) { const res = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/${isJoining ? 'groupJoin' : 'groupCreate'}`, { method: 'POST', body: JSON.stringify(data), headers: { Authorization: `Bearer ${token}` } } ); if (res.ok) { mutate('me'); // TODO REFACTOR router.refresh(); } } return (

    {!isJoining ? ( <>
    ) : ( <>