Skip to content

Commit

Permalink
Merge pull request #49452 from shubham1206agra/missing-details-flow-p…
Browse files Browse the repository at this point in the history
…art2

Refactor on missing details flow
  • Loading branch information
mountiny authored Oct 2, 2024
2 parents 3946b22 + 9e424cb commit 05dcac8
Show file tree
Hide file tree
Showing 16 changed files with 639 additions and 388 deletions.
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1840,6 +1840,7 @@ const CONST = {
DATE_OF_BIRTH: 1,
ADDRESS: 2,
PHONE_NUMBER: 3,
CONFIRM: 4,
},
INDEX_LIST: ['1', '2', '3', '4'],
},
Expand Down
5 changes: 1 addition & 4 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1275,10 +1275,7 @@ const ROUTES = {
route: 'restricted-action/workspace/:policyID',
getRoute: (policyID: string) => `restricted-action/workspace/${policyID}` as const,
},
MISSING_PERSONAL_DETAILS: {
route: 'missing-personal-details/workspace/:policyID',
getRoute: (policyID: string) => `missing-personal-details/workspace/${policyID}` as const,
},
MISSING_PERSONAL_DETAILS: 'missing-personal-details',
POLICY_ACCOUNTING_NETSUITE_SUBSIDIARY_SELECTOR: {
route: 'settings/workspaces/:policyID/accounting/netsuite/subsidiary-selector',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/netsuite/subsidiary-selector` as const,
Expand Down
13 changes: 3 additions & 10 deletions src/components/ReportActionItem/IssueCardMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,15 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject';

type IssueCardMessageProps = {
action: OnyxEntry<ReportAction>;

policyID: string | undefined;
};

function IssueCardMessage({action, policyID}: IssueCardMessageProps) {
function IssueCardMessage({action}: IssueCardMessageProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const [privatePersonalDetails] = useOnyx(ONYXKEYS.PRIVATE_PERSONAL_DETAILS);
const [session] = useOnyx(ONYXKEYS.SESSION);

const assigneeAccountID = (action?.originalMessage as IssueNewCardOriginalMessage)?.assigneeAccountID;
const assigneeAccountID = (ReportActionsUtils.getOriginalMessage(action) as IssueNewCardOriginalMessage)?.assigneeAccountID;

const missingDetails =
!privatePersonalDetails?.legalFirstName ||
Expand All @@ -45,12 +43,7 @@ function IssueCardMessage({action, policyID}: IssueCardMessageProps) {
<RenderHTML html={`<muted-text>${ReportActionsUtils.getCardIssuedMessage(action, true)}</muted-text>`} />
{shouldShowAddMissingDetailsButton && (
<Button
onPress={() => {
if (!policyID) {
return;
}
Navigation.navigate(ROUTES.MISSING_PERSONAL_DETAILS.getRoute(policyID));
}}
onPress={() => Navigation.navigate(ROUTES.MISSING_PERSONAL_DETAILS)}
success
style={[styles.alignSelfStart, styles.mt3]}
text={translate('workspace.expensifyCard.addShippingDetails')}
Expand Down
27 changes: 27 additions & 0 deletions src/hooks/usePersonalDetailsFormSubmit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type {FormOnyxKeys} from '@components/Form/types';
import type {OnyxFormKey} from '@src/ONYXKEYS';
import ONYXKEYS from '@src/ONYXKEYS';
import useStepFormSubmit from './useStepFormSubmit';
import type {SubStepProps} from './useSubStep/types';

type UsePersonalDetailsFormSubmitParams = Pick<SubStepProps, 'onNext'> & {
formId?: OnyxFormKey;
fieldIds: Array<FormOnyxKeys<typeof ONYXKEYS.FORMS.PERSONAL_DETAILS_FORM>>;
shouldSaveDraft: boolean;
};

/**
* Hook for handling submit method in Missing Personal Details substeps.
* When user is in editing mode, we should save values only when user confirms the change
* @param onNext - callback
* @param fieldIds - field IDs for particular step
* @param shouldSaveDraft - if we should save draft values
*/
export default function usePersonalDetailsFormSubmit({onNext, fieldIds, shouldSaveDraft}: UsePersonalDetailsFormSubmitParams) {
return useStepFormSubmit<typeof ONYXKEYS.FORMS.PERSONAL_DETAILS_FORM>({
formId: ONYXKEYS.FORMS.PERSONAL_DETAILS_FORM,
onNext,
fieldIds,
shouldSaveDraft,
});
}
2 changes: 1 addition & 1 deletion src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1182,7 +1182,7 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
},
[SCREENS.RIGHT_MODAL.MISSING_PERSONAL_DETAILS]: {
screens: {
[SCREENS.MISSING_PERSONAL_DETAILS_ROOT]: ROUTES.MISSING_PERSONAL_DETAILS.route,
[SCREENS.MISSING_PERSONAL_DETAILS_ROOT]: ROUTES.MISSING_PERSONAL_DETAILS,
},
},
[SCREENS.RIGHT_MODAL.DEBUG]: {
Expand Down
4 changes: 1 addition & 3 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1496,9 +1496,7 @@ type RestrictedActionParamList = {
};

type MissingPersonalDetailsParamList = {
[SCREENS.MISSING_PERSONAL_DETAILS_ROOT]: {
policyID: string;
};
[SCREENS.MISSING_PERSONAL_DETAILS_ROOT]: undefined;
};

type DebugParamList = {
Expand Down
120 changes: 120 additions & 0 deletions src/pages/MissingPersonalDetails/MissingPersonalDetailsContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import React, {useCallback, useMemo, useRef} from 'react';
import type {ForwardedRef} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import InteractiveStepSubHeader from '@components/InteractiveStepSubHeader';
import type {InteractiveStepSubHeaderHandle} from '@components/InteractiveStepSubHeader';
import ScreenWrapper from '@components/ScreenWrapper';
import useLocalize from '@hooks/useLocalize';
import useSubStep from '@hooks/useSubStep';
import useThemeStyles from '@hooks/useThemeStyles';
import * as FormActions from '@libs/actions/FormActions';
import Navigation from '@libs/Navigation/Navigation';
import * as PersonalDetails from '@userActions/PersonalDetails';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {PersonalDetailsForm} from '@src/types/form';
import type {CardList, PrivatePersonalDetails} from '@src/types/onyx';
import Address from './substeps/Address';
import Confirmation from './substeps/Confirmation';
import DateOfBirth from './substeps/DateOfBirth';
import LegalName from './substeps/LegalName';
import PhoneNumber from './substeps/PhoneNumber';
import type {CustomSubStepProps} from './types';
import {getInitialSubstep, getSubstepValues} from './utils';

type MissingPersonalDetailsContentProps = {
privatePersonalDetails: OnyxEntry<PrivatePersonalDetails>;
cardList: OnyxEntry<CardList>;
draftValues: OnyxEntry<PersonalDetailsForm>;
};

const formSteps = [LegalName, DateOfBirth, Address, PhoneNumber, Confirmation];

function MissingPersonalDetailsContent({privatePersonalDetails, cardList, draftValues}: MissingPersonalDetailsContentProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const ref: ForwardedRef<InteractiveStepSubHeaderHandle> = useRef(null);

const values = useMemo(() => getSubstepValues(privatePersonalDetails, draftValues), [privatePersonalDetails, draftValues]);

const startFrom = useMemo(() => getInitialSubstep(values), [values]);

const firstUnissuedCard = useMemo(() => Object.values(cardList ?? {}).find((card) => card.state === CONST.EXPENSIFY_CARD.STATE.STATE_NOT_ISSUED), [cardList]);

const handleFinishStep = useCallback(() => {
if (!values) {
return;
}
PersonalDetails.updatePersonalDetailsAndShipExpensifyCard(values, firstUnissuedCard?.cardID ?? 0);
FormActions.clearDraftValues(ONYXKEYS.FORMS.PERSONAL_DETAILS_FORM);
Navigation.goBack();
}, [firstUnissuedCard?.cardID, values]);

const {
componentToRender: SubStep,
isEditing,
nextScreen,
prevScreen,
screenIndex,
moveTo,
goToTheLastStep,
} = useSubStep<CustomSubStepProps>({bodyContent: formSteps, startFrom, onFinished: handleFinishStep});

const handleBackButtonPress = () => {
if (isEditing) {
goToTheLastStep();
return;
}

// Clicking back on the first screen should dismiss the modal
if (screenIndex === CONST.MISSING_PERSONAL_DETAILS_INDEXES.MAPPING.LEGAL_NAME) {
FormActions.clearDraftValues(ONYXKEYS.FORMS.PERSONAL_DETAILS_FORM);
Navigation.goBack();
return;
}
ref.current?.movePrevious();
prevScreen();
};

const handleNextScreen = useCallback(() => {
if (isEditing) {
goToTheLastStep();
return;
}
ref.current?.moveNext();
nextScreen();
}, [goToTheLastStep, isEditing, nextScreen]);

return (
<ScreenWrapper
includeSafeAreaPaddingBottom={false}
shouldEnableMaxHeight
testID={MissingPersonalDetailsContent.displayName}
>
<HeaderWithBackButton
title={translate('workspace.expensifyCard.addShippingDetails')}
onBackButtonPress={handleBackButtonPress}
/>
<View style={[styles.ph5, styles.mb3, styles.mt3, {height: CONST.NETSUITE_FORM_STEPS_HEADER_HEIGHT}]}>
<InteractiveStepSubHeader
ref={ref}
startStepIndex={startFrom}
stepNames={CONST.MISSING_PERSONAL_DETAILS_INDEXES.INDEX_LIST}
/>
</View>
<SubStep
isEditing={isEditing}
onNext={handleNextScreen}
onMove={moveTo}
screenIndex={screenIndex}
personalDetailsValues={values}
/>
</ScreenWrapper>
);
}

MissingPersonalDetailsContent.displayName = 'MissingPersonalDetailsContent';

export default MissingPersonalDetailsContent;
Loading

0 comments on commit 05dcac8

Please sign in to comment.