Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev to main #252

Merged
merged 13 commits into from
Sep 27, 2023
Merged
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
2 changes: 1 addition & 1 deletion backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ First start the database:
```
docker run --rm -itd --network cselectives-network --name cselectives-db -e POSTGRES_PASSWORD=password -e POSTGRES_DB=mydb -p 5432:5432 postgres
# Initialise db schema:
DATABASE_URL="postgresql://postgres:[email protected]:5432/mydb?schema=cselectives" npx prisma migrate dev
DATABASE_URL="postgresql://postgres:[email protected]:5432/mydb?schema=unilectives" npx prisma migrate dev
```

Then dragonfly (redis):
Expand Down
5 changes: 3 additions & 2 deletions frontend/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
"typescript.enablePromptUseWorkspaceTsdk": true,
"githubPullRequests.ignoredPullRequestBranches": ["develop"]
}
9 changes: 9 additions & 0 deletions frontend/package-lock.json

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

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"next-auth": "^4.22.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"schema-dts": "^1.1.2",
"tailwind-scrollbar": "^3.0.1",
"typescript": "5.0.3"
},
Expand Down
10 changes: 8 additions & 2 deletions frontend/src/app/admin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ import AdminContent from "@/components/AdminContent/AdminContent";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import navbar from "@/assets/navbar.svg";
import { Metadata } from "next";

