Skip to content

Commit

Permalink
Merge pull request #18 from NUS-Fintech-Society/epic/DEV-3-authentica…
Browse files Browse the repository at this point in the history
…tion

Sprint 1 - Authentication
  • Loading branch information
gnimnix authored Mar 19, 2024
2 parents 9e9a5c0 + 511eb22 commit 3f60a1b
Show file tree
Hide file tree
Showing 23 changed files with 413 additions and 130 deletions.
File renamed without changes.
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
"dependencies": {
"@tanstack/react-query": "^5.18.0",
"@tanstack/react-query-devtools": "^5.18.0",
"@types/js-cookie": "^3.0.6",
"@uidotdev/usehooks": "^2.4.1",
"date-fns": "^3.3.1",
"js-cookie": "^3.0.5",
"localforage": "^1.10.0",
"match-sorter": "^6.3.4",
"msw": "^2.1.5",
Expand All @@ -24,6 +26,7 @@
"sort-by": "^1.2.0"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.4.2",
"@testing-library/react": "^14.2.1",
"@types/node": "^20.11.13",
"@types/react": "^18.2.43",
Expand All @@ -36,7 +39,8 @@
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"jsdom": "^24.0.0",
"typescript": "^5.2.2",
"tsc-alias": "^1.8.8",
"typescript": "^5.4.2",
"vite": "^5.0.8",
"vite-tsconfig-paths": "^4.3.2",
"vitest": "^1.2.2"
Expand Down
47 changes: 47 additions & 0 deletions src/api/authentication.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import resolveURL from "./fetch";
import Cookies from "js-cookie";

const LOGIN_URL = resolveURL('/auth/login');
const LOGOUT_URL = resolveURL('/auth/logout');
const GET_CSRF_URL = resolveURL('/auth/csrf');

export const signIn = async (username: string, password: string) => {
const csrfmiddlewaretoken = Cookies.get("csrftoken");
if (csrfmiddlewaretoken === undefined) throw new Error("No CSRF Token Present")
return await fetch(LOGIN_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include',
body: JSON.stringify({username, password, csrfmiddlewaretoken}),
});
};


export const signOut = async (): Promise<Response> => {
const csrfmiddlewaretoken = Cookies.get("csrftoken");
if (csrfmiddlewaretoken === undefined) throw new Error("No CSRF Token Present")
const response = await fetch(LOGOUT_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include',
body: JSON.stringify({ csrfmiddlewaretoken })
});

Cookies.remove("csrftoken")

return response;
};

export const getCSRF = async (): Promise<Response> => {
return await fetch(GET_CSRF_URL, {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json"
},
});
};
1 change: 1 addition & 0 deletions src/api/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

