Skip to content

Commit

Permalink
Added semester functionality
Browse files Browse the repository at this point in the history
Clicking the current semester gets rid of "grade" area when submitting review. Added new boolean tracking whether or not the review was submitted during the semester.

Added new constants file that stores the current semester. Needs to be updated regularly... Can we find a better solution?
  • Loading branch information
mjaydenkim committed Jan 10, 2025
1 parent 108eb39 commit 79e3b55
Show file tree
Hide file tree
Showing 13 changed files with 150 additions and 38 deletions.
12 changes: 12 additions & 0 deletions client/src/modules/Course/Components/Course.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { Session } from '../../../session-store';
import { useAuthOptionalLogin } from '../../../auth/auth_utils';

import ReviewModal from './ReviewModal';
import { compareSems } from 'common/CourseCard';

enum PageStatus {

Check warning on line 32 in client/src/modules/Course/Components/Course.tsx

View workflow job for this annotation

GitHub Actions / build

'PageStatus' is already declared in the upper scope on line 32 column 6

Check warning on line 32 in client/src/modules/Course/Components/Course.tsx

View workflow job for this annotation

GitHub Actions / build

'PageStatus' is defined but never used

Check warning on line 32 in client/src/modules/Course/Components/Course.tsx

View workflow job for this annotation

GitHub Actions / build

'PageStatus' is already declared in the upper scope on line 32 column 6

Check warning on line 32 in client/src/modules/Course/Components/Course.tsx

View workflow job for this annotation

GitHub Actions / build

'PageStatus' is defined but never used
Loading,

Check warning on line 33 in client/src/modules/Course/Components/Course.tsx

View workflow job for this annotation

GitHub Actions / build

'Loading' is already declared in the upper scope on line 12 column 8

Check warning on line 33 in client/src/modules/Course/Components/Course.tsx

View workflow job for this annotation

GitHub Actions / build

'Loading' is defined but never used

Check warning on line 33 in client/src/modules/Course/Components/Course.tsx

View workflow job for this annotation

GitHub Actions / build

'Loading' is already declared in the upper scope on line 12 column 8

Check warning on line 33 in client/src/modules/Course/Components/Course.tsx

View workflow job for this annotation

GitHub Actions / build

'Loading' is defined but never used
Expand Down Expand Up @@ -101,6 +102,14 @@ export const Course = () => {
return 0;
}

/**
* Sorts reviews based on descending semester (or by date if not available).
*/
const sortBySem = (a: Review, b: Review) =>
b.semester && a.semester
? compareSems(a.semester,b.semester)
: sortByDate(a,b)

/**
* Update state to conditionally render sticky bottom-right review button
*/
Expand Down Expand Up @@ -176,6 +185,8 @@ export const Course = () => {
setCourseReviews([...courseReviews].sort(sortByDate));
} else if (value === 'professor') {
setCourseReviews([...courseReviews].sort(sortByProf));
} else if (value === 'semester') {
setCourseReviews([...courseReviews].sort(sortBySem));
}
}

Expand Down Expand Up @@ -299,6 +310,7 @@ export const Course = () => {
<option value="helpful">Most Helpful</option>
<option value="recent">Recent</option>
<option value="professor">Professor</option>
<option value="semester">Semester</option>
</select>
</div>
</div>
Expand Down
16 changes: 8 additions & 8 deletions client/src/modules/Course/Components/PreviewReviewCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef } from 'react';
import axios from 'axios';

import { Review as ReviewType } from 'common';
import { convertSemAbbreviation } from 'common/CourseCard'

