Skip to content

Commit decf6dc

Browse files
committed
make table components and make data & types
1 parent b66e171 commit decf6dc

File tree

10 files changed

+827
-469
lines changed

10 files changed

+827
-469
lines changed

src/app/contests/page.tsx

Lines changed: 65 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,93 @@
11
'use client';
22

3-
import { Trophy, Users, FileCode2, Plus } from 'lucide-react';
4-
import { Button } from 'react-bootstrap';
3+
import React from 'react';
4+
import { Plus, Trophy } from 'lucide-react';
55

6+
import ContestTable, { Contest } from '@/components/ContestTable';
7+
import contestsData from '@/data/contestsData';
68
import { Checkbox } from '@/components/ui/checkbox';
7-
import ContestsTable from '@/components/ContestsTable';
9+
import { Button } from '@/components/ui/button';
10+
import ContestCards from '@/components/ContestCards';
811
import Footer from '@/components/Footer';
9-
// import contests from '@/data/contests';
1012

1113
export default function ContestsPage() {
14+
const [contests, setContests] = React.useState<Contest[]>(contestsData);
15+
16+
const [favoriteOnly, setFavoriteOnly] = React.useState(false);
17+
18+
const onClickFavorite = (id: Contest['id']) => {
19+
setContests((prev) =>
20+
prev.map((c) => (c.id === id ? { ...c, isFavorite: !c.isFavorite } : c)),
21+
);
22+
};
23+
24+
const filteredContests = React.useMemo(
25+
() => (favoriteOnly ? contests.filter((p) => p.isFavorite) : contests),
26+
[contests, favoriteOnly],
27+
);
28+
29+
const onEnter = (id: Contest['id']) => {
30+
// TODO: enter the contest/{id} detail edit page
31+
console.log('enter', id);
32+
};
33+
34+
const onDelete = (id: Contest['id']) => {
35+
// TODO: delete the contest/{id} immediately
36+
const ok = window.confirm('Are you sure you want to delete this?');
37+
if (!ok) return;
38+
setContests((prev) => prev.filter((c) => c.id !== id));
39+
};
40+
1241
return (
1342
<div className='min-h-screen bg-gradient-to-br from-gray-50 to-gray-100'>
14-
<div className='container px-4 py-8 mx-auto'>
15-
<div className='flex items-center justify-between mb-8'>
43+
<div className='container px-4 py-6 mx-auto'>
44+
<div className='flex items-center justify-between mb-6'>
1645
<div>
1746
<h1 className='text-3xl font-bold text-gray-900 flex items-center gap-3'>
1847
<Trophy className='h-8 w-8 text-primary' />
1948
Contests
2049
</h1>
21-
<p className='text-gray-600 mt-1'>{contests.length} contests available</p>
50+
<p className='text-gray-600 mt-1'>
51+
{filteredContests.length} contests available
52+
</p>
2253
</div>
23-
<div className='flex items-center gap-6'>
24-
<div className='flex items-center gap-6'>
25-
<div className='flex items-center gap-2'>
26-
<Checkbox id='favorites' /> {/* TODO: Implement favorite filter */}
27-
<label
28-
htmlFor='favorites'
29-
className='text-sm font-medium text-gray-700'
30-
>
31-
Only favorite
32-
</label>
33-
</div>
34-
<div className='flex items-center gap-2'>
35-
<Checkbox id='activity' />{' '}
36-
{/* TODO: Implement view only my-activity filter */}
37-
<label htmlFor='activity' className='text-sm font-medium text-gray-700'>
38-
Only my activity
39-
</label>
40-
</div>
54+
<div className='flex items-center gap-4'>
55+
<div className='flex items-center gap-2'>
56+
<Checkbox
57+
id='favorites'
58+
checked={favoriteOnly}
59+
onCheckedChange={(v) => setFavoriteOnly(Boolean(v))}
60+
aria-controls='contests-table'
61+
/>
62+
<label htmlFor='favorites' className='text-sm cursor-pointer'>
63+
Only favorite
64+
</label>
65+
</div>
66+
{/* TODO: get user-info, and add filter function and onClick state */}
67+
<div className='flex items-center gap-2'>
68+
<Checkbox id='activity' />
69+
<label htmlFor='activity' className='text-sm'>
70+
Only my activity
71+
</label>
4172
</div>
4273
<Button
74+
onClick={() => console.log('Creating new contests!')}
4375
className='inline-flex flex-row flex-nowrap items-center gap-2 whitespace-nowrap leading-none
4476
bg-amber-400 hover:bg-amber-500 text-white px-4 py-2 h-auto rounded-xl shadow'
4577
>
4678
<Plus className='h-4 w-4 shrink-0' />
47-
<span className='font-medium inline-block'>New Contest</span>
79+
<span className='font-medium inline-block'>Create Contest</span>
4880
</Button>
4981
</div>
5082
</div>
5183

52-
<ContestsTable contests={contests} />
53-
54-
{/* TODO: Make Components */}
55-
<div className='grid grid-cols-1 md:grid-cols-3 gap-6 mt-8'>
56-
<div className='bg-white rounded-xl p-6 border border-gray-200/60 shadow-lg'>
57-
<div className='flex items-center gap-3'>
58-
<div className='w-12 h-12 bg-gradient-to-br from-green-500 to-emerald-600 rounded-lg flex items-center justify-center'>
59-
<Trophy className='h-6 w-6 text-white' />
60-
</div>
61-
<div>
62-
<p className='text-2xl font-bold text-gray-900'>3</p>
63-
<p className='text-sm text-gray-600'>Total Contests</p>
64-
</div>
65-
</div>
66-
</div>
67-
<div className='bg-white rounded-xl p-6 border border-gray-200/60 shadow-lg'>
68-
<div className='flex items-center gap-3'>
69-
<div className='w-12 h-12 bg-gradient-to-br from-purple-500 to-pink-600 rounded-lg flex items-center justify-center'>
70-
<FileCode2 className='h-6 w-6 text-white' />
71-
</div>
72-
<div>
73-
<p className='text-2xl font-bold text-gray-900'>45</p>
74-
<p className='text-sm text-gray-600'>Total Problems</p>
75-
</div>
76-
</div>
77-
</div>
78-
<div className='bg-white rounded-xl p-6 border border-gray-200/60 shadow-lg'>
79-
<div className='flex items-center gap-3'>
80-
<div className='w-12 h-12 bg-gradient-to-br from-blue-500 to-cyan-600 rounded-lg flex items-center justify-center'>
81-
<Users className='h-6 w-6 text-white' />
82-
</div>
83-
<div>
84-
<p className='text-2xl font-bold text-gray-900'>479</p>
85-
<p className='text-sm text-gray-600'>Total Participants</p>
86-
</div>
87-
</div>
88-
</div>
89-
</div>
84+
<ContestTable
85+
contests={filteredContests}
86+
onClickFavorite={onClickFavorite}
87+
onEnter={onEnter}
88+
onDelete={onDelete}
89+
/>
90+
<ContestCards contests={filteredContests} />
9091
</div>
9192
<Footer />
9293
</div>

0 commit comments

Comments
 (0)