Skip to content
Closed
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 @@ -9,13 +9,15 @@ import { AdditionalSalaryRequestSection } from '../SharedComponents/AdditionalSa
import { SpouseComponent } from '../SharedComponents/SpouseComponent';

export const AboutForm: React.FC = () => {
const { currentStep } = useAdditionalSalaryRequest();
const { currentStep, hcmUser } = useAdditionalSalaryRequest();
const { t } = useTranslation();
const theme = useTheme();

const { staffInfo } = hcmUser || {};

// TODO: Replace with actual data from API/context
const name = 'Doc, John';
const accountNumber = '00123456';
const name = staffInfo?.preferredName ?? '';
const accountNumber = staffInfo?.personNumber ?? '';
const primaryAccountBalance = 20307.58;
const remainingAllowableSalary = 17500.0;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
fragment AdditionalSalaryRequestFields on AdditionalSalaryRequest {
id
currentYearSalaryNotReceived
previousYearSalaryNotReceived
phoneNumber
status
feedback
user {
id
firstName
lastName
}
}

fragment AdditionalSalaryRequestDetailsFields on AdditionalSalaryRequest {
...AdditionalSalaryRequestFields
personNumber
additionalSalaryWithinMax
adoption
traditional403bContribution
roth403bContribution
counselingNonMedical
healthcareExpensesExceedingLimit
babysittingMinistryEvents
childrenMinistryTripExpenses
childrenCollegeEducation
movingExpense
seminary
housingDownPayment
autoPurchase
expensesNotApprovedWithin90Days
totalAdditionalSalaryRequested
deductTwelvePercent
traditional403bContributionRequested
usingSpouseSalary
}

query AdditionalSalaryRequest($requestId: ID!) {
additionalSalaryRequest(id: $requestId) {
...AdditionalSalaryRequestFields
createdAt
updatedAt
}
}

query AdditionalSalaryRequests {
additionalSalaryRequests {
nodes {
...AdditionalSalaryRequestDetailsFields
}
}
}

mutation CreateAdditionalSalaryRequest(
$attributes: AdditionalSalaryRequestAttributesInput
) {
createAdditionalSalaryRequest(input: { attributes: $attributes }) {
additionalSalaryRequest {
...AdditionalSalaryRequestDetailsFields
}
}
}

mutation DeleteAdditionalSalaryRequest($id: ID!) {
deleteAdditionalSalaryRequest(input: { id: $id }) {
id
}
}

mutation SubmitAdditionalSalaryRequest($id: ID!) {
submitAdditionalSalaryRequest(input: { id: $id }) {
additionalSalaryRequest {
...AdditionalSalaryRequestDetailsFields
}
}
}

mutation UpdateAdditionalSalaryRequest(
$id: ID!
$attributes: AdditionalSalaryRequestAttributesInput!
) {
updateAdditionalSalaryRequest(input: { id: $id, attributes: $attributes }) {
additionalSalaryRequest {
...AdditionalSalaryRequestDetailsFields
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { createContext, useCallback, useMemo, useState } from 'react';
import { ApolloError } from '@apollo/client';
import { FormikProvider, useFormik } from 'formik';
import { useTranslation } from 'react-i18next';
import * as yup from 'yup';
Expand All @@ -8,7 +9,16 @@
import { amount } from 'src/lib/yupHelpers';
import { FormEnum } from '../../Shared/CalculationReports/Shared/sharedTypes';
import { Steps } from '../../Shared/CalculationReports/StepsList/StepsList';
import {
HcmDataQuery,
useHcmDataQuery,
} from '../../Shared/HcmData/HCMData.generated';
import { CompleteFormValues } from '../AdditionalSalaryRequest';
import {
AdditionalSalaryRequestQuery,
AdditionalSalaryRequestsQuery,
useAdditionalSalaryRequestQuery,
} from '../AdditionalSalaryRequest.generated';
import { AdditionalSalaryRequestSectionEnum } from '../AdditionalSalaryRequestHelper';
import { calculateCompletionPercentage } from './calculateCompletionPercentage';

Expand All @@ -23,6 +33,16 @@
toggleDrawer: () => void;
setIsDrawerOpen: (open: boolean) => void;
handleCancel: () => void;
hcmUser: HcmDataQuery['hcm'][0] | null;
hcmSpouse: HcmDataQuery['hcm'][1] | null;
requestData?: AdditionalSalaryRequestQuery['additionalSalaryRequest'] | null;
requestError?: ApolloError;

requestsData?:
| AdditionalSalaryRequestsQuery['additionalSalaryRequests']['nodes']
| null;
requestsError?: ApolloError;
requestId?: string;
};

const AdditionalSalaryRequestContext =
Expand Down Expand Up @@ -55,153 +75,179 @@
);
const locale = useLocale();

const { data: hcmData } = useHcmDataQuery();

const { data: requestsData, error: requestsError } =
useAdditionalSalaryRequestsQuery();

const requestId = 'c1a68821-5fb6-4e5e-b308-9263539af9d8';

const { data: requestData, error: requestError } =
useAdditionalSalaryRequestQuery({
variables: { requestId },
skip: !requestId,
});

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],
);

