Skip to content

Commit 672cf5f

Browse files
authored
Merge pull request #31 from nicolelim02/feat/questions
Fix markdown rendered and test cases
2 parents 7ee68ca + 72487f9 commit 672cf5f

File tree

43 files changed

+818
-537
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+818
-537
lines changed

frontend/.prettierignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
build
2+
coverage
3+
4+
*.html

frontend/.prettierrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

frontend/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88

99
3. Run `npm run dev` for development mode, which includes features like automatic server restart when you make code changes.
1010

11-
4. The application is available at http://localhost:5173.
11+
4. The application is available at http://localhost:5173.

frontend/eslint.config.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
1-
import js from '@eslint/js'
2-
import globals from 'globals'
3-
import reactHooks from 'eslint-plugin-react-hooks'
4-
import reactRefresh from 'eslint-plugin-react-refresh'
5-
import tseslint from 'typescript-eslint'
1+
import js from "@eslint/js";
2+
import globals from "globals";
3+
import reactHooks from "eslint-plugin-react-hooks";
4+
import reactRefresh from "eslint-plugin-react-refresh";
5+
import tseslint from "typescript-eslint";
66

77
export default tseslint.config(
8-
{ ignores: ['dist'] },
8+
{ ignores: ["dist", "coverage"] },
99
{
1010
extends: [js.configs.recommended, ...tseslint.configs.recommended],
11-
files: ['**/*.{ts,tsx}'],
11+
files: ["**/*.{ts,tsx}"],
1212
languageOptions: {
1313
ecmaVersion: 2020,
1414
globals: globals.browser,
1515
},
1616
plugins: {
17-
'react-hooks': reactHooks,
18-
'react-refresh': reactRefresh,
17+
"react-hooks": reactHooks,
18+
"react-refresh": reactRefresh,
1919
},
2020
rules: {
2121
...reactHooks.configs.recommended.rules,
22-
'react-refresh/only-export-components': [
23-
'warn',
22+
"react-refresh/only-export-components": [
23+
"warn",
2424
{ allowConstantExport: true },
2525
],
2626
},
27-
},
28-
)
27+
}
28+
);

