peer-at-code-web/ui/Puzzles.tsx
2023-03-28 09:27:48 +02:00

121 lines
5 KiB
TypeScript

'use client';
import { usePuzzles } from '@/lib/hooks/use-puzzles';
import { type Chapter } from '@/lib/puzzles';
import { cn } from '@/lib/utils';
import AppLink from './AppLink';
import Icon from './Icon';
export default function Puzzles({ token }: { token: string }) {
const { data, isLoading } = usePuzzles({ token });
// SOme chapters have a start date and a end date (for example, the first chapter is only available for 2 weeks), I want to want to lock the chapter if the current date is not between the start and end date
// I want to display a message to the user if the chapter is locked
function isChapterLocked(chapter: Chapter) {
return (
chapter.startDay &&
chapter.endDay &&
new Date() > new Date(chapter.startDay) &&
new Date() < new Date(chapter.endDay)
);
}
return (
<>
{(!isLoading &&
data?.map((chapter) => (
<div key={chapter.id} className="flex flex-col space-y-4">
<div className="flex items-center justify-between">
<h3 className="text-xl font-semibold sm:text-2xl">
Chapitre {chapter.id} - {chapter.name}{' '}
</h3>
<div className="h-1 w-1/4 rounded-lg bg-gray-200">
<div className="h-1 w-1/2 rounded-lg bg-gradient-to-tl from-brand to-brand-accent" />
</div>
</div>
<ul
className={cn('flex flex-col space-y-4', {
// If the chapter is locked i want to add a class to li children to make them unclickable
'pointer-events-none': isChapterLocked(chapter)
})}
>
{chapter.puzzles &&
chapter.puzzles.map((puzzle) => (
<AppLink key={puzzle.id} href={`/dashboard/puzzles/${puzzle.id}`}>
<li
className={cn(
'group flex items-center justify-between rounded-md border-2 bg-primary-700 p-4 font-code hover:bg-primary-600',
{
'border-green-600/30': puzzle.tags
?.map((tag) => tag.name.toLowerCase())
.includes('easy'),
'border-yellow-600/30': puzzle.tags
?.map((tag) => tag.name.toLowerCase())
.includes('medium'),
'border-red-600/30': puzzle.tags
?.map((tag) => tag.name.toLowerCase())
.includes('hard'),
'border-highlight-secondary/30': !puzzle.tags?.length
}
)}
>
<div className="flex gap-x-2">
<span className="text-base font-semibold">{puzzle.name}</span>
{puzzle.tags?.length && (
<div className="flex gap-x-2 text-sm text-muted">
{puzzle.tags
.filter((tag) => !['easy', 'medium', 'hard'].includes(tag.name))
.map((tag, i) => (
<span
key={i}
className={cn('inline-block rounded-md bg-primary-900 px-2 py-1')}
>
{tag.name}
</span>
))}
</div>
)}
</div>
<Icon
className="-translate-x-2 transform-gpu duration-300 group-hover:translate-x-0"
name="arrow-right-line"
/>
</li>
</AppLink>
))}
</ul>
</div>
))) || (
<div className="flex flex-col space-y-6">
{[...Array(3).keys()].map((i) => (
<div key={i} className="flex flex-col space-y-4">
<div className="flex items-center justify-between">
<span className="inline-block h-8 w-1/2 rounded-lg bg-primary-600" />
<span
className="inline-block h-1 w-1/4 animate-pulse rounded-lg bg-primary-600"
style={{
animationDelay: `${i * 0.05}s`,
animationDuration: '1s'
}}
/>
</div>
<ul className="flex flex-col space-y-4">
{[...Array(6).keys()].map((j) => (
<span
key={j}
className="inline-block h-14 animate-pulse rounded-lg bg-primary-600"
style={{
animationDelay: `${j * 0.05}s`,
animationDuration: '1s'
}}
/>
))}
</ul>
</div>
))}
</div>
)}
</>
);
}