feat: refactor RoomCard and RoomList components, add SkeletonRoomCard for loading state

This commit is contained in:
Rémi 2025-01-04 16:11:05 +01:00
parent 85deb66a54
commit f54a8ccc0a
5 changed files with 122 additions and 151 deletions

View File

@ -1,6 +1,6 @@
"use client";
'use client';
import { parseDate, Time } from "@internationalized/date";
import { parseDate, Time } from '@internationalized/date';
import {
Button,
@ -9,66 +9,80 @@ import {
CardHeader,
DateInput,
Divider,
TimeInput,
} from "@nextui-org/react";
import { Room } from "./Room";
import moment from "moment";
import { useRouter } from "next/navigation";
TimeInput
} from '@nextui-org/react';
import { Room } from './Room';
import moment from 'moment';
import { useRouter } from 'next/navigation';
export const RoomCard = ({
id,
name,
date,
Times,
Presentator
}: Room) => {
export const RoomCard = ({ id, name, date, Times, Presentator }: Room) => {
const router = useRouter();
return (
<Card className="w-[300px]">
<Card className='w-[300px]'>
<CardHeader>
<div className="flex flex-col">
<p className="text-md">{name}</p>
<p className="text-small text-default-500">{Presentator.username}</p>
<div className='flex flex-col'>
<p className='text-md'>{name}</p>
<p className='text-small text-default-500'>
{Presentator.username}
</p>
</div>
</CardHeader>
<Divider />
<CardBody>
{Times.map((time) => (
<div className="flex flex-col gap-2" key={`${time.id}`}>
<DateInput isReadOnly label="Date" value={parseDate(moment(date).format("YYYY-MM-DD"))} />
<div className="flex items-center gap-2">
{Times.map(time => (
<div className='flex flex-col gap-2' key={`${time.id}`}>
<DateInput
isReadOnly
label='Date'
value={parseDate(moment(date).format('YYYY-MM-DD'))}
/>
<div className='flex items-center gap-2'>
<TimeInput
isReadOnly
label="Start"
label='Start'
hourCycle={24}
value={
new Time(moment(time.startTime).hours(), moment(time.startTime).minutes())
new Time(
moment(time.startTime).hours(),
moment(time.startTime).minutes()
)
}
/>
<span>-</span>
<TimeInput
isReadOnly
label="End"
label='End'
hourCycle={24}
value={new Time(moment(time.endTime).hours(), moment(time.endTime).minutes())}
value={
new Time(
moment(time.endTime).hours(),
moment(time.endTime).minutes()
)
}
/>
</div>
</div>
))}
</CardBody>
<div className="flex p-2">
<Button
className={"bg-transparent text-foreground border-default-200"}
color="primary"
radius="full"
size="sm"
variant={"bordered"}
onPress={() => {
router.push(`/room/${id}`);
}}
>Join</Button>
</div>
{moment(date).dayOfYear() === moment().dayOfYear() && (
<div className='flex p-2'>
<Button
className={
''
}
color='primary'
radius='full'
size='sm'
variant={'flat'}
onPress={() => {
router.push(`/room/${id}`);
}}
>
Join
</Button>
</div>
)}
</Card>
);
};

View File

@ -2,6 +2,7 @@
import { useEffect, useRef } from 'react';
import { RoomCard } from './Card';
import { Room } from './Room';
import { SkeletonRoomCard } from './SkeletonRoomCard';
export const RoomList = ({ rooms }: { rooms: Room[] }) => {
const scrollContainerRef = useRef<HTMLDivElement>(null);
@ -9,14 +10,17 @@ export const RoomList = ({ rooms }: { rooms: Room[] }) => {
const handleWheel = (event: WheelEvent) => {
if (event.deltaY === 0) return;
if (event.ctrlKey || event.shiftKey || event.altKey) return;
const scrollContainer = scrollContainerRef.current;
if (!scrollContainer) return;
const goLeft = event.deltaY < 0;
const isEnd = goLeft ? scrollContainer.scrollLeft === 0 : scrollContainer.scrollLeft + scrollContainer.clientWidth >= scrollContainer.scrollWidth;
const isEnd = goLeft
? scrollContainer.scrollLeft === 0
: scrollContainer.scrollLeft + scrollContainer.clientWidth >=
scrollContainer.scrollWidth;
if (isEnd) return;
event.preventDefault();
const scrollAmount = 10;
@ -49,17 +53,27 @@ export const RoomList = ({ rooms }: { rooms: Room[] }) => {
className='overflow-x-auto scrollbar-hide rounded-xl bg-default-100'
>
<ul className='flex'>
{rooms.map(room => (
<li key={room.id} className='p-2'>
<RoomCard
id={room.id}
name={room.name}
date={room.date}
Presentator={room.Presentator}
Times={room.Times}
/>
</li>
))}
{rooms?.length > 0 ? (
rooms.map(room => (
<li key={room.id} className='p-2'>
<RoomCard
id={room.id}
name={room.name}
date={room.date}
Presentator={room.Presentator}
Times={room.Times}
/>
</li>
))
) : (
<>
{Array.from({ length: 5 }).map((_, i) => (
<li key={i} className='p-2'>
<SkeletonRoomCard />
</li>
))}
</>
)}
</ul>
</div>
);

View File

@ -0,0 +1,30 @@
"use client"
import { Card, Skeleton, Divider } from "@nextui-org/react"
export const SkeletonRoomCard = () => {
return (
<Card className='w-[200px] space-y-5 p-4' radius='lg'>
<div className='flex flex-col gap-2'>
<Skeleton className='w-4/5 rounded-lg'>
<div className='h-3 w-4/5 rounded-lg bg-default-200' />
</Skeleton>
<Skeleton className='w-2/5 rounded-lg'>
<div className='h-3 w-2/5 rounded-lg bg-default-300' />
</Skeleton>
</div>
<Divider />
<Skeleton className='rounded-lg'>
<div className='h-12 rounded-lg bg-default-300' />
</Skeleton>
<div className='flex items-center gap-2'>
<Skeleton className='rounded-lg w-1/2'>
<div className='h-10 rounded-lg bg-default-300' />
</Skeleton>
<span>-</span>
<Skeleton className='rounded-lg w-1/2'>
<div className='h-10 rounded-lg bg-default-300' />
</Skeleton>
</div>
</Card>
)
}

View File

@ -1,19 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer utilities {
.scrollbar::-webkit-scrollbar {
height: 10px;
}
.scrollbar::-webkit-scrollbar-track {
border-radius: 100vh;
background: #5a5a5a54;
}
.scrollbar::-webkit-scrollbar-thumb {
background: #414141;
border-radius: 100vh;
}
}

View File

@ -7,34 +7,6 @@ import { RoomList } from './components/Room/List';
import { Header } from './components/Header';
import { axiosInstance } from './lib/axios';
const SkeletonCard = () => {
return (
<Card className='w-[200px] space-y-5 p-4' radius='lg'>
<div className='flex flex-col gap-2'>
<Skeleton className='w-4/5 rounded-lg'>
<div className='h-3 w-4/5 rounded-lg bg-default-200' />
</Skeleton>
<Skeleton className='w-2/5 rounded-lg'>
<div className='h-3 w-2/5 rounded-lg bg-default-300' />
</Skeleton>
</div>
<Divider />
<Skeleton className='rounded-lg'>
<div className='h-12 rounded-lg bg-default-300' />
</Skeleton>
<div className='flex items-center gap-2'>
<Skeleton className='rounded-lg w-1/2'>
<div className='h-10 rounded-lg bg-default-300' />
</Skeleton>
<span>-</span>
<Skeleton className='rounded-lg w-1/2'>
<div className='h-10 rounded-lg bg-default-300' />
</Skeleton>
</div>
</Card>
);
};
const HomePage = () => {
const [roomsLoading, setRoomsLoading] = useState(true);
const [rooms, setRooms] = useState<{
@ -80,61 +52,18 @@ const HomePage = () => {
<>
<Header />
<main className='flex flex-col gap-8 p-4'>
{roomsLoading ? (
<>
<section className='flex flex-col gap-2'>
<h2 className='font-semibold text-lg'>
Cours a venir
</h2>
<div className='flex gap-4'>
<SkeletonCard />
<SkeletonCard />
<SkeletonCard />
</div>
</section>
<section className='flex flex-col gap-2'>
<h2 className='font-semibold text-lg'>
Cours actuels
</h2>
<div className='flex gap-4'>
<SkeletonCard />
<SkeletonCard />
<SkeletonCard />
</div>
</section>
<section className='flex flex-col gap-2'>
<h2 className='font-semibold text-lg'>
Cours passés
</h2>
<div className='flex gap-4'>
<SkeletonCard />
<SkeletonCard />
<SkeletonCard />
</div>
</section>
</>
) : (
<>
<section className='flex flex-col gap-2'>
<h2 className='font-semibold text-lg'>
Cours a venir
</h2>
<RoomList rooms={rooms.future} />
</section>
<section className='flex flex-col gap-2'>
<h2 className='font-semibold text-lg'>
Cours actuels
</h2>
<RoomList rooms={rooms.actual} />
</section>
<section className='flex flex-col gap-2'>
<h2 className='font-semibold text-lg'>
Cours passés
</h2>
<RoomList rooms={rooms.past} />
</section>
</>
)}
<section className='flex flex-col gap-2'>
<h2 className='font-semibold text-lg'>Upcoming</h2>
<RoomList rooms={rooms.future} />
</section>
<section className='flex flex-col gap-2'>
<h2 className='font-semibold text-lg'>Current</h2>
<RoomList rooms={rooms.actual} />
</section>
<section className='flex flex-col gap-2'>
<h2 className='font-semibold text-lg'>Past</h2>
<RoomList rooms={rooms.past} />
</section>
</main>
</>
);