Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
760b5fb
add shadcn dashboard
crespofer May 13, 2025
f21db9e
add admin env
crespofer May 13, 2025
4306fb8
add valid admin ids
crespofer May 13, 2025
380ff38
create admin procedure
crespofer May 13, 2025
e7f9e2f
add admin router
crespofer May 13, 2025
e65b229
create get all courses procedure
crespofer May 13, 2025
ea71150
update to only fetch approved courses
crespofer May 17, 2025
886dc87
create procedure to fetch pending courses
crespofer May 17, 2025
1645039
remove unecessary things from dashboard
crespofer May 17, 2025
ed08ad1
rename shad dashboard to admin
crespofer May 17, 2025
e061d7d
revert using next Image component
crespofer May 18, 2025
bf2578c
remove shadcn dashboard
crespofer May 18, 2025
e4d073d
set up new admin dashboard w mock data
crespofer May 18, 2025
c6ac19c
restore admin router
crespofer May 18, 2025
6dbbcbf
update pending courses with trpc data
crespofer May 18, 2025
babe05b
set default count to 1
crespofer May 18, 2025
7ed1a9d
get approved courses from trpc on admin
crespofer May 18, 2025
14c6272
split admin tables into components
crespofer May 19, 2025
eb3292c
add shadcn tabs
crespofer May 19, 2025
3887774
add tabs for tables
crespofer May 19, 2025
dc21847
add shad alert-dialog to project
crespofer May 19, 2025
8eb75cd
add ui dialog to deny course
crespofer May 19, 2025
17ba09a
create deny course procedure
crespofer May 19, 2025
400bcda
add deny functionality to table
crespofer May 19, 2025
91753b7
switch to fetching on client pending courses
crespofer May 19, 2025
f7b9c10
switch to fetching on client approved table
crespofer May 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ AUTH_GITHUB_SECRET=""
# Prisma
# https://www.prisma.io/docs/reference/database-reference/connection-urls#env
DATABASE_URL="file:./db.sqlite"

# Admin IDs
ADMIN_FER=""
192 changes: 192 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@
"@auth/prisma-adapter": "^2.7.2",
"@hookform/resolvers": "^5.0.1",
"@prisma/client": "^6.5.0",
"@radix-ui/react-alert-dialog": "^1.1.13",
"@radix-ui/react-avatar": "^1.1.9",
"@radix-ui/react-dropdown-menu": "^2.1.14",
"@radix-ui/react-label": "^2.1.6",
"@radix-ui/react-navigation-menu": "^1.2.11",
"@radix-ui/react-slot": "^1.2.2",
"@radix-ui/react-tabs": "^1.1.11",
"@t3-oss/env-nextjs": "^0.12.0",
"@tanstack/react-query": "^5.69.0",
"@trpc/client": "^11.0.0",
Expand Down
2 changes: 1 addition & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ model Course {
name String @unique // Calculus 2
code String @unique // MAC2312
url String?
count Int @default(0)
count Int @default(1)
pending Boolean @default(true)
notes Note[]
}
102 changes: 102 additions & 0 deletions src/app/admin/ApprovedCourseTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
"use client";

import { useState } from "react";
import { api } from "~/trpc/react";

const ITEMS_PER_PAGE = 10;

export default function ApprovedCourseTable() {
const [approvedPage, setApprovedPage] = useState(1);

const {data: courses, isLoading, error } = api.admin.getAllApprovedCourses.useQuery();

const handleEdit = (id: string) => {
console.log("Edit:", id);
};

const paginate = <T,>(data: T[], page: number) =>
data.slice((page - 1) * ITEMS_PER_PAGE, page * ITEMS_PER_PAGE);

const renderPagination = (
totalItems: number,
currentPage: number,
setPage: (n: number) => void,
) => {
const totalPages = Math.ceil(totalItems / ITEMS_PER_PAGE);
if (totalPages <= 1) return null;

return (
<div className="mt-4 flex justify-center space-x-2">
{Array.from({ length: totalPages }, (_, i) => (
<button
key={i}
onClick={() => setPage(i + 1)}
className={`cursor-pointer rounded border px-3 py-1 ${
currentPage === i + 1
? "bg-blue-600 text-white"
: "bg-white hover:bg-gray-100"
}`}
>
{i + 1}
</button>
))}
</div>
);
};

return (
<>
<div className="overflow-x-auto">
<table className="min-w-full rounded-lg border border-gray-200 bg-white shadow">
<thead className="bg-gray-100">
<tr>
<th className="px-4 py-2 text-left">Name</th>
<th className="px-4 py-2 text-left">Code</th>
<th className="px-4 py-2 text-left">Actions</th>
</tr>
</thead>
<tbody>
{isLoading ? (
<tr>
<td colSpan={4} className="py-4 text-center">
Loading...
</td>
</tr>
) : error ? (
<tr>
<td colSpan={4} className="py-4 text-center text-red-500">
Error loading courses
</td>
</tr>
) : courses && courses.length > 0 ? (
paginate(courses, approvedPage).map((course) => (
<tr key={course.id} className="border-t">
<td className="px-4 py-2">{course.name}</td>
<td className="px-4 py-2">
{course.code.replace(/^([A-Z]{3})(\d{4})$/, "$1 $2")}
</td>
<td className="px-4 py-2">
<button
onClick={() => handleEdit(course.id)}
className="cursor-pointer rounded bg-yellow-500 px-3 py-1 text-white hover:bg-yellow-600"
>
Edit
</button>
</td>
</tr>
))
) : (
<tr>
<td colSpan={4} className="py-4 text-center">
No Approved Courses
</td>
</tr>
)}
</tbody>
</table>
</div>
{courses &&
renderPagination(courses.length, approvedPage, setApprovedPage)}
</>
);
}
Loading