Skip to content

Commit 87ee1cb

Browse files
Merge pull request #10 from CodeChefVIT/harshit/users
changes for snajay
2 parents 80734c5 + 914087d commit 87ee1cb

16 files changed

Lines changed: 386 additions & 190 deletions

File tree

src/api/auth.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const login = async(email: string, password: string) =>{
66
const response = await axios.post('/auth/login', {email, password})
77
return response.data as data;
88
}catch(err){
9+
910
throw err;
1011
}
1112
}

src/api/fetchTeamDetails.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { TeamsFromSearch, type Team, type TeamResponse } from "@/data/schema";
2+
import { TeamResponseSchema } from "@/data/schema";
3+
import axios from "./axiosConfig";
4+
5+
export const fetchTeamDetails = async ({ uuid }: { uuid: string}) => {
6+
try {
7+
const response1 = await axios.get<TeamResponse>(
8+
`admin/teams/${uuid}`
9+
);
10+
// const response2 = await axios.get(`/admin/teams/leader/${uuid}`)
11+
const response3 = await axios.get<TeamsFromSearch>(`/admin/members/${uuid}`)
12+
console.log(response1.data.data.team )
13+
console.log(response3.data.data.team )
14+
return{
15+
team: response1.data.data.team,
16+
members: response3.data.data.team
17+
}
18+
} catch (err) {
19+
console.log(err);
20+
throw err;
21+
}
22+
};

src/api/fetchTeams.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,27 @@ import { type Team, type TeamsResponse } from "@/data/schema";
22
import { TeamsResponseSchema } from "@/data/schema";
33
import axios from "./axiosConfig";
44

