Skip to content
Merged

Aws #10

Show file tree
Hide file tree
Changes from all commits
Commits
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
31 changes: 23 additions & 8 deletions src/app/admin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,38 @@ import AdminCreateCourseForm from "~/components/AdminCreateCourseForm";
import ApprovedCourseTable from "./ApprovedCourseTable";
import PendingCourseTable from "./PendingCourseTable";

import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs";
import { auth } from "~/server/auth";
import { redirect } from "next/navigation";
import { adminIds } from "~/consts/admins";

export default async function AdminDashboard() {
const session = await auth();
if (!session) {
redirect("/api/auth/signin");
}
if (!adminIds.has(session.user.id)) {
redirect("/");
}

export default function AdminDashboard() {

return (
<main className="py- mx-auto max-w-6xl px-4 pt-15">
<h1 className="mb-6 text-2xl font-bold">Admin Dashboard</h1>

<Tabs defaultValue="pending" className="w-full">
<TabsList>
<TabsTrigger className="cursor-pointer" value="pending">Pending Courses</TabsTrigger>
<TabsTrigger className="cursor-pointer" value="approved">Approved Courses</TabsTrigger>
<TabsTrigger className="cursor-pointer" value="create">Create Course</TabsTrigger>
<TabsTrigger className="cursor-pointer" value="pending">
Pending Courses
</TabsTrigger>
<TabsTrigger className="cursor-pointer" value="approved">
Approved Courses
</TabsTrigger>
<TabsTrigger className="cursor-pointer" value="create">
Create Course
</TabsTrigger>
</TabsList>
<TabsContent value="pending">
<PendingCourseTable/>
<PendingCourseTable />
</TabsContent>
<TabsContent value="approved">
<ApprovedCourseTable />
Expand All @@ -26,7 +42,6 @@ export default function AdminDashboard() {
<AdminCreateCourseForm />
</TabsContent>
</Tabs>

</main>
);
}
8 changes: 7 additions & 1 deletion src/app/courses/[courseCode]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { notFound } from "next/navigation";
import { notFound, redirect } from "next/navigation";
import NoteCard from "~/components/NoteCard";
import { auth } from "~/server/auth";

type paramsType = Promise<{courseCode: string}>;

Expand All @@ -11,6 +12,11 @@ export default async function CoursePage(props: { params: paramsType}) {
notFound();
}

const session = await auth();
if(!session) {
redirect("/api/auth/signin");
}

// const notes = trpc
// if(!notes) notFound()
// if notes.length < 0
Expand Down
142 changes: 8 additions & 134 deletions src/app/request-course/page.tsx
Original file line number Diff line number Diff line change
@@ -1,144 +1,18 @@
"use client";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
import { Button } from "~/components/ui/button";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "~/components/ui/form";
import { Input } from "~/components/ui/input";
import { Loader2 } from "lucide-react";
import { toast } from "sonner"
import { redirect } from "next/navigation";
import RequestCourseForm from "~/components/RequestCourseForm";
import { auth } from "~/server/auth";

import { api } from "~/trpc/react";
import { useState } from "react";
export default async function RequestCourses() {
const session = await auth();

const formSchema = z.object({
courseName: z.string().min(1).min(10).max(60),
coursePrefix: z.string().min(1).min(3).max(3),
courseCode: z.string().min(1).min(4).max(4),
});

export default function RequestCourses() {
const [message, setMessage] = useState<null | string>(null);

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
});
const createCourse = api.course.requestCourse.useMutation({
onSuccess: (result) => {
if (result.message) {
setMessage(result.message);
} else if (result.newCourse) {
toast.success(`${result.newCourse.code} successfully requested`)
}
},
onError: (error) => {
toast.error("Something went wrong");
console.error(error.message, error.data);
},
onSettled: () => {
form.reset({
courseName: "",
courseCode: "",
coursePrefix: "",
})}
});

function onSubmit(values: z.infer<typeof formSchema>) {
const capitalPrefix = values.coursePrefix.toUpperCase();
createCourse.mutate({
name: values.courseName,
prefix: capitalPrefix,
code: values.courseCode,
});
if(!session) {
redirect("/api/auth/signin");
}

return (
<main className="mx-auto max-w-7xl px-4 py-8 pt-15">
<h1 className="mb-6 text-3xl font-bold">Request to add a Course</h1>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="mx-auto max-w-3xl space-y-8 py-10"
>
<FormField
control={form.control}
name="courseName"
render={({ field }) => (
<FormItem>
<FormLabel>Course Name</FormLabel>
<FormControl>
<Input
placeholder="Computer Science 1"
type="text"
{...field}
/>
</FormControl>

<FormMessage />
</FormItem>
)}
/>

<div className="grid grid-cols-12 gap-4">
<div className="col-span-6">
<FormField
control={form.control}
name="coursePrefix"
render={({ field }) => (
<FormItem>
<FormLabel>Course Prefix</FormLabel>
<FormControl>
<Input placeholder="COP" type="text" {...field} />
</FormControl>
<FormDescription>
This should be the three letters
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</div>

<div className="col-span-6">
<FormField
control={form.control}
name="courseCode"
render={({ field }) => (
<FormItem>
<FormLabel>Course Code</FormLabel>
<FormControl>
<Input placeholder="3502" type="text" {...field} />
</FormControl>
<FormDescription>
This should be the numbers following the course prefix
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</div>
</div>
{createCourse.isPending ? (
<Button disabled>
<Loader2 className="animate-spin" />
Loading
</Button>
) : (
<Button className="cursor-pointer" type="submit">
Submit
</Button>
)}
{message && <p className="text-red-600">{message}</p>}
</form>
</Form>
<RequestCourseForm />
</main>
);
}
7 changes: 7 additions & 0 deletions src/app/upload/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { redirect } from "next/navigation";
import UploadNoteForm from "~/components/UploadNoteForm";
import { auth } from "~/server/auth";
import { api } from "~/trpc/server";

export default async function UploadPage() {
const session = await auth();
if(!session) {
redirect("/api/auth/signin");
}

const courses = await api.course.fetchCourses();

return (
Expand Down
1 change: 1 addition & 0 deletions src/components/NoteCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default function NoteCard({ id, title, createdAt }: NoteCardProps) {
src={blurredNote}
alt={`Preview of ${title}`}
fill
sizes="(max-width: 768px) 100vw, 400px"
className="object-cover group-hover:scale-105 transition-transform"
/>
</div>
Expand Down
141 changes: 141 additions & 0 deletions src/components/RequestCourseForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"use client";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
import { Button } from "~/components/ui/button";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "~/components/ui/form";
import { Input } from "~/components/ui/input";
import { Loader2 } from "lucide-react";
import { toast } from "sonner"

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

const formSchema = z.object({
courseName: z.string().min(1).min(10).max(60),
coursePrefix: z.string().min(1).min(3).max(3),
courseCode: z.string().min(1).min(4).max(4),
});

export default function RequestCourseForm() {
const [message, setMessage] = useState<null | string>(null);

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
});
const createCourse = api.course.requestCourse.useMutation({
onSuccess: (result) => {
if (result.message) {
setMessage(result.message);
} else if (result.newCourse) {
toast.success(`${result.newCourse.code} successfully requested`)
}
},
onError: (error) => {
toast.error("Something went wrong");
console.error(error.message, error.data);
},
onSettled: () => {
form.reset({
courseName: "",
courseCode: "",
coursePrefix: "",
})}
});

function onSubmit(values: z.infer<typeof formSchema>) {
const capitalPrefix = values.coursePrefix.toUpperCase();
createCourse.mutate({
name: values.courseName,
prefix: capitalPrefix,
code: values.courseCode,
});
}

return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="mx-auto max-w-3xl space-y-8 py-10"
>
<FormField
control={form.control}
name="courseName"
render={({ field }) => (
<FormItem>
<FormLabel>Course Name</FormLabel>
<FormControl>
<Input
placeholder="Computer Science 1"
type="text"
{...field}
/>
</FormControl>

<FormMessage />
</FormItem>
)}
/>

<div className="grid grid-cols-12 gap-4">
<div className="col-span-6">
<FormField
control={form.control}
name="coursePrefix"
render={({ field }) => (
<FormItem>
<FormLabel>Course Prefix</FormLabel>
<FormControl>
<Input placeholder="COP" type="text" {...field} />
</FormControl>
<FormDescription>
This should be the three letters
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</div>

<div className="col-span-6">
<FormField
control={form.control}
name="courseCode"
render={({ field }) => (
<FormItem>
<FormLabel>Course Code</FormLabel>
<FormControl>
<Input placeholder="3502" type="text" {...field} />
</FormControl>
<FormDescription>
This should be the numbers following the course prefix
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</div>
</div>
{createCourse.isPending ? (
<Button disabled>
<Loader2 className="animate-spin" />
Loading
</Button>
) : (
<Button className="cursor-pointer" type="submit">
Submit
</Button>
)}
{message && <p className="text-red-600">{message}</p>}
</form>
</Form>
);
}
Loading