From cb824c0286a33f9fb224646ba7361cc6c8eebc9d Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 11 Mar 2025 16:49:00 -0400 Subject: [PATCH 01/12] [#52] Create page to show saved opportunities https://pm.rafaelcenzano.com/work_packages/52 From a028a05d7935902a2823c5cc7b5b83c817079a75 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 11 Mar 2025 17:41:59 -0400 Subject: [PATCH 02/12] add saved page --- src/App.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index 935bbffb..f69ebba4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,7 +10,8 @@ import StaffPage from "./staff/pages/Staff.tsx"; import Department from "./staff/pages/Department.tsx"; import CreatePost from "./staff/pages/CreatePost.tsx"; import IndividualPost from "./opportunities/pages/IndividualPost.js"; -import ProfilePage from "./shared/pages/Profile.tsx"; +import ProfilePage from "./individuals/pages/Profile.tsx"; +import SavedPage from "./individuals/pages/Saved.tsx"; import LoginRedirection from "./auth/Login.tsx"; import LogoutRedirection from "./auth/Logout.tsx"; import StickyFooter from "./shared/components/Navigation/StickyFooter.tsx"; @@ -37,6 +38,7 @@ function App() { } /> } /> + } /> } From 8c5f1068a73b91df28a9ef89b9dfc394e4672aa9 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 11 Mar 2025 17:42:07 -0400 Subject: [PATCH 03/12] new type for opportunities --- src/types/opportunity.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/types/opportunity.ts diff --git a/src/types/opportunity.ts b/src/types/opportunity.ts new file mode 100644 index 00000000..48fc2ebd --- /dev/null +++ b/src/types/opportunity.ts @@ -0,0 +1,13 @@ +export type Opportunity = { + id: string; + name: string; + description: string; + recommended_experience?: string; + pay?: number; + credits?: string; + semester: string; + year: number; + application_due: string; + active: boolean; + location: string; +} \ No newline at end of file From d06cf641244c3a935898121ab4afdd66cd0bb1a0 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 11 Mar 2025 17:42:12 -0400 Subject: [PATCH 04/12] cleanup title --- src/staff/pages/Departments.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/staff/pages/Departments.tsx b/src/staff/pages/Departments.tsx index 1884229a..a6d7528e 100644 --- a/src/staff/pages/Departments.tsx +++ b/src/staff/pages/Departments.tsx @@ -46,7 +46,7 @@ export default function Departments() { return ( <> -

+

Departments

{!departments && "Loading..."} From 47b9d0974f720404bbb6b69d934e18b9363d341e Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 11 Mar 2025 17:42:30 -0400 Subject: [PATCH 05/12] move pages to new directory --- src/{shared => individuals}/pages/EditProfile.js | 0 src/{shared => individuals}/pages/Profile.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/{shared => individuals}/pages/EditProfile.js (100%) rename src/{shared => individuals}/pages/Profile.tsx (94%) diff --git a/src/shared/pages/EditProfile.js b/src/individuals/pages/EditProfile.js similarity index 100% rename from src/shared/pages/EditProfile.js rename to src/individuals/pages/EditProfile.js diff --git a/src/shared/pages/Profile.tsx b/src/individuals/pages/Profile.tsx similarity index 94% rename from src/shared/pages/Profile.tsx rename to src/individuals/pages/Profile.tsx index 5b91fc15..dc808303 100644 --- a/src/shared/pages/Profile.tsx +++ b/src/individuals/pages/Profile.tsx @@ -1,6 +1,6 @@ import React, { useEffect } from "react"; import { useState } from "react"; -import ProfileComponents from "../components/Profile/ProfileComponents.tsx"; +import ProfileComponents from "../../shared/components/Profile/ProfileComponents.tsx"; import { useAuth } from "../../context/AuthContext.tsx"; import { Profile } from "../../types/profile.ts"; // import EditProfile from "./EditProfile"; From 47d8ce45853c1b7c713b498557c5819b0f1ee837 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 11 Mar 2025 17:42:37 -0400 Subject: [PATCH 06/12] add new saved page --- src/shared/components/Navigation/MainNavigation.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shared/components/Navigation/MainNavigation.tsx b/src/shared/components/Navigation/MainNavigation.tsx index 62131eea..978b1d70 100644 --- a/src/shared/components/Navigation/MainNavigation.tsx +++ b/src/shared/components/Navigation/MainNavigation.tsx @@ -15,6 +15,7 @@ export default function MainNavigation() { { name: "Create", href: "/create", current: false }, { name: "Staff", href: "/staff", current: false }, { name: "Profile", href: "/profile", current: false }, + { name: "Saved", href: "/saved", current: false }, { name: "Sign Out", href: "/signout", current: false }, ] : [{ name: "Sign In", href: "/signin", current: false }]; From d667d0a055a575778ec0038d9b2155f3a6e0c5e1 Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Tue, 11 Mar 2025 17:42:48 -0400 Subject: [PATCH 07/12] new page to list saved opportunities --- src/individuals/pages/Saved.tsx | 154 ++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 src/individuals/pages/Saved.tsx diff --git a/src/individuals/pages/Saved.tsx b/src/individuals/pages/Saved.tsx new file mode 100644 index 00000000..723f091b --- /dev/null +++ b/src/individuals/pages/Saved.tsx @@ -0,0 +1,154 @@ +import React, { useEffect } from "react"; +import { useState } from "react"; +import { useAuth } from "../../context/AuthContext.tsx"; +import { Opportunity } from "../../types/opportunity.ts"; + +export default function SavedPage() { + const { auth } = useAuth(); + + if (!auth.isAuthenticated) { + window.location.href = "/login"; + } + + const [saved, setSaved] = useState(null); + + const fetchSaved = async () => { + try { + const response = await fetch( + `${process.env.REACT_APP_BACKEND_SERVER}/savedOpportunities`, { + credentials: "include", + } + ); + + if (!response.ok) { + throw new Error("Saved not found"); + } + + const data = await response.json(); + setSaved(data); + console.log(data); + } catch { + console.log("Error fetching saved"); + } + } + + useEffect(() => { + fetchSaved(); + setSaved([{ + id: "1", + name: "Test Opportunity", + description: "This is a test opportunity", + recommended_experience: "None", + pay: 0, + credits: "0", + semester: "Fall", + year: 2021, + application_due: "2025-03-14", + active: true, + location: "Remote", + }, + { + id: "2", + name: "Test Opportunity2", + description: "This is a test opportunity", + recommended_experience: "None", + pay: 0, + credits: "0", + semester: "Fall", + year: 2021, + application_due: "2025-03-31", + active: true, + location: "Remote", + }, + { + id: "3", + name: "Test Opportunity3", + description: "This is a test opportunity", + recommended_experience: "None", + pay: 0, + credits: "0", + semester: "Fall", + year: 2021, + application_due: "2025-02-14", + active: true, + location: "Remote", + }]); + }, []); + + return ( +
+

+ Saved Opportunities +

+ {!saved && "Loading..."} + {saved && ( + + + + + + + + + + + + + + {saved.map((opportunity) => ( + + + + + + + + + + + + + ))} +
NameDescriptionRecommended ExperiencePayCreditsSemesterYearApplication DueLocationUnsave
{opportunity.name}{opportunity.description}{opportunity.recommended_experience}{opportunity.pay}{opportunity.credits}{opportunity.semester}{opportunity.year} { + const today = new Date(); + const dueDate = new Date(opportunity.application_due); + const oneWeek = 7 * 24 * 60 * 60 * 1000; + + if (dueDate < today) { + return "red"; + } else if (dueDate.getTime() - today.getTime() <= oneWeek) { + return "orange"; + } else { + return "black"; + } + })() + }}> + {new Date(opportunity.application_due).toLocaleDateString("en-US")} + {opportunity.location} + +
+ )} +
+ ); +}; From 203e984a592d9250265caed5d6b6ba4ea30bd52f Mon Sep 17 00:00:00 2001 From: Rafael Cenzano <32753063+RafaelCenzano@users.noreply.github.com> Date: Fri, 17 Oct 2025 14:59:43 -0400 Subject: [PATCH 08/12] Update to allow for unsaving --- src/individuals/pages/Saved.tsx | 54 ++++++++------------------------- src/utils.ts | 9 ++++++ 2 files changed, 22 insertions(+), 41 deletions(-) create mode 100644 src/utils.ts diff --git a/src/individuals/pages/Saved.tsx b/src/individuals/pages/Saved.tsx index 723f091b..5aba6c26 100644 --- a/src/individuals/pages/Saved.tsx +++ b/src/individuals/pages/Saved.tsx @@ -2,6 +2,7 @@ import React, { useEffect } from "react"; import { useState } from "react"; import { useAuth } from "../../context/AuthContext.tsx"; import { Opportunity } from "../../types/opportunity.ts"; +import { getCookie } from "../../utils.ts"; export default function SavedPage() { const { auth } = useAuth(); @@ -12,6 +13,8 @@ export default function SavedPage() { const [saved, setSaved] = useState(null); + const csrfToken = getCookie('csrf_access_token'); + const fetchSaved = async () => { try { const response = await fetch( @@ -34,45 +37,6 @@ export default function SavedPage() { useEffect(() => { fetchSaved(); - setSaved([{ - id: "1", - name: "Test Opportunity", - description: "This is a test opportunity", - recommended_experience: "None", - pay: 0, - credits: "0", - semester: "Fall", - year: 2021, - application_due: "2025-03-14", - active: true, - location: "Remote", - }, - { - id: "2", - name: "Test Opportunity2", - description: "This is a test opportunity", - recommended_experience: "None", - pay: 0, - credits: "0", - semester: "Fall", - year: 2021, - application_due: "2025-03-31", - active: true, - location: "Remote", - }, - { - id: "3", - name: "Test Opportunity3", - description: "This is a test opportunity", - recommended_experience: "None", - pay: 0, - credits: "0", - semester: "Fall", - year: 2021, - application_due: "2025-02-14", - active: true, - location: "Remote", - }]); }, []); return ( @@ -126,17 +90,25 @@ export default function SavedPage() {