Skip to content

Commit f48bb22

Browse files
committed
Implement type-safe parsing for numeric values in TargetCalculationService
1 parent 0a73427 commit f48bb22

1 file changed

Lines changed: 27 additions & 11 deletions

File tree

backend/src/services/target-calculation-service.ts

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,22 @@ RESULT:
204204

205205
// === UTILITY CALCULATION METHODS ===
206206

207+
/**
208+
* Type-safe parsing of numeric values that might be strings or numbers
209+
* @param value The value to parse (string | number | null | undefined)
210+
* @param defaultValue The default value to use if parsing fails
211+
* @returns A valid number
212+
*/
213+
private parseNumericValue(value: string | number | null | undefined, defaultValue: number): number {
214+
if (value == null) return defaultValue;
215+
if (typeof value === 'number') return isNaN(value) ? defaultValue : value;
216+
if (typeof value === 'string') {
217+
const parsed = parseFloat(value);
218+
return isNaN(parsed) ? defaultValue : parsed;
219+
}
220+
return defaultValue;
221+
}
222+
207223
/**
208224
* Round a number to a specified number of decimal places
209225
* @param value The number to round
@@ -702,8 +718,8 @@ RESULT:
702718
const userTimeSavings = distinctUsers.map(userId => {
703719
const userSurveys = this.surveysWeekly.filter(survey => survey.userId === userId);
704720
const totalPercent = userSurveys.reduce((sum, survey) => {
705-
// Always parse percentTimeSaved as float
706-
const percentTimeSaved = survey.percentTimeSaved != null ? parseFloat(survey.percentTimeSaved as any) : 0;
721+
// Use type-safe parsing for percentTimeSaved
722+
const percentTimeSaved = this.parseNumericValue(survey.percentTimeSaved, 0);
707723
return sum + percentTimeSaved;
708724
}, 0);
709725
return totalPercent / userSurveys.length; // Average percent time saved per user
@@ -712,17 +728,17 @@ RESULT:
712728
// Average across all users
713729
const avgPercentTimeSaved = userTimeSavings.reduce((sum, percent) => sum + percent, 0) / userTimeSavings.length;
714730

715-
// Convert settings values to numbers (parse from string if needed)
716-
const hoursPerYear = this.settings.hoursPerYear != null ? parseFloat(this.settings.hoursPerYear as any) : 2000;
717-
const percentCoding = this.settings.percentCoding != null ? parseFloat(this.settings.percentCoding as any) : 50;
731+
// Convert settings values to numbers using type-safe parsing
732+
const hoursPerYear = this.parseNumericValue(this.settings.hoursPerYear, 2000);
733+
const percentCoding = this.parseNumericValue(this.settings.percentCoding, 50);
718734

719735
// Calculate weekly hours saved based on settings and average percent
720736
const weeklyHours = hoursPerYear / 50; // Assuming 50 working weeks
721737
const weeklyDevHours = weeklyHours * (percentCoding / 100);
722738
const avgWeeklyTimeSaved = weeklyDevHours * (avgPercentTimeSaved / 100);
723739

724740
// Calculate max based on settings
725-
const maxPercentTimeSaved = this.settings.percentTimeSaved != null ? parseFloat(this.settings.percentTimeSaved as any) : 20;
741+
const maxPercentTimeSaved = this.parseNumericValue(this.settings.percentTimeSaved, 20);
726742
const maxWeeklyTimeSaved = weeklyDevHours * (maxPercentTimeSaved / 100);
727743

728744
// Use default value of 2 if calculated value is 0 or very small
@@ -794,11 +810,11 @@ RESULT:
794810
const adoptedDevs = this.calculateAdoptedDevs().current;
795811
const weeklyTimeSavedHrs = this.calculateWeeklyTimeSavedHrs().current; // This now includes default of 2 if needed
796812

797-
// Always parse settings values as numbers (from string if needed)
798-
const hoursPerYear = this.settings.hoursPerYear != null ? parseFloat(this.settings.hoursPerYear as any) : 2000;
813+
// Use type-safe parsing for settings values
814+
const hoursPerYear = this.parseNumericValue(this.settings.hoursPerYear, 2000);
799815
const weeksInYear = Math.round(hoursPerYear / 40) || 50; // Calculate weeks and ensure it's a number
800816

801-
const devCostPerYear = this.settings.devCostPerYear != null ? parseFloat(this.settings.devCostPerYear as any) : 0;
817+
const devCostPerYear = this.parseNumericValue(this.settings.devCostPerYear, 0);
802818
const hourlyRate = devCostPerYear > 0 ? (devCostPerYear / hoursPerYear) : 50;
803819

804820
const annualSavings = weeklyTimeSavedHrs * weeksInYear * hourlyRate * adoptedDevs;
@@ -834,8 +850,8 @@ RESULT:
834850
const adoptedDevs = this.calculateAdoptedDevs().current;
835851
const weeklyTimeSavedHrs = this.calculateWeeklyTimeSavedHrs().current; // This now includes default of 2 if needed
836852

837-
// Always parse hours per year as number
838-
const hoursPerYear = this.settings.hoursPerYear != null ? parseFloat(this.settings.hoursPerYear as any) : 2000;
853+
// Use type-safe parsing for hours per year
854+
const hoursPerYear = this.parseNumericValue(this.settings.hoursPerYear, 2000);
839855
const hoursPerWeek = hoursPerYear / 50 || 40; // Default to 40 if undefined
840856

841857
// Calculate productivity boost factor (not percentage)

0 commit comments

Comments
 (0)