Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,130 +54,132 @@
FormEnum.AdditionalSalary,
);
const locale = useLocale();
const totalSteps = steps.length;

const createCurrencyValidation = useCallback(
(fieldName: string, max?: number) => {
let schema = amount(fieldName, t);
if (max) {
schema = schema.max(
max,
t('Exceeds {{amount}} limit', {
amount: currencyFormat(max, 'USD', locale, {
showTrailingZeros: true,
}),
}),
);
}
return schema;
},
[t],
);

const initialValues: CompleteFormValues = {
currentYearSalary: '0',
previousYearSalary: '0',
additionalSalary: '0',
adoption: '0',
contribution403b: '0',
counseling: '0',
healthcareExpenses: '0',
babysitting: '0',
childrenMinistryTrip: '0',
childrenCollege: '0',
movingExpense: '0',
seminary: '0',
housingDownPayment: '0',
autoPurchase: '0',
reimbursableExpenses: '0',
defaultPercentage: false,
telephoneNumber: '',
};

const validationSchema = useMemo(
() =>
yup.object({
currentYearSalary: createCurrencyValidation(t("Current Year's Salary")),
previousYearSalary: createCurrencyValidation(
t("Previous Year's Salary"),
),
additionalSalary: createCurrencyValidation(t('Additional Salary')),
adoption: createCurrencyValidation(t('Adoption'), 15000), // replace with MpdGoalMiscConstants value when possible
contribution403b: createCurrencyValidation(t('403(b) Contribution')), // Can't be greater than salary (will be pulled from HCM)
counseling: createCurrencyValidation(t('Counseling')),
healthcareExpenses: createCurrencyValidation(t('Healthcare Expenses')),
babysitting: createCurrencyValidation(t('Babysitting')),
childrenMinistryTrip: createCurrencyValidation(
t("Children's Ministry Trip"),
), // Need to pull number of children from HCM and multiply by 21000 for max
childrenCollege: createCurrencyValidation(t("Children's College")),
movingExpense: createCurrencyValidation(t('Moving Expense')),
seminary: createCurrencyValidation(t('Seminary')),
housingDownPayment: createCurrencyValidation(
t('Housing Down Payment'),
50000,
), // replace with MpdGoalMiscConstants value when possible
autoPurchase: createCurrencyValidation(t('Auto Purchase')), // Max will eventually be a constant, no determined value yet
reimbursableExpenses: createCurrencyValidation(
t('Reimbursable Expenses'),
),
defaultPercentage: yup.boolean(),
telephoneNumber: yup
.string()
.required(t('Telephone number is required'))
.matches(
/^[\d\s\-\(\)\+]+$/,
t('Please enter a valid telephone number'),
),
}),
[createCurrencyValidation, t],
);

// Step Handlers
const [currentStep, setCurrentStep] = useState(
AdditionalSalaryRequestSectionEnum.AboutForm,
);

const handleNextStep = useCallback(() => {
const next = objects[currentIndex + 1];
nextStep();

setCurrentStep(next);
}, [currentIndex, objects, nextStep]);

const handlePreviousStep = useCallback(() => {
const next = objects[currentIndex - 1];
previousStep();

setCurrentStep(next);
}, [currentIndex, objects, previousStep]);

const [isDrawerOpen, setIsDrawerOpen] = useState(true);
const toggleDrawer = useCallback(() => {
setIsDrawerOpen((prev) => !prev);
}, []);

const handleCancel = () => {
// Implement cancel logic here
};

const handleSubmit = useCallback(
(_values: CompleteFormValues) => {
//TODO: Submit form values
handleNextStep();
},
[handleNextStep],
);

const formik = useFormik<CompleteFormValues>({
initialValues: providedInitialValues || initialValues,
validationSchema,
onSubmit: handleSubmit,
enableReinitialize: true,
});

const percentComplete = useMemo(
() => calculateCompletionPercentage(formik.values),
[formik.values],
() =>
calculateCompletionPercentage(formik.values, currentIndex, totalSteps),
[formik.values, currentIndex, totalSteps],

Check warning on line 182 in src/components/Reports/AdditionalSalaryRequest/Shared/AdditionalSalaryRequestContext.tsx

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ Getting worse: Large Method

AdditionalSalaryRequestProvider:React.FC<Props> increases from 150 to 152 lines of code, threshold = 120. Large functions with many lines of code are generally harder to understand and lower the code health. Avoid adding more lines to this function.
);

