Skip to content

Commit 77c8bca

Browse files
authored
Merge pull request #30 from Octasol/addsearch
Added search feature in leaderboard
2 parents 07533fa + 2ae584a commit 77c8bca

File tree

5 files changed

+105
-20
lines changed

5 files changed

+105
-20
lines changed

src/app/(pages)/layout.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ const Layout = ({ children }: Props) => {
1111
const [verifiedEmail, setVerifiedEmail] = useState(true);
1212

1313
const verified = async (): Promise<void> => {
14-
console.log("session", session);
15-
1614
if (session && session.accessToken) {
1715
setVerifiedEmail(session.isVerifiedEmail);
1816
}

src/app/(pages)/leaderboard/page.tsx

Lines changed: 104 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,49 @@ import RankCard from "@/components/RankCard";
1313
import { Profile } from "@/lib/types";
1414
import { leaderboard } from "@/config/axios/Breakpoints";
1515
import { useRouter } from "next/navigation";
16-
import { ChevronLeft, ChevronRight } from "lucide-react";
16+
import { ChevronLeft, ChevronRight, Search, SearchIcon, X } from "lucide-react";
1717
import { useSelector } from "react-redux";
18+
import LoginButton from "@/components/Button/LoginButton";
19+
import { Input } from "@/components/ui/input";
1820

1921
const Leaderboard = () => {
2022
const router = useRouter();
2123
const [profile, setProfile] = useState<Profile[]>([]);
2224
const user = useSelector((state: any) => state.user);
2325
const [currentPage, setCurrentPage] = useState(1);
2426
const recordsPerPage = 15;
27+
const [isOpen, setIsOpen] = useState(false);
28+
const [search, setSearch] = useState("");
29+
const [filteredProfiles, setFilteredProfiles] = useState<Profile[]>([]);
30+
31+
useEffect(() => {
32+
const fetchProfiles = async () => {
33+
const { response } = await POST(leaderboard, {});
34+
setProfile(response?.data);
35+
setFilteredProfiles(response?.data);
36+
};
37+
fetchProfiles();
38+
}, []);
39+
40+
useEffect(() => {
41+
if (search) {
42+
const rankedProfiles = profile.map((p, index) => ({
43+
...p,
44+
rank: index + 1,
45+
}));
46+
setFilteredProfiles(
47+
rankedProfiles.filter((p) =>
48+
p.githubUsername.toLowerCase().includes(search.toLowerCase())
49+
)
50+
);
51+
} else {
52+
setFilteredProfiles([]);
53+
}
54+
}, [search, profile]);
55+
56+
const toggleSearch = () => {
57+
setIsOpen(!isOpen);
58+
};
2559

2660
const response = async () => {
2761
const { response } = await POST(leaderboard, {});
@@ -60,7 +94,7 @@ const Leaderboard = () => {
6094

6195
return (
6296
<>
63-
<div className="w-full flex justify-center items-center text-3xl font-bold tracking-widest">
97+
<div className="w-full hidden md:flex justify-center items-center text-3xl font-bold tracking-widest">
6498
LEADERBOARD
6599
</div>
66100
<div className="w-full h-fit pt-4">
@@ -79,7 +113,67 @@ const Leaderboard = () => {
79113
</div>
80114
</div>
81115

82-
<div className="flex flex-col justify-center items-center container max-w-5xl">
116+
<div className="absolute bottom-[82vh] md:bottom-10 right-[10px] z-30 max-w-[500px]">
117+
<div>
118+
<button
119+
onClick={toggleSearch}
120+
className="px-4 py-3 border-[1px] rounded-full border-slate-800 bg-black flex justify-center items-center gap-4"
121+
>
122+
<SearchIcon size={20} />
123+
<p className="hidden md:flex">Search</p>
124+
</button>
125+
</div>
126+
127+
<div
128+
className={`fixed w-full md:w-1/2 lg:w-1/3 h-4/6 bottom-0 right-0 z-30 border-[1px] bg-black border-slate-800 transition-transform duration-500 ease-in-out rounded-lg ${
129+
isOpen ? "translate-x-0" : "translate-x-full"
130+
}`}
131+
>
132+
<div className="p-4 flex flex-col gap-4">
133+
<div className="flex justify-between px-4 items-center">
134+
<h2 className="text-xl font-bold">Search Panel</h2>
135+
<X size={20} onClick={toggleSearch} className="cursor-pointer" />
136+
</div>
137+
<hr />
138+
<div>
139+
<Input
140+
id="first-name"
141+
placeholder="Enter name"
142+
name="name"
143+
value={search}
144+
onChange={(e) => setSearch(e.target.value)}
145+
/>
146+
</div>
147+
<div className="mt-4 max-h-[430px] overflow-y-auto">
148+
{search && filteredProfiles.length > 0 ? (
149+
<ul>
150+
{filteredProfiles.map((item) => (
151+
<li
152+
key={item.githubUsername}
153+
className="p-2 border-b cursor-pointer hover:bg-gray-700"
154+
onClick={() => userProfile(item.githubUsername)}
155+
>
156+
<div className="flex justify-between">
157+
<p className="w-[60px]">{item.rank}</p>
158+
<p className="w-[210px] flex justify-start">
159+
{item.githubUsername}
160+
</p>
161+
<p className="w-[80px] flex justify-end">
162+
{item.totalPoints}
163+
</p>
164+
</div>
165+
</li>
166+
))}
167+
</ul>
168+
) : search ? (
169+
<p className="text-center text-gray-400">No user found</p>
170+
) : null}
171+
</div>
172+
</div>
173+
</div>
174+
</div>
175+
176+
<div className="flex flex-col justify-center items-center px-4 md:container md:max-w-5xl">
83177
<Table>
84178
<TableHeader>
85179
<TableRow>
@@ -124,12 +218,13 @@ const Leaderboard = () => {
124218
</Table>
125219
</div>
126220
)}
127-
<div className="flex justify-between items-center py-6 w-full">
221+
<div className="flex justify-between items-center pt-6 pb-6 md:pb-16 w-full">
128222
<button
129223
onClick={handlePreviousPage}
130224
disabled={currentPage === 1}
131-
className={`px-4 py-2 rounded ${currentPage === 1 ? "opacity-50 cursor-not-allowed" : ""
132-
}`}
225+
className={`px-4 py-2 rounded ${
226+
currentPage === 1 ? "opacity-50 cursor-not-allowed" : ""
227+
}`}
133228
>
134229
<ChevronLeft color="white" size={40} />
135230
</button>
@@ -141,15 +236,14 @@ const Leaderboard = () => {
141236
<button
142237
onClick={handleNextPage}
143238
disabled={currentPage === totalPages}
144-
className={`px-4 py-2 rounded ${currentPage === totalPages ? "opacity-50 cursor-not-allowed" : ""
145-
}`}
239+
className={`px-4 py-2 rounded ${
240+
currentPage === totalPages ? "opacity-50 cursor-not-allowed" : ""
241+
}`}
146242
>
147243
<ChevronRight color="white" size={40} />
148244
</button>
149245
</div>
150246
</div>
151-
152-
{/* Pagination controls */}
153247
</>
154248
);
155249
};

src/components/Login/Login.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,6 @@ const Login = () => {
3939
const user = useSelector((state: any) => state.user);
4040
const sessionToVerifyEmail = useSelector((state: any) => state.user);
4141

42-
useEffect(() => {
43-
console.log("session", sessionToVerifyEmail.isVerifiedEmail);
44-
});
45-
4642
interface SessionUser {
4743
name?: string | null;
4844
email?: string | null;

src/components/Sidebar/index.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@ const Sidebar = ({ verified }: Props) => {
2323

2424
const isActive = (linkPath: string) => pathname.includes(linkPath);
2525

26-
useEffect(() => {
27-
console.log("session", verified);
28-
}, [verified]);
29-
3026
return (
3127
<>
3228
<div className="w-full flex justify-between">

src/lib/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export interface Profile {
22
githubUsername: string;
33
totalPoints: number;
4+
rank: number;
45
}
56

67
export interface GithubDevProfile {

0 commit comments

Comments
 (0)