From 0021e81f16e634b2f6e4cfa5bd07ef5bbed9d55b Mon Sep 17 00:00:00 2001 From: Hadley99 Date: Sat, 7 Feb 2026 12:49:57 +0530 Subject: [PATCH 1/6] refactor: centralize feature API calls - Move cohorts, dashboard, search and trainee-profile HTTP calls into feature api/api.ts modules - Update React Query hooks to consume typed API helpers - Extract shared search response and trainee save request types Refs: #287 --- client/src/features/cohorts/api/api.ts | 7 +++ .../features/cohorts/data/useCohortsData.tsx | 8 +--- client/src/features/dashboard/api/api.ts | 7 +++ .../dashboard/data/useDashboardData.tsx | 10 ++-- client/src/features/search/Search.ts | 6 +++ client/src/features/search/api/api.ts | 7 +++ client/src/features/search/data/queries.ts | 19 +------- .../education/strikes/api/api.ts | 33 +++++++++++++ .../education/strikes/data/strike-queries.ts | 23 +++------ .../education/tests/api/api.ts | 33 +++++++++++++ .../education/tests/data/test-queries.ts | 21 ++------- .../trainee-profile/interactions/api/api.ts | 47 +++++++++++++++++++ .../interactions/data/interaction-queries.ts | 34 +++----------- .../trainee-profile/personal-info/api/api.ts | 13 +++++ .../personal-info/api/types.ts | 13 +++++ .../personal-info/data/useTraineeInfoData.tsx | 33 +++---------- 16 files changed, 198 insertions(+), 116 deletions(-) create mode 100644 client/src/features/cohorts/api/api.ts create mode 100644 client/src/features/dashboard/api/api.ts create mode 100644 client/src/features/search/api/api.ts create mode 100644 client/src/features/trainee-profile/education/strikes/api/api.ts create mode 100644 client/src/features/trainee-profile/education/tests/api/api.ts create mode 100644 client/src/features/trainee-profile/interactions/api/api.ts create mode 100644 client/src/features/trainee-profile/personal-info/api/api.ts create mode 100644 client/src/features/trainee-profile/personal-info/api/types.ts diff --git a/client/src/features/cohorts/api/api.ts b/client/src/features/cohorts/api/api.ts new file mode 100644 index 00000000..d051204f --- /dev/null +++ b/client/src/features/cohorts/api/api.ts @@ -0,0 +1,7 @@ +import axios from 'axios'; +import { Cohort } from '../Cohorts'; + +export const getCohorts = async () => { + const { data } = await axios.get('/api/cohorts'); + return data; +}; diff --git a/client/src/features/cohorts/data/useCohortsData.tsx b/client/src/features/cohorts/data/useCohortsData.tsx index a5231559..0c321ad7 100644 --- a/client/src/features/cohorts/data/useCohortsData.tsx +++ b/client/src/features/cohorts/data/useCohortsData.tsx @@ -1,6 +1,5 @@ -import { Cohort } from '../Cohorts'; -import axios from 'axios'; import { useQuery } from '@tanstack/react-query'; +import { getCohorts } from '../api/api'; /** * A React Query hook that fetches cohort data form api for specific dates. @@ -8,10 +7,7 @@ import { useQuery } from '@tanstack/react-query'; export const useCohortsData = () => { return useQuery({ queryKey: ['CohortsInfo'], - queryFn: async () => { - const { data } = await axios.get(`/api/cohorts`); - return data; - }, + queryFn: getCohorts, refetchOnWindowFocus: false, // Prevent refetching on window focus }); }; diff --git a/client/src/features/dashboard/api/api.ts b/client/src/features/dashboard/api/api.ts new file mode 100644 index 00000000..32481d53 --- /dev/null +++ b/client/src/features/dashboard/api/api.ts @@ -0,0 +1,7 @@ +import axios from 'axios'; +import { DashboardData } from '../Dashboard'; + +export const getDashboardData = async (startDate?: string, endDate?: string): Promise => { + const response = await axios.get(`/api/dashboard?startDate=${startDate}&endDate=${endDate}`); + return response.data; +}; diff --git a/client/src/features/dashboard/data/useDashboardData.tsx b/client/src/features/dashboard/data/useDashboardData.tsx index 3c433fb0..f393cfe3 100644 --- a/client/src/features/dashboard/data/useDashboardData.tsx +++ b/client/src/features/dashboard/data/useDashboardData.tsx @@ -1,9 +1,8 @@ -import { DashboardData } from '../Dashboard'; -import axios from 'axios'; import { useQuery } from '@tanstack/react-query'; +import { getDashboardData } from '../api/api'; /** - * A React Query hook that fetches dashboard data form api for specific dates. + * A React Query hook that fetches dashboard data from api for specific dates. * * @param {string | undefined} startDate * @param {string | undefined} endDate @@ -11,10 +10,7 @@ import { useQuery } from '@tanstack/react-query'; export const useDashboardData = (startDate: string | undefined, endDate: string | undefined) => { return useQuery({ queryKey: ['DashboardInfo'], - queryFn: async () => { - const response = await axios.get(`/api/dashboard?startDate=${startDate}&endDate=${endDate}`); - return response.data; - }, + queryFn: () => getDashboardData(startDate, endDate), refetchOnWindowFocus: false, // Prevent refetching on window focus }); }; diff --git a/client/src/features/search/Search.ts b/client/src/features/search/Search.ts index 994bbc4d..19044fc9 100644 --- a/client/src/features/search/Search.ts +++ b/client/src/features/search/Search.ts @@ -5,3 +5,9 @@ export interface SearchResult { profilePath: string; cohort: number | null; } + +export interface SearchResultResponse { + hits: { + data: SearchResult[]; + }; +} diff --git a/client/src/features/search/api/api.ts b/client/src/features/search/api/api.ts new file mode 100644 index 00000000..a5c143c8 --- /dev/null +++ b/client/src/features/search/api/api.ts @@ -0,0 +1,7 @@ +import axios from 'axios'; +import { SearchResult, SearchResultResponse } from '../Search'; + +export const getSearchResults = async (query: string): Promise => { + const response = await axios.get(`/api/search?q=${query}&limit=20`); + return response.data.hits.data; +}; diff --git a/client/src/features/search/data/queries.ts b/client/src/features/search/data/queries.ts index ba138c51..e609351f 100644 --- a/client/src/features/search/data/queries.ts +++ b/client/src/features/search/data/queries.ts @@ -1,6 +1,5 @@ -import { SearchResult } from '../Search'; -import axios from 'axios'; import { useQuery } from '@tanstack/react-query'; +import { getSearchResults } from '../api/api'; export const searchKeys = { all: ['search'] as const, // for broad invalidation @@ -11,23 +10,9 @@ export const searchKeys = { export const useSearch = (query: string) => { return useQuery({ queryKey: searchKeys.byQuery(query), - queryFn: async () => { - const response = await axios.get(`/api/search?q=${query}&limit=20`); - const trainees: SearchResult[] = response.data.hits.data.map((trainee: SearchResult) => trainee); - return trainees; - }, + queryFn: () => getSearchResults(query), enabled: query.length > 1, // Query runs only if search string has more than 1 character refetchOnMount: false, refetchOnWindowFocus: false, }); }; - -interface SearchResultResponse { - hits: { - data: SearchResult[]; - }; -} -export const getSearchResults = async (query: string): Promise => { - const response = await axios.get(`/api/search?q=${query}&limit=20`); - return response.data.hits.data; -}; diff --git a/client/src/features/trainee-profile/education/strikes/api/api.ts b/client/src/features/trainee-profile/education/strikes/api/api.ts new file mode 100644 index 00000000..c1b92beb --- /dev/null +++ b/client/src/features/trainee-profile/education/strikes/api/api.ts @@ -0,0 +1,33 @@ +import axios from 'axios'; +import { Strike } from '../../../../../data/types/Trainee'; + +export const getStrikes = async (traineeId: string) => { + const { data } = await axios.get(`/api/trainees/${traineeId}/strikes`); + return data; +}; + +export const addStrike = async (traineeId: string, strike: Strike) => { + try { + await axios.post(`/api/trainees/${traineeId}/strikes`, strike); + } catch (error) { + if (axios.isAxiosError(error)) { + throw new Error(error.response?.data?.error || 'Failed to add strike'); + } + throw error; + } +}; + +export const deleteStrike = async (traineeId: string, strikeId: string) => { + await axios.delete(`/api/trainees/${traineeId}/strikes/${strikeId}`); +}; + +export const editStrike = async (traineeId: string, strike: Strike) => { + try { + await axios.put(`/api/trainees/${traineeId}/strikes/${strike.id}`, strike); + } catch (error) { + if (axios.isAxiosError(error)) { + throw new Error(error.response?.data?.error || 'Failed to edit strike'); + } + throw error; + } +}; diff --git a/client/src/features/trainee-profile/education/strikes/data/strike-queries.ts b/client/src/features/trainee-profile/education/strikes/data/strike-queries.ts index fb0c0ccd..d5b2937f 100644 --- a/client/src/features/trainee-profile/education/strikes/data/strike-queries.ts +++ b/client/src/features/trainee-profile/education/strikes/data/strike-queries.ts @@ -1,7 +1,6 @@ import { useMutation, useQuery } from '@tanstack/react-query'; - import { Strike } from '../../../../../data/types/Trainee'; -import axios from 'axios'; +import { getStrikes, addStrike, deleteStrike, editStrike } from '../api/api'; /** * Hook to add a strike to a trainee. @@ -10,11 +9,7 @@ import axios from 'axios'; */ export const useAddStrike = (traineeId: string) => { return useMutation({ - mutationFn: async (strike: Strike) => { - return axios.post(`/api/trainees/${traineeId}/strikes`, strike).catch((error) => { - throw new Error(error.response?.data?.error || 'Failed to add strike'); - }); - }, + mutationFn: (strike: Strike) => addStrike(traineeId, strike), }); }; @@ -27,8 +22,8 @@ export const useGetStrikes = (traineeId: string) => { return useQuery({ queryKey: ['strikes', traineeId], queryFn: async () => { - const { data } = await axios.get(`/api/trainees/${traineeId}/strikes`); - return orderStrikesByDateDesc(data as Strike[]); + const data = await getStrikes(traineeId); + return orderStrikesByDateDesc(data); }, enabled: !!traineeId, refetchOnWindowFocus: false, @@ -43,9 +38,7 @@ export const useGetStrikes = (traineeId: string) => { export const useDeleteStrike = (traineeId: string) => { return useMutation({ - mutationFn: async (strikeId: string) => { - return axios.delete(`/api/trainees/${traineeId}/strikes/${strikeId}`); - }, + mutationFn: (strikeId: string) => deleteStrike(traineeId, strikeId), }); }; @@ -55,11 +48,7 @@ export const useDeleteStrike = (traineeId: string) => { */ export const useEditStrike = (traineeId: string) => { return useMutation({ - mutationFn: async (strike: Strike) => { - return axios.put(`/api/trainees/${traineeId}/strikes/${strike.id}`, strike).catch((error) => { - throw new Error(error.response?.data?.error || 'Failed to edit strike'); - }); - }, + mutationFn: (strike: Strike) => editStrike(traineeId, strike), }); }; diff --git a/client/src/features/trainee-profile/education/tests/api/api.ts b/client/src/features/trainee-profile/education/tests/api/api.ts new file mode 100644 index 00000000..64815cd8 --- /dev/null +++ b/client/src/features/trainee-profile/education/tests/api/api.ts @@ -0,0 +1,33 @@ +import axios from 'axios'; +import { Test } from '../../../../../data/types/Trainee'; + +export const getTests = async (traineeId: string) => { + const { data } = await axios.get(`/api/trainees/${traineeId}/tests`); + return data; +}; + +export const addTest = async (traineeId: string, test: Test) => { + try { + await axios.post(`/api/trainees/${traineeId}/tests`, test); + } catch (error) { + if (axios.isAxiosError(error)) { + throw new Error(error.response?.data?.error || 'Failed to add test'); + } + throw error; + } +}; + +export const deleteTest = async (traineeId: string, testId: string) => { + await axios.delete(`/api/trainees/${traineeId}/tests/${testId}`); +}; + +export const editTest = async (traineeId: string, test: Test) => { + try { + await axios.put(`/api/trainees/${traineeId}/tests/${test.id}`, test); + } catch (error) { + if (axios.isAxiosError(error)) { + throw new Error(error.response?.data?.error || 'Failed to edit test'); + } + throw error; + } +}; diff --git a/client/src/features/trainee-profile/education/tests/data/test-queries.ts b/client/src/features/trainee-profile/education/tests/data/test-queries.ts index 604d2914..d7ae5708 100644 --- a/client/src/features/trainee-profile/education/tests/data/test-queries.ts +++ b/client/src/features/trainee-profile/education/tests/data/test-queries.ts @@ -1,7 +1,6 @@ import { useMutation, useQuery } from '@tanstack/react-query'; - import { Test } from '../../../../../data/types/Trainee'; -import axios from 'axios'; +import { getTests, addTest, deleteTest, editTest } from '../api/api'; /** * Hook to add a test to a trainee. @@ -10,11 +9,7 @@ import axios from 'axios'; */ export const useAddTest = (traineeId: string) => { return useMutation({ - mutationFn: async (test: Test) => { - return axios.post(`/api/trainees/${traineeId}/tests`, test).catch((error) => { - throw new Error(error.response?.data?.error || 'Failed to add test'); - }); - }, + mutationFn: (test: Test) => addTest(traineeId, test), }); }; @@ -27,7 +22,7 @@ export const useGetTests = (traineeId: string) => { return useQuery({ queryKey: ['tests', traineeId], queryFn: async () => { - const { data } = await axios.get(`/api/trainees/${traineeId}/tests`); + const data = await getTests(traineeId); return orderTestsByDateDesc(data); }, @@ -44,9 +39,7 @@ export const useGetTests = (traineeId: string) => { export const useDeleteTest = (traineeId: string) => { return useMutation({ - mutationFn: (testId: string) => { - return axios.delete(`/api/trainees/${traineeId}/tests/${testId}`); - }, + mutationFn: (testId: string) => deleteTest(traineeId, testId), }); }; @@ -56,11 +49,7 @@ export const useDeleteTest = (traineeId: string) => { */ export const useEditTest = (traineeId: string) => { return useMutation({ - mutationFn: async (test: Test) => { - return axios.put(`/api/trainees/${traineeId}/tests/${test.id}`, test).catch((error) => { - throw new Error(error.response?.data?.error || 'Failed to edit test'); - }); - }, + mutationFn: (test: Test) => editTest(traineeId, test), }); }; diff --git a/client/src/features/trainee-profile/interactions/api/api.ts b/client/src/features/trainee-profile/interactions/api/api.ts new file mode 100644 index 00000000..f39731fa --- /dev/null +++ b/client/src/features/trainee-profile/interactions/api/api.ts @@ -0,0 +1,47 @@ +import axios from 'axios'; +import { Interaction } from '../Interactions'; + +export const getInteractions = async (traineeId: string) => { + try { + const { data } = await axios.get(`/api/trainees/${traineeId}/interactions`); + return data as Interaction[]; + } catch (error) { + if (axios.isAxiosError(error)) { + throw new Error(error.response?.data?.error || 'Failed to get interactions'); + } + throw new Error('Failed to get interactions'); + } +}; + +export const addInteraction = async (traineeId: string, interaction: Partial) => { + try { + await axios.post(`/api/trainees/${traineeId}/interactions`, interaction); + } catch (error) { + if (axios.isAxiosError(error)) { + throw new Error(error.response?.data?.error || 'Failed to add interaction'); + } + throw error; + } +}; + +export const deleteInteraction = async (traineeId: string, interactionId: string) => { + try { + await axios.delete(`/api/trainees/${traineeId}/interactions/${interactionId}`); + } catch (error) { + if (axios.isAxiosError(error)) { + throw new Error(error.response?.data?.error || 'Failed to delete interaction'); + } + throw error; + } +}; + +export const editInteraction = async (traineeId: string, interaction: Interaction) => { + try { + await axios.put(`/api/trainees/${traineeId}/interactions/${interaction.id}`, interaction); + } catch (error) { + if (axios.isAxiosError(error)) { + throw new Error(error.response?.data?.error || 'Failed to edit interaction'); + } + throw error; + } +}; diff --git a/client/src/features/trainee-profile/interactions/data/interaction-queries.ts b/client/src/features/trainee-profile/interactions/data/interaction-queries.ts index 47f73cb7..a2d0269f 100644 --- a/client/src/features/trainee-profile/interactions/data/interaction-queries.ts +++ b/client/src/features/trainee-profile/interactions/data/interaction-queries.ts @@ -1,7 +1,6 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; - import { Interaction } from '../Interactions'; -import axios from 'axios'; +import { getInteractions, addInteraction, deleteInteraction, editInteraction } from '../api/api'; /** * gets all interactions for a trainee @@ -12,15 +11,8 @@ export const useGetInteractions = (traineeId: string) => { return useQuery({ queryKey: ['interactions', traineeId], queryFn: async () => { - try { - const { data } = await axios.get(`/api/trainees/${traineeId}/interactions`); - return orderInteractionsByDateDesc(data as Interaction[]); - } catch (error) { - if (axios.isAxiosError(error)) { - throw new Error(error.response?.data?.error || 'Failed to get interactions'); - } - throw new Error('Failed to get interactions'); - } + const data = await getInteractions(traineeId); + return orderInteractionsByDateDesc(data); }, enabled: !!traineeId, refetchOnWindowFocus: false, @@ -39,13 +31,9 @@ const orderInteractionsByDateDesc = (data: Interaction[]): Interaction[] => { export const useAddInteraction = (traineeId: string) => { const queryClient = useQueryClient(); - // partial becase not all fields are sent to the backend + // partial because not all fields are sent to the backend return useMutation({ - mutationFn: async (interaction: Partial) => { - return await axios.post(`/api/trainees/${traineeId}/interactions`, interaction).catch((error) => { - throw new Error(error.response?.data?.error || 'Failed to add interaction'); - }); - }, + mutationFn: (interaction: Partial) => addInteraction(traineeId, interaction), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['interactions', traineeId] }); }, @@ -61,11 +49,7 @@ export const useDeleteInteraction = (traineeId: string) => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async (interactionId: string) => { - return await axios.delete(`/api/trainees/${traineeId}/interactions/${interactionId}`).catch((error) => { - throw new Error(error.response?.data?.error || 'Failed to delete interaction'); - }); - }, + mutationFn: (interactionId: string) => deleteInteraction(traineeId, interactionId), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['interactions', traineeId] }); }, @@ -80,11 +64,7 @@ export const useDeleteInteraction = (traineeId: string) => { export const useEditInteraction = (traineeId: string) => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async (interaction: Interaction) => { - return axios.put(`/api/trainees/${traineeId}/interactions/${interaction.id}`, interaction).catch((error) => { - throw new Error(error.response?.data?.error || 'Failed to edit interaction'); - }); - }, + mutationFn: (interaction: Interaction) => editInteraction(traineeId, interaction), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['interactions', traineeId] }); }, diff --git a/client/src/features/trainee-profile/personal-info/api/api.ts b/client/src/features/trainee-profile/personal-info/api/api.ts new file mode 100644 index 00000000..bed4e33a --- /dev/null +++ b/client/src/features/trainee-profile/personal-info/api/api.ts @@ -0,0 +1,13 @@ +import axios from 'axios'; +import { Trainee } from '../../../../data/types/Trainee'; +import { SaveTraineeRequestData } from './types'; + +export const getTraineeInfo = async (traineeId: string): Promise => { + const { data } = await axios.get(`/api/trainees/${traineeId}`); + return data; +}; + +export const saveTraineeInfo = async (traineeId: string, dataToSave: SaveTraineeRequestData): Promise => { + const response = await axios.patch(`/api/trainees/${traineeId}`, dataToSave); + return response.data; +}; diff --git a/client/src/features/trainee-profile/personal-info/api/types.ts b/client/src/features/trainee-profile/personal-info/api/types.ts new file mode 100644 index 00000000..d568677a --- /dev/null +++ b/client/src/features/trainee-profile/personal-info/api/types.ts @@ -0,0 +1,13 @@ +import { + TraineeContactInfo, + TraineeEducationInfo, + TraineeEmploymentInfo, + TraineePersonalInfo, +} from '../../../../data/types/Trainee'; + +export interface SaveTraineeRequestData { + personalInfo?: Partial; + contactInfo?: Partial; + educationInfo?: Partial; + employmentInfo?: Partial; +} diff --git a/client/src/features/trainee-profile/personal-info/data/useTraineeInfoData.tsx b/client/src/features/trainee-profile/personal-info/data/useTraineeInfoData.tsx index b3944fec..dfcba073 100644 --- a/client/src/features/trainee-profile/personal-info/data/useTraineeInfoData.tsx +++ b/client/src/features/trainee-profile/personal-info/data/useTraineeInfoData.tsx @@ -1,13 +1,7 @@ -import { - Trainee, - TraineeContactInfo, - TraineeEducationInfo, - TraineeEmploymentInfo, - TraineePersonalInfo, -} from '../../../../data/types/Trainee'; +import { Trainee } from '../../../../data/types/Trainee'; import { useMutation, useQuery } from '@tanstack/react-query'; - -import axios from 'axios'; +import { getTraineeInfo, saveTraineeInfo } from '../api/api'; +import { SaveTraineeRequestData } from '../api/types'; /** * A React Query hook that fetches trainee information data form api. @@ -17,11 +11,7 @@ import axios from 'axios'; export const useTraineeInfoData = (traineeId: string) => { return useQuery({ queryKey: ['traineeInfo', traineeId], - queryFn: async () => { - const { data } = await axios.get(`/api/trainees/${traineeId}`); - - return data; - }, + queryFn: () => getTraineeInfo(traineeId), enabled: !!traineeId, //Added because it keeps rendering refetchOnMount: false, // Prevent refetching on component mount @@ -29,14 +19,6 @@ export const useTraineeInfoData = (traineeId: string) => { }); }; -//fixme: move to types -export interface SaveTraineeRequestData { - personalInfo?: Partial; - contactInfo?: Partial; - educationInfo?: Partial; - employmentInfo?: Partial; -} - //fixme: move to data/trainee/mutations.ts /** * A React Query hook that saves trainee information data to api. @@ -45,9 +27,8 @@ export interface SaveTraineeRequestData { */ export const useSaveTraineeInfo = (traineeId: string) => { return useMutation({ - mutationFn: async (dataToSave: SaveTraineeRequestData) => { - const response = await axios.patch(`/api/trainees/${traineeId}`, dataToSave); - return response.data; - }, + mutationFn: (dataToSave: SaveTraineeRequestData) => saveTraineeInfo(traineeId, dataToSave), }); }; + +export type { SaveTraineeRequestData }; From 00ece083a2bdd486bf4b0f7574dab2e832743d16 Mon Sep 17 00:00:00 2001 From: Hadley99 Date: Sat, 7 Feb 2026 19:19:34 +0530 Subject: [PATCH 2/6] Improved error handling --- .../trainee-profile/education/strikes/api/api.ts | 6 ++++-- .../features/trainee-profile/education/tests/api/api.ts | 6 ++++-- .../src/features/trainee-profile/interactions/api/api.ts | 9 ++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/client/src/features/trainee-profile/education/strikes/api/api.ts b/client/src/features/trainee-profile/education/strikes/api/api.ts index c1b92beb..0f737daa 100644 --- a/client/src/features/trainee-profile/education/strikes/api/api.ts +++ b/client/src/features/trainee-profile/education/strikes/api/api.ts @@ -13,7 +13,8 @@ export const addStrike = async (traineeId: string, strike: Strike) => { if (axios.isAxiosError(error)) { throw new Error(error.response?.data?.error || 'Failed to add strike'); } - throw error; + + throw new Error(error instanceof Error ? error.message : 'An unexpected error occurred'); } }; @@ -28,6 +29,7 @@ export const editStrike = async (traineeId: string, strike: Strike) => { if (axios.isAxiosError(error)) { throw new Error(error.response?.data?.error || 'Failed to edit strike'); } - throw error; + + throw new Error(error instanceof Error ? error.message : 'An unexpected error occurred'); } }; diff --git a/client/src/features/trainee-profile/education/tests/api/api.ts b/client/src/features/trainee-profile/education/tests/api/api.ts index 64815cd8..419baa4c 100644 --- a/client/src/features/trainee-profile/education/tests/api/api.ts +++ b/client/src/features/trainee-profile/education/tests/api/api.ts @@ -13,7 +13,8 @@ export const addTest = async (traineeId: string, test: Test) => { if (axios.isAxiosError(error)) { throw new Error(error.response?.data?.error || 'Failed to add test'); } - throw error; + + throw new Error(error instanceof Error ? error.message : 'An unexpected error occurred'); } }; @@ -28,6 +29,7 @@ export const editTest = async (traineeId: string, test: Test) => { if (axios.isAxiosError(error)) { throw new Error(error.response?.data?.error || 'Failed to edit test'); } - throw error; + + throw new Error(error instanceof Error ? error.message : 'An unexpected error occurred'); } }; diff --git a/client/src/features/trainee-profile/interactions/api/api.ts b/client/src/features/trainee-profile/interactions/api/api.ts index f39731fa..7224a8a2 100644 --- a/client/src/features/trainee-profile/interactions/api/api.ts +++ b/client/src/features/trainee-profile/interactions/api/api.ts @@ -20,7 +20,8 @@ export const addInteraction = async (traineeId: string, interaction: Partial Date: Sat, 7 Feb 2026 19:29:53 +0530 Subject: [PATCH 3/6] Removed try/catch to preserve 401 redirect functionality --- .../features/trainee-profile/interactions/api/api.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/client/src/features/trainee-profile/interactions/api/api.ts b/client/src/features/trainee-profile/interactions/api/api.ts index 7224a8a2..95b4c98f 100644 --- a/client/src/features/trainee-profile/interactions/api/api.ts +++ b/client/src/features/trainee-profile/interactions/api/api.ts @@ -2,15 +2,8 @@ import axios from 'axios'; import { Interaction } from '../Interactions'; export const getInteractions = async (traineeId: string) => { - try { - const { data } = await axios.get(`/api/trainees/${traineeId}/interactions`); - return data as Interaction[]; - } catch (error) { - if (axios.isAxiosError(error)) { - throw new Error(error.response?.data?.error || 'Failed to get interactions'); - } - throw new Error('Failed to get interactions'); - } + const { data } = await axios.get(`/api/trainees/${traineeId}/interactions`); + return data; }; export const addInteraction = async (traineeId: string, interaction: Partial) => { From 12d309397b8043372924bb77d5a30a3febb4b289 Mon Sep 17 00:00:00 2001 From: Hadley99 Date: Sat, 7 Feb 2026 19:38:16 +0530 Subject: [PATCH 4/6] improved parameter handling --- client/src/features/dashboard/api/api.ts | 8 +++++++- client/src/features/search/api/api.ts | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/client/src/features/dashboard/api/api.ts b/client/src/features/dashboard/api/api.ts index 32481d53..93453c2c 100644 --- a/client/src/features/dashboard/api/api.ts +++ b/client/src/features/dashboard/api/api.ts @@ -2,6 +2,12 @@ import axios from 'axios'; import { DashboardData } from '../Dashboard'; export const getDashboardData = async (startDate?: string, endDate?: string): Promise => { - const response = await axios.get(`/api/dashboard?startDate=${startDate}&endDate=${endDate}`); + const params = { + ...(startDate && { startDate }), + ...(endDate && { endDate }), + }; + + const response = await axios.get('/api/dashboard', { params }); + return response.data; }; diff --git a/client/src/features/search/api/api.ts b/client/src/features/search/api/api.ts index a5c143c8..5dcbd11b 100644 --- a/client/src/features/search/api/api.ts +++ b/client/src/features/search/api/api.ts @@ -2,6 +2,8 @@ import axios from 'axios'; import { SearchResult, SearchResultResponse } from '../Search'; export const getSearchResults = async (query: string): Promise => { - const response = await axios.get(`/api/search?q=${query}&limit=20`); + const response = await axios.get('/api/search', { + params: { query, limit: 20 }, + }); return response.data.hits.data; }; From c230afd1fde01d7b6f545175093d8687d0f6fb0a Mon Sep 17 00:00:00 2001 From: Hadley99 Date: Sat, 7 Feb 2026 19:39:03 +0530 Subject: [PATCH 5/6] refactor: streamline API response handling in trainee info functions --- .../interactions/data/interaction-queries.ts | 4 ++-- .../src/features/trainee-profile/personal-info/api/api.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/features/trainee-profile/interactions/data/interaction-queries.ts b/client/src/features/trainee-profile/interactions/data/interaction-queries.ts index a2d0269f..27551f27 100644 --- a/client/src/features/trainee-profile/interactions/data/interaction-queries.ts +++ b/client/src/features/trainee-profile/interactions/data/interaction-queries.ts @@ -11,8 +11,8 @@ export const useGetInteractions = (traineeId: string) => { return useQuery({ queryKey: ['interactions', traineeId], queryFn: async () => { - const data = await getInteractions(traineeId); - return orderInteractionsByDateDesc(data); + const interactions = await getInteractions(traineeId); + return orderInteractionsByDateDesc(interactions); }, enabled: !!traineeId, refetchOnWindowFocus: false, diff --git a/client/src/features/trainee-profile/personal-info/api/api.ts b/client/src/features/trainee-profile/personal-info/api/api.ts index bed4e33a..801dbb8e 100644 --- a/client/src/features/trainee-profile/personal-info/api/api.ts +++ b/client/src/features/trainee-profile/personal-info/api/api.ts @@ -2,12 +2,12 @@ import axios from 'axios'; import { Trainee } from '../../../../data/types/Trainee'; import { SaveTraineeRequestData } from './types'; -export const getTraineeInfo = async (traineeId: string): Promise => { +export const getTraineeInfo = async (traineeId: string) => { const { data } = await axios.get(`/api/trainees/${traineeId}`); return data; }; -export const saveTraineeInfo = async (traineeId: string, dataToSave: SaveTraineeRequestData): Promise => { - const response = await axios.patch(`/api/trainees/${traineeId}`, dataToSave); - return response.data; +export const saveTraineeInfo = async (traineeId: string, dataToSave: SaveTraineeRequestData) => { + const { data } = await axios.patch(`/api/trainees/${traineeId}`, dataToSave); + return data; }; From cd655347b10c926b6b4068d243007fe06f1e4ada Mon Sep 17 00:00:00 2001 From: Hadley99 Date: Sun, 8 Feb 2026 07:05:55 +0530 Subject: [PATCH 6/6] fixed params for axios --- client/src/features/search/api/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/features/search/api/api.ts b/client/src/features/search/api/api.ts index 5dcbd11b..8ab7b614 100644 --- a/client/src/features/search/api/api.ts +++ b/client/src/features/search/api/api.ts @@ -3,7 +3,7 @@ import { SearchResult, SearchResultResponse } from '../Search'; export const getSearchResults = async (query: string): Promise => { const response = await axios.get('/api/search', { - params: { query, limit: 20 }, + params: { q: query, limit: 20 }, }); return response.data.hits.data; };