const contextValue = useMemo<AdditionalSalaryRequestType>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { CompleteFormValues } from '../AdditionalSalaryRequest';
import { defaultCompleteFormValues } from '../CompleteForm/CompleteForm.mock';
import { calculateCompletionPercentage } from './calculateCompletionPercentage';

const totalSteps = 3;

describe('calculateCompletionPercentage', () => {
const createFormValues = (
overrides: Partial<CompleteFormValues> = {},
Expand All @@ -25,12 +27,14 @@ describe('calculateCompletionPercentage', () => {
...overrides,
});

it('should return 0 when all fields are empty', () => {
it('should return start percentage when all fields are empty', () => {
const values = createFormValues();
expect(calculateCompletionPercentage(values)).toBe(0);

// Step 1 complete + 0 filled fields --> 1/18 = 5.55%
expect(calculateCompletionPercentage(values, 0, totalSteps)).toBe(5);
});

it('should return 100 when all fields are filled', () => {
it('should return 95 when all fields are filled', () => {
const values = createFormValues({
currentYearSalary: '50000',
previousYearSalary: '48000',
Expand All @@ -49,15 +53,43 @@ describe('calculateCompletionPercentage', () => {
reimbursableExpenses: '750',
telephoneNumber: '555-1234',
});
expect(calculateCompletionPercentage(values)).toBe(100);

// Steps 1 & 2 complete + all fields filled --> 17/18 = 94.44%
expect(calculateCompletionPercentage(values, 1, totalSteps)).toBe(95);
});

it('should return 100 when all fields are filled and all steps completed', () => {
const values = createFormValues({
currentYearSalary: '50000',
previousYearSalary: '48000',
additionalSalary: '5000',
adoption: '1000',
contribution403b: '2000',
counseling: '500',
healthcareExpenses: '1500',
babysitting: '800',
childrenMinistryTrip: '1200',
childrenCollege: '3000',
movingExpense: '2500',
seminary: '1000',
housingDownPayment: '10000',
autoPurchase: '5000',
reimbursableExpenses: '750',
telephoneNumber: '555-1234',
});

// Steps 1, 2, & 3 complete + all fields filled --> 18/18 = 100%
expect(calculateCompletionPercentage(values, 2, totalSteps)).toBe(100);
});

it('should exclude defaultPercentage from calculation', () => {
const values = createFormValues({
currentYearSalary: '50000',
defaultPercentage: true,
});
expect(calculateCompletionPercentage(values)).toBe(6);

// Step 1 & 2 complete + 1 filled field --> 3/18 = 16.66%
expect(calculateCompletionPercentage(values, 1, totalSteps)).toBe(16);
});

it('should treat zero values as unfilled', () => {
Expand All @@ -66,14 +98,18 @@ describe('calculateCompletionPercentage', () => {
previousYearSalary: '0',
additionalSalary: '50000',
});
expect(calculateCompletionPercentage(values)).toBe(6);

// Steps 1 & 2 complete + 1 filled field --> 3/18 = 16.66%
expect(calculateCompletionPercentage(values, 1, totalSteps)).toBe(16);
});

it('should handle decimal values correctly', () => {
const values = createFormValues({
currentYearSalary: '50000.50',
previousYearSalary: '48000.75',
});
expect(calculateCompletionPercentage(values)).toBe(13);

// Step 1 & 2 complete + 2 filled fields --> 4/18 = 22.22%
expect(calculateCompletionPercentage(values, 1, totalSteps)).toBe(21);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import { CompleteFormValues } from '../AdditionalSalaryRequest';

export const calculateCompletionPercentage = (
values: CompleteFormValues,
currentIndex: number,
totalSteps: number,
): number => {
const fields = Object.values(values).filter(
(value) => typeof value === 'string' || typeof value === 'number',
);

const stepsCompleted = currentIndex + 1;
const totalFields = fields.length;

const filledFields = fields.filter((value) => {
Expand All @@ -28,5 +30,9 @@ export const calculateCompletionPercentage = (
return value > 0;
}).length;

return totalFields > 0 ? Math.round((filledFields / totalFields) * 100) : 0;
return totalFields > 0
? Math.round(
((stepsCompleted + filledFields) / (totalSteps + totalFields)) * 100,
)
: 0;
};
Loading