import styles from '../Styles/ReviewCard.module.css';
import previewstyle from '../Styles/PreviewCard.module.css';
Expand Down Expand Up @@ -114,7 +115,11 @@ export default function PreviewReviewCard({
' ' +
courseNum?.toUpperCase() +
' | ' +
professornames}
professornames +
(_review.semester
? ', ' + convertSemAbbreviation(_review.semester)
: '')
}
</div>
</>
);
Expand Down Expand Up @@ -193,14 +198,9 @@ export default function PreviewReviewCard({
<span className={styles.bold}>
{_review.grade && /^([^0-9]*)$/.test(_review.grade)
? _review.grade
: 'N/A'}
: _review.writtenDuringSemester ? 'N/A (Review written during semester)' : 'N/A'
}
</span>
{_review.semester ? (
<>
{' '} | {' '}
<span className={styles.bold}>{_review.semester}</span>
</>
) : ''}
</div>
</div>
<div
Expand Down
17 changes: 9 additions & 8 deletions client/src/modules/Course/Components/ReviewCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { useLocation } from 'react-router-dom';
import axios from 'axios';

import { Review as ReviewType } from 'common';
import { convertSemAbbreviation } from 'common/CourseCard'

import styles from '../Styles/ReviewCard.module.css';

import { getAuthToken, useAuthOptionalLogin } from '../../../auth/auth_utils';
import { isCurrentSem } from 'common/CourseCard';

// use review.visible for pending

Expand Down Expand Up @@ -126,7 +128,11 @@ export default function ReviewCard({
' ' +
courseNum?.toUpperCase() +
' | ' +
professornames}
professornames +
(_review.semester
? ', ' + convertSemAbbreviation(_review.semester)
: '')
}
</p>
</>
);
Expand Down Expand Up @@ -205,14 +211,9 @@ export default function ReviewCard({
<span className={styles.bold}>
{_review.grade && /^([^0-9]*)$/.test(_review.grade)
? _review.grade
: 'N/A'}
: _review.writtenDuringSemester ? 'N/A (Review written during semester)' : 'N/A'
}
</span>
{_review.semester ? (
<>
{' '} | {' '}
<span className={styles.bold}>{_review.semester}</span>
</>
) : ''}
</div>
<div>
Major{' '}
Expand Down
51 changes: 37 additions & 14 deletions client/src/modules/Course/Components/ReviewModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import MultiSelect from './MultiSelect';
import SingleSelect from './SingleSelect';
import RatingInput from './RatingInput';

import { SEMESTER_FORMAT } from 'common/CourseCard'

// CSS FILES
import styles from '../Styles/ReviewModal.module.css';
import closeIcon from '../../../assets/icons/X.svg';
Expand All @@ -13,6 +15,8 @@ import closeIcon from '../../../assets/icons/X.svg';
import majors from '../../Globals/majors';
import AnonymousWarning from './AnonymousWarning';
import { useAuthOptionalLogin } from '../../../auth/auth_utils';
import { CURRENT_SEMESTER } from 'common/constants';
import { compareWithCurrentSem } from 'common/CourseCard';

const ReviewModal = ({
open,
Expand Down Expand Up @@ -56,6 +60,7 @@ const ReviewModal = ({
const [selectedGrade, setSelectedGrade] = useState<string>('');
const [selectedSem, setSelectedSem] = useState<string>('');
const [reviewText, setReviewText] = useState<string>('');
const [isCurrentSem, setIsCurrentSem] = useState<boolean>(false);

const [overall, setOverall] = useState<number>(3);
const [difficulty, setDifficulty] = useState<number>(3);
Expand All @@ -75,21 +80,23 @@ const ReviewModal = ({
});
const [allowSubmit, setAllowSubmit] = useState<boolean>(false);

const SEMESTER_FORMAT: RegExp = new RegExp('^(SP|SU|WI|FA)\\d{2}$');

useEffect(() => {
if (!professorOptions.includes('Not Listed')) {
professorOptions.push('Not Listed');
}
}, [professorOptions]);

useEffect(() => {
setAllowSubmit(valid.professor && valid.semester && valid.major && valid.grade && valid.text);
setAllowSubmit(valid.professor && valid.semester && valid.major && (valid.grade !== isCurrentSem) && valid.text);
if (isLoggedIn) {
getNoReviews();
}
}, [valid]);

useEffect(() => {
if (isCurrentSem) onGradeChange('');
}, [isCurrentSem])

/**
* Determines if the current user has no reviews, so they should receive
* the anonymous modal
Expand All @@ -112,9 +119,16 @@ const ReviewModal = ({
}

function onSelectedSemChange(newSem: string) {
setSelectedSem(newSem);
if (SEMESTER_FORMAT.test(newSem)) setValid({ ...valid, semester: true });
else setValid({ ...valid, semester: false });
if (newSem.includes("Current")) {
setIsCurrentSem(true);
setSelectedSem(newSem.substring(0,4));
} else {
setIsCurrentSem(false);
setSelectedSem(newSem)
}

let validSemFormat = SEMESTER_FORMAT.test(newSem.substring(0,4));
setValid({ ...valid, semester: validSemFormat });
}

function onMajorChange(newSelectedMajors: string[]) {
Expand Down Expand Up @@ -155,7 +169,8 @@ const ReviewModal = ({
isCovid: false,
grade: selectedGrade,
major: selectedMajors,
semester: selectedSem
semester: selectedSem,
writtenDuringSemester: isCurrentSem,
};
submitReview(newReview);
}
Expand Down Expand Up @@ -244,17 +259,24 @@ const ReviewModal = ({
</div>
<div className={styles['sem-grade-selects']}>
<SingleSelect
options={semsOffered.toReversed()}
options={
semsOffered
.toReversed()
.filter((sem) => compareWithCurrentSem(sem) <= 0)
.map((sem) => sem === CURRENT_SEMESTER ? sem + " (Current)" : sem)
}
value={selectedSem}
onChange={onSelectedSemChange}
placeholder="Semester Taken"
/>
<SingleSelect
options={gradeoptions}
value={selectedGrade}
onChange={onGradeChange}
placeholder="Grade Received"
/>
{!isCurrentSem &&
<SingleSelect
options={gradeoptions}
value={selectedGrade}
onChange={onGradeChange}
placeholder="Grade Received"
/>
}
</div>
<MultiSelect
options={majorOptions}
Expand Down Expand Up @@ -306,6 +328,7 @@ type NewReview = {
grade: string;
major: string[];
semester: string;
writtenDuringSemester: boolean;
};

type Valid = {
Expand Down
25 changes: 18 additions & 7 deletions client/src/modules/Profile/Component/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { useAuthMandatoryLogin } from '../../../auth/auth_utils';
import { randomPicture } from '../../Globals/profile_picture';

import styles from '../Styles/Profile.module.css';
import { compareSems } from 'common/CourseCard';

const Profile = () => {
const [loading, setLoading] = useState(true);
Expand Down Expand Up @@ -91,6 +92,14 @@ const Profile = () => {
return 0
}

/**
* Sorts reviews based on descending semester.
*/
const sortBySem = (a: ReviewType, b: ReviewType) =>
b.semester && a.semester
? compareSems(a.semester,b.semester)
: sortByDate(a,b)

/**
* Hook that handles
* 1. Get + Set reviews
Expand Down Expand Up @@ -198,6 +207,8 @@ const Profile = () => {
setApprovedReviews([...approvedReviews].sort(sortByDate));
} else if (value === 'professor') {
setApprovedReviews([...approvedReviews].sort(sortByProf))
} else if (value === 'semester') {
setApprovedReviews([...approvedReviews].sort(sortBySem));
}
}

Expand Down Expand Up @@ -227,7 +238,9 @@ const Profile = () => {

<div className={styles.reviewsection}>
<div className={styles.bar}>
<h2>My Reviews ({pendingReviews.length + approvedReviews.length})</h2>
<h2>
My Reviews ({pendingReviews.length + approvedReviews.length})
</h2>
<div>
<label htmlFor="sort-reviews-by">Sort By:</label>
<select
Expand All @@ -237,6 +250,8 @@ const Profile = () => {
>
<option value="helpful">Most Helpful</option>
<option value="recent">Recent</option>
<option value="professor">Professor</option>
<option value="semester">Semester</option>
</select>
</div>
</div>
Expand All @@ -249,15 +264,11 @@ const Profile = () => {
setHide={setHidePastReviews}
pendingReviews={pendingReviews}
/>
<PastReviews
pastReviews={approvedReviews}
/>
<PastReviews pastReviews={approvedReviews} />
</>
)}
{reviews.length > 0 && pendingReviews.length === 0 && (
<PastReviews
pastReviews={approvedReviews}
/>
<PastReviews pastReviews={approvedReviews} />
)}
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions client/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export type NewReview = {
grade: string;
major: string[];
semester: string;
writtenDuringSemester: boolean;
};
53 changes: 53 additions & 0 deletions common/CourseCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
Additonal functions used in the CourseCard component.
*/

import { CURRENT_SEMESTER } from './constants';

export const SEMESTER_FORMAT = new RegExp('^(SP|SU|WI|FA)\\d{2}$');

/**
* Helper function to convert semester abbreviations to a full word
*/
Expand All @@ -20,6 +24,55 @@ export function semAbbreviationToWord(sem) {
}
}

/**
* Return full semester label -- eg. "FA20" --> "Fall 2020".
* Assumes 21st century (probably safe for now).
* @param sem abbreviated semester text
*/
export function convertSemAbbreviation(sem) {
return SEMESTER_FORMAT.test(sem)
? semAbbreviationToWord(sem.substring(0, 2)) + " 20" + sem.substring(2)
: sem
}

/**
* Comparison function for two semesters.
* Returns -1 if semOne is less than semTwo
* 1 if semOne is greater than semTwo
* 0 otherwise (if they are equal)
*/
export function compareSems(semOne, semTwo) {
if (!SEMESTER_FORMAT.test(semOne) || !SEMESTER_FORMAT.test(semTwo)) {
throw new Error("When comparing semesters, both must be in abbreviated semester format.")
}

const semOrder = ['WI', 'SP', 'SU', 'FA'];
let semOneTermIndex = semOrder.indexOf(semOne.substring(0,2))
let semOneYear = parseInt(semOne.substring(2))
let semTwoTermIndex = semOrder.indexOf(semTwo.substring(0,2))
let semTwoYear = parseInt(semTwo.substring(2))

if (semOneYear < semTwoYear) return -1;
if (semOneYear > semTwoYear) return 1;
if (semOneTermIndex < semTwoTermIndex) return -1;
if (semOneTermIndex > semTwoTermIndex) return 1;
return 0;
}

/**
* Returns -1 if sem is less than current semester
* 1 if sem is greater than current semester
* 0 otherwise (if they are equal)
*/
export function compareWithCurrentSem(sem) {
if (!SEMESTER_FORMAT.test(sem)) throw new Error("Semester must be in abbreviated format.")
return compareSems(sem, CURRENT_SEMESTER)
}

export function isCurrentSem(sem) {
return compareWithCurrentSem(sem) === 0;
}

/**
* Get a human-readable string representing a list of [up to] the last 2 semesters this class was offered.
*/
Expand Down
1 change: 1 addition & 0 deletions common/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const CURRENT_SEMESTER = "WI25"
1 change: 1 addition & 0 deletions common/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export interface Review {
grade?: string;
major?: string[];
semester?: string;
writtenDuringSemester?: boolean;
}

export interface Professor {
Expand Down
Loading

0 comments on commit 79e3b55

Please sign in to comment.