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 && (
+
+
+ | Name |
+ Description |
+ Recommended Experience |
+ Pay |
+ Credits |
+ Semester |
+ Year |
+ Application Due |
+ Location |
+ Unsave |
+
+ {saved.map((opportunity) => (
+
+ | {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() {