export default async function () {
export const metadata: Metadata = {
title: `Admin Dashboard | Unilectives - UNSW Course Reviews`,
description: `Manage and resolve reports left on particular course reviews by Unilectives users.`,
}

export default async function AdminDashboard() {
const session = await getServerSession(authOptions);
const { reviews } = (await validatedReq(
"GET",
Expand All @@ -32,7 +38,7 @@ export default async function () {
priority
/>
<div className="flex flex-col w-full px-12 py-6 gap-6">
<p className="font-bold text-3xl">Dashboard</p>
<p className="font-bold text-3xl">Admin Dashboard</p>
<p>Welcome to the admin dashboard!</p>
<AdminContent
reports={reports}
Expand Down
60 changes: 51 additions & 9 deletions frontend/src/app/course/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
import Image from "next/image";
import waves from "../../../assets/waves.svg";
import { LinkIcon } from "@heroicons/react/24/solid";
import { Suspense } from "react";
import TermsGroup from "@/components/TermsGroup/TermsGroup";
import Link from "next/link";
import DoughnutChart from "@/components/DoughnutChart/DoughnutChart";
import { notFound } from "next/navigation";
import ReviewsBar from "@/components/ReviewsBar/ReviewsBar";
import Rating from "@/components/Rating/Rating";
import ReviewSearchbar from "@/components/ReviewSearchBar/ReviewSearchBar";
import ReviewsBar from "@/components/ReviewsBar/ReviewsBar";
import TermsGroup from "@/components/TermsGroup/TermsGroup";
import { authOptions } from "@/lib/auth";
import { Course, Reviews } from "@/types/api";
import { get, validatedReq } from "@/utils/request";
import { LinkIcon } from "@heroicons/react/24/solid";
import { Metadata } from "next";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import Image from "next/image";
import Link from "next/link";
import { notFound } from "next/navigation";
import { Suspense } from "react";
import { AggregateRating, WithContext } from "schema-dts";
import waves from "../../../assets/waves.svg";
import { signOut } from "next-auth/react";

export async function generateMetadata(props: {
params: {
[key: string]: string;
};
}): Promise<Metadata> {
const { course } = (await get(`/course/${props.params.id.toUpperCase()}`)) as {
course: Course;
};
return {
title: `${course.courseCode} | Unilectives - UNSW Course Reviews`,
description: `Considering ${course.courseCode} at UNSW? Dive into real student reviews giving you unfiltered perspectives on the course. Get the scoop on teaching quality, workload, and more.`,
};
}

export default async function ReviewPage({
params,
}: {
Expand Down Expand Up @@ -48,6 +64,28 @@ export default async function ReviewPage({
}
}

const metaLD: WithContext<AggregateRating> = {
"@context": "https://schema.org",
"@type": "AggregateRating",
ratingCount: course.reviewCount,
ratingValue: course.reviewCount === 0 ? 0 : course.overallRating,
bestRating: 5,
itemReviewed: {
"@type": "Course",
name: course.title,
courseCode: course.courseCode,
description: course.description,
url: `//www.handbook.unsw.edu.au/undergraduate/courses/${new Date().getFullYear()}/${
course.courseCode
}`,
provider: {
"@type": "CollegeOrUniversity",
name: "University of New South Wales",
sameAs: "https://www.unsw.edu.au/",
},
},
};

return (
<div className="isolate">
{/* Header */}
Expand All @@ -66,6 +104,10 @@ export default async function ReviewPage({
{/* Course details */}
<div className="flex gap-8 pt-12 px-16 md:px-8 lg:pt-8 md:flex-wrap">
<Suspense fallback={<div>Loading...</div>}>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(metaLD) }}
/>
<section className="space-y-4 w-full block md:static md:max-h-full sticky top-8 max-h-[calc(100vh-4rem)] overflow-y-scroll scrollbar-none">
<h1 className="text-6xl font-bold break-words">
{course.courseCode}
Expand Down
5 changes: 0 additions & 5 deletions frontend/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ import { authOptions } from "@/lib/auth";
import { AlertProvider } from "@/lib/snackbar-context";
import Navbar from "@/components/Navbar/Navbar";

export const metadata = {
title: "uni-lectives",
description: "Course review website for UNSW made by CSESoc",
};

export default async function RootLayout({
children,
}: {
Expand Down
77 changes: 61 additions & 16 deletions frontend/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,76 @@
import Image from "next/image";
import LandingPageContent from "@/components/LandingPageContent/LandingPageContent";
import navbar from "@/assets/navbar.svg";
import { Metadata } from "next";
import { ItemList, WithContext } from "schema-dts";
import { get } from "@/utils/request";
import { Course, Courses } from "@/types/api";

export async function generateMetadata(): Promise<Metadata> {
return {
title: `Home | Unilectives - UNSW Course Reviews`,
description: `A course review website for UNSW made by CSESoc`,
};
}

export default async function Home() {
const { courses: initialCourses } = (await get(
"/courses?offset=0"
)) as Courses;

const metaLD: WithContext<ItemList> = {
"@context": "https://schema.org",
"@type": "ItemList",
itemListElement: initialCourses.map((course: Course, index: number) => ({
"@type": "ListItem",
position: index + 1,
item: {
"@type": "Course",
url: `//www.handbook.unsw.edu.au/undergraduate/courses/${new Date().getFullYear()}/${
course.courseCode
}`,
name: course.title,
description: course.description,
provider: {
"@type": "CollegeOrUniversity",
name: "University of New South Wales",
sameAs: "https://www.unsw.edu.au/",
},
aggregateRating: {
"@type": "AggregateRating",
ratingCount: course.reviewCount,
ratingValue: course.reviewCount === 0 ? 0 : course.overallRating,
bestRating: 5,
},
},
})),
};

export default function Home() {
return (
<div className="mb-20">
{/* Navbar */}
<div>
<Image
src={navbar}
width={1000}
height={500}
alt="landing page graphic"
layout="responsive"
priority
/>
</div>
{/* Landing page graphic */}
<Image
src={navbar}
width={1000}
height={500}
alt="landing page graphic"
layout="responsive"
priority
/>
{/* Hero Section */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(metaLD) }}
/>
<div className="flex flex-row w-full justify-center items-center mt-10">
<div className="flex flex-row w-5/6 space-y-0 justify-between items-left md:space-y-4 md:flex-col md:items-center">
<div className="flex flex-col w-full gap-3">
<p className="drop-shadow-md text-base sm:text-xs">
CSESoc presents
</p>
<p className="justify-center font-bold text-unilectives-blue text-7xl sm:text-4xl">
uni-lectives
</p>
<h1 className="justify-center font-bold text-unilectives-blue text-7xl sm:text-4xl">
unilectives
</h1>
<p className="justify-center font-semibold text-base sm:text-xs">
Your one-stop shop for UNSW course and elective reviews.
</p>
Expand All @@ -34,7 +79,7 @@ export default function Home() {
</div>
{/* Course Section */}
<div className="flex flex-col justify-center items-center mt-10">
<LandingPageContent />
<LandingPageContent initialCourses={initialCourses} />
</div>
</div>
);
Expand Down
9 changes: 8 additions & 1 deletion frontend/src/app/terms-and-conditions/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
export default function TermsAndConditionsPage() {
import { Metadata } from "next";

export const metadata: Metadata = {
title: `Terms & Conditions | Unilectives - UNSW Course Reviews`,
description: `Terms and Conditions for Unilectives - UNSW Course Reviews`,
}

export default function TermsAndConditions() {
return (
<div className="p-20 xs:m-12 sm:m-12 xs:text-xs sm:text-sm">
<h1 className="text-lg font-bold">Terms and Conditions</h1>
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/app/user/[zid]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ import { validatedReq } from "@/utils/request";
import UserPageContent from "@/components/UserPageContent/UserPageContent";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { Metadata } from "next";

export async function generateMetadata(props: {
params: {
[key: string]: string;
};
}): Promise<Metadata> {
return {
title: `${props.params.zid} Profile | Unilectives - UNSW Course Reviews`,
description: `Curious about ${props.params.zid}'s reviews? Check out their profile to see what courses they've reviewed and bookmarked.`,
};
}

export default async function UserPage({
params,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/CourseCard/CourseCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default function CourseCard({
<div className="box-border px-6 py-7 bg-unilectives-card hover:bg-gray-100 shadow-lg rounded-xl space-y-2 cursor-pointer">
{/* Course courseCode + Ratings */}
<div className="flex flex-wrap justify-between text-2xl gap-x-4">
<h1 className="font-bold w-[8ch]">{courseCode}</h1>
<h2 className="font-bold w-[8ch]">{courseCode}</h2>
<div className="text-left">
{/* StarRating */}
<div className="text-2xl inline">
Expand Down
29 changes: 12 additions & 17 deletions frontend/src/components/CoursesList/CoursesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,19 @@ import { get } from "@/utils/request";
import { sortCourses } from "@/utils/sortCourses";
import SortDropdown from "../SortDropdown/SortDropdown";

export default function CoursesList({ searchTerm }: { searchTerm?: string }) {
export default function CoursesList({
initialCourses,
searchTerm,
}: {
initialCourses: Course[];
searchTerm: string;
}) {
const courseFinishedRef = useRef(false);
const indexRef = useRef(0);
const indexRef = useRef(initialCourses.length);
const searchCoursesRef = useRef<Course[]>([]);

const [displayCourses, setDisplayCourses] = useState<Course[]>([]);
const [displayCourses, setDisplayCourses] =
useState<Course[]>(initialCourses);
const [initialLoading, setInitialLoading] = useState(true);
const [selected, setSelected] = useState("");

Expand Down Expand Up @@ -58,7 +65,7 @@ export default function CoursesList({ searchTerm }: { searchTerm?: string }) {
useEffect(() => {
const resetRefs = () => {
courseFinishedRef.current = false;
indexRef.current = 0;
indexRef.current = initialCourses.length;
searchCoursesRef.current = [];
};
const getSearchResults = async () => {
Expand All @@ -74,20 +81,8 @@ export default function CoursesList({ searchTerm }: { searchTerm?: string }) {
indexRef.current += paginationOffset;
setInitialLoading(false);
};
const getDefaultResults = async () => {
try {
const { courses } = (await get(`/courses?offset=0`)) as Courses;
setDisplayCourses(courses);
indexRef.current += paginationOffset;
} catch (err) {
setDisplayCourses([]);
}
setInitialLoading(false);
};
const getInitialDisplayCourses = () => {
if (searchTerm === "") {
getDefaultResults();
} else {
if (searchTerm !== "") {
getSearchResults();
}
};
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/DeleteModal/DeleteModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export default function DeleteModal({
leaveTo="opacity-0 scale-95"
>
<Dialog.Panel className="w full max-w-md transform overflow-hidden rounded-md text-left align-middle shadow-xl transition-all bg-unilectives-modal px-8 py-6 space-y-4 isolate">
<Dialog.Title as="h1" className="text-2xl font-bold">
<Dialog.Title as="h2" className="text-2xl font-bold">
Delete {group.charAt(0).toUpperCase() + group.slice(1)}
</Dialog.Title>
<hr className="border-black/25"></hr>
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/components/EditReviewModal/EditReviewModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export default function EditReviewModal({
<Dialog.Panel className="w-full max-w-5xl transform overflow-hidden rounded-md text-left align-middle shadow-xl transition-all bg-unilectives-modal px-12 py-8 space-y-5 isolate">
{/* Modal title + close button */}
<div className="flex justify-between items-center">
<Dialog.Title as="h1" className="text-2xl font-bold">
<Dialog.Title as="h2" className="text-2xl font-bold">
Edit Your Review
</Dialog.Title>
<button onClick={closeModal}>
Expand Down Expand Up @@ -186,10 +186,9 @@ export default function EditReviewModal({
/>
</div>
<div className="flex flex-wrap gap-5 justify-between items-center">
{/* Terms & Condition */}
{/* Terms & Conditions */}
<p>
By clicking Confirm, you have agreed to the{" "}
{/* TODO: Change link to the Terms and Condition page */}
<Link
href="/"
target="_blank"
Expand Down
Loading