Skip to content
Merged
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 @@ -96,7 +96,9 @@ describe('PdsGoalCalculator', () => {
});
// Switching Pay Type clears payRate, so the user must re-enter it before
// Continue becomes enabled.
const payRateInput = await findByRole('spinbutton', { name: 'Pay Rate' });
const payRateInput = await findByRole('spinbutton', {
name: 'Annual Pay Rate',
});
userEvent.type(payRateInput, '50000');

await waitFor(() => expect(continueButton).not.toBeDisabled());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ describe('SetupStep', () => {

userEvent.clear(goalNameInput);

const payRateInput = await findByRole('spinbutton', { name: 'Pay Rate' });
const payRateInput = await findByRole('spinbutton', {
name: 'Hourly Pay Rate',
});
userEvent.clear(payRateInput);

const hoursInput = await findByRole('spinbutton', {
Expand Down Expand Up @@ -182,21 +184,24 @@ describe('SetupStep', () => {
await findByRole('textbox', { name: 'Goal Name' });

expect(
queryByRole('spinbutton', { name: 'Pay Rate' }),
queryByRole('spinbutton', { name: /Pay Rate/ }),
Comment thread
wjames111 marked this conversation as resolved.
).not.toBeInTheDocument();
});

it('shows dynamic Pay Rate helper text based on salary type', async () => {
it('shows dynamic Pay Rate label and helper text based on salary type', async () => {
const { findByRole, findByText, rerender } = renderSetup({
calculationMock: fullTimeSalariedMock,
});

await findByRole('spinbutton', { name: 'Pay Rate' });
await findByRole('spinbutton', { name: 'Annual Pay Rate' });
expect(await findByText('Enter yearly salary')).toBeInTheDocument();
expect(await findByText('per year')).toBeInTheDocument();

rerender(setupTree({ calculationMock: fullTimeHourlyMock }));

await findByRole('spinbutton', { name: 'Hourly Pay Rate' });
expect(await findByText('Enter hourly rate')).toBeInTheDocument();
expect(await findByText('per hour')).toBeInTheDocument();
});

it('403b field is disabled', async () => {
Expand Down
9 changes: 8 additions & 1 deletion src/components/HrTools/PdsGoalCalculator/Setup/SetupStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,139 +107,146 @@
const payRateHelperText = isSalaried
? t('Enter yearly salary')
: t('Enter hourly rate');
const payRateLabel = isSalaried ? t('Annual Pay Rate') : t('Hourly Pay Rate');
Comment thread
wjames111 marked this conversation as resolved.
const payRateUnitSuffix = isSalaried ? t('per year') : t('per hour');

const handleOpenHoursCalculator = () => {
setRightPanelContent(
<HoursPerWeekGrid
onApply={(average) => {
saveField({ hoursWorkedPerWeek: average });
}}
/>,
);
};

return (
<>
<Box pb={4}>
<Typography variant="h6">{t('Settings')}</Typography>
<Typography pt={1}>
{t('What do you want to call this goal?')}
</Typography>
</Box>
<AutosaveTextField
fieldName="name"
schema={schema}
label={t('Goal Name')}
/>

<Divider sx={{ my: 4, mx: -4 }} />

<Box pb={4}>
<Typography variant="h6">{t('Calculator Setup')}</Typography>
<Typography>
{t('Take a moment to verify your information.')}
</Typography>
</Box>

<Card sx={{ padding: theme.spacing(3) }}>
<Box display="flex" alignItems="center" gap={1} mb={3}>
<Avatar
src={userData?.user.avatar}
alt={userData?.user.firstName ?? undefined}
variant="rounded"
sx={{ width: theme.spacing(4.5), height: theme.spacing(4.5) }}
/>
<Typography data-testid="info-name-typography" variant="subtitle1">
{userData?.user.firstName}
</Typography>
</Box>
<Grid container spacing={3}>
<Grid item xs={12}>
<AutosaveTextField
fieldName="formType"
schema={schema}
select
label={t('Form Type')}
helperText={
<>
<Box component="span" display="block">
{t(
'Default includes reimbursable expenses and 403b contributions in the goal total.',
)}
</Box>
<Box component="span" display="block">
{t(
'Simple excludes them; existing entries are preserved and will count again if you switch back.',
)}
</Box>
</>
}
>
<MenuItem value={DesignationSupportFormType.Detailed}>
{t('Default')}
</MenuItem>
<MenuItem value={DesignationSupportFormType.Simple}>
{t('Simple')}
</MenuItem>
</AutosaveTextField>
</Grid>

<Grid item xs={12}>
<AutosaveTextField
fieldName="status"
schema={schema}
select
label={t('Employment Status')}
>
<MenuItem value={DesignationSupportStatus.FullTime}>
{t('Full-time')}
</MenuItem>
<MenuItem value={DesignationSupportStatus.PartTime}>
{t('Part-time')}
</MenuItem>
</AutosaveTextField>
</Grid>

<Grid item xs={12}>
{/* Manual TextField (not AutosaveTextField) because changing Pay
Type must atomically clear payRate as well; AutosaveTextField
only writes the single bound fieldName. */}
<TextField
fullWidth
size="small"
variant="outlined"
select
label={t('Pay Type')}
helperText={t('Changing this clears Pay Rate.')}
value={calculation?.salaryOrHourly ?? ''}
disabled={!calculation || isMutating}
onChange={(event) => {
const newValue = event.target
.value as DesignationSupportSalaryType;
if (newValue !== calculation?.salaryOrHourly) {
saveField({ salaryOrHourly: newValue, payRate: null });
}
}}
>
<MenuItem value={DesignationSupportSalaryType.Salaried}>
{t('Salaried')}
</MenuItem>
<MenuItem value={DesignationSupportSalaryType.Hourly}>
{t('Hourly')}
</MenuItem>
</TextField>
</Grid>

{payType && (
<Grid item xs={12}>
<AutosaveTextField
fieldName="payRate"
schema={schema}
label={t('Pay Rate')}
label={payRateLabel}
Comment thread
wjames111 marked this conversation as resolved.
type="number"
helperText={payRateHelperText}
InputProps={{
startAdornment: <CurrencyAdornment />,
endAdornment: (
Comment thread
wjames111 marked this conversation as resolved.
<InputAdornment position="end">
{payRateUnitSuffix}
</InputAdornment>
),

Check warning on line 249 in src/components/HrTools/PdsGoalCalculator/Setup/SetupStep.tsx

View check run for this annotation

CodeScene Delta Analysis / CodeScene Code Health Review (main)

❌ Getting worse: Complex Method

SetupStep:React.FC increases in cyclomatic complexity from 21 to 23, threshold = 15. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
}}
/>
</Grid>
Expand Down
Loading