5-
export const fetchTeams = async ({ page, limit }: { page: number; limit: number }) => {
5+
export const fetchTeams = async ({
6+
limit,
7+
cursorId,
8+
}: {
9+
limit: number;
10+
cursorId?: string;
11+
}) => {
612
try {
7-
const response = await axios.get<TeamsResponse>(
8-
`admin/teams?page=${page}&limit=${limit}`
9-
);
13+
14+
const url = cursorId
15+
? `admin/teams?limit=${limit}&cursor=${cursorId}`
16+
: `admin/teams?limit=${limit}`;
17+
18+
const response = await axios.get<TeamsResponse>(url);
19+
1020
const parsedResponse = TeamsResponseSchema.parse(response.data);
11-
return { teams: parsedResponse.data.teams };
21+
const teams = parsedResponse.data.teams;
22+
const nextCursor = teams!=null ? teams[teams.length - 1]?.ID : null;
23+
24+
return { teams, nextCursor };
25+
// return response.data.data.teams
1226
} catch (err) {
1327
console.log(err);
1428
throw err;

src/api/fetchUsers.ts

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,38 @@ import { usersResponseSchema } from "@/data/schema";
33
import axios from "./axiosConfig";
44

55
export const fetchUsers = async ({
6-
page,
76
limit,
7+
cursorId,
8+
name,
89
}: {
9-
page: number;
1010
limit: number;
11+
cursorId?: string;
12+
name?: string;
1113
}) => {
1214
try {
13-
const response = await axios.get<UserResponse>(
14-
`admin/users?page=${page}&limit=${limit}`
15-
);
15+
const params = new URLSearchParams({ limit: String(limit) });
16+
17+
if (name) {
18+
params.append("name", name);
19+
} else if (cursorId) {
20+
params.append("cursor", cursorId);
21+
}
22+
23+
const url = `admin/users?${params.toString()}`;
24+
25+
const response = await axios.get<UserResponse>(url);
1626

1727
const parsedResponse = usersResponseSchema.parse(response.data);
18-
return {users: parsedResponse.data.users, totalPages: 100};
28+
const users = parsedResponse.data.users;
29+
console.log(users);
30+
const nextCursor = users != null ? users[users.length - 1]?.ID : null;
31+
32+
return {
33+
users,
34+
nextCursor,
35+
};
1936
} catch (err) {
2037
console.log(err);
2138
throw err;
2239
}
23-
};
40+
};

src/app/layout.tsx

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
11
// app/layout.tsx
2+
import { ThemeProvider } from "@/components/theme-provider";
23
import Providers from "@/lib/Providers";
34
import "@/styles/globals.css";
45
import { GeistSans } from "geist/font/sans";
56
import { type Metadata } from "next";
67
import { Toaster } from "react-hot-toast";
7-
import { ThemeProvider } from "@/components/theme-provider";
88

9-
import {
10-
Sheet,
11-
SheetContent,
12-
SheetTrigger,
13-
} from "@/components/ui/sheet";
14-
import { Button } from "@/components/ui/button";
15-
import Link from "next/link";
169
import {
1710
Avatar,
1811
AvatarFallback,
1912
AvatarImage,
2013
} from "@/components/ui/avatar";
14+
import { Button } from "@/components/ui/button";
2115
import {
2216
DropdownMenu,
2317
DropdownMenuContent,
@@ -26,12 +20,19 @@ import {
2620
} from "@/components/ui/dropdown-menu";
2721
import { ScrollArea } from "@/components/ui/scroll-area";
2822
import {
29-
HomeIcon,
30-
UsersIcon,
23+
Sheet,
24+
SheetContent,
25+
SheetTrigger,
26+
} from "@/components/ui/sheet";
27+
import {
3128
GroupIcon,
32-
MenuIcon,
29+
HomeIcon,
3330
LogOutIcon,
31+
MenuIcon,
32+
Search,
33+
UsersIcon
3434
} from "lucide-react";
35+
import Link from "next/link";
3536

3637

3738
export const metadata: Metadata = {
@@ -76,7 +77,7 @@ export default function RootLayout({
7677
<Sidebar />
7778
<div className="flex flex-col flex-1">
7879
<Navbar />
79-
<main className="flex-1 p-8">
80+
<main className=" p-8 overflow-y-scroll">
8081
{children}
8182
</main>
8283
</div>
@@ -94,14 +95,15 @@ export default function RootLayout({
9495
{ name: "Dashboard", href: "/dashboard", icon: HomeIcon },
9596
{ name: "Users", href: "/users", icon: UsersIcon },
9697
{ name: "Teams", href: "/teams", icon: GroupIcon },
98+
{name: "Search Team", href: "/team_search", icon: Search}
9799
];
98100

99101
return (
100102
<aside className="border-r border-gray-200 h-full w-64 dark:border-gray-700">
101103
<ScrollArea className="h-full">
102104
<div className="p-4">
103105
<Link href="/" className="text-2xl font-bold mb-6 block">
104-
CodeChef Admin
106+
Devsoc Admin
105107
</Link>
106108
</div>
107109
<nav className="px-2 py-4">

src/app/page.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1+
"use client"
2+
13
import Image from "next/image";
24
import Link from "next/link";
35
import logo from "../../public/cc-logo.svg";
6+
import { useEffect } from "react";
7+
import { useRouter } from "next/navigation";
48

59
export default function HomePage() {
10+
const router = useRouter();
11+
useEffect(()=>{
12+
router.push("/users")
613

14+
}, [])
715
return (
816
<>
9-
<main className="flex min-h-screen flex-col items-center justify-center p-8">
17+
<main className=" flex min-h-screen flex-col items-center justify-center p-8">
1018
<div className="w-full max-w-xl rounded-lg bg-white p-8 text-center text-black shadow-lg">
1119
<Image
1220
src={logo as HTMLImageElement}

src/app/team_search/page.tsx

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
"use client";
2+
import { useQuery } from "@tanstack/react-query";
3+
import { fetchTeamDetails } from "@/api/fetchTeamDetails";
4+
import { useState } from "react";
5+
import Image from "next/image";
6+
import loading from "@/assets/images/loading.gif";
7+
import Link from "next/link";
8+
9+
// Member interface to match API response
10+
interface Member {
11+
FirstName: string;
12+
LastName: string;
13+
IsLeader: boolean;
14+
GithubProfile: string;
15+
RegNo: string;
16+
PhoneNo: string;
17+
}
18+
19+
// Team interface to match API response
20+
interface Team {
21+
ID: string;
22+
Name: string;
23+
NumberOfPeople: number;
24+
RoundQualified: number;
25+
Code: string;
26+
IsBanned: boolean;
27+
}
28+
29+
// Expected API response structure
30+
interface TeamResponse {
31+
team: Team;
32+
members: Member[];
33+
}
34+
35+
// MemberCard component to display member details
36+
function MemberCard({ member }: { member: Member }) {
37+
return (
38+
<div className="border p-3 rounded-md shadow-md bg-black text-white mb-2">
39+
<p className="font-semibold">
40+
{member.FirstName} {member.LastName} ({member.IsLeader ? "Leader" : "Member"})
41+
</p>
42+
<p>Registration Number: {member.RegNo}</p>
43+
<p>Phone: {member.PhoneNo}</p>
44+
<p>
45+
GitHub Profile:{" "}
46+
<Link
47+
href={member.GithubProfile}
48+
target="_blank"
49+
50+
className="text-blue-400 underline"
51+
>
52+
{member.GithubProfile}
53+
</Link>
54+
</p>
55+
</div>
56+
);
57+
}
58+
59+
// Main component
60+
export default function TeamSearch() {
61+
// const [uuid, setUuid] = useState<string>("");
62+
63+
// const {
64+
// data: teamList,
65+
// isLoading,
66+
// isError,
67+
// } = useQuery<TeamResponse>({
68+
// queryKey: ["theTeams", uuid],
69+
// queryFn: () => fetchTeamDetails({ uuid }),
70+
// enabled: !!uuid, // Ensures API call only happens when UUID is entered
71+
// });
72+
73+
return (
74+
// <div className={`${!teamList? "h-[70vh]": "h-auto"} w-[100%] mx-auto p-4 border rounded-md shadow-lg bg-black text-white`}>
75+
// Input field for UUID
76+
// <div className="flex flex-col items-center mb-4">
77+
// <input
78+
// className="w-[50%] p-2 border rounded-md bg-gray-800 text-white"
79+
// placeholder="Enter team ID"
80+
// value={uuid}
81+
// onChange={(e) => setUuid(e.target.value)}
82+
// type="text"
83+
// />
84+
// </div>
85+
86+
// {/* Loading Indicator */}
87+
// {isLoading && (
88+
// <div className="flex justify-center">
89+
// <Image className="w-[50%]" src={loading} width={100} height={100} alt="Loading..." />
90+
// </div>
91+
// )}
92+
93+
// {/* Error Message */}
94+
// {isError && <div className="text-red-500">Error fetching team data</div>}
95+
96+
// {/* Display Team Details */}
97+
// {teamList && (
98+
// <div className="p-3 border rounded-md shadow-md bg-black text-white">
99+
// <h2 className="text-xl font-bold py-2">Team Information</h2>
100+
// <p>ID: {teamList.team.ID}</p>
101+
// <p>Name: {teamList.team.Name}</p>
102+
// <p>Number of People: {teamList.team.NumberOfPeople}</p>
103+
// <p>Round Qualified: {teamList.team.RoundQualified}</p>
104+
// <p>Code: {teamList.team.Code}</p>
105+
// <p>Banned: {teamList.team.IsBanned ? "Yes" : "No"}</p>
106+
107+
// {/* Display Members */}
108+
// <h2 className="text-xl font-bold mt-4 py-2">Team Members</h2>
109+
// {teamList.members.map((member) => (
110+
// <MemberCard key={member.RegNo} member={member} />
111+
// ))}
112+
// {teamList.members.map((member) => (
113+
// <MemberCard key={member.RegNo} member={member} />
114+
// ))}
115+
// </div>
116+
// )}
117+
// </div>
118+
<></>
119+
);
120+
}

src/app/teams/page.tsx

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import { useState } from "react";
1313
import { TeamModal } from "@/components/table/team-modal";
1414

1515
export default function Teams() {
16-
const [pageIndex, setPageIndex] = useState(0);
17-
const [pageSize, setPageSize] = useState(10);
16+
const [cursorHistory, setCursorHistory] = useState<string[]>([]);
17+
const [currentCursor, setCurrentCursor] = useState<string | undefined>(undefined);
1818
const [selectedTeam, setSelectedTeam] = useState<Team | null>(null);
1919
const [open, setOpen] = useState(false);
2020

@@ -25,19 +25,31 @@ export default function Teams() {
2525
isLoading,
2626
isError,
2727
} = useQuery({
28-
queryKey: ["teams", pageIndex, pageSize],
29-
queryFn: () => fetchTeams({ page: pageIndex + 1, limit: pageSize }),
28+
queryKey: ["users", currentCursor],
29+
queryFn: () => fetchTeams({limit: 1, cursorId: currentCursor}),
30+
// placeholderData: (previousData) => previousData,
3031
});
3132

32-
const handlePageChange = (page: number)=>{
33-
setPageIndex(page);
34-
queryClient.invalidateQueries({queryKey: ["teams"]});
35-
}
33+
const handleNextPage = () => {
34+
if (teamList?.nextCursor) {
35+
console.log("yes cursor available")
36+
setCursorHistory((prev) => [...prev, currentCursor ?? ""]); // Store current cursor
37+
setCurrentCursor(teamList.nextCursor); // Move to the next page
38+
}
39+
};
3640

37-
const handlePageSizeChange = (size: number)=>{
38-
setPageSize(size);
39-
queryClient.invalidateQueries({queryKey: ["teams"]});
40-
}
41+
const handlePrevPage = () => {
42+
if (cursorHistory.length > 0) {
43+
const prevCursor = cursorHistory[cursorHistory.length - 1]; // Get last cursor
44+
setCursorHistory((prev) => prev.slice(0, -1)); // Remove last cursor from history
45+
setCurrentCursor(prevCursor ?? undefined); // Move to previous page
46+
}
47+
};
48+
49+
// const handlePageSizeChange = (size: number)=>{
50+
// setPageSize(size);
51+
// queryClient.invalidateQueries({queryKey: ["teams"]});
52+
// }
4153

4254
if (isLoading) {
4355
<>loading...</>;
@@ -63,11 +75,8 @@ export default function Teams() {
6375
<DataTable<Team, string>
6476
columns={teamCol}
6577
data={teamList?.teams ?? []}
66-
pageCount = {100}
67-
onPageChange={setPageIndex}
68-
onPageSizeChange={setPageSize}
69-
currentPage = {pageIndex}
70-
pageSize = {pageSize}
78+
handleNextPage={handleNextPage}
79+
handlePrevPage={handlePrevPage}
7180
onRowClick={handleRowClick}
7281
/>
7382
</div>

0 commit comments

Comments
 (0)