Skip to content

Commit e433641

Browse files
committed
Merge remote-tracking branch 'origin/main' into PEER-223-Matching-Cancellation-Endpoint
Merge
2 parents 02e3fbd + b3c2ee8 commit e433641

File tree

11 files changed

+78
-27
lines changed

11 files changed

+78
-27
lines changed

backend/matching/src/services/get-match-items.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { logger } from '@/lib/utils';
12
import type { IMatchItemsResponse, IMatchType } from '@/types';
23

34
import { createRoom } from './collab';
@@ -16,12 +17,18 @@ export async function getMatchItems(
1617
throw new Error('Both user IDs are required');
1718
}
1819

19-
const [attemptedQuestions1, attemptedQuestions2] = await Promise.all([
20-
fetchAttemptedQuestions(userId1),
21-
fetchAttemptedQuestions(userId2),
22-
]);
20+
let allAttemptedQuestions: number[] = [];
21+
22+
try {
23+
const [attemptedQuestions1, attemptedQuestions2] = await Promise.all([
24+
fetchAttemptedQuestions(userId1),
25+
fetchAttemptedQuestions(userId2),
26+
]);
27+
allAttemptedQuestions = [...new Set([...attemptedQuestions1, ...attemptedQuestions2])];
28+
} catch (error) {
29+
logger.error('Error in getMatchItems: Failed to fetch attempted questions', error);
30+
}
2331

24-
const allAttemptedQuestions = [...new Set([...attemptedQuestions1, ...attemptedQuestions2])];
2532
const topics = topic?.split('|') ?? [];
2633
const payload = {
2734
attemptedQuestions: allAttemptedQuestions,
@@ -35,16 +42,21 @@ export async function getMatchItems(
3542
// Get a random question
3643
const question = await getRandomQuestion(payload);
3744

45+
if (!question) {
46+
logger.info('No matching question found');
47+
return undefined;
48+
}
49+
3850
const roomId = await createRoom(userId1, userId2, question.id.toString());
3951

40-
console.log('Successfully got match items');
52+
logger.info('Successfully got match items');
4153
return {
4254
roomId,
4355
questionId: question.id,
4456
// question,
4557
};
4658
} catch (error) {
47-
console.error('Error in getMatchItems:', error);
59+
logger.error('Error in getMatchItems:', error);
4860
return undefined;
4961
}
5062
}

backend/question/src/services/post/index.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,17 @@ export const createQuestionService = async (payload: ICreateQuestionPayload) =>
2626

2727
export const updateQuestionService = async (payload: IUpdateQuestionPayload) => {
2828
try {
29+
const updateSet: Partial<typeof questions.$inferInsert> = {};
30+
31+
if (payload.title !== undefined) updateSet.title = payload.title;
32+
if (payload.description !== undefined) updateSet.description = payload.description;
33+
if (payload.difficulty !== undefined) updateSet.difficulty = payload.difficulty;
34+
if (payload.topics !== undefined && Array.isArray(payload.topics))
35+
updateSet.topic = payload.topics.map(String);
36+
2937
const [updatedQuestion] = await db
3038
.update(questions)
31-
.set({
32-
title: payload.title,
33-
description: payload.description,
34-
difficulty: payload.difficulty,
35-
topic: payload.topics.map(String),
36-
})
39+
.set(updateSet)
3740
.where(eq(questions.id, Number(payload.id)))
3841
.returning();
3942

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"eslint": "^9.9.0",
6161
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
6262
"eslint-plugin-react-refresh": "^0.4.9",
63+
"eslint-plugin-simple-import-sort": "^12.1.1",
6364
"globals": "^15.9.0",
6465
"postcss": "^8.4.47",
6566
"tailwindcss": "^3.4.11",

frontend/src/routes/login/logic.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { zodResolver } from '@hookform/resolvers/zod';
22
import { useMutation } from '@tanstack/react-query';
3+
import { AxiosError } from 'axios';
4+
import { useState } from 'react';
35
import { useForm } from 'react-hook-form';
46
import { useNavigate } from 'react-router-dom';
57
import { z } from 'zod';
@@ -15,6 +17,8 @@ export const loginFormSchema = z.object({
1517
type ILoginFormSchema = z.infer<typeof loginFormSchema>;
1618

1719
export const useLoginForm = () => {
20+
const [errorMessage, setErrorMessage] = useState<string | null>(null);
21+
1822
const navigate = useNavigate();
1923
const form = useForm<ILoginFormSchema>({
2024
resolver: zodResolver(loginFormSchema),
@@ -35,9 +39,19 @@ export const useLoginForm = () => {
3539
// TODO: Revalidate with is-authed User Svc EP and put as user
3640
// details provider on each route request
3741
localStorage.setItem('cachedUserID', userID);
42+
navigate(0);
43+
} else {
44+
setErrorMessage('An error occured. Please try again later.');
45+
}
46+
},
47+
onError: (error: AxiosError) => {
48+
if (error.response?.status === 401 || error.response?.status === 404) {
49+
setErrorMessage('Invalid Username or Password.');
50+
} else if (error.response?.status === 409) {
51+
setErrorMessage('Too many failed attempts. Please try again later.');
52+
} else {
53+
setErrorMessage('An error occurred. Please try again later.');
3854
}
39-
40-
navigate(0);
4155
},
4256
});
4357

@@ -52,5 +66,5 @@ export const useLoginForm = () => {
5266
sendLoginRequest(payload);
5367
};
5468

55-
return { form, onSubmit: form.handleSubmit(onSubmit), isPending };
69+
return { form, onSubmit: form.handleSubmit(onSubmit), isPending, errorMessage };
5670
};

frontend/src/routes/login/login-form.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { ROUTES } from '@/lib/routes';
1515
import { useLoginForm } from './logic';
1616

1717
export const LoginForm = () => {
18-
const { form, onSubmit, isPending } = useLoginForm();
18+
const { form, onSubmit, isPending, errorMessage } = useLoginForm();
1919

2020
return (
2121
<Card className='bg-primary-foreground border-border mx-auto flex size-full max-w-sm flex-col justify-center md:ml-auto md:mr-8 md:max-h-[600px]'>
@@ -61,6 +61,7 @@ export const LoginForm = () => {
6161
</FormItem>
6262
)}
6363
/>
64+
{errorMessage && <p className='mt text-center text-sm text-red-500'>{errorMessage}</p>}
6465
<Button className='w-full' type='submit'>
6566
Login
6667
</Button>

frontend/src/routes/match/logic.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ export const loader =
2929
};
3030

3131
const formSchema = z.object({
32-
selectedTopics: z.string().min(1, 'Topic cannot be empty').array(),
33-
difficulty: z.string().min(1, 'Difficulty cannot be empty'),
32+
selectedTopics: z.array(z.string()).min(1, 'Please select at least one topic'),
33+
difficulty: z.string().min(1, 'Please select a difficulty'),
3434
});
3535

3636
export type IRequestMatchFormSchema = z.infer<typeof formSchema>;
@@ -61,8 +61,6 @@ export const useRequestMatchForm = () => {
6161
setSocketPort(data.socketPort);
6262
return;
6363
}
64-
65-
console.error(`[MatchService::match::request]: Unexpected response: ${JSON.stringify(data)}`);
6664
},
6765
});
6866