const setApiURL = () => {
if (import.meta.env.DEV) {
return import.meta.env.VITE_IGNORE_MSW.toLowerCase() === "true" ? "http://localhost:8000" : "http://localhost:5173"
Expand Down
50 changes: 50 additions & 0 deletions src/assets/css/authentication/MobileLoginContainer.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* MobileLoginContainer.module.css */
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* Example to fill the screen */
padding: 20px; /* Padding for smaller screens */
background: linear-gradient(180deg, #0C1747 0%, rgba(37, 60, 92, 0.62) 100%);
border: 1px black solid;
}



/* For small mobile phones */
@media (max-width: 480px) {
/* styles for screens smaller than 600px */
.loginForm {
width: 100%; /* Full width on mobile */
min-width: 320px; /* But not too small */
padding: 20px;
background-color: white;
border-radius: 4px;
/* Add more styling as needed */
}
}

/* For large mobile phones */
@media (min-width: 481px) and (max-width: 768px) {
/* styles for screens smaller than 600px */
.loginForm {
width: 100%; /* Full width on mobile */
padding: 20px;
background-color: white;
border-radius: 4px;
/* Add more styling as needed */
}
}

/* For tablets */
@media (min-width: 768px) and (max-width: 1024px) {
/* styles for screens between 601px and 1024px */
.loginForm {
width: 100%; /* Full width on mobile */
padding: 20px;
background-color: white;
border-radius: 4px;
/* Add more styling as needed */
}
}

22 changes: 22 additions & 0 deletions src/assets/css/authentication/WebLoginContainer.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* WebLoginContainer.module.css */
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* Example to fill the screen */
background: linear-gradient(180deg, #0C1747 0%, rgba(37, 60, 92, 0.62) 100%);
border: 1px black solid;
}

/* For desktops */
@media (min-width: 1025px) {
/* styles for screens larger than 1024px */
}
.loginForm {
width: 100%; /* Full width on mobile */
max-width: 1280px; /* But not too wide */
padding: 20px;
background-color: white;
border-radius: 4px;
/* Add more styling as needed */
}
68 changes: 0 additions & 68 deletions src/assets/css/index.css

This file was deleted.

42 changes: 0 additions & 42 deletions src/assets/css/testpage.css

This file was deleted.

13 changes: 13 additions & 0 deletions src/components/authentication/MobileLoginContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import styles from '../../assets/css/authentication/MobileLoginContainer.module.css'; // Import mobile-specific CSS

const MobileLoginContainer = () => {
return (
<div className={styles.container}>
<div className={styles.loginForm}>
{/* Your login form goes here */}
</div>
</div>
);
}

export default MobileLoginContainer;
13 changes: 13 additions & 0 deletions src/components/authentication/WebLoginContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import styles from '../../assets/css/authentication/WebLoginContainer.module.css'; // Import web-specific CSS

const WebLoginContainer = () => {
return (
<div className={styles.container}>
<div className={styles.loginForm}>
{/* Your login form goes here */}
</div>
</div>
);
}

export default WebLoginContainer;
8 changes: 8 additions & 0 deletions src/components/constants.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const BREAKPOINTS = {
XS: 0,
SM: 576,
MD: 768,
LG: 992,
XL: 1200,
XXL: 1400
}
4 changes: 2 additions & 2 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { RouterProvider } from "react-router-dom";

import router from "./routes/router.tsx";
import './assets/css/index.css'
import router from "routes/router.tsx";
import 'css/reset.css'

const queryClient = new QueryClient()

Expand Down
46 changes: 46 additions & 0 deletions src/mocks/authentication/auth_handlers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//src/mocks/authentication/auth_handlers.ts

import { http, HttpResponse } from "msw"
import resolveURL from "../../api/fetch";

export const mockCSRFToken: string = "SUPERSECRETCSRFTOKEN"
export const mockUsername: string = "testuser"
export const mockPassword: string = "mockpassword"


type responseData = {
username: string | undefined
password: string | undefined
csrfmiddlewaretoken: string | undefined
}


export const auth_handlers = [
http.post(resolveURL("/auth/csrf"), () => {
return new HttpResponse(null, {
headers: {
'Set-Cookie': `csrftoken=${mockCSRFToken}; expires=Tue, 31 Dec 2024 23:59:59 GMT; Max-Age=31449600; Path=/; SameSite=Lax`
}
})
}),

http.post<object, responseData>(resolveURL("/auth/login"), async ({ request }) => {
const data = await request.json()
if (data.csrfmiddlewaretoken !== mockCSRFToken) return new HttpResponse(null, {status: 403})

if (data.username !== mockUsername || data.password !== mockPassword) return new HttpResponse(null, {status: 403})

return new HttpResponse(null, {
headers: {
'Set-Cookie': `csrftoken=${mockCSRFToken}; expires=Tue, 31 Dec 2024 23:59:59 GMT; Max-Age=31449600; Path=/; SameSite=Lax`
}
})
}),

http.post<object, responseData>(resolveURL("/auth/logout"), async ({ request }) => {
const data = await request.json()
if (data.csrfmiddlewaretoken !== mockCSRFToken) return new HttpResponse(null, {status: 403})

return new HttpResponse(null, { status: 200 })
})
]
11 changes: 9 additions & 2 deletions src/mocks/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
//src/mocks/browser.js
//src/mocks/handlers.ts

import { http, HttpResponse } from "msw"
import resolveURL from "../api/fetch.ts";

import { auth_handlers } from "./authentication/auth_handlers.ts";

export const handlers = [

const default_handlers = [
http.get(resolveURL('/resource'), () => {
return HttpResponse.json({
result: "Hello World!"
})
})
]


export const handlers = [
...default_handlers,
...auth_handlers
]
Loading

0 comments on commit 3f60a1b

Please sign in to comment.