frontend/jest.config.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,10 @@ const config: Config = {
9191

9292
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
9393
moduleNameMapper: {
94-
'\\.(css)$': '<rootDir>/__mocks__/styleMock.ts',
95-
'\\.(svg)$': '<rootDir>/__mocks__/styleMock.ts',
94+
"\\.(css)$": "<rootDir>/__mocks__/styleMock.ts",
95+
"\\.(svg)$": "<rootDir>/__mocks__/styleMock.ts",
96+
// "@uiw/react-md-editor":
97+
// "<rootDir>/node_modules/@uiw/react-md-editor/esm/index",
9698
},
9799

98100
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader

frontend/package-lock.json

Lines changed: 0 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
"@mui/material": "^6.1.0",
2323
"@uiw/react-md-editor": "^4.0.4",
2424
"axios": "^1.7.7",
25-
"markdown-to-jsx": "^7.5.0",
2625
"react": "^18.3.1",
2726
"react-dom": "^18.3.1",
2827
"react-router-dom": "^6.26.2",

frontend/src/components/ChangePasswordModal/index.tsx

Lines changed: 78 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,43 @@
1-
import { forwardRef, useState } from 'react';
2-
import { Box, Button, Stack, Typography } from '@mui/material';
3-
import PasswordTextField from '../PasswordTextField';
4-
import { userClient } from '../../utils/api';
5-
import axios from 'axios';
6-
import { FAILED_PW_UPDATE_MESSAGE, SUCCESS_PW_UPDATE_MESSAGE } from '../../utils/constants';
1+
import { forwardRef, useState } from "react";
2+
import { Box, Button, Stack, Typography } from "@mui/material";
3+
import PasswordTextField from "../PasswordTextField";
4+
import { userClient } from "../../utils/api";
5+
import axios from "axios";
6+
import {
7+
FAILED_PW_UPDATE_MESSAGE,
8+
SUCCESS_PW_UPDATE_MESSAGE,
9+
} from "../../utils/constants";
710

811
interface ChangePasswordModalProps {
912
handleClose: () => void;
1013
userId: string;
11-
onUpdate: (isProfileEdit: boolean, message: string, isSuccess: boolean) => void;
14+
onUpdate: (
15+
isProfileEdit: boolean,
16+
message: string,
17+
isSuccess: boolean,
18+
) => void;
1219
}
1320

14-
const ChangePasswordModal = forwardRef<HTMLDivElement, ChangePasswordModalProps>((props, ref) => {
21+
const ChangePasswordModal = forwardRef<
22+
HTMLDivElement,
23+
ChangePasswordModalProps
24+
>((props, ref) => {
1525
const { handleClose, userId, onUpdate } = props;
16-
const [currPassword, setCurrPassword] = useState<string>('');
17-
const [newPassword, setNewPassword] = useState<string>('');
18-
const [confirmPassword, setConfirmPassword] = useState<string>('');
26+
const [currPassword, setCurrPassword] = useState<string>("");
27+
const [newPassword, setNewPassword] = useState<string>("");
28+
const [confirmPassword, setConfirmPassword] = useState<string>("");
1929

20-
const [isCurrPasswordValid, setIsCurrPasswordValid] = useState<boolean>(false);
30+
const [isCurrPasswordValid, setIsCurrPasswordValid] =
31+
useState<boolean>(false);
2132
const [isNewPasswordValid, setIsNewPasswordValid] = useState<boolean>(false);
22-
const [isConfirmPasswordValid, setIsConfirmPasswordValid] = useState<boolean>(false);
23-
24-
const isUpdateDisabled = !(isCurrPasswordValid && isNewPasswordValid && isConfirmPasswordValid);
33+
const [isConfirmPasswordValid, setIsConfirmPasswordValid] =
34+
useState<boolean>(false);
35+
36+
const isUpdateDisabled = !(
37+
isCurrPasswordValid &&
38+
isNewPasswordValid &&
39+
isConfirmPasswordValid
40+
);
2541

2642
const handleSubmit = async () => {
2743
const accessToken = localStorage.getItem("token");
@@ -32,13 +48,14 @@ const ChangePasswordModal = forwardRef<HTMLDivElement, ChangePasswordModalProps>
3248
{
3349
oldPassword: currPassword,
3450
newPassword: newPassword,
35-
},
51+
},
3652
{
3753
headers: {
3854
Authorization: `Bearer ${accessToken}`,
3955
"Content-Type": "application/json",
4056
},
41-
});
57+
},
58+
);
4259
handleClose();
4360
onUpdate(false, SUCCESS_PW_UPDATE_MESSAGE, true);
4461
} catch (error) {
@@ -53,47 +70,64 @@ const ChangePasswordModal = forwardRef<HTMLDivElement, ChangePasswordModalProps>
5370
};
5471

5572
return (
56-
<Box
73+
<Box
5774
ref={ref}
5875
sx={(theme) => ({
5976
backgroundColor: theme.palette.common.white,
6077
display: "flex",
6178
width: 600,
6279
flexDirection: "column",
6380
alignItems: "center",
64-
borderRadius: '16px',
81+
borderRadius: "16px",
6582
padding: "40px",
6683
})}
6784
>
6885
<Typography component="h1" variant="h3">
6986
Change Password
7087
</Typography>
71-
<PasswordTextField
72-
label="Current password"
73-
passwordVal={false}
74-
password={currPassword}
75-
setPassword={setCurrPassword}
76-
isMatch={false}
77-
setValidity={setIsCurrPasswordValid} />
78-
<PasswordTextField
79-
label="New password"
80-
passwordVal={true}
81-
password={newPassword}
82-
setPassword={setNewPassword}
83-
isMatch={true}
88+
<PasswordTextField
89+
label="Current password"
90+
passwordVal={false}
91+
password={currPassword}
92+
setPassword={setCurrPassword}
93+
isMatch={false}
94+
setValidity={setIsCurrPasswordValid}
95+
/>
96+
<PasswordTextField
97+
label="New password"
98+
passwordVal={true}
99+
password={newPassword}
100+
setPassword={setNewPassword}
101+
isMatch={true}
84102
passwordToMatch={confirmPassword}
85-
setValidity={setIsNewPasswordValid} />
86-
<PasswordTextField
87-
label="Confirm new password"
88-
passwordVal={false}
89-
password={confirmPassword}
90-
setPassword={setConfirmPassword}
91-
isMatch={true}
92-
passwordToMatch={newPassword}
93-
setValidity={setIsConfirmPasswordValid} />
94-
<Stack direction="row" spacing={2} sx={{marginTop: 2, width: '100%'}}>
95-
<Button variant="contained" color="secondary" onClick={handleClose} sx={{ flexGrow: 1 }}>Cancel</Button>
96-
<Button variant="contained" disabled={isUpdateDisabled} onClick={handleSubmit} sx={{ flexGrow: 1 }}>Update</Button>
103+
setValidity={setIsNewPasswordValid}
104+
/>
105+
<PasswordTextField
106+
label="Confirm new password"
107+
passwordVal={false}
108+
password={confirmPassword}
109+
setPassword={setConfirmPassword}
110+
isMatch={true}
111+
passwordToMatch={newPassword}
112+
setValidity={setIsConfirmPasswordValid}
113+
/>
114+
<Stack direction="row" spacing={2} sx={{ marginTop: 2, width: "100%" }}>
115+
<Button
116+
variant="contained"
117+
color="secondary"
118+
onClick={handleClose}
119+
sx={{ flexGrow: 1 }}
120+
>
121+
Cancel
122+
</Button>
123+
<Button
124+
variant="contained"
125+
disabled={isUpdateDisabled}
126+
onClick={handleSubmit}
127+
sx={{ flexGrow: 1 }}
128+
>
129+
Update
130+
</Button>
97131
</Stack>
98132
</Box>
99133
);

frontend/src/components/CustomTextField/index.tsx

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import { Visibility, VisibilityOff } from "@mui/icons-material";
2-
import { IconButton, InputAdornment, TextField, TextFieldPropsSizeOverrides, TextFieldVariants, Tooltip } from "@mui/material";
3-
import { OverridableStringUnion } from '@mui/types';
2+
import {
3+
IconButton,
4+
InputAdornment,
5+
TextField,
6+
TextFieldPropsSizeOverrides,
7+
TextFieldVariants,
8+
Tooltip,
9+
} from "@mui/material";
10+
import { OverridableStringUnion } from "@mui/types";
411
import { useState } from "react";
512

613
const passwordRequirements = (
@@ -16,8 +23,11 @@ const passwordRequirements = (
1623
// Adapted from https://muhimasri.com/blogs/mui-validation/
1724
type CustomTextFieldProps = {
1825
label: string;
19-
variant?: TextFieldVariants;
20-
size?: OverridableStringUnion<"small" | "medium", TextFieldPropsSizeOverrides>;
26+
variant?: TextFieldVariants;
27+
size?: OverridableStringUnion<
28+
"small" | "medium",
29+
TextFieldPropsSizeOverrides
30+
>;
2131
required?: boolean;
2232
emptyField?: boolean;
2333
validator?: (value: string) => string;
@@ -40,7 +50,7 @@ const CustomTextField: React.FC<CustomTextFieldProps> = ({
4050

4151
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
4252
const input = event.target.value;
43-
53+
4454
let errorMessage = "";
4555
if (validator) {
4656
errorMessage = validator(input);
@@ -51,7 +61,11 @@ const CustomTextField: React.FC<CustomTextFieldProps> = ({
5161
};
5262

5363
return (
54-
<Tooltip title={isPasswordField && passwordRequirements} placement="right" arrow>
64+
<Tooltip
65+
title={isPasswordField && passwordRequirements}
66+
placement="right"
67+
arrow
68+
>
5569
<TextField
5670
label={label}
5771
variant={variant}
@@ -66,12 +80,15 @@ const CustomTextField: React.FC<CustomTextFieldProps> = ({
6680
input: {
6781
endAdornment: isPasswordField && (
6882
<InputAdornment position="end">
69-
<IconButton onClick={() => setShowPassword(!showPassword)} edge="end">
83+
<IconButton
84+
onClick={() => setShowPassword(!showPassword)}
85+
edge="end"
86+
>
7087
{showPassword ? <VisibilityOff /> : <Visibility />}
7188
</IconButton>
7289
</InputAdornment>
7390
),
74-
}
91+
},
7592
}}
7693
/>
7794
</Tooltip>

0 commit comments

Comments
 (0)