From 34e803621301006a888bd2f5253bd1c381888da5 Mon Sep 17 00:00:00 2001 From: Chin Rui Bin <52031118+camille-readbean@users.noreply.github.com> Date: Mon, 17 Jul 2023 00:04:08 +0800 Subject: [PATCH 01/17] Fix branch to checkout --- infra/playbooks/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/playbooks/deploy.yaml b/infra/playbooks/deploy.yaml index 4f8af6f..bb7a1a7 100644 --- a/infra/playbooks/deploy.yaml +++ b/infra/playbooks/deploy.yaml @@ -11,7 +11,7 @@ repo: https://{{ git_username }}:{{ git_pat }}@github.com/camille-readbean/ezConnect.git dest: /home/azureuser/ezConnect update: yes - version: prepms2 + version: release-ms3 force: yes - name: Update and upgrade apt packages From 8f5b2c97569e35bac4c2a78ac6b5388d6d6fbf91 Mon Sep 17 00:00:00 2001 From: Li Ting Date: Mon, 17 Jul 2023 13:10:24 +0800 Subject: [PATCH 02/17] Change init.sql --- backend/pre_data/init.sql | 136 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 4 deletions(-) diff --git a/backend/pre_data/init.sql b/backend/pre_data/init.sql index d48e3b2..b155432 100644 --- a/backend/pre_data/init.sql +++ b/backend/pre_data/init.sql @@ -5,6 +5,7 @@ CREATE TABLE alembic_version ( CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num) ); +INFO [alembic.runtime.migration] Running upgrade -> 22be9cc508e8, empty message -- Running upgrade -> 22be9cc508e8 CREATE TABLE course ( @@ -134,8 +135,135 @@ CREATE TABLE semester_course ( INSERT INTO alembic_version (version_num) VALUES ('22be9cc508e8') RETURNING alembic_version.version_num; -COMMIT; +INFO [alembic.runtime.migration] Running upgrade 22be9cc508e8 -> 0f60b0932ff1, empty message +-- Running upgrade 22be9cc508e8 -> 0f60b0932ff1 -COPY programme FROM '/pre_data/programmes.csv' DELIMITER ',' CSV HEADER; -COPY degree FROM '/pre_data/degrees.csv' DELIMITER ',' CSV HEADER; -COPY course FROM '/pre_data/courses.csv' DELIMITER ',' CSV HEADER; \ No newline at end of file +CREATE TABLE personal_study_plan ( + id UUID NOT NULL, + date_updated TIMESTAMP WITHOUT TIME ZONE NOT NULL, + title VARCHAR(150), + creator_id UUID NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY(creator_id) REFERENCES users (azure_ad_oid) +); + +CREATE TABLE published_study_plan ( + id UUID NOT NULL, + date_updated TIMESTAMP WITHOUT TIME ZONE NOT NULL, + title VARCHAR(150) NOT NULL, + description TEXT NOT NULL, + num_of_likes INTEGER NOT NULL, + creator_id UUID NOT NULL, + personal_study_plan_id UUID NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY(creator_id) REFERENCES users (azure_ad_oid), + FOREIGN KEY(personal_study_plan_id) REFERENCES personal_study_plan (id) +); + +CREATE TABLE favorited_study_plan ( + user_id UUID NOT NULL, + published_study_plan_id UUID NOT NULL, + FOREIGN KEY(published_study_plan_id) REFERENCES published_study_plan (id), + FOREIGN KEY(user_id) REFERENCES users (azure_ad_oid) +); + +CREATE TABLE liked_study_plan ( + user_id UUID NOT NULL, + published_study_plan_id UUID NOT NULL, + FOREIGN KEY(published_study_plan_id) REFERENCES published_study_plan (id), + FOREIGN KEY(user_id) REFERENCES users (azure_ad_oid) +); + +ALTER TABLE study_plan_semester ADD COLUMN personal_study_plan_id UUID; + +ALTER TABLE study_plan_semester ADD COLUMN published_study_plan_id UUID; + +ALTER TABLE study_plan_semester DROP CONSTRAINT semesters_in_study_plan_unique; + +ALTER TABLE study_plan_semester ADD CONSTRAINT semesters_in_published_study_plan_unique UNIQUE (published_study_plan_id, semester_number); + +ALTER TABLE study_plan_semester DROP CONSTRAINT study_plan_semester_study_plan_id_fkey; + +ALTER TABLE study_plan_semester ADD CONSTRAINT published_study_plan_semester FOREIGN KEY(published_study_plan_id) REFERENCES published_study_plan (id); + +ALTER TABLE study_plan_semester ADD CONSTRAINT personal_study_plan_semester FOREIGN KEY(personal_study_plan_id) REFERENCES personal_study_plan (id); + +ALTER TABLE study_plan_semester DROP COLUMN study_plan_id; + +DROP TABLE study_plan; + +UPDATE alembic_version SET version_num='0f60b0932ff1' WHERE alembic_version.version_num = '22be9cc508e8'; + +INFO [alembic.runtime.migration] Running upgrade 0f60b0932ff1 -> 5d9bb93bb669, empty message +-- Running upgrade 0f60b0932ff1 -> 5d9bb93bb669 + +CREATE TABLE viewed_study_plan ( + user_id UUID NOT NULL, + published_study_plan_id UUID NOT NULL, + date_viewed TIMESTAMP WITHOUT TIME ZONE NOT NULL, + FOREIGN KEY(published_study_plan_id) REFERENCES published_study_plan (id), + FOREIGN KEY(user_id) REFERENCES users (azure_ad_oid) +); + +ALTER TABLE favorited_study_plan ADD COLUMN date_favourited TIMESTAMP WITHOUT TIME ZONE NOT NULL; + +ALTER TABLE favorited_study_plan ADD CONSTRAINT unique_user_favourited_study_plan UNIQUE (user_id, published_study_plan_id); + +ALTER TABLE liked_study_plan ADD COLUMN date_liked TIMESTAMP WITHOUT TIME ZONE NOT NULL; + +ALTER TABLE liked_study_plan ADD CONSTRAINT unique_user_liked_study_plan UNIQUE (user_id, published_study_plan_id); + +UPDATE alembic_version SET version_num='5d9bb93bb669' WHERE alembic_version.version_num = '0f60b0932ff1'; + +INFO [alembic.runtime.migration] Running upgrade 5d9bb93bb669 -> 9d4370465dbd, empty message +-- Running upgrade 5d9bb93bb669 -> 9d4370465dbd + +CREATE TABLE academic_plan ( + id UUID NOT NULL, + published_study_plan_id UUID NOT NULL, + first_degree_id UUID NOT NULL, + second_degree_id UUID, + second_major VARCHAR(150), + PRIMARY KEY (id), + FOREIGN KEY(first_degree_id) REFERENCES degree (id), + FOREIGN KEY(published_study_plan_id) REFERENCES published_study_plan (id), + FOREIGN KEY(second_degree_id) REFERENCES degree (id) +); + +CREATE TABLE minor_academic_plan ( + minor_id UUID, + academic_plan_id UUID, + FOREIGN KEY(academic_plan_id) REFERENCES academic_plan (id), + FOREIGN KEY(minor_id) REFERENCES programme (id) +); + +CREATE TABLE special_programmes_academic_plan ( + special_programme_id UUID, + academic_plan_id UUID, + FOREIGN KEY(academic_plan_id) REFERENCES academic_plan (id), + FOREIGN KEY(special_programme_id) REFERENCES programme (id) +); + +UPDATE alembic_version SET version_num='9d4370465dbd' WHERE alembic_version.version_num = '5d9bb93bb669'; + +INFO [alembic.runtime.migration] Running upgrade 9d4370465dbd -> f0c3451c1967, empty message +-- Running upgrade 9d4370465dbd -> f0c3451c1967 + +ALTER TABLE prerequisites ADD COLUMN prerequisite_str TEXT; + +ALTER TABLE prerequisites ALTER COLUMN course_code TYPE VARCHAR(12); + +ALTER TABLE prerequisites DROP CONSTRAINT prerequisites_prerequisite_code_fkey; + +ALTER TABLE prerequisites DROP COLUMN prerequisite_code; + +UPDATE alembic_version SET version_num='f0c3451c1967' WHERE alembic_version.version_num = '9d4370465dbd'; + +INFO [alembic.runtime.migration] Running upgrade f0c3451c1967 -> e534acc545c3, empty message +-- Running upgrade f0c3451c1967 -> e534acc545c3 + +ALTER TABLE prerequisites ALTER COLUMN course_code SET NOT NULL; + +UPDATE alembic_version SET version_num='e534acc545c3' WHERE alembic_version.version_num = 'f0c3451c1967'; + +COMMIT; \ No newline at end of file From bf7817c8972d343df1481378286e96b5316ba65d Mon Sep 17 00:00:00 2001 From: Li Ting Date: Mon, 17 Jul 2023 15:40:52 +0800 Subject: [PATCH 03/17] Update init.sql again --- backend/pre_data/init.sql | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/backend/pre_data/init.sql b/backend/pre_data/init.sql index b155432..f781e49 100644 --- a/backend/pre_data/init.sql +++ b/backend/pre_data/init.sql @@ -5,9 +5,6 @@ CREATE TABLE alembic_version ( CONSTRAINT alembic_version_pkc PRIMARY KEY (version_num) ); -INFO [alembic.runtime.migration] Running upgrade -> 22be9cc508e8, empty message --- Running upgrade -> 22be9cc508e8 - CREATE TABLE course ( course_code VARCHAR(12) NOT NULL, course_name VARCHAR(100), @@ -135,9 +132,6 @@ CREATE TABLE semester_course ( INSERT INTO alembic_version (version_num) VALUES ('22be9cc508e8') RETURNING alembic_version.version_num; -INFO [alembic.runtime.migration] Running upgrade 22be9cc508e8 -> 0f60b0932ff1, empty message --- Running upgrade 22be9cc508e8 -> 0f60b0932ff1 - CREATE TABLE personal_study_plan ( id UUID NOT NULL, date_updated TIMESTAMP WITHOUT TIME ZONE NOT NULL, @@ -194,9 +188,6 @@ DROP TABLE study_plan; UPDATE alembic_version SET version_num='0f60b0932ff1' WHERE alembic_version.version_num = '22be9cc508e8'; -INFO [alembic.runtime.migration] Running upgrade 0f60b0932ff1 -> 5d9bb93bb669, empty message --- Running upgrade 0f60b0932ff1 -> 5d9bb93bb669 - CREATE TABLE viewed_study_plan ( user_id UUID NOT NULL, published_study_plan_id UUID NOT NULL, @@ -215,9 +206,6 @@ ALTER TABLE liked_study_plan ADD CONSTRAINT unique_user_liked_study_plan UNIQUE UPDATE alembic_version SET version_num='5d9bb93bb669' WHERE alembic_version.version_num = '0f60b0932ff1'; -INFO [alembic.runtime.migration] Running upgrade 5d9bb93bb669 -> 9d4370465dbd, empty message --- Running upgrade 5d9bb93bb669 -> 9d4370465dbd - CREATE TABLE academic_plan ( id UUID NOT NULL, published_study_plan_id UUID NOT NULL, @@ -246,9 +234,6 @@ CREATE TABLE special_programmes_academic_plan ( UPDATE alembic_version SET version_num='9d4370465dbd' WHERE alembic_version.version_num = '5d9bb93bb669'; -INFO [alembic.runtime.migration] Running upgrade 9d4370465dbd -> f0c3451c1967, empty message --- Running upgrade 9d4370465dbd -> f0c3451c1967 - ALTER TABLE prerequisites ADD COLUMN prerequisite_str TEXT; ALTER TABLE prerequisites ALTER COLUMN course_code TYPE VARCHAR(12); @@ -259,11 +244,13 @@ ALTER TABLE prerequisites DROP COLUMN prerequisite_code; UPDATE alembic_version SET version_num='f0c3451c1967' WHERE alembic_version.version_num = '9d4370465dbd'; -INFO [alembic.runtime.migration] Running upgrade f0c3451c1967 -> e534acc545c3, empty message --- Running upgrade f0c3451c1967 -> e534acc545c3 - ALTER TABLE prerequisites ALTER COLUMN course_code SET NOT NULL; UPDATE alembic_version SET version_num='e534acc545c3' WHERE alembic_version.version_num = 'f0c3451c1967'; -COMMIT; \ No newline at end of file +COMMIT; + +COPY programme FROM '/pre_data/programmes.csv' DELIMITER ',' CSV HEADER; +COPY degree FROM '/pre_data/degrees.csv' DELIMITER ',' CSV HEADER; +COPY course FROM '/pre_data/courses.csv' DELIMITER ',' CSV HEADER; +COPY prerequisites FROM '/pre_data/prerequisites.csv' DELIMITER ',' CSV HEADER; \ No newline at end of file From 18b7ff9f6be90d9d913dc33a08fa4902886f80d9 Mon Sep 17 00:00:00 2001 From: Li Ting Date: Tue, 18 Jul 2023 12:20:37 +0800 Subject: [PATCH 04/17] Fix issue where published study plan cannot be deleted and add delete comfirmation --- backend/ezConnect/study_plan/studyplan.py | 4 +- .../PersonalStudyPlanList.js | 74 +++++++++++++++---- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/backend/ezConnect/study_plan/studyplan.py b/backend/ezConnect/study_plan/studyplan.py index d45252a..99c405f 100644 --- a/backend/ezConnect/study_plan/studyplan.py +++ b/backend/ezConnect/study_plan/studyplan.py @@ -94,9 +94,7 @@ def delete_study_plan(study_plan_id): if personal_study_plan: if personal_study_plan.published_version is not None: - published_study_plan = personal_study_plan.published_version - db.session.delete(published_study_plan) - db.session.commit() + delete_study_plan(personal_study_plan.published_version.id) db.session.delete(personal_study_plan) db.session.commit() diff --git a/frontend/src/Pages/StudyPlan/StudyPlanMainPage/PersonalStudyPlanList.js b/frontend/src/Pages/StudyPlan/StudyPlanMainPage/PersonalStudyPlanList.js index a5e3c3e..62d0745 100644 --- a/frontend/src/Pages/StudyPlan/StudyPlanMainPage/PersonalStudyPlanList.js +++ b/frontend/src/Pages/StudyPlan/StudyPlanMainPage/PersonalStudyPlanList.js @@ -1,5 +1,14 @@ +import { useState } from "react"; import { Link } from "react-router-dom"; import { AiFillDelete } from "react-icons/ai"; +import { + Button, + Dialog, + DialogTitle, + DialogContent, + DialogContentText, + DialogActions, +} from "@mui/material"; function PersonalStudyPlanList({ personalStudyPlans, @@ -7,6 +16,9 @@ function PersonalStudyPlanList({ createNewStudyPlan, deleteStudyPlan, }) { + const [isDeleteComfirmationBoxOpen, setIsDeleteComfirmationBoxOpen] = + useState(false); + const makeCard = (studyPlanInformation) => { const title = studyPlanInformation["title"]; const dateUpdated = studyPlanInformation["date_updated"]; @@ -14,23 +26,55 @@ function PersonalStudyPlanList({ // TODO: improve styling return ( -
- + setIsDeleteComfirmationBoxOpen(false)} + aria-labelledby="alert-dialog-title" + aria-describedby="alert-dialog-description" > - {title} - -
-

