Skip to content

Commit 01ec32b

Browse files
Refactor authentication flow and UI enhancements
- Updated AxiosProvider to include auth token in requests using Cognito. - Enhanced ForgotPassword and ResetPassword forms with improved UI and error handling. - Added new translations for better user experience. - Refactored styles for consistency across authentication pages. - Cleaned up package-lock.json by removing unused dependencies.
1 parent 40de18c commit 01ec32b

File tree

14 files changed

+423
-110
lines changed

14 files changed

+423
-110
lines changed

frontend/src/common/api/reportService.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,15 @@ const determineCategory = (filename: string): ReportCategory => {
165165
* @returns Promise with the latest reports
166166
*/
167167
export const fetchLatestReports = async (limit = 3): Promise<MedicalReport[]> => {
168+
169+
const headers = await getAuthConfig();
170+
console.log('headers', JSON.stringify(headers));
171+
console.log('API_URL', `${API_URL}/api/reports/latest?limit=${limit}`);
172+
168173
try {
169-
const response = await axios.get(`${API_URL}/api/reports/latest?limit=${limit}`, await getAuthConfig());
174+
const response = await axios.get(`${API_URL}/api/reports/latest?limit=${limit}`, headers);
170175
console.log('response', response.data);
176+
console.log('response headers', response.headers);
171177
console.log('API_URL', API_URL);
172178
return response.data;
173179
} catch (error) {

frontend/src/common/providers/AxiosProvider.tsx

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { PropsWithChildren, useEffect, useState } from 'react';
2+
import { InternalAxiosRequestConfig } from 'axios';
23

34
import { AxiosContext, customAxios } from './AxiosContext';
5+
import CognitoAuthService from 'common/services/auth/cognito-auth-service';
46

57
/**
68
* The `AxiosProvider` React component creates, maintains, and provides
@@ -12,12 +14,36 @@ const AxiosProvider = ({ children }: PropsWithChildren): JSX.Element => {
1214
const [isReady, setIsReady] = useState(false);
1315

1416
useEffect(() => {
15-
// use axios interceptors
17+
// Add request interceptor to include auth token
18+
const requestInterceptor = customAxios.interceptors.request.use(
19+
async (config: InternalAxiosRequestConfig) => {
20+
try {
21+
// Get tokens from Cognito
22+
const tokens = await CognitoAuthService.getUserTokens();
23+
24+
// If tokens exist, add Authorization header
25+
if (tokens?.access_token) {
26+
// Make sure headers exists
27+
config.headers = config.headers || {};
28+
config.headers.Authorization = `Bearer ${tokens.access_token}`;
29+
}
30+
31+
return config;
32+
} catch (error) {
33+
console.error('Error adding auth token to request:', error);
34+
return config;
35+
}
36+
},
37+
(error) => {
38+
return Promise.reject(error);
39+
}
40+
);
1641

1742
setIsReady(true);
1843

1944
return () => {
20-
// eject axios interceptors
45+
// Eject axios interceptors when component unmounts
46+
customAxios.interceptors.request.eject(requestInterceptor);
2147
};
2248
}, []);
2349

frontend/src/common/utils/i18n/resources/en/auth.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"remember-me": "Remember me",
2222
"username": "Username",
2323
"email": "Email Address",
24+
"email_address": "Email Address",
2425
"first-name": "First Name",
2526
"last-name": "Last Name",
2627
"confirm-password": "Confirm Password",
@@ -42,18 +43,24 @@
4243
"confirm": "Confirm",
4344
"resend-code": "Resend Code",
4445
"forgot-password": "Forgot Password?",
46+
"back.to.signin": "← Back to Log in",
4547
"password-recovery": {
46-
"title": "Password Recovery",
47-
"message": "Enter your email address and we'll send you instructions to reset your password.",
48+
"title": "Forgot your Password?",
49+
"message": "Enter your account email, and we'll send you reset instructions.",
4850
"success": "Password reset instructions sent to your email.",
4951
"email-sent": "We've sent a verification code to your email.",
5052
"enter-code": "Enter the verification code and your new password below."
5153
},
5254
"password-reset": {
5355
"title": "Reset Password",
56+
"message": "Set a new password for your account.",
5457
"success": "Password reset successful!",
5558
"button": "Reset Password"
5659
},
60+
"account-not-found": {
61+
"title": "Account not found",
62+
"message": "An account with this email address doesn't exist."
63+
},
5764
"password-requirements": "Password Requirements:",
5865
"email-verification": {
5966
"title": "Email Verification",

frontend/src/pages/Auth/ForgotPassword/ForgotPasswordPage.scss

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,69 @@
11
.ls-forgot-password-page {
2-
&__container {
2+
&__content {
3+
--background: var(--ion-color-background);
4+
}
5+
6+
&__background {
7+
width: 100%;
8+
height: 100%;
39
display: flex;
410
flex-direction: column;
5-
height: 100%;
11+
align-items: center;
12+
padding: 2rem 1.5rem;
13+
}
14+
15+
&__logo-container {
16+
display: flex;
17+
align-items: center;
618
justify-content: center;
19+
margin-bottom: 2.5rem;
20+
}
21+
22+
&__logo {
23+
width: 3.5rem;
24+
height: auto;
25+
margin-right: 0.75rem;
26+
}
27+
28+
&__logo-text {
29+
color: white;
30+
font-size: 1.75rem;
31+
font-weight: 600;
32+
}
33+
34+
&__container {
35+
display: flex;
36+
flex-direction: column;
37+
width: 100%;
38+
max-width: 30rem;
39+
}
40+
41+
&__card {
42+
background-color: #ffffff;
43+
border-radius: 1.5rem;
44+
box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.15);
45+
padding: 2.5rem 2rem;
46+
width: 100%;
47+
max-width: 30rem;
48+
margin: 0 auto;
49+
}
50+
51+
&__header {
52+
margin-bottom: 2.5rem;
53+
54+
h1 {
55+
font-size: 2rem;
56+
font-weight: 600;
57+
color: #333;
58+
margin-bottom: 0.5rem;
59+
margin-top: 0;
60+
}
61+
62+
p {
63+
font-size: 1.125rem;
64+
color: #666;
65+
margin: 0;
66+
}
767
}
868

969
&__form {

frontend/src/pages/Auth/ForgotPassword/ForgotPasswordPage.tsx

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { IonContent, IonPage } from '@ionic/react';
1+
import { IonContent, IonPage, IonImg } from '@ionic/react';
22
import { useTranslation } from 'react-i18next';
33

44
import './ForgotPasswordPage.scss';
55
import { PropsWithTestId } from 'common/components/types';
66
import ProgressProvider from 'common/providers/ProgressProvider';
7-
import Header from 'common/components/Header/Header';
87
import ForgotPasswordForm from './components/ForgotPasswordForm';
98
import Container from 'common/components/Content/Container';
9+
import logo from 'assets/logo_ls.png';
1010

1111
/**
1212
* Properties for the `ForgotPasswordPage` component.
@@ -24,12 +24,19 @@ const ForgotPasswordPage = ({ testid = 'page-forgot-password' }: ForgotPasswordP
2424
return (
2525
<IonPage className="ls-forgot-password-page" data-testid={testid}>
2626
<ProgressProvider>
27-
<Header title={t('password-recovery.title', { ns: 'auth' })} />
28-
29-
<IonContent fullscreen className="ion-padding">
30-
<Container className="ls-forgot-password-page__container" fixed>
31-
<ForgotPasswordForm className="ls-forgot-password-page__form" />
32-
</Container>
27+
<IonContent fullscreen className="ls-forgot-password-page__content">
28+
<div className="ls-forgot-password-page__background">
29+
<div className="ls-forgot-password-page__logo-container">
30+
<IonImg src={logo} alt="Logo" className="ls-forgot-password-page__logo" />
31+
<span className="ls-forgot-password-page__logo-text">{t('app.name', { ns: 'common' })}</span>
32+
</div>
33+
34+
<Container className="ls-forgot-password-page__container" fixed>
35+
<div className="ls-forgot-password-page__card">
36+
<ForgotPasswordForm className="ls-forgot-password-page__form" />
37+
</div>
38+
</Container>
39+
</div>
3340
</IonContent>
3441
</ProgressProvider>
3542
</IonPage>
Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,149 @@
11
.ls-forgot-password-form {
22
padding: 1rem;
3+
display: flex;
4+
flex-direction: column;
5+
align-items: center;
6+
width: 100%;
7+
8+
&__icon-container {
9+
display: flex;
10+
justify-content: center;
11+
margin-bottom: 2rem;
12+
}
13+
14+
&__icon-circle {
15+
width: 8.5rem;
16+
height: 8.5rem;
17+
border-radius: 50%;
18+
background-color: rgba(252, 123, 244, 0.05);
19+
display: flex;
20+
justify-content: center;
21+
align-items: center;
22+
position: relative;
23+
24+
&::after {
25+
content: '';
26+
position: absolute;
27+
width: 100%;
28+
height: 100%;
29+
border-radius: 50%;
30+
border: 1px solid rgba(252, 123, 244, 0.2);
31+
box-sizing: border-box;
32+
}
33+
}
34+
35+
&__icon {
36+
width: 3rem;
37+
height: 3rem;
38+
color: #fc4b95;
39+
}
40+
41+
&__title {
42+
font-size: 1.25rem;
43+
font-weight: 700;
44+
color: #31343f;
45+
margin-bottom: 1rem;
46+
text-align: center;
47+
}
48+
49+
&__field {
50+
margin-bottom: 16px;
51+
}
52+
53+
&__label {
54+
display: block;
55+
margin-bottom: 8px;
56+
font-weight: 500;
57+
}
358

459
&__input {
560
margin-bottom: 1rem;
61+
width: 100%;
62+
63+
border: 1px solid #ccc;
64+
border-radius: 0.75rem;
65+
--padding-start: 1rem;
66+
--padding-end: 1rem;
67+
--padding-top: 0.875rem;
68+
--padding-bottom: 0.875rem;
69+
--highlight-color: var(--ion-color-primary);
70+
font-size: 1rem;
71+
height: 3.25rem;
72+
73+
&::part(native) {
74+
padding: 0;
75+
}
676
}
777

878
&__button {
9-
margin-top: 1rem;
79+
margin-top: 2rem;
80+
width: 100%;
81+
height: 3.75rem;
82+
font-size: 1.125rem;
83+
font-weight: 600;
84+
--border-radius: 0.625rem;
85+
--box-shadow: 0 0.5rem 0.75rem rgba(67, 96, 240, 0.08);
86+
--background: var(--ion-color-primary);
87+
--color: #ffffff;
1088
}
1189

1290
&__message {
13-
margin-bottom: 1rem;
91+
margin-bottom: 2.5rem;
92+
text-align: center;
93+
color: #31343f;
94+
max-width: 20rem;
95+
font-size: 0.875rem;
96+
line-height: 1.5;
97+
opacity: 0.8;
1498
}
1599

16100
&__success {
17101
margin-bottom: 1rem;
18102
text-align: center;
19103
}
104+
105+
&__error {
106+
margin-bottom: 1rem;
107+
width: 100%;
108+
}
109+
110+
&__custom-error {
111+
margin-bottom: 1rem;
112+
width: 100%;
113+
border-radius: 0.5rem;
114+
background-color: #f9edf0;
115+
padding: 1rem;
116+
}
117+
118+
&__error-title {
119+
font-weight: 700;
120+
font-size: 0.875rem;
121+
color: #b01b3f;
122+
margin-bottom: 0.25rem;
123+
}
124+
125+
&__error-message {
126+
font-size: 0.875rem;
127+
color: #2d2d2d;
128+
}
129+
130+
&__back-link {
131+
margin-top: 2rem;
132+
text-align: center;
133+
cursor: pointer;
134+
font-size: 0.875rem;
135+
136+
ion-text {
137+
color: #666666;
138+
139+
.login-text {
140+
color: #4360f0;
141+
font-weight: 600;
142+
}
143+
144+
&:hover {
145+
text-decoration: underline;
146+
}
147+
}
148+
}
20149
}

0 commit comments

Comments
 (0)