Skip to content

Commit 94dbf12

Browse files
authored
Merge pull request #852 from Sim-sat/strict-null-checks
Strict null checks
2 parents 2a1cf6a + c549305 commit 94dbf12

139 files changed

Lines changed: 1925 additions & 1535 deletions

File tree

Some content is hidden

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

SparkyFitnessFrontend/src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
import { ThemeProvider } from '@/contexts/ThemeContext';
1616
import DraggableChatbotButton from '@/components/DraggableChatbotButton';
1717
import AboutDialog from '@/components/AboutDialog';
18-
import NewReleaseDialog from '@/components/NewReleaseDialog';
18+
import NewReleaseDialog, { ReleaseInfo } from '@/components/NewReleaseDialog';
1919
import AppSetup from '@/components/AppSetup';
2020
import { Toaster } from '@/components/ui/toaster';
2121
import {
@@ -100,7 +100,7 @@ export const ComponentFallback = () => {
100100
};
101101
const Root = () => {
102102
const [showAboutDialog, setShowAboutDialog] = useState(false);
103-
const [latestRelease, setLatestRelease] = useState(null);
103+
const [latestRelease, setLatestRelease] = useState<ReleaseInfo | null>(null);
104104
const [showNewReleaseDialog, setShowNewReleaseDialog] = useState(false);
105105
const { data: appVersion } = useCurrentVersionQuery();
106106
const navigate = useNavigate();

SparkyFitnessFrontend/src/api/Chatbot/Chatbot_FoodHandler.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -271,12 +271,12 @@ export const addFoodOption = async (
271271
try {
272272
const { foodOptions, mealType, quantity, unit, entryDate } =
273273
originalMetadata;
274-
const selectedOption = foodOptions[optionIndex];
274+
const selectedOption = foodOptions?.[optionIndex];
275275

276276
if (!selectedOption) {
277277
error(
278278
userLoggingLevel,
279-
`[${transactionId}] Invalid option index:`,
279+
`[${transactionId}] Invalid option index or missing foodOptions:`,
280280
optionIndex
281281
);
282282
return {
@@ -502,7 +502,7 @@ export const addFoodOption = async (
502502

503503
const calories = Math.round(
504504
(selectedOption.calories || 0) *
505-
(quantity / (selectedOption.serving_size || 100))
505+
((quantity ?? 0) / (selectedOption.serving_size || 100))
506506
);
507507

508508
return {

SparkyFitnessFrontend/src/api/Chatbot/Chatbot_MeasurementHandler.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,11 @@ export const processMeasurementInput = async (
188188

189189
let categoryId: string;
190190
let existingCategory = null;
191-
let categorySearchError: ApiError = null;
191+
let categorySearchError: ApiError = {};
192192
try {
193193
existingCategory = await searchCustomCategory(customMeasurementName);
194194
} catch (err: unknown) {
195-
categorySearchError = err;
195+
categorySearchError = err as ApiError;
196196
}
197197

198198
if (categorySearchError && categorySearchError.code !== 'PGRST116') {
@@ -220,15 +220,15 @@ export const processMeasurementInput = async (
220220
`Custom category "${customMeasurementName}" not found, creating...`
221221
);
222222
let newCategory = null;
223-
let categoryCreateError: ApiError = null;
223+
let categoryCreateError: ApiError = {};
224224
try {
225225
newCategory = await createCustomCategory({
226226
name: customMeasurementName,
227227
frequency: 'Daily',
228228
measurement_type: 'numeric',
229229
});
230230
} catch (err: unknown) {
231-
categoryCreateError = err;
231+
categoryCreateError = err as ApiError;
232232
}
233233

234234
if (categoryCreateError) {
@@ -245,7 +245,7 @@ export const processMeasurementInput = async (
245245

246246
// Now insert the custom measurement entry
247247
const valueToLog = measurement.value ?? measurement.systolic;
248-
let customEntryError: ApiError = null;
248+
let customEntryError: ApiError = {};
249249

250250
if (valueToLog === undefined || valueToLog === null) {
251251
error(
@@ -264,7 +264,7 @@ export const processMeasurementInput = async (
264264
entry_timestamp: new Date().toISOString(),
265265
});
266266
} catch (err: unknown) {
267-
customEntryError = err;
267+
customEntryError = err as ApiError;
268268
}
269269

270270
if (customEntryError) {

SparkyFitnessFrontend/src/api/Chatbot/sparkyChatService.ts

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ export const processUserInput = async (
217217
try {
218218
const jsonMatch = aiResponse.response.match(/```json\n([\s\S]*?)\n```/);
219219
let jsonString = jsonMatch ? jsonMatch[1] : aiResponse.response;
220-
jsonString = stripJsonComments(jsonString); // Strip comments before parsing
220+
jsonString = stripJsonComments(jsonString ?? ''); // Strip comments before parsing
221221

222222
parsedResponse = JSON.parse(jsonString);
223223
info(
@@ -269,8 +269,8 @@ export const processUserInput = async (
269269
foodResponse.metadata;
270270

271271
const foodOptions = await callAIForFoodOptions(
272-
foodName,
273-
unit,
272+
foodName ?? '',
273+
unit ?? '',
274274
userLoggingLevel,
275275
activeAIServiceSetting as AIService
276276
);
@@ -348,7 +348,7 @@ export const processUserInput = async (
348348
case 'chat':
349349
return await processChatInput(
350350
parsedResponse.data || {},
351-
parsedResponse.response,
351+
parsedResponse.response ?? '',
352352
userLoggingLevel
353353
);
354354
default: {
@@ -615,23 +615,26 @@ const extractDateFromInput = (
615615
/(\d{1,2})[/-](\d{1,2})(?:[/-](\d{2,4}))?/
616616
);
617617
if (dateMatch) {
618-
const month = parseInt(dateMatch[1], 10);
619-
const day = parseInt(dateMatch[2], 10);
620-
let year = today.getFullYear();
621-
622-
if (dateMatch[3]) {
623-
year = parseInt(dateMatch[3], 10);
624-
if (year < 100) {
625-
year += 2000;
618+
const [, monthStr, dayStr, yearStr] = dateMatch;
619+
if (monthStr && dayStr) {
620+
const month = parseInt(monthStr, 10);
621+
const day = parseInt(dayStr, 10);
622+
let year = today.getFullYear();
623+
624+
if (yearStr) {
625+
year = parseInt(yearStr, 10);
626+
if (year < 100) {
627+
year += 2000;
628+
}
626629
}
627-
}
628630

629-
if (month >= 1 && month <= 12 && day >= 1 && day <= 31) {
630-
const date = new Date(year, month - 1, day);
631-
if (!dateMatch[3] && date > today) {
632-
date.setFullYear(year - 1);
631+
if (month >= 1 && month <= 12 && day >= 1 && day <= 31) {
632+
const date = new Date(year, month - 1, day);
633+
if (!yearStr && date > today) {
634+
date.setFullYear(year - 1);
635+
}
636+
return date.toISOString().split('T')[0];
633637
}
634-
return date.toISOString().split('T')[0];
635638
}
636639
}
637640
return undefined;

SparkyFitnessFrontend/src/api/Exercises/exerciseEntryService.ts

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ export const fetchExerciseEntries = async (
3535
sets: ex.sets ? ex.sets : [], // Parse sets if it's a JSON string
3636
exercise_snapshot: {
3737
...ex.exercise_snapshot, // Use the existing snapshot
38+
id: ex.exercise_snapshot.id ?? '',
39+
name: ex.exercise_snapshot.name ?? '',
40+
calories_per_hour: ex.exercise_snapshot.calories_per_hour ?? 0,
41+
category: ex.exercise_snapshot.category ?? '',
3842
equipment: parseJsonArray(ex.exercise_snapshot.equipment),
3943
primary_muscles: parseJsonArray(
4044
ex.exercise_snapshot.primary_muscles
@@ -47,14 +51,14 @@ export const fetchExerciseEntries = async (
4751
},
4852
activity_details: ex.activity_details
4953
? ex.activity_details.map((detail) => ({
50-
id: detail.id,
51-
key: detail.detail_type,
54+
id: detail.id ?? '',
55+
key: detail.detail_type ?? '',
5256
value:
5357
typeof detail.detail_data === 'object'
5458
? JSON.stringify(detail.detail_data, null, 2)
5559
: String(detail.detail_data),
5660
provider_name: detail.provider_name,
57-
detail_type: detail.detail_type,
61+
detail_type: detail.detail_type ?? '',
5862
}))
5963
: [],
6064
}))
@@ -66,26 +70,30 @@ export const fetchExerciseEntries = async (
6670
sets: entry.sets ? entry.sets : [], // Parse sets if it's a JSON string
6771
exercise_snapshot: {
6872
...entry.exercise_snapshot, // Use the existing snapshot
69-
equipment: parseJsonArray(entry.exercise_snapshot.equipment),
73+
id: entry.exercise_snapshot?.id ?? '',
74+
name: entry.exercise_snapshot?.name ?? '',
75+
category: entry.exercise_snapshot?.category ?? '',
76+
calories_per_hour: entry.exercise_snapshot?.calories_per_hour ?? 0,
77+
equipment: parseJsonArray(entry.exercise_snapshot?.equipment),
7078
primary_muscles: parseJsonArray(
71-
entry.exercise_snapshot.primary_muscles
79+
entry.exercise_snapshot?.primary_muscles
7280
),
7381
secondary_muscles: parseJsonArray(
74-
entry.exercise_snapshot.secondary_muscles
82+
entry.exercise_snapshot?.secondary_muscles
7583
),
76-
instructions: parseJsonArray(entry.exercise_snapshot.instructions),
77-
images: parseJsonArray(entry.exercise_snapshot.images),
84+
instructions: parseJsonArray(entry.exercise_snapshot?.instructions),
85+
images: parseJsonArray(entry.exercise_snapshot?.images),
7886
},
7987
activity_details: entry.activity_details
8088
? entry.activity_details.map((detail) => ({
81-
id: detail.id,
82-
key: detail.detail_type,
89+
id: detail.id ?? '',
90+
key: detail.detail_type ?? '',
8391
value:
8492
typeof detail.detail_data === 'object'
8593
? JSON.stringify(detail.detail_data, null, 2)
8694
: String(detail.detail_data),
8795
provider_name: detail.provider_name,
88-
detail_type: detail.detail_type,
96+
detail_type: detail.detail_type ?? '',
8997
}))
9098
: [],
9199
};
@@ -107,8 +115,8 @@ export const createExerciseEntry = async (payload: {
107115
sets: WorkoutPresetSet[];
108116
image_url?: string;
109117
calories_burned?: number;
110-
distance?: number;
111-
avg_heart_rate?: number;
118+
distance?: number | null;
119+
avg_heart_rate?: number | null;
112120
imageFile?: File | null;
113121
activity_details?: {
114122
provider_name?: string;
@@ -184,9 +192,9 @@ export interface UpdateExerciseEntryPayload {
184192
calories_burned?: number;
185193
notes?: string;
186194
sets?: WorkoutPresetSet[];
187-
image_url?: string;
188-
distance?: number;
189-
avg_heart_rate?: number;
195+
image_url?: string | null;
196+
distance?: number | null;
197+
avg_heart_rate?: number | null;
190198
imageFile?: File | null;
191199
activity_details?: {
192200
id?: string;

SparkyFitnessFrontend/src/api/Exercises/exerciseSearchService.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import { apiCall } from '@/api/api';
22
import { Exercise } from '@/types/exercises';
33

4+
interface ExerciseSearchParams {
5+
searchTerm: string;
6+
equipmentFilter?: string;
7+
muscleGroupFilter?: string;
8+
}
49
export const searchExercises = async (
510
query: string,
611
equipmentFilter: string[] = [],
712
muscleGroupFilter: string[] = []
813
): Promise<Exercise[]> => {
9-
const params: Record<string, string> = {
14+
const params: ExerciseSearchParams = {
1015
searchTerm: query,
1116
};
1217
if (equipmentFilter.length > 0) {
@@ -22,6 +27,14 @@ export const searchExercises = async (
2227
return Array.isArray(result) ? result : [];
2328
};
2429

30+
interface ExternalExerciseSearchParams {
31+
query: string;
32+
providerId: string;
33+
providerType: string;
34+
equipmentFilter?: string;
35+
muscleGroupFilter?: string;
36+
limit?: number;
37+
}
2538
export const searchExternalExercises = async (
2639
query: string,
2740
providerId: string,
@@ -30,7 +43,7 @@ export const searchExternalExercises = async (
3043
muscleGroupFilter: string[] = [],
3144
limit?: number
3245
): Promise<Exercise[]> => {
33-
const params: Record<string, string | number> = {
46+
const params: ExternalExerciseSearchParams = {
3447
query: query,
3548
providerId: providerId,
3649
providerType: providerType,

SparkyFitnessFrontend/src/api/Exercises/workoutPresets.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,16 @@ export const deleteWorkoutPreset = async (
4646
});
4747
};
4848

49+
interface WorkoutSearchParams {
50+
searchTerm: string;
51+
limit?: number;
52+
}
53+
4954
export const searchWorkoutPresets = async (
5055
searchTerm: string,
5156
limit?: number
5257
): Promise<WorkoutPreset[]> => {
53-
const params: Record<string, string | number> = { searchTerm };
58+
const params: WorkoutSearchParams = { searchTerm };
5459
if (limit !== undefined) {
5560
params.limit = limit;
5661
}

SparkyFitnessFrontend/src/api/Foods/enhancedCustomFoodFormService.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ export const saveFood = async (
115115
// Create new food
116116
// The first variant in the array is always the primary unit for the food
117117
const primaryVariant = variants[0];
118+
if (!primaryVariant) {
119+
throw new Error('Primary variant is undefined');
120+
}
118121
const foodToCreate = {
119122
name: foodData.name,
120123
brand: foodData.brand,

SparkyFitnessFrontend/src/api/Foods/fatSecret.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,15 @@ const parseFoodDescription = (description: string) => {
3838
let serving_unit: string | undefined;
3939

4040
if (servingMatch) {
41-
serving_size = parseFloat(servingMatch[1]);
42-
serving_unit = servingMatch[2].trim();
41+
serving_size = parseFloat(servingMatch[1] ?? '1');
42+
serving_unit = servingMatch[2]?.trim();
4343
}
4444

4545
return {
46-
calories: caloriesMatch ? parseFloat(caloriesMatch[1]) : 0,
47-
fat: fatMatch ? parseFloat(fatMatch[1]) : 0,
48-
carbs: carbsMatch ? parseFloat(carbsMatch[1]) : 0,
49-
protein: proteinMatch ? parseFloat(proteinMatch[1]) : 0,
46+
calories: caloriesMatch ? parseFloat(caloriesMatch[1] ?? '0') : 0,
47+
fat: fatMatch ? parseFloat(fatMatch[1] ?? '0') : 0,
48+
carbs: carbsMatch ? parseFloat(carbsMatch[1] ?? '0') : 0,
49+
protein: proteinMatch ? parseFloat(proteinMatch[1] ?? '0') : 0,
5050
serving_size,
5151
serving_unit,
5252
};

SparkyFitnessFrontend/src/api/Foods/mealPlanTemplate.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ export const createMealPlanTemplate = async (
2626

2727
export const updateMealPlanTemplate = async (
2828
userId: string,
29-
templateId: string,
3029
templateData: Partial<MealPlanTemplate>,
3130
currentClientDate?: string
3231
): Promise<MealPlanTemplate> => {
33-
return await api.put(`/meal-plan-templates/${templateId}`, {
32+
if (!templateData.id) {
33+
throw new Error('TemplateId is undefined');
34+
}
35+
return await api.put(`/meal-plan-templates/${templateData.id}`, {
3436
body: { ...templateData, userId, currentClientDate },
3537
});
3638
};

0 commit comments

Comments
 (0)