From 42223915864316c0e8441e747686fbe95804ce74 Mon Sep 17 00:00:00 2001
From: Lu Xinming
Date: Tue, 19 Mar 2024 19:48:50 +0800
Subject: [PATCH 1/3] added prettier
---
.prettierignore | 3 +++
.prettierrc | 1 +
package.json | 1 +
yarn.lock | 5 +++++
4 files changed, 10 insertions(+)
create mode 100644 .prettierignore
create mode 100644 .prettierrc
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..1b07c39
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,3 @@
+# Ignore artifacts:
+build
+coverage
\ No newline at end of file
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1 @@
+{}
diff --git a/package.json b/package.json
index 57b0849..f6061a5 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"jsdom": "^24.0.0",
+ "prettier": "3.2.5",
"tsc-alias": "^1.8.8",
"typescript": "^5.4.2",
"vite": "^5.0.8",
diff --git a/yarn.lock b/yarn.lock
index 93e88e7..6b8f157 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3037,6 +3037,11 @@ prelude-ls@^1.2.1:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
+prettier@3.2.5:
+ version "3.2.5"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368"
+ integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==
+
pretty-format@^27.0.2:
version "27.5.1"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e"
From e34321488eda400249777b906cecfc756b7e4c6e Mon Sep 17 00:00:00 2001
From: Lu Xinming
Date: Tue, 19 Mar 2024 19:48:58 +0800
Subject: [PATCH 2/3] ran prettier
---
.eslintrc.cjs | 24 +--
.github/ISSUE_TEMPLATE/bug_report.md | 24 +--
.github/ISSUE_TEMPLATE/feature_request.md | 7 +-
.github/pull_request_template.md | 7 +-
.github/workflows/autoupdate.yml | 8 +-
.github/workflows/test.yml | 4 +-
README.md | 21 +-
public/mockServiceWorker.js | 186 +++++++++---------
src/api/authentication.ts | 35 ++--
src/api/fetch.ts | 15 +-
.../MobileLoginContainer.module.css | 69 ++++---
.../WebLoginContainer.module.css | 24 +--
src/assets/css/reset.css | 73 +++----
.../authentication/MobileLoginContainer.tsx | 10 +-
.../authentication/WebLoginContainer.tsx | 10 +-
src/components/constants.tsx | 5 +-
src/main.tsx | 31 +--
src/mocks/authentication/auth_handlers.ts | 73 +++----
src/mocks/handlers.ts | 21 +-
src/mocks/server.ts | 5 +-
src/mocks/worker.ts | 10 +-
src/routes/App.tsx | 11 +-
src/routes/router.tsx | 11 +-
src/routes/shared/TestPage.tsx | 16 +-
tests/authentication/auth.test.tsx | 39 ++--
tests/test.test.tsx | 25 +--
vite.config.ts | 16 +-
vitest.setup.ts | 12 +-
28 files changed, 406 insertions(+), 386 deletions(-)
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index f8a9fb4..2158fdf 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -2,31 +2,31 @@ module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
- 'eslint:recommended',
- 'plugin:@typescript-eslint/recommended',
- 'plugin:react/recommended',
- 'plugin:react-hooks/recommended',
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:react/recommended",
+ "plugin:react-hooks/recommended",
],
- ignorePatterns: ['dist', '.eslintrc.cjs'],
- parser: '@typescript-eslint/parser',
+ ignorePatterns: ["dist", ".eslintrc.cjs"],
+ parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 2021,
- sourceType: 'module',
+ sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
- plugins: ['react-refresh', '@typescript-eslint', 'react', 'react-hooks'],
+ plugins: ["react-refresh", "@typescript-eslint", "react", "react-hooks"],
rules: {
"react/react-in-jsx-scope": "off",
- 'react-refresh/only-export-components': [
- 'warn',
+ "react-refresh/only-export-components": [
+ "warn",
{ allowConstantExport: true },
],
},
settings: {
react: {
- version: 'detect',
+ version: "detect",
},
},
-}
+};
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index dd84ea7..9b77ea7 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,10 +1,9 @@
---
name: Bug report
about: Create a report to help us improve
-title: ''
-labels: ''
-assignees: ''
-
+title: ""
+labels: ""
+assignees: ""
---
**Describe the bug**
@@ -12,6 +11,7 @@ A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
+
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
@@ -24,15 +24,17 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- - OS: [e.g. iOS]
- - Browser [e.g. chrome, safari]
- - Version [e.g. 22]
+
+- OS: [e.g. iOS]
+- Browser [e.g. chrome, safari]
+- Version [e.g. 22]
**Smartphone (please complete the following information):**
- - Device: [e.g. iPhone6]
- - OS: [e.g. iOS8.1]
- - Browser [e.g. stock browser, safari]
- - Version [e.g. 22]
+
+- Device: [e.g. iPhone6]
+- OS: [e.g. iOS8.1]
+- Browser [e.g. stock browser, safari]
+- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index bbcbbe7..2bc5d5f 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -1,10 +1,9 @@
---
name: Feature request
about: Suggest an idea for this project
-title: ''
-labels: ''
-assignees: ''
-
+title: ""
+labels: ""
+assignees: ""
---
**Is your feature request related to a problem? Please describe.**
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index abf02fe..6b46775 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,12 +1,15 @@
# Pull Request
## Description
+
[Provide a brief description of the changes in this pull request.]
## Related Issues
+
[Reference any related issues that this pull request addresses or resolves.]
## Checklist
+
Please review and check the following before submitting your pull request:
- [ ] I have read the [CONTRIBUTING.md](../CONTRIBUTING.md) document.
@@ -17,6 +20,7 @@ Please review and check the following before submitting your pull request:
- [ ] I have added comments to my code, particularly in areas that may be confusing.
## Screenshots (if applicable)
+
[Include any relevant screenshots or GIFs to visually demonstrate the changes.]
### Desktop
@@ -24,8 +28,9 @@ Please review and check the following before submitting your pull request:
### Mobile
## Additional Information
+
[Include any additional information that might be helpful for reviewers or maintainers.]
## Reviewer Notes
-[Optional: Include specific instructions or notes for reviewers, if necessary.]
+[Optional: Include specific instructions or notes for reviewers, if necessary.]
diff --git a/.github/workflows/autoupdate.yml b/.github/workflows/autoupdate.yml
index 0e3a813..56a858e 100644
--- a/.github/workflows/autoupdate.yml
+++ b/.github/workflows/autoupdate.yml
@@ -2,9 +2,9 @@ name: autoupdate
on:
# This will trigger on all pushes to all branches.
push:
- # Alternatively, you can only trigger if commits are pushed to certain branches, e.g.:
- branches:
- - main
+ # Alternatively, you can only trigger if commits are pushed to certain branches, e.g.:
+ branches:
+ - main
jobs:
autoupdate:
@@ -13,6 +13,6 @@ jobs:
steps:
- uses: docker://chinthakagodawita/autoupdate-action:v1
env:
- GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
+ GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
PR_FILTER: "labelled"
PR_LABELS: "epic"
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index adf4948..57b0dc5 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -22,10 +22,10 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: 20
- cache: 'yarn'
+ cache: "yarn"
- name: Install dependencies
run: yarn
- name: Run Vitest
- run: yarn vitest
\ No newline at end of file
+ run: yarn vitest
diff --git a/README.md b/README.md
index b5dcdae..ac71066 100644
--- a/README.md
+++ b/README.md
@@ -5,10 +5,11 @@ This template provides a minimal setup to get React working in Vite with HMR and
## Setup Guide
This project was set up with NodeJS v20.11.0 LTS with yarn.
+
1. Install packages
- ```shell
- yarn
- ```
+ ```shell
+ yarn
+ ```
2. Create a file `.env.development.local` in root folder with the following information
```text
VITE_IGNORE_MSW=false
@@ -16,9 +17,9 @@ This project was set up with NodeJS v20.11.0 LTS with yarn.
If you would like to ignore mock service worker, set it to `true`.
3. Create another file `.env.test.local` in root folder with same content as above
4. Run the development server
- ```shell
- yarn dev
- ```
+ ```shell
+ yarn dev
+ ```
## Dependencies
@@ -47,12 +48,12 @@ If you are developing a production application, we recommend updating the config
export default {
// other rules...
parserOptions: {
- ecmaVersion: 'latest',
- sourceType: 'module',
- project: ['./tsconfig.json', './tsconfig.node.json'],
+ ecmaVersion: "latest",
+ sourceType: "module",
+ project: ["./tsconfig.json", "./tsconfig.node.json"],
tsconfigRootDir: __dirname,
},
-}
+};
```
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
diff --git a/public/mockServiceWorker.js b/public/mockServiceWorker.js
index a2745d1..1af3a7c 100644
--- a/public/mockServiceWorker.js
+++ b/public/mockServiceWorker.js
@@ -8,124 +8,124 @@
* - Please do NOT serve this file on production.
*/
-const INTEGRITY_CHECKSUM = '223d191a56023cd36aa88c802961b911'
-const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
-const activeClientIds = new Set()
+const INTEGRITY_CHECKSUM = "223d191a56023cd36aa88c802961b911";
+const IS_MOCKED_RESPONSE = Symbol("isMockedResponse");
+const activeClientIds = new Set();
-self.addEventListener('install', function () {
- self.skipWaiting()
-})
+self.addEventListener("install", function () {
+ self.skipWaiting();
+});
-self.addEventListener('activate', function (event) {
- event.waitUntil(self.clients.claim())
-})
+self.addEventListener("activate", function (event) {
+ event.waitUntil(self.clients.claim());
+});
-self.addEventListener('message', async function (event) {
- const clientId = event.source.id
+self.addEventListener("message", async function (event) {
+ const clientId = event.source.id;
if (!clientId || !self.clients) {
- return
+ return;
}
- const client = await self.clients.get(clientId)
+ const client = await self.clients.get(clientId);
if (!client) {
- return
+ return;
}
const allClients = await self.clients.matchAll({
- type: 'window',
- })
+ type: "window",
+ });
switch (event.data) {
- case 'KEEPALIVE_REQUEST': {
+ case "KEEPALIVE_REQUEST": {
sendToClient(client, {
- type: 'KEEPALIVE_RESPONSE',
- })
- break
+ type: "KEEPALIVE_RESPONSE",
+ });
+ break;
}
- case 'INTEGRITY_CHECK_REQUEST': {
+ case "INTEGRITY_CHECK_REQUEST": {
sendToClient(client, {
- type: 'INTEGRITY_CHECK_RESPONSE',
+ type: "INTEGRITY_CHECK_RESPONSE",
payload: INTEGRITY_CHECKSUM,
- })
- break
+ });
+ break;
}
- case 'MOCK_ACTIVATE': {
- activeClientIds.add(clientId)
+ case "MOCK_ACTIVATE": {
+ activeClientIds.add(clientId);
sendToClient(client, {
- type: 'MOCKING_ENABLED',
+ type: "MOCKING_ENABLED",
payload: true,
- })
- break
+ });
+ break;
}
- case 'MOCK_DEACTIVATE': {
- activeClientIds.delete(clientId)
- break
+ case "MOCK_DEACTIVATE": {
+ activeClientIds.delete(clientId);
+ break;
}
- case 'CLIENT_CLOSED': {
- activeClientIds.delete(clientId)
+ case "CLIENT_CLOSED": {
+ activeClientIds.delete(clientId);
const remainingClients = allClients.filter((client) => {
- return client.id !== clientId
- })
+ return client.id !== clientId;
+ });
// Unregister itself when there are no more clients
if (remainingClients.length === 0) {
- self.registration.unregister()
+ self.registration.unregister();
}
- break
+ break;
}
}
-})
+});
-self.addEventListener('fetch', function (event) {
- const { request } = event
+self.addEventListener("fetch", function (event) {
+ const { request } = event;
// Bypass navigation requests.
- if (request.mode === 'navigate') {
- return
+ if (request.mode === "navigate") {
+ return;
}
// Opening the DevTools triggers the "only-if-cached" request
// that cannot be handled by the worker. Bypass such requests.
- if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
- return
+ if (request.cache === "only-if-cached" && request.mode !== "same-origin") {
+ return;
}
// Bypass all requests when there are no active clients.
// Prevents the self-unregistered worked from handling requests
// after it's been deleted (still remains active until the next reload).
if (activeClientIds.size === 0) {
- return
+ return;
}
// Generate unique request ID.
- const requestId = crypto.randomUUID()
- event.respondWith(handleRequest(event, requestId))
-})
+ const requestId = crypto.randomUUID();
+ event.respondWith(handleRequest(event, requestId));
+});
async function handleRequest(event, requestId) {
- const client = await resolveMainClient(event)
- const response = await getResponse(event, client, requestId)
+ const client = await resolveMainClient(event);
+ const response = await getResponse(event, client, requestId);
// Send back the response clone for the "response:*" life-cycle events.
// Ensure MSW is active and ready to handle the message, otherwise
// this message will pend indefinitely.
if (client && activeClientIds.has(client.id)) {
- ;(async function () {
- const responseClone = response.clone()
+ (async function () {
+ const responseClone = response.clone();
sendToClient(
client,
{
- type: 'RESPONSE',
+ type: "RESPONSE",
payload: {
requestId,
isMockedResponse: IS_MOCKED_RESPONSE in response,
@@ -137,11 +137,11 @@ async function handleRequest(event, requestId) {
},
},
[responseClone.body],
- )
- })()
+ );
+ })();
}
- return response
+ return response;
}
// Resolve the main client for the given event.
@@ -149,49 +149,49 @@ async function handleRequest(event, requestId) {
// that registered the worker. It's with the latter the worker should
// communicate with during the response resolving phase.
async function resolveMainClient(event) {
- const client = await self.clients.get(event.clientId)
+ const client = await self.clients.get(event.clientId);
- if (client?.frameType === 'top-level') {
- return client
+ if (client?.frameType === "top-level") {
+ return client;
}
const allClients = await self.clients.matchAll({
- type: 'window',
- })
+ type: "window",
+ });
return allClients
.filter((client) => {
// Get only those clients that are currently visible.
- return client.visibilityState === 'visible'
+ return client.visibilityState === "visible";
})
.find((client) => {
// Find the client ID that's recorded in the
// set of clients that have registered the worker.
- return activeClientIds.has(client.id)
- })
+ return activeClientIds.has(client.id);
+ });
}
async function getResponse(event, client, requestId) {
- const { request } = event
+ const { request } = event;
// Clone the request because it might've been already used
// (i.e. its body has been read and sent to the client).
- const requestClone = request.clone()
+ const requestClone = request.clone();
function passthrough() {
- const headers = Object.fromEntries(requestClone.headers.entries())
+ const headers = Object.fromEntries(requestClone.headers.entries());
// Remove internal MSW request header so the passthrough request
// complies with any potential CORS preflight checks on the server.
// Some servers forbid unknown request headers.
- delete headers['x-msw-intention']
+ delete headers["x-msw-intention"];
- return fetch(requestClone, { headers })
+ return fetch(requestClone, { headers });
}
// Bypass mocking when the client is not active.
if (!client) {
- return passthrough()
+ return passthrough();
}
// Bypass initial page load requests (i.e. static assets).
@@ -199,22 +199,22 @@ async function getResponse(event, client, requestId) {
// means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
// and is not ready to handle requests.
if (!activeClientIds.has(client.id)) {
- return passthrough()
+ return passthrough();
}
// Bypass requests with the explicit bypass header.
// Such requests can be issued by "ctx.fetch()".
- const mswIntention = request.headers.get('x-msw-intention')
- if (['bypass', 'passthrough'].includes(mswIntention)) {
- return passthrough()
+ const mswIntention = request.headers.get("x-msw-intention");
+ if (["bypass", "passthrough"].includes(mswIntention)) {
+ return passthrough();
}
// Notify the client that a request has been intercepted.
- const requestBuffer = await request.arrayBuffer()
+ const requestBuffer = await request.arrayBuffer();
const clientMessage = await sendToClient(
client,
{
- type: 'REQUEST',
+ type: "REQUEST",
payload: {
id: requestId,
url: request.url,
@@ -233,38 +233,38 @@ async function getResponse(event, client, requestId) {
},
},
[requestBuffer],
- )
+ );
switch (clientMessage.type) {
- case 'MOCK_RESPONSE': {
- return respondWithMock(clientMessage.data)
+ case "MOCK_RESPONSE": {
+ return respondWithMock(clientMessage.data);
}
- case 'MOCK_NOT_FOUND': {
- return passthrough()
+ case "MOCK_NOT_FOUND": {
+ return passthrough();
}
}
- return passthrough()
+ return passthrough();
}
function sendToClient(client, message, transferrables = []) {
return new Promise((resolve, reject) => {
- const channel = new MessageChannel()
+ const channel = new MessageChannel();
channel.port1.onmessage = (event) => {
if (event.data && event.data.error) {
- return reject(event.data.error)
+ return reject(event.data.error);
}
- resolve(event.data)
- }
+ resolve(event.data);
+ };
client.postMessage(
message,
[channel.port2].concat(transferrables.filter(Boolean)),
- )
- })
+ );
+ });
}
async function respondWithMock(response) {
@@ -273,15 +273,15 @@ async function respondWithMock(response) {
// instance will have status code set to 0. Since it's not possible to create
// a Response instance with status code 0, handle that use-case separately.
if (response.status === 0) {
- return Response.error()
+ return Response.error();
}
- const mockedResponse = new Response(response.body, response)
+ const mockedResponse = new Response(response.body, response);
Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, {
value: true,
enumerable: true,
- })
+ });
- return mockedResponse
+ return mockedResponse;
}
diff --git a/src/api/authentication.ts b/src/api/authentication.ts
index 587c747..17160a4 100644
--- a/src/api/authentication.ts
+++ b/src/api/authentication.ts
@@ -1,37 +1,38 @@
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');
+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")
+ if (csrfmiddlewaretoken === undefined)
+ throw new Error("No CSRF Token Present");
return await fetch(LOGIN_URL, {
- method: 'POST',
+ method: "POST",
headers: {
- 'Content-Type': 'application/json'
+ "Content-Type": "application/json",
},
- credentials: 'include',
- body: JSON.stringify({username, password, csrfmiddlewaretoken}),
+ credentials: "include",
+ body: JSON.stringify({ username, password, csrfmiddlewaretoken }),
});
};
-
export const signOut = async (): Promise => {
const csrfmiddlewaretoken = Cookies.get("csrftoken");
- if (csrfmiddlewaretoken === undefined) throw new Error("No CSRF Token Present")
+ if (csrfmiddlewaretoken === undefined)
+ throw new Error("No CSRF Token Present");
const response = await fetch(LOGOUT_URL, {
- method: 'POST',
+ method: "POST",
headers: {
- 'Content-Type': 'application/json'
+ "Content-Type": "application/json",
},
- credentials: 'include',
- body: JSON.stringify({ csrfmiddlewaretoken })
+ credentials: "include",
+ body: JSON.stringify({ csrfmiddlewaretoken }),
});
- Cookies.remove("csrftoken")
+ Cookies.remove("csrftoken");
return response;
};
@@ -41,7 +42,7 @@ export const getCSRF = async (): Promise => {
method: "POST",
credentials: "include",
headers: {
- "Content-Type": "application/json"
+ "Content-Type": "application/json",
},
});
-};
\ No newline at end of file
+};
diff --git a/src/api/fetch.ts b/src/api/fetch.ts
index 250dd63..191ee9f 100644
--- a/src/api/fetch.ts
+++ b/src/api/fetch.ts
@@ -1,13 +1,14 @@
-
const setApiURL = () => {
if (import.meta.env.DEV) {
- return import.meta.env.VITE_IGNORE_MSW.toLowerCase() === "true" ? "http://localhost:8000" : "http://localhost:5173"
+ return import.meta.env.VITE_IGNORE_MSW.toLowerCase() === "true"
+ ? "http://localhost:8000"
+ : "http://localhost:5173";
}
- return import.meta.env.VITE_API_URL
-}
+ return import.meta.env.VITE_API_URL;
+};
-export const apiURL = setApiURL()
+export const apiURL = setApiURL();
export default function resolveURL(path: string): string {
- return `${apiURL}${path}`
-}
\ No newline at end of file
+ return `${apiURL}${path}`;
+}
diff --git a/src/assets/css/authentication/MobileLoginContainer.module.css b/src/assets/css/authentication/MobileLoginContainer.module.css
index 5c8c3c9..e1358f9 100644
--- a/src/assets/css/authentication/MobileLoginContainer.module.css
+++ b/src/assets/css/authentication/MobileLoginContainer.module.css
@@ -1,50 +1,47 @@
/* 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;
- }
-
-
+ 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 */
- }
+ /* 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 */
- }
+ /* 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 */
- }
+ /* 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 */
+ }
}
-
\ No newline at end of file
diff --git a/src/assets/css/authentication/WebLoginContainer.module.css b/src/assets/css/authentication/WebLoginContainer.module.css
index 46104b8..b0d0059 100644
--- a/src/assets/css/authentication/WebLoginContainer.module.css
+++ b/src/assets/css/authentication/WebLoginContainer.module.css
@@ -4,19 +4,19 @@
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%);
+ background: linear-gradient(180deg, #0c1747 0%, rgba(37, 60, 92, 0.62) 100%);
border: 1px black solid;
- }
-
- /* For desktops */
+}
+
+/* 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 */
- }
\ No newline at end of file
+.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 */
+}
diff --git a/src/assets/css/reset.css b/src/assets/css/reset.css
index e304ecb..1843f13 100644
--- a/src/assets/css/reset.css
+++ b/src/assets/css/reset.css
@@ -8,102 +8,109 @@
- The "symbol *" part is to solve Firefox SVG sprite bug
- The "html" element is excluded, otherwise a bug in Chrome breaks the CSS hyphens property (https://github.com/elad2412/the-new-css-reset/issues/36)
*/
-*:where(:not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)) {
- all: unset;
- display: revert;
+*:where(
+ :not(html, iframe, canvas, img, svg, video, audio):not(svg *, symbol *)
+ ) {
+ all: unset;
+ display: revert;
}
/* Preferred box-sizing value */
*,
*::before,
*::after {
- box-sizing: border-box;
+ box-sizing: border-box;
}
/* Fix mobile Safari increase font-size on landscape mode */
html {
- -moz-text-size-adjust: none;
- -webkit-text-size-adjust: none;
- text-size-adjust: none;
+ -moz-text-size-adjust: none;
+ -webkit-text-size-adjust: none;
+ text-size-adjust: none;
}
/* Reapply the pointer cursor for anchor tags */
-a, button {
- cursor: revert;
+a,
+button {
+ cursor: revert;
}
/* Remove list styles (bullets/numbers) */
-ol, ul, menu, summary {
- list-style: none;
+ol,
+ul,
+menu,
+summary {
+ list-style: none;
}
/* For images to not be able to exceed their container */
img {
- max-inline-size: 100%;
- max-block-size: 100%;
+ max-inline-size: 100%;
+ max-block-size: 100%;
}
/* removes spacing between cells in tables */
table {
- border-collapse: collapse;
+ border-collapse: collapse;
}
/* Safari - solving issue when using user-select:none on the text input doesn't working */
-input, textarea {
- -webkit-user-select: auto;
+input,
+textarea {
+ -webkit-user-select: auto;
}
/* revert the 'white-space' property for textarea elements on Safari */
textarea {
- white-space: revert;
+ white-space: revert;
}
/* minimum style to allow to style meter element */
meter {
- -webkit-appearance: revert;
- appearance: revert;
+ -webkit-appearance: revert;
+ appearance: revert;
}
/* preformatted text - use only for this feature */
:where(pre) {
- all: revert;
- box-sizing: border-box;
+ all: revert;
+ box-sizing: border-box;
}
/* reset default text opacity of input placeholder */
::placeholder {
- color: unset;
+ color: unset;
}
/* fix the feature of 'hidden' attribute.
display:revert; revert to element instead of attribute */
:where([hidden]) {
- display: none;
+ display: none;
}
/* revert for bug in Chromium browsers
- fix for the content editable attribute will work properly.
- webkit-user-select: auto; added for Safari in case of using user-select:none on wrapper element*/
:where([contenteditable]:not([contenteditable="false"])) {
- -moz-user-modify: read-write;
- -webkit-user-modify: read-write;
- overflow-wrap: break-word;
- -webkit-line-break: after-white-space;
- -webkit-user-select: auto;
+ -moz-user-modify: read-write;
+ -webkit-user-modify: read-write;
+ overflow-wrap: break-word;
+ -webkit-line-break: after-white-space;
+ -webkit-user-select: auto;
}
/* apply back the draggable feature - exist only in Chromium and Safari */
:where([draggable="true"]) {
- -webkit-user-drag: element;
+ -webkit-user-drag: element;
}
/* Revert Modal native behavior */
:where(dialog:modal) {
- all: revert;
- box-sizing: border-box;
+ all: revert;
+ box-sizing: border-box;
}
/* Remove details summary webkit styles */
::-webkit-details-marker {
- display: none;
-}
\ No newline at end of file
+ display: none;
+}
diff --git a/src/components/authentication/MobileLoginContainer.tsx b/src/components/authentication/MobileLoginContainer.tsx
index 46b43d9..2021696 100644
--- a/src/components/authentication/MobileLoginContainer.tsx
+++ b/src/components/authentication/MobileLoginContainer.tsx
@@ -1,13 +1,11 @@
-import styles from '../../assets/css/authentication/MobileLoginContainer.module.css'; // Import mobile-specific CSS
+import styles from "../../assets/css/authentication/MobileLoginContainer.module.css"; // Import mobile-specific CSS
const MobileLoginContainer = () => {
return (
-
- {/* Your login form goes here */}
-
+
{/* Your login form goes here */}
);
-}
+};
-export default MobileLoginContainer;
\ No newline at end of file
+export default MobileLoginContainer;
diff --git a/src/components/authentication/WebLoginContainer.tsx b/src/components/authentication/WebLoginContainer.tsx
index 8bbc0a9..d4974e1 100644
--- a/src/components/authentication/WebLoginContainer.tsx
+++ b/src/components/authentication/WebLoginContainer.tsx
@@ -1,13 +1,11 @@
-import styles from '../../assets/css/authentication/WebLoginContainer.module.css'; // Import web-specific CSS
+import styles from "../../assets/css/authentication/WebLoginContainer.module.css"; // Import web-specific CSS
const WebLoginContainer = () => {
return (
-
- {/* Your login form goes here */}
-
+
{/* Your login form goes here */}
);
-}
+};
-export default WebLoginContainer;
\ No newline at end of file
+export default WebLoginContainer;
diff --git a/src/components/constants.tsx b/src/components/constants.tsx
index 83fc9ed..0ba2208 100644
--- a/src/components/constants.tsx
+++ b/src/components/constants.tsx
@@ -1,8 +1,9 @@
+// Breakpoints based on Bootstrap 5
export const BREAKPOINTS = {
XS: 0,
SM: 576,
MD: 768,
LG: 992,
XL: 1200,
- XXL: 1400
-}
+ XXL: 1400,
+};
diff --git a/src/main.tsx b/src/main.tsx
index a6fc1c1..aa82700 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,31 +1,34 @@
-import React from 'react'
-import ReactDOM from 'react-dom/client'
-import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
+import React from "react";
+import ReactDOM from "react-dom/client";
+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 'css/reset.css'
+import "css/reset.css";
-const queryClient = new QueryClient()
+const queryClient = new QueryClient();
async function enableMocking() {
- if (!import.meta.env.DEV || import.meta.env.VITE_IGNORE_MSW.toLowerCase() === "true") {
- return
+ if (
+ !import.meta.env.DEV ||
+ import.meta.env.VITE_IGNORE_MSW.toLowerCase() === "true"
+ ) {
+ return;
}
- const { worker } = await import('./mocks/worker')
+ const { worker } = await import("@/mocks/worker");
- return worker.start({ onUnhandledRequest: "bypass" })
+ return worker.start({ onUnhandledRequest: "bypass" });
}
enableMocking().then(() => {
- ReactDOM.createRoot(document.getElementById('root')!).render(
+ ReactDOM.createRoot(document.getElementById("root")!).render(
-
-
+
+
,
- )
-})
+ );
+});
diff --git a/src/mocks/authentication/auth_handlers.ts b/src/mocks/authentication/auth_handlers.ts
index 1aaf295..7b25d6e 100644
--- a/src/mocks/authentication/auth_handlers.ts
+++ b/src/mocks/authentication/auth_handlers.ts
@@ -1,46 +1,53 @@
//src/mocks/authentication/auth_handlers.ts
-import { http, HttpResponse } from "msw"
+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"
-
+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
-}
-
+ 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`
- }
- })
+ "Set-Cookie": `csrftoken=${mockCSRFToken}; expires=Tue, 31 Dec 2024 23:59:59 GMT; Max-Age=31449600; Path=/; SameSite=Lax`,
+ },
+ });
}),
- http.post
>
- )
+ );
}
-export default TestPage
\ No newline at end of file
+export default TestPage;
diff --git a/tests/authentication/auth.test.tsx b/tests/authentication/auth.test.tsx
index 387656e..2f879c8 100644
--- a/tests/authentication/auth.test.tsx
+++ b/tests/authentication/auth.test.tsx
@@ -1,27 +1,30 @@
-import { describe, expect, test } from "vitest"
+import { describe, expect, test } from "vitest";
import Cookies from "js-cookie";
-import {getCSRF, signIn, signOut} from "@/api/authentication.ts";
-import { mockCSRFToken, mockUsername, mockPassword } from "@/mocks/authentication/auth_handlers";
+import { getCSRF, signIn, signOut } from "@/api/authentication.ts";
+import {
+ mockCSRFToken,
+ mockUsername,
+ mockPassword,
+} from "@/mocks/authentication/auth_handlers";
describe("authentication helper functions", () => {
-
test("should get csrf token", async () => {
- const response = await getCSRF()
- expect(response.status).toBe(200)
- expect(response.headers.has('Set-Cookie'))
- expect(response.headers.get('Set-Cookie')).contains(mockCSRFToken)
- expect(Cookies.get("csrftoken")).toBe(mockCSRFToken)
- })
+ const response = await getCSRF();
+ expect(response.status).toBe(200);
+ expect(response.headers.has("Set-Cookie"));
+ expect(response.headers.get("Set-Cookie")).contains(mockCSRFToken);
+ expect(Cookies.get("csrftoken")).toBe(mockCSRFToken);
+ });
test("should be able to signIn", async () => {
- const response = await signIn(mockUsername, mockPassword)
- expect(response.status).toBe(200)
- })
+ const response = await signIn(mockUsername, mockPassword);
+ expect(response.status).toBe(200);
+ });
test("should be able to signOut and csrftoken cookie cleared", async () => {
- const response = await signOut()
- expect(response.status).toBe(200)
- expect(Cookies.get("csrftoken")).toBeUndefined()
- })
-})
\ No newline at end of file
+ const response = await signOut();
+ expect(response.status).toBe(200);
+ expect(Cookies.get("csrftoken")).toBeUndefined();
+ });
+});
diff --git a/tests/test.test.tsx b/tests/test.test.tsx
index cc901f0..d8dea35 100644
--- a/tests/test.test.tsx
+++ b/tests/test.test.tsx
@@ -1,17 +1,20 @@
-import {beforeEach, describe, expect, test } from "vitest"
-import {render, screen} from "@testing-library/react"
-import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
-import TestPage from "routes/shared/TestPage.tsx"
+import { beforeEach, describe, expect, test } from "vitest";
+import { render, screen } from "@testing-library/react";
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+import TestPage from "routes/shared/TestPage.tsx";
-const queryClient = new QueryClient()
+const queryClient = new QueryClient();
describe("Test Page", () => {
-
beforeEach(() => {
- render()
- })
+ render(
+
+
+ ,
+ );
+ });
test("Should show Hello World!", async () => {
- expect(await screen.findByText(/Hello World!/)).toBeDefined()
- })
-})
\ No newline at end of file
+ expect(await screen.findByText(/Hello World!/)).toBeDefined();
+ });
+});
diff --git a/vite.config.ts b/vite.config.ts
index 5f093a1..4d360df 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,8 +1,8 @@
///
///
-import { defineConfig } from 'vite'
-import react from '@vitejs/plugin-react'
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
@@ -10,16 +10,16 @@ export default defineConfig({
test: {
globals: true,
environment: "jsdom",
- setupFiles: ["./vitest.setup.ts"]
+ setupFiles: ["./vitest.setup.ts"],
},
resolve: {
alias: [
+ // path aliases to simplify imports
{ find: "@", replacement: "/src" },
{ find: "assets", replacement: "/src/assets" },
{ find: "css", replacement: "/src/assets/css" },
- { find: "img", replacement: "/src/assets/img" },
{ find: "components", replacement: "/src/components" },
- { find: "routes", replacement: "/src/routes" }
- ]
- }
-})
+ { find: "routes", replacement: "/src/routes" },
+ ],
+ },
+});
diff --git a/vitest.setup.ts b/vitest.setup.ts
index 68e58dc..a25a1a7 100644
--- a/vitest.setup.ts
+++ b/vitest.setup.ts
@@ -1,7 +1,7 @@
-import { afterAll, afterEach, beforeAll } from 'vitest'
-import { server } from "./src/mocks/server"
-import "@testing-library/jest-dom"
+import { afterAll, afterEach, beforeAll } from "vitest";
+import { server } from "./src/mocks/server";
+import "@testing-library/jest-dom";
-beforeAll(() => server.listen({ onUnhandledRequest: 'error' })) // test would throw error if calls to undefined endpoints are made
-afterAll(() => server.close())
-afterEach(() => server.resetHandlers())
+beforeAll(() => server.listen({ onUnhandledRequest: "error" })); // test would throw error if calls to undefined endpoints are made
+afterAll(() => server.close());
+afterEach(() => server.resetHandlers());
From 725d90b995e95b9b8f7ad8eab3659eaf0a2f6968 Mon Sep 17 00:00:00 2001
From: markgcera <>
Date: Tue, 19 Mar 2024 21:33:26 +0800
Subject: [PATCH 3/3] add trial code for layout container
---
src/assets/css/layout.tsx | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 src/assets/css/layout.tsx
diff --git a/src/assets/css/layout.tsx b/src/assets/css/layout.tsx
new file mode 100644
index 0000000..9aea721
--- /dev/null
+++ b/src/assets/css/layout.tsx
@@ -0,0 +1,38 @@
+// import React from 'react';
+// import Navbar from './Navbar'; // Import the Navbar component.
+
+// interface LayoutProps {
+// children: React.ReactNode;
+// }
+
+// const Layout: React.FC = ({ children }) => {
+// return (
+// <>
+// {/* The Navbar will always be rendered at the top */}
+// {children} {/* This is where the page-specific content will go */}
+// >
+// );
+// };
+
+// export default Layout;
+
+
+
+// An example usage of this layout.tsx container is shown below as HomePage.tsx
+
+// HomePage.tsx
+// import React from 'react';
+// import Layout from './Layout'; // Import the Layout component
+
+// const HomePage = () => {
+// return (
+//
+// {/* Everything here will be passed as children to the Layout */}
+// Welcome to the Home Page
+// This is some introductory text on the home page.
+// {/* More content can follow */}
+//
+// );
+// };
+
+// export default HomePage;
\ No newline at end of file