diff --git a/client/src/App.tsx b/client/src/App.tsx index 3eb973a..d326fba 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -16,16 +16,13 @@ function App() { } path="/" /> } path="/signup" /> } path="/signin" /> - } path="/springboard/:accessToken" /> - } - path="/manage-account/:accessToken" - /> + } path="/springboard" /> + } path="/manage-account" /> } path="/community" /> } path="/createPost" /> - } path="/editPost/:id" /> - } path="/schedule"/> + } path="/editPost/:id" /> + } path="/schedule" /> ); } diff --git a/client/src/components/SignInModule.tsx b/client/src/components/SignInModule.tsx index 1ae48a8..763d136 100644 --- a/client/src/components/SignInModule.tsx +++ b/client/src/components/SignInModule.tsx @@ -38,7 +38,8 @@ export default function SignInModule() { axios .post(config.serverAddress + "/users/login", values) .then((response) => { - navigate("/springboard/" + response.data.accessToken); + localStorage.setItem("accessToken", response.data.accessToken); + navigate("/springboard/"); }) .catch((error) => { popErrorToast(error); diff --git a/client/src/components/SignUpModule.tsx b/client/src/components/SignUpModule.tsx index 65f1fb8..7eb6a25 100644 --- a/client/src/components/SignUpModule.tsx +++ b/client/src/components/SignUpModule.tsx @@ -1,12 +1,12 @@ import { Button, Checkbox, Link } from "@nextui-org/react"; import { Formik, Form, Field, ErrorMessage } from "formik"; import * as Yup from "yup"; -import axios from "axios"; import config from "../config"; import NextUIFormikInput from "./NextUIFormikInput"; import { useNavigate } from "react-router-dom"; import { popErrorToast } from "../utilities"; import { useState } from "react"; +import instance from "../security/http"; const validationSchema = Yup.object({ firstName: Yup.string() @@ -61,7 +61,7 @@ export default function SignUpModule() { const handleSubmit = async (values: any) => { try { - const response = await axios.post( + const response = await instance.post( config.serverAddress + "/users/register", values ); diff --git a/client/src/components/UpdateAccountModule.tsx b/client/src/components/UpdateAccountModule.tsx index dd4086c..2c3a565 100644 --- a/client/src/components/UpdateAccountModule.tsx +++ b/client/src/components/UpdateAccountModule.tsx @@ -1,4 +1,3 @@ -import axios from "axios"; import * as Yup from "yup"; import config from "../config"; import { useEffect, useState } from "react"; @@ -19,26 +18,23 @@ import NextUIFormikInput from "./NextUIFormikInput"; import { useNavigate } from "react-router-dom"; import UserProfilePicture from "./UserProfilePicture"; import { popErrorToast } from "../utilities"; +import instance from "../security/http"; -export default function UpdateAccountModule({ - accessToken, -}: { - accessToken: string; -}) { +export default function UpdateAccountModule() { const navigate = useNavigate(); let [userInformation, setUserInformation] = useState(); const { isOpen, onOpen, onOpenChange } = useDisclosure(); useEffect(() => { - retrieveUserInformation(accessToken!) + retrieveUserInformation() .then((response) => { setUserInformation(response); }) .catch(() => { - navigate("/springboard/" + accessToken); + navigate("/springboard/"); }); - }, [accessToken]); + }, []); const validationSchema = Yup.object({ firstName: Yup.string() @@ -70,17 +66,12 @@ export default function UpdateAccountModule({ const handleSubmit = async (values: any) => { try { - const response = await axios.put( + const response = await instance.put( `${config.serverAddress}/users/individual/${userInformation.id}`, - values, - { - headers: { - Authorization: `Bearer ${accessToken}`, - }, - } + values ); console.log("User updated successfully:", response.data); - navigate("/springboard/" + accessToken); + navigate("/springboard/"); } catch (error) { popErrorToast(error); } @@ -103,16 +94,8 @@ export default function UpdateAccountModule({ }; const archiveAccount = () => { - axios - .put( - config.serverAddress + "/users/archive/" + userInformation.id, - null, - { - headers: { - Authorization: `Bearer ${accessToken}`, - }, - } - ) + instance + .put(config.serverAddress + "/users/archive/" + userInformation.id) .then(() => { navigate("/signin"); }) @@ -143,7 +126,7 @@ export default function UpdateAccountModule({ - - - )} - - ) - } - - - ); + return ( + +
+ + + + + +
+
+ {!loading && ( + + {({ isValid, dirty, isSubmitting }) => ( +
+
+ +
+
+

Image

+
+
+ +
+
+ +
+
+ +
+
+ )} +
+ )} +
+
+ ); } -export default editPost \ No newline at end of file +export default editPost; diff --git a/client/src/pages/ManageUserAccountPage.tsx b/client/src/pages/ManageUserAccountPage.tsx index d60a676..e841a4c 100644 --- a/client/src/pages/ManageUserAccountPage.tsx +++ b/client/src/pages/ManageUserAccountPage.tsx @@ -1,15 +1,19 @@ -import { useParams } from "react-router-dom"; import DefaultLayout from "../layouts/default"; import UpdateAccountModule from "../components/UpdateAccountModule"; +import { useNavigate } from "react-router-dom"; export default function ManageUserAccountPage() { - let { accessToken } = useParams(); // TODO: Replace AT from props with AT from localstorage + const navigate = useNavigate(); + let accessToken = localStorage.getItem("accessToken"); + if (!accessToken) { + navigate("/signin"); + } return (
- +
diff --git a/client/src/pages/SchedulePage.tsx b/client/src/pages/SchedulePage.tsx index 52b9a20..204f99e 100644 --- a/client/src/pages/SchedulePage.tsx +++ b/client/src/pages/SchedulePage.tsx @@ -1,9 +1,17 @@ -import { Card, CardBody, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow } from '@nextui-org/react'; +import { + Card, + CardBody, + Table, + TableBody, + TableCell, + TableColumn, + TableHeader, + TableRow, +} from "@nextui-org/react"; import DefaultLayout from "../layouts/default"; -import { useEffect, useState } from 'react'; -import axios from 'axios'; -import config from '../config'; - +import { useEffect, useState } from "react"; +import config from "../config"; +import instance from "../security/http"; interface Schedule { id: number; @@ -14,11 +22,11 @@ interface Schedule { } export default function SchedulePage() { - const [scheduleList, setScheduleList] = useState([]); useEffect(() => { - axios.get(config.serverAddress + '/schedule') + instance + .get(config.serverAddress + "/schedule") .then((res) => { const schedules = res.data.map((schedule: Schedule) => ({ ...schedule, @@ -27,83 +35,91 @@ export default function SchedulePage() { setScheduleList(schedules); }) .catch((err) => { - console.error('Error fetching schedules:', err); + console.error("Error fetching schedules:", err); }); - }, []); + }, []); - return ( - -
-

Karang Guni Schedule

-
- - - Date - Time - Location - Postal Code - Status - - - {scheduleList.map((schedule) => ( - - {((schedule.dateTime as unknown) as Date).toLocaleDateString()} - {((schedule.dateTime as unknown) as Date).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} - {schedule.location} - {schedule.postalCode} - {schedule.status} - - ))} - -
-
+ return ( + +
+

Karang Guni Schedule

+
+ + + Date + Time + Location + Postal Code + Status + + + {scheduleList.map((schedule) => ( + + + {( + schedule.dateTime as unknown as Date + ).toLocaleDateString()} + + + {(schedule.dateTime as unknown as Date).toLocaleTimeString( + [], + { hour: "2-digit", minute: "2-digit" } + )} + + {schedule.location} + {schedule.postalCode} + {schedule.status} + + ))} + +
+
+
+
-
-
- - -

Paper

-

$0.05 to 0.20/KG

-
    -
  • Cardboard ($0.20/kg)
  • -
  • Newspaper and B&W ($0.11/kg)
  • -
  • Mix paper ($0.05/kg)
  • -
-
-
-
-
- - -

Paper

-

$0.05 to 0.20/KG

-
    -
  • Cardboard ($0.20/kg)
  • -
  • Newspaper and B&W ($0.11/kg)
  • -
  • Mix paper ($0.05/kg)
  • -
-
-
-
-
- - -

Paper

-

$0.05 to 0.20/KG

-
    -
  • Cardboard ($0.20/kg)
  • -
  • Newspaper and B&W ($0.11/kg)
  • -
  • Mix paper ($0.05/kg)
  • -
-
-
-
-
+ + +

Paper

+

$0.05 to 0.20/KG

+
    +
  • Cardboard ($0.20/kg)
  • +
  • Newspaper and B&W ($0.11/kg)
  • +
  • Mix paper ($0.05/kg)
  • +
+
+
+
+
+ + +

Paper

+

$0.05 to 0.20/KG

+
    +
  • Cardboard ($0.20/kg)
  • +
  • Newspaper and B&W ($0.11/kg)
  • +
  • Mix paper ($0.05/kg)
  • +
+
+
+
+
+ + +

Paper

+

$0.05 to 0.20/KG

+
    +
  • Cardboard ($0.20/kg)
  • +
  • Newspaper and B&W ($0.11/kg)
  • +
  • Mix paper ($0.05/kg)
  • +
+
+
- -
-
- ); - } \ No newline at end of file +
+
+
+
+ ); +} diff --git a/client/src/pages/SpringboardPage.tsx b/client/src/pages/SpringboardPage.tsx index bc45935..392518e 100644 --- a/client/src/pages/SpringboardPage.tsx +++ b/client/src/pages/SpringboardPage.tsx @@ -1,4 +1,4 @@ -import { useNavigate, useParams } from "react-router-dom"; +import { useNavigate } from "react-router-dom"; import DefaultLayout from "../layouts/default"; import { useEffect, useState } from "react"; import { Button, Card, Link } from "@nextui-org/react"; @@ -9,13 +9,15 @@ import { retrieveUserInformation } from "../security/users"; import UserProfilePicture from "../components/UserProfilePicture"; export default function SpringboardPage() { - let { accessToken } = useParams(); // TODO: Replace AT from props with AT from localstorage + const navigate = useNavigate(); + let accessToken = localStorage.getItem("accessToken"); + if (!accessToken) { + navigate("/signin"); + } let [userInformation, setUserInformation] = useState(); let [accountUnavailable, setAccountUnavaliable] = useState(false); let timeOfDay = getTimeOfDay(); - const navigate = useNavigate(); - let greeting = ""; if (timeOfDay === 0) { greeting = "Good morning"; @@ -26,11 +28,11 @@ export default function SpringboardPage() { } useEffect(() => { - retrieveUserInformation(accessToken!) + retrieveUserInformation() .then((response) => { setUserInformation(response); }) - .catch((error) => { + .catch((_) => { setAccountUnavaliable(true); }); return; @@ -60,7 +62,7 @@ export default function SpringboardPage() { } onPress={() => { - navigate("/manage-account/" + accessToken); + navigate("/manage-account/"); }} > Manage your account @@ -68,7 +70,6 @@ export default function SpringboardPage() { @@ -77,25 +78,21 @@ export default function SpringboardPage() { title="Community Forums" subtitle="Be involved in discussions among your neighbourhood" linkToPage="" - > -
diff --git a/client/src/security/http.ts b/client/src/security/http.ts new file mode 100644 index 0000000..437f5da --- /dev/null +++ b/client/src/security/http.ts @@ -0,0 +1,29 @@ +import axios from "axios"; +import config from "../config"; + +const instance = axios.create({ + baseURL: config.serverAddress, +}); + +// Add a request interceptor +instance.interceptors.request.use( + function (config) { + console.log("yessss"); + // Do something before request is sent + let accessToken = localStorage.getItem("accessToken"); + if (accessToken) { + config.headers["Authorization"] = `Bearer ${accessToken}`; + } + if (config.data && config.data.user) { + delete config.data.user; + } + return config; + }, + function (error) { + // Do something with request error + + localStorage.clear(); + return Promise.reject(error); + } +); +export default instance; diff --git a/client/src/security/users.ts b/client/src/security/users.ts index d1c586f..3c3b9c2 100644 --- a/client/src/security/users.ts +++ b/client/src/security/users.ts @@ -1,20 +1,12 @@ -import axios, { AxiosError } from "axios"; +import { AxiosError } from "axios"; import config from "../config"; +import instance from "./http"; -export async function retrieveUserInformation(accessToken: string) { +export async function retrieveUserInformation() { try { - let userId = await axios.get(`${config.serverAddress}/users/auth`, { - headers: { - Authorization: `Bearer ${accessToken}`, - }, - }); - let userInformation = await axios.get( - `${config.serverAddress}/users/individual/${userId.data.id}`, - { - headers: { - Authorization: `Bearer ${accessToken}`, - }, - } + let userId = await instance.get(`${config.serverAddress}/users/auth`); + let userInformation = await instance.get( + `${config.serverAddress}/users/individual/${userId.data.id}` ); return userInformation.data; } catch (error) {