- Last updated: {dateUpdated} -

- deleteStudyPlan(id)} - /> + + {"Are you sure you want to delete your study plan?"} + + + + Deleting your study plan would also remove its published version + (if any). + + + + + + +
+
+ + {title} + +
+

+ Last updated: {dateUpdated} +

+ setIsDeleteComfirmationBoxOpen(true)} + /> +
-
+ ); }; From d9fe1c57411c040d114a10cfb6fef9f52e4d96c6 Mon Sep 17 00:00:00 2001 From: Li Ting Date: Fri, 21 Jul 2023 22:41:57 +0800 Subject: [PATCH 05/17] Fix some bugs and make improvements to study plan --- backend/ezConnect/models.py | 10 ++- backend/ezConnect/swagger.yml | 1 + .../Pages/StudyPlan/StudyPlanEditor/Editor.js | 9 ++- .../StudyPlan/StudyPlanEditor/EditorMenu.js | 9 ++- .../StudyPlan/StudyPlanEditor/Publisher.js | 5 +- .../PersonalStudyPlanList.js | 22 +++--- .../StudyPlanMainPage/StudyPlanSearchBar.js | 15 ++-- .../StudyPlan/StudyPlanPost.js/PopUpPost.js | 69 +++++++++++-------- 8 files changed, 87 insertions(+), 53 deletions(-) diff --git a/backend/ezConnect/models.py b/backend/ezConnect/models.py index 0dd23b5..e37f9f2 100644 --- a/backend/ezConnect/models.py +++ b/backend/ezConnect/models.py @@ -139,7 +139,7 @@ def __repr__(self): class PersonalStudyPlan(db.Model): id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) date_updated = Column(DateTime, nullable=False, default=datetime.utcnow) - title = Column(String(150), default="Blank study plan") + title = Column(String(150), default="My study plan") creator_id = Column( UUID(as_uuid=True), db.ForeignKey('users.azure_ad_oid'), @@ -186,7 +186,7 @@ def get_semester_list_in_order(self): class PublishedStudyPlan(db.Model): id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) date_updated = Column(DateTime, nullable=False, default=datetime.utcnow) - title = Column(String(150), nullable=False, default="Blank study plan") + title = Column(String(150), nullable=False, default="My study plan") description = Column(Text, nullable=False, default="") num_of_likes = Column( Integer, @@ -199,7 +199,11 @@ class PublishedStudyPlan(db.Model): db.ForeignKey('users.azure_ad_oid'), nullable=False ) - semesters = db.relationship('StudyPlanSemester', backref='published_study_plan') + semesters = db.relationship( + 'StudyPlanSemester', + backref='published_study_plan', + order_by='StudyPlanSemester.semester_number' + ) personal_study_plan_id = Column( UUID(as_uuid=True), db.ForeignKey('personal_study_plan.id'), diff --git a/backend/ezConnect/swagger.yml b/backend/ezConnect/swagger.yml index afcbc49..9b1845b 100644 --- a/backend/ezConnect/swagger.yml +++ b/backend/ezConnect/swagger.yml @@ -148,6 +148,7 @@ components: type: string format: uuid example: 87654321-1234-1234-1234-1234abcdef00 + nullable: true semester_number: type: integer example: 3 diff --git a/frontend/src/Pages/StudyPlan/StudyPlanEditor/Editor.js b/frontend/src/Pages/StudyPlan/StudyPlanEditor/Editor.js index 917b7c5..70d6fe5 100644 --- a/frontend/src/Pages/StudyPlan/StudyPlanEditor/Editor.js +++ b/frontend/src/Pages/StudyPlan/StudyPlanEditor/Editor.js @@ -43,7 +43,7 @@ export default function Editor({ studyPlanId, instance }) { const onDragEnd = (result, semesterInformation, setSemesterInformation) => { if (!result.destination) return; const { source, destination } = result; - setLastInteractedSemesterIndex(destination.droppableId); + setLastInteractedSemesterIndex(parseInt(destination.droppableId)); if (source.droppableId !== destination.droppableId) { const sourceSemester = semesterInformation[source.droppableId]; const destSemester = semesterInformation[destination.droppableId]; @@ -191,7 +191,11 @@ export default function Editor({ studyPlanId, instance }) { updateStudyPlan(true); setIsModified(false); }} - className="bg-sky-200 rounded-md px-2 py-1 hover:bg-sky-300 transition" + className={`${ + isModified + ? `bg-red-300 hover:bg-red-400` + : `bg-green-300 hover:bg-green-400` + } rounded-md px-2 py-1 transition`} > {isModified ? <>Save : <>Saved} @@ -199,6 +203,7 @@ export default function Editor({ studyPlanId, instance }) { title={title} setSemesterInformation={setSemesterInformation} setIsModified={setIsModified} + isPublished={isPublished} setIsShowPublisher={setIsShowPublisher} semesterInformation={semesterInformation} setIsShowValidator={setIsShowValidator} diff --git a/frontend/src/Pages/StudyPlan/StudyPlanEditor/EditorMenu.js b/frontend/src/Pages/StudyPlan/StudyPlanEditor/EditorMenu.js index f391c85..f3e6036 100644 --- a/frontend/src/Pages/StudyPlan/StudyPlanEditor/EditorMenu.js +++ b/frontend/src/Pages/StudyPlan/StudyPlanEditor/EditorMenu.js @@ -18,20 +18,23 @@ function EditorOptions({ title, setSemesterInformation, setIsModified, + isPublished, setIsShowPublisher, setIsShowValidator, semesterInformation, setLastInteractedSemesterIndex, }) { const addSemester = () => { + const semesterNumber = semesterInformation.length + 1; const newSemesterInfo = { course_codes: [], id: null, - semester_number: semesterInformation.length, + semester_number: semesterNumber, total_units: 0, }; const newSemesterInfoArray = [...semesterInformation, newSemesterInfo]; setSemesterInformation(newSemesterInfoArray); + setLastInteractedSemesterIndex(semesterNumber - 1); setIsModified(true); }; @@ -47,7 +50,7 @@ function EditorOptions({ return ( - + @@ -98,7 +101,7 @@ function EditorOptions({ } rounded-md px-2 py-1 w-full`} onClick={() => setIsShowPublisher(true)} > - Publish + {isPublished ? <>Update/unpublish : <>Publish} )} diff --git a/frontend/src/Pages/StudyPlan/StudyPlanEditor/Publisher.js b/frontend/src/Pages/StudyPlan/StudyPlanEditor/Publisher.js index 99fb50e..6aeaf56 100644 --- a/frontend/src/Pages/StudyPlan/StudyPlanEditor/Publisher.js +++ b/frontend/src/Pages/StudyPlan/StudyPlanEditor/Publisher.js @@ -88,6 +88,7 @@ function Publisher({ } ).then(() => { setIsPublished(true); + window.alert("Study Plan Published!"); setIsFetchAgain((previous) => !previous); }); }; @@ -142,11 +143,11 @@ function Publisher({ setTitle(event.target.value)} - helperText="An informative and succinct title" + helperText="An informative and succinct title. This title is separate from the title of your personal copy of the study plan." margin="dense" /> -
- - {title} - +
navigate(`/studyplan/editor/${id}`)} + className="group relative bg-white rounded-lg w-64 min-w-[256px] h-44 p-3 m-2 shadow-md overflow-hidden hover:cursor-pointer" + > +

{title}

Last updated: {dateUpdated}

setIsDeleteComfirmationBoxOpen(true)} + onClick={(event) => { + event.stopPropagation(); + setIsDeleteComfirmationBoxOpen(true); + }} />
@@ -81,7 +83,7 @@ function PersonalStudyPlanList({ return (

- Click on a study plan title to continue editing! + Click on a study plan to continue editing!

-
- setIsFilterTabOpen((previous) => !previous)} - /> +
+ +
+ setIsFilterTabOpen((previous) => !previous)} + /> +
+
{isFilterTabOpen ? (
diff --git a/frontend/src/Pages/StudyPlan/StudyPlanPost.js/PopUpPost.js b/frontend/src/Pages/StudyPlan/StudyPlanPost.js/PopUpPost.js index 47aedd2..7c9f78b 100644 --- a/frontend/src/Pages/StudyPlan/StudyPlanPost.js/PopUpPost.js +++ b/frontend/src/Pages/StudyPlan/StudyPlanPost.js/PopUpPost.js @@ -1,6 +1,7 @@ import { useState } from "react"; import { useNavigate } from "react-router-dom"; import { RxCross2 } from "react-icons/rx"; +import Tooltip from "@mui/material/Tooltip"; import { AiFillHeart, AiOutlineHeart, @@ -153,25 +154,29 @@ function PopUpPost({

Created by: {creatorName}

{isLikedBy ? ( -
- - - -

{numOfLikes}

-
+ +
+ + + +

{numOfLikes}

+
+
) : ( -
- - - -

{numOfLikes}

-
+ +
+ + + +

{numOfLikes}

+
+
)}
@@ -186,17 +191,25 @@ function PopUpPost({ {isFavouritedBy ? ( - - - + +
+ + + +
+
) : ( - + +
+ +
+
)}
From 1f8df692c2246f4cb8a55e80f82e900b91aa9418 Mon Sep 17 00:00:00 2001 From: Li Ting Date: Fri, 21 Jul 2023 23:55:51 +0800 Subject: [PATCH 06/17] Add delete button to semester menu --- .../Pages/StudyPlan/StudyPlanEditor/Editor.js | 1 + .../StudyPlan/StudyPlanEditor/EditorMenu.js | 182 +++++++++++------- .../DeleteComfirmationBox.js | 48 +++++ .../PersonalStudyPlanList.js | 47 +---- 4 files changed, 168 insertions(+), 110 deletions(-) create mode 100644 frontend/src/Pages/StudyPlan/StudyPlanMainPage/DeleteComfirmationBox.js diff --git a/frontend/src/Pages/StudyPlan/StudyPlanEditor/Editor.js b/frontend/src/Pages/StudyPlan/StudyPlanEditor/Editor.js index 70d6fe5..2a62c5c 100644 --- a/frontend/src/Pages/StudyPlan/StudyPlanEditor/Editor.js +++ b/frontend/src/Pages/StudyPlan/StudyPlanEditor/Editor.js @@ -201,6 +201,7 @@ export default function Editor({ studyPlanId, instance }) { { const studyPlan = document.getElementById("studyPlan"); @@ -16,6 +19,7 @@ const downloadStudyPlan = (title) => { function EditorOptions({ title, + studyPlanId, setSemesterInformation, setIsModified, isPublished, @@ -24,6 +28,10 @@ function EditorOptions({ semesterInformation, setLastInteractedSemesterIndex, }) { + const navigate = useNavigate(); + const [isDeleteComfirmationBoxOpen, setIsDeleteComfirmationBoxOpen] = + useState(false); + const addSemester = () => { const semesterNumber = semesterInformation.length + 1; const newSemesterInfo = { @@ -48,79 +56,109 @@ function EditorOptions({ setIsModified(true); }; + const deleteStudyPlan = (studyPlanId) => { + fetch( + `${process.env.REACT_APP_API_ENDPOINT}/api/studyplan/${studyPlanId}`, + { + method: "DELETE", + } + ).then(() => navigate("/studyplan")); + }; + return ( - - - - - -
- - {({ active }) => ( - - )} - - - {({ active }) => ( - - )} - -
- - {({ active }) => ( - - )} - -
- - {({ active }) => ( - - )} - -
- - {({ active }) => ( - - )} - -
-
-
+ <> + + + + + + +
+ + {({ active }) => ( + + )} + + + {({ active }) => ( + + )} + +
+ + {({ active }) => ( + + )} + +
+ + {({ active }) => ( + + )} + +
+ + {({ active }) => ( + + )} + +
+ + {({ active }) => ( + + )} + +
+
+
+ ); } diff --git a/frontend/src/Pages/StudyPlan/StudyPlanMainPage/DeleteComfirmationBox.js b/frontend/src/Pages/StudyPlan/StudyPlanMainPage/DeleteComfirmationBox.js new file mode 100644 index 0000000..869c95c --- /dev/null +++ b/frontend/src/Pages/StudyPlan/StudyPlanMainPage/DeleteComfirmationBox.js @@ -0,0 +1,48 @@ +import { + Button, + Dialog, + DialogTitle, + DialogContent, + DialogContentText, + DialogActions, +} from "@mui/material"; + +export default function DeleteComfirmationBox({ + studyPlanId, + deleteStudyPlan, + isDeleteComfirmationBoxOpen, + setIsDeleteComfirmationBoxOpen, +}) { + return ( + setIsDeleteComfirmationBoxOpen(false)} + aria-labelledby="alert-dialog-title" + aria-describedby="alert-dialog-description" + > + + {"Are you sure you want to delete your study plan?"} + + + + Deleting your study plan would also remove its published version (if + any). + + + + + + + + ); +} diff --git a/frontend/src/Pages/StudyPlan/StudyPlanMainPage/PersonalStudyPlanList.js b/frontend/src/Pages/StudyPlan/StudyPlanMainPage/PersonalStudyPlanList.js index 836e935..7d53989 100644 --- a/frontend/src/Pages/StudyPlan/StudyPlanMainPage/PersonalStudyPlanList.js +++ b/frontend/src/Pages/StudyPlan/StudyPlanMainPage/PersonalStudyPlanList.js @@ -1,14 +1,7 @@ import { useState } from "react"; import { useNavigate } from "react-router-dom"; import { AiFillDelete } from "react-icons/ai"; -import { - Button, - Dialog, - DialogTitle, - DialogContent, - DialogContentText, - DialogActions, -} from "@mui/material"; +import DeleteComfirmationBox from "./DeleteComfirmationBox"; function PersonalStudyPlanList({ personalStudyPlans, @@ -19,6 +12,7 @@ function PersonalStudyPlanList({ const navigate = useNavigate(); const [isDeleteComfirmationBoxOpen, setIsDeleteComfirmationBoxOpen] = useState(false); + const [deleteStudyPlanId, setDeleteStudyPlanId] = useState(""); const makeCard = (studyPlanInformation) => { const title = studyPlanInformation["title"]; @@ -28,36 +22,12 @@ function PersonalStudyPlanList({ // TODO: improve styling return ( <> - setIsDeleteComfirmationBoxOpen(false)} - aria-labelledby="alert-dialog-title" - aria-describedby="alert-dialog-description" - > - - {"Are you sure you want to delete your study plan?"} - - - - Deleting your study plan would also remove its published version - (if any). - - - - - - - +
navigate(`/studyplan/editor/${id}`)} className="group relative bg-white rounded-lg w-64 min-w-[256px] h-44 p-3 m-2 shadow-md overflow-hidden hover:cursor-pointer" @@ -71,6 +41,7 @@ function PersonalStudyPlanList({ className="hidden cursor-pointer group-hover:block hover:bg-slate-200 p-1 h-6 w-6 rounded-md transition" onClick={(event) => { event.stopPropagation(); + setDeleteStudyPlanId(id); setIsDeleteComfirmationBoxOpen(true); }} /> From 2aafeedd7ec0caafeff31e92493c66e42af6bf0d Mon Sep 17 00:00:00 2001 From: Li Ting Date: Sat, 22 Jul 2023 11:59:45 +0800 Subject: [PATCH 07/17] Add 404 page --- frontend/src/App.js | 3 ++- frontend/src/Pages/404.js | 20 ++++++++++++++++++++ frontend/src/Pages/404_Image.jpg | Bin 0 -> 28776 bytes 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 frontend/src/Pages/404.js create mode 100644 frontend/src/Pages/404_Image.jpg diff --git a/frontend/src/App.js b/frontend/src/App.js index b2b0011..9c28e8d 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,4 +1,3 @@ -// import { useEffect, useState } from "react"; import { MsalProvider } from '@azure/msal-react'; import { Route, Routes } from "react-router-dom"; import LoginPage from "./Pages/LoginPage"; @@ -18,6 +17,7 @@ import RequestMentor from './Pages/Mentoring/RequestMentor'; import RequestMentee from './Pages/Mentoring/RequestMentee'; import AcceptMatch from './Pages/Mentoring/AcceptMatch'; import FavouritedStudyPlanPage from './Pages/StudyPlan/PersonalTabs/FavouritedStudyPlanPage'; +import NotFound from './Pages/404'; const Pages = () => { return ( @@ -51,6 +51,7 @@ const Pages = () => { } /> } /> } /> + } />