const contextValue = useMemo<AdditionalSalaryRequestType>(
() => ({
steps,
currentIndex,
percentComplete,
currentStep,
handleNextStep,
handlePreviousStep,
isDrawerOpen,
toggleDrawer,
setIsDrawerOpen,
handleCancel,
hcmUser: hcmData?.hcm?.[0] ?? null,
hcmSpouse: hcmData?.hcm?.[1] ?? null,
requestsData,
requestData,
requestsError,
requestError,
requestId,
}),
[
steps,
currentIndex,
percentComplete,
currentStep,
handleNextStep,
handlePreviousStep,
isDrawerOpen,
toggleDrawer,
hcmData,
requestsData,
requestData,
requestsError,
requestError,
requestId,

Check warning on line 250 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 172 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.
],
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,20 @@ import ImportExportIcon from '@mui/icons-material/ImportExport';
import { Box, Link, Typography } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import { useTranslation } from 'react-i18next';
import { useLocale } from 'src/hooks/useLocale';
import { currencyFormat } from 'src/lib/intlFormat';
import { useAdditionalSalaryRequest } from '../Shared/AdditionalSalaryRequestContext';

export const SpouseComponent: React.FC = () => {
const { t } = useTranslation();
const theme = useTheme();
const { hcmSpouse } = useAdditionalSalaryRequest();
const locale = useLocale();
const currency = 'USD';
const { staffInfo } = hcmSpouse || {};

const name = staffInfo?.preferredName ?? '';
const remainingAllowableSalary = currencyFormat(12200, currency, locale);
return (
<Box>
<Box
Expand All @@ -21,12 +31,14 @@ export const SpouseComponent: React.FC = () => {
sx={{ transform: 'rotate(90deg)' }}
/>
<Link href="#" variant="body1" underline="hover" onClick={() => {}}>
{t('Request additional salary from jane')}
{t('Request additional salary from {{name}}', { name })}
</Link>
</Box>

<Typography variant="caption" color="text.secondary">
{t('Up to her remaining allowable salary of $12,200')}
{t('Up to her remaining allowable salary of {{amount}}', {
amount: remainingAllowableSalary,
})}
</Typography>
</Box>
);
Expand Down
19 changes: 17 additions & 2 deletions src/components/Reports/Shared/HcmData/HCMData.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ query HcmData {
peopleGroupSupportType
assignmentStatus
assignmentCategory
boardCapException
isInternational
maritalStatus
}
mhaRequest {
currentApprovedOverallAmount
lastUpdatedDate
currentApprovedAmountForStaff
lastUpdatedDate
}
exceptionSalaryCap {
amount
Expand All @@ -39,9 +42,21 @@ query HcmData {
currentRothContributionPercentage
maximumContributionLimit
}
yearToDate {
additionalSalaryPaymentsReceived
bonus
fourOThreeBLimit
fourOThreeBMakeUpLimitAmount
grossEarnings
lastRegularPaymentDate
postTaxFourOThreeBContributions
preTaxFourOThreeBContributions
rothFourOThreeBContributions
taxableDeductions
}
currentSalary {
lastUpdated
grossSalaryAmount
lastUpdated
}
}
}
12 changes: 12 additions & 0 deletions src/components/Reports/Shared/HcmData/mockData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ const noMhaAndNoException: HcmDataQuery['hcm'][0] = {
lastUpdated: '2023-04-01',
grossSalaryAmount: 60000,
},
yearToDate: {
additionalSalaryPaymentsReceived: 0,
bonus: 0,
fourOThreeBLimit: 19500,
fourOThreeBMakeUpLimitAmount: 0,
grossEarnings: 20000,
lastRegularPaymentDate: '2023-05-01',
postTaxFourOThreeBContributions: 2000,
preTaxFourOThreeBContributions: 3000,
rothFourOThreeBContributions: 1000,
taxableDeductions: 500,
},
};

const mhaAndNoException: HcmDataQuery['hcm'][0] = {
Expand Down
Loading