frontend/src/routes/match/waiting-room/waiting.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ export const WaitingRoom = ({ socketPort, setIsModalOpen }: IWaitingRoomProps) =
174174
<div className='flex flex-col items-center justify-center'>
175175
{uiState.icon}
176176
{uiState.description.startsWith('RoomId') ? (
177-
<p className='flex flex-col gap-1'>
177+
<div className='flex flex-col gap-1'>
178178
<div className='flex flex-col gap-0'>
179179
<label className='text-lg'>Room Id:</label>
180180
<span className='text-md max-w-[400px] truncate text-balance font-mono'>
@@ -187,7 +187,7 @@ export const WaitingRoom = ({ socketPort, setIsModalOpen }: IWaitingRoomProps) =
187187
{uiState.description.split('\nQuestionId: ')[1]}
188188
</span>
189189
</div>
190-
</p>
190+
</div>
191191
) : (
192192
<p className='mt-4 whitespace-pre-wrap text-lg'>{uiState.description}</p>
193193
)}

frontend/src/routes/signup/logic.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { zodResolver } from '@hookform/resolvers/zod';
22
import { useMutation } from '@tanstack/react-query';
3+
import { AxiosError } from 'axios';
4+
import { useState } from 'react';
35
import { useForm } from 'react-hook-form';
46
import { useNavigate } from 'react-router-dom';
57
import { z } from 'zod';
@@ -49,6 +51,7 @@ type ISignupFormSchema = z.infer<typeof signUpSchema>;
4951

5052
export const useSignupForm = () => {
5153
const navigate = useNavigate();
54+
const [errorMessage, setErrorMessage] = useState<string | null>(null);
5255

5356
const form = useForm<ISignupFormSchema>({
5457
resolver: zodResolver(signUpSchema),
@@ -71,9 +74,25 @@ export const useSignupForm = () => {
7174
mutationFn: signUp,
7275
onSuccess: (_response, _params, _context) => {
7376
form.reset();
77+
setErrorMessage(null);
78+
const userID = _response?.data?.id;
79+
80+
if (userID) {
81+
// TODO: Revalidate with is-authed User Svc EP and put as user
82+
// details provider on each route request
83+
localStorage.setItem('cachedUserID', userID);
84+
}
85+
7486
// TODO: Add email validation page OR sign user in
7587
navigate('/');
7688
},
89+
onError: (error: AxiosError) => {
90+
if (error.response?.status === 409) {
91+
setErrorMessage('User with this username or email already exists.');
92+
} else {
93+
setErrorMessage('An error occurred. Please try again later.');
94+
}
95+
},
7796
});
7897

7998
const onSubmit = (formData: ISignupFormSchema) => {
@@ -90,5 +109,5 @@ export const useSignupForm = () => {
90109
sendSignUpRequest(payload);
91110
};
92111

93-
return { form, onSubmit: form.handleSubmit(onSubmit), status, isPending };
112+
return { form, onSubmit: form.handleSubmit(onSubmit), status, isPending, errorMessage };
94113
};

frontend/src/routes/signup/signup-form.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { ROUTES } from '@/lib/routes';
1414
import { useSignupForm } from './logic';
1515

1616
export const SignUpForm = () => {
17-
const { form, onSubmit, isPending: isDisabled } = useSignupForm();
17+
const { form, onSubmit, isPending: isDisabled, errorMessage } = useSignupForm();
1818
return (
1919
<Card className='bg-primary-foreground border-border flex max-w-sm flex-col justify-center border'>
2020
<CardHeader className='flex items-center'>
@@ -118,6 +118,9 @@ export const SignUpForm = () => {
118118
</FormItem>
119119
)}
120120
/>
121+
{errorMessage && (
122+
<p className='mt-2 text-center text-sm text-red-500'>{errorMessage}</p>
123+
)}
121124
<Button type='submit' disabled={isDisabled} className='mt-4 w-full'>
122125
Sign Up
123126
</Button>

frontend/src/services/match-service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const requestMatch = (
2828
})
2929
.catch((error) => {
3030
console.error('Request failed:', error);
31-
return null;
31+
throw error;
3232
});
3333
};
3434

0 commit comments

Comments
 (0)