Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle blocked copilot and Expensify card flows gracefully #52103

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
a047d8a
show DelegateNoAccessModal for restricted delegate actions
ChavdaSachin Nov 6, 2024
b0465b9
Merge remote-tracking branch 'upstream/main' into fix-50796/Handle-bl…
ChavdaSachin Nov 7, 2024
f33b43f
LegalNamePage
ChavdaSachin Nov 13, 2024
cd5a453
DOB
ChavdaSachin Nov 13, 2024
61b69c1
PhoneNumber
ChavdaSachin Nov 13, 2024
feff84b
Address
ChavdaSachin Nov 13, 2024
7cadc0f
Wallet
ChavdaSachin Nov 13, 2024
285b061
cleanup
ChavdaSachin Nov 13, 2024
617282c
Switch To OD
ChavdaSachin Nov 13, 2024
7adfac1
Payment method menuItems
ChavdaSachin Nov 13, 2024
c1b09af
Payment method menuitems
ChavdaSachin Nov 13, 2024
6b74659
Delegate menu items
ChavdaSachin Nov 13, 2024
c095972
Dependent cleanup
ChavdaSachin Nov 13, 2024
cb314b3
SubscriptionPage
ChavdaSachin Nov 13, 2024
85da30a
lint
ChavdaSachin Nov 13, 2024
c6a2529
lint
ChavdaSachin Nov 13, 2024
3906089
Merge remote-tracking branch 'upstream/main' into fix-50796/Handle-bl…
ChavdaSachin Nov 13, 2024
ead9296
lint
ChavdaSachin Nov 13, 2024
853ccde
cleanup
ChavdaSachin Nov 13, 2024
887356c
DelegateNoAccessWrapper initial implementation
ChavdaSachin Nov 19, 2024
d3eb43f
Merge main
ChavdaSachin Nov 19, 2024
5df885f
Add DelegateNoAccessWrapper
ChavdaSachin Nov 20, 2024
08e7be3
Wrapper Use Guidelines
ChavdaSachin Nov 20, 2024
96d6216
Merge Main
ChavdaSachin Nov 20, 2024
4d1b7e1
Cleanup and lint
ChavdaSachin Nov 20, 2024
5fa58ff
Merge main and some minor changes
ChavdaSachin Nov 23, 2024
e68f388
Cleanup
ChavdaSachin Nov 23, 2024
a7d8cb3
Revert accidental chages to ios/Podfile.lock
ChavdaSachin Nov 23, 2024
43c3e6c
Show Not So Fast.. modal on clicking private profile credentials
ChavdaSachin Nov 25, 2024
79792d5
lint and some cleanup
ChavdaSachin Nov 25, 2024
bfe6d6e
prettier
ChavdaSachin Nov 25, 2024
97c9677
disable single execution for special case
ChavdaSachin Nov 28, 2024
72d0ba3
refactor DelegateNoAccessModal
ChavdaSachin Dec 3, 2024
993841d
Restrict actions for copilot - issue Expensify card, add company card…
ChavdaSachin Dec 3, 2024
9a6492d
Merge Main
ChavdaSachin Dec 3, 2024
fe02315
Restrict Choose-bank-account-step for copilot and lint
ChavdaSachin Dec 4, 2024
1cd8fa5
Merge Main
ChavdaSachin Dec 4, 2024
b720e98
Prettier
ChavdaSachin Dec 4, 2024
edfbbcd
Merge Main
ChavdaSachin Dec 4, 2024
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
6 changes: 6 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4500,6 +4500,12 @@ const CONST = {
ALL: 'all',
SUBMITTER: 'submitter',
},
DELEGATE: {
DENIED_ACCESS_VARIANTS: {
DELEGATE: 'delegate',
SUBMITTER: 'submitter',
},
},
DELEGATE_ROLE_HELPDOT_ARTICLE_LINK: 'https://help.expensify.com/expensify-classic/hubs/copilots-and-delegates/',
STRIPE_GBP_AUTH_STATUSES: {
SUCCEEDED: 'succeeded',
Expand Down
6 changes: 5 additions & 1 deletion src/components/AddressForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ type AddressFormProps = {

/** A unique Onyx key identifying the form */
formID: typeof ONYXKEYS.FORMS.GET_PHYSICAL_CARD_FORM | typeof ONYXKEYS.FORMS.HOME_ADDRESS_FORM;

/** Whether or not validation should be skipped */
skipValidation?: boolean;
};

function AddressForm({
Expand All @@ -70,6 +73,7 @@ function AddressForm({
street2 = '',
submitButtonText = '',
zip = '',
skipValidation = false,
}: AddressFormProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
Expand Down Expand Up @@ -139,7 +143,7 @@ function AddressForm({
<FormProvider
style={[styles.flexGrow1, styles.mh5]}
formID={formID}
validate={validator}
validate={skipValidation ? undefined : validator}
onSubmit={onSubmit}
submitButtonText={submitButtonText}
enabledWhenOffline
Expand Down
8 changes: 4 additions & 4 deletions src/components/DelegateNoAccessModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import useDelegateUserDetails from '@hooks/useDelegateUserDetails';
import useLocalize from '@hooks/useLocalize';
import CONST from '@src/CONST';
import ConfirmModal from './ConfirmModal';
Expand All @@ -8,14 +9,13 @@ import TextLink from './TextLink';
type DelegateNoAccessModalProps = {
isNoDelegateAccessMenuVisible: boolean;
onClose: () => void;
delegatorEmail: string;
};

export default function DelegateNoAccessModal({isNoDelegateAccessMenuVisible = false, onClose, delegatorEmail = ''}: DelegateNoAccessModalProps) {
export default function DelegateNoAccessModal({isNoDelegateAccessMenuVisible = false, onClose}: DelegateNoAccessModalProps) {
const {translate} = useLocalize();
const noDelegateAccessPromptStart = translate('delegate.notAllowedMessageStart', {accountOwnerEmail: delegatorEmail});
const {delegatorEmail} = useDelegateUserDetails();
const noDelegateAccessPromptStart = translate('delegate.notAllowedMessageStart', {accountOwnerEmail: delegatorEmail ?? ''});
const noDelegateAccessHyperLinked = translate('delegate.notAllowedMessageHyperLinked');

const delegateNoAccessPrompt = (
<Text>
{noDelegateAccessPromptStart}
Expand Down
71 changes: 71 additions & 0 deletions src/components/DelegateNoAccessWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import {OnyxEntry, useOnyx} from 'react-native-onyx';

Check failure on line 2 in src/components/DelegateNoAccessWrapper.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Imports "OnyxEntry" are only used as type

Check failure on line 2 in src/components/DelegateNoAccessWrapper.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Imports "OnyxEntry" are only used as type
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import AccountUtils from '@libs/AccountUtils';
import Navigation from '@libs/Navigation/Navigation';
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';

Check failure on line 9 in src/components/DelegateNoAccessWrapper.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'ROUTES' is defined but never used

Check failure on line 9 in src/components/DelegateNoAccessWrapper.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

'ROUTES' is defined but never used
import {Account} from '@src/types/onyx';

Check failure on line 10 in src/components/DelegateNoAccessWrapper.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

All imports in the declaration are only used as types. Use `import type`

Check failure on line 10 in src/components/DelegateNoAccessWrapper.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

All imports in the declaration are only used as types. Use `import type`
import callOrReturn from '@src/types/utils/callOrReturn';
import {FullPageNotFoundViewProps} from './BlockingViews/FullPageNotFoundView';

Check failure on line 12 in src/components/DelegateNoAccessWrapper.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

All imports in the declaration are only used as types. Use `import type`

Check failure on line 12 in src/components/DelegateNoAccessWrapper.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

All imports in the declaration are only used as types. Use `import type`

const DENIED_ACCESS_VARIANTS = {
[CONST.DELEGATE.DENIED_ACCESS_VARIANTS.DELEGATE]: (account: OnyxEntry<Account>) => isDelegate(account),
[CONST.DELEGATE.DENIED_ACCESS_VARIANTS.SUBMITTER]: (account: OnyxEntry<Account>) => isSubmitter(account),
} as const satisfies Record<string, (account: OnyxEntry<Account>) => boolean>;

type AccessDeniedVariants = keyof typeof DENIED_ACCESS_VARIANTS;

type DelegateNoAccessWrapperProps = {
accessDeniedVariants?: AccessDeniedVariants[];
FullPageNotFoundViewProps?: FullPageNotFoundViewProps;
shouldShowFullScreenFallback?: boolean;
children: (() => React.ReactNode) | React.ReactNode;
};

type PageNotFoundFallbackProps = {
shouldShowFullScreenFallback?: boolean;
};

function isDelegate(account: OnyxEntry<Account>) {
const isActingAsDelegate = !!account?.delegatedAccess?.delegate;
return isActingAsDelegate;
}

function isSubmitter(account: OnyxEntry<Account>) {
const isDelegateOnlySubmitter = AccountUtils.isDelegateOnlySubmitter(account);
return isDelegateOnlySubmitter;
}

function PageNotFoundFallback({shouldShowFullScreenFallback}: PageNotFoundFallbackProps) {

Check failure on line 42 in src/components/DelegateNoAccessWrapper.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Do not use negated variable names

Check failure on line 42 in src/components/DelegateNoAccessWrapper.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Do not use negated variable names
const {shouldUseNarrowLayout} = useResponsiveLayout();
return (
<NotFoundPage
shouldForceFullScreen={shouldShowFullScreenFallback}
onBackButtonPress={() => {
if (shouldShowFullScreenFallback) {
Navigation.dismissModal();
return;
}
Navigation.goBack();
}}
shouldShowBackButton={!shouldShowFullScreenFallback ? shouldUseNarrowLayout : undefined}
/>
);
}

function DelegateNoAccessWrapper({accessDeniedVariants = [], shouldShowFullScreenFallback, ...props}: DelegateNoAccessWrapperProps) {
const [account] = useOnyx(ONYXKEYS.ACCOUNT);
const isPageAccessDenied = accessDeniedVariants.reduce((acc, variant) => {
const accessDeniedFunction = DENIED_ACCESS_VARIANTS[variant];
return acc || accessDeniedFunction(account);
}, false);
if (isPageAccessDenied) {
return <PageNotFoundFallback shouldShowFullScreenFallback={shouldShowFullScreenFallback} />;
}
return callOrReturn(props.children);
}

export default DelegateNoAccessWrapper;
2 changes: 1 addition & 1 deletion src/components/Form/FormProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type FormProviderProps<TFormID extends OnyxFormKey = OnyxFormKey> = FormProps<TF
children: ((props: {inputValues: FormOnyxValues<TFormID>}) => ReactNode) | ReactNode;

/** Callback to validate the form */
validate?: (values: FormOnyxValues<TFormID>) => FormInputErrors<TFormID>;
validate?: (values: FormOnyxValues<TFormID>) => FormInputErrors<TFormID> | undefined;

/** Should validate function be called when input loose focus */
shouldValidateOnBlur?: boolean;
Expand Down
21 changes: 19 additions & 2 deletions src/pages/AddressPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, {useCallback, useEffect, useState} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import {type OnyxEntry, useOnyx} from 'react-native-onyx';

Check failure on line 2 in src/pages/AddressPage.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Prefer using a top-level type-only import instead of inline type specifiers

Check failure on line 2 in src/pages/AddressPage.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Prefer using a top-level type-only import instead of inline type specifiers
import AddressForm from '@components/AddressForm';
import DelegateNoAccessModal from '@components/DelegateNoAccessModal';
import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
Expand Down Expand Up @@ -37,6 +38,17 @@
const [city, setCity] = useState(address?.city);
const [zipcode, setZipcode] = useState(address?.zip);

const [account] = useOnyx(ONYXKEYS.ACCOUNT);
const isActingAsDelegate = !!account?.delegatedAccess?.delegate;
const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false);

// For delegates, modifying legal address is a restricted action.
// So, on pressing submit, skip validation and show delegateNoAccessModal
const skipValidation = isActingAsDelegate;
const handleSubmit = (values: FormOnyxValues<typeof ONYXKEYS.FORMS.HOME_ADDRESS_FORM>) => {
isActingAsDelegate ? setIsNoDelegateAccessMenuVisible(true) : updateAddress(values);

Check failure on line 49 in src/pages/AddressPage.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Expected an assignment or function call and instead saw an expression

Check failure on line 49 in src/pages/AddressPage.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Expected an assignment or function call and instead saw an expression
};

useEffect(() => {
if (!address) {
return;
Expand Down Expand Up @@ -91,7 +103,7 @@
) : (
<AddressForm
formID={ONYXKEYS.FORMS.HOME_ADDRESS_FORM}
onSubmit={updateAddress}
onSubmit={handleSubmit}
submitButtonText={translate('common.save')}
city={city}
country={currentCountry}
Expand All @@ -100,8 +112,13 @@
street1={street1}
street2={street2}
zip={zipcode}
skipValidation={skipValidation}
/>
)}
<DelegateNoAccessModal
isNoDelegateAccessMenuVisible={isNoDelegateAccessMenuVisible}
onClose={() => setIsNoDelegateAccessMenuVisible(false)}
/>
</ScreenWrapper>
);
}
Expand Down
13 changes: 13 additions & 0 deletions src/pages/settings/InitialSettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import AccountSwitcher from '@components/AccountSwitcher';
import AccountSwitcherSkeletonView from '@components/AccountSwitcherSkeletonView';
import ConfirmModal from '@components/ConfirmModal';
import DelegateNoAccessModal from '@components/DelegateNoAccessModal';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import {InitialURLContext} from '@components/InitialURLContextProvider';
Expand Down Expand Up @@ -83,6 +84,10 @@
const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
const [privatePersonalDetails] = useOnyx(ONYXKEYS.PRIVATE_PERSONAL_DETAILS);

const [account] = useOnyx(ONYXKEYS.ACCOUNT);
const isActingAsDelegate = !!account?.delegatedAccess?.delegate;
const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false);

const network = useNetwork();
const theme = useTheme();
const styles = useThemeStyles();
Expand Down Expand Up @@ -242,6 +247,10 @@
}
: {
action() {
if (isActingAsDelegate) {
setIsNoDelegateAccessMenuVisible(true);
return;
}
resetExitSurveyForm(() => Navigation.navigate(ROUTES.SETTINGS_EXIT_SURVEY_REASON));
},
}),
Expand Down Expand Up @@ -270,7 +279,7 @@
},
],
};
}, [styles.pt4, signOut, setInitialURL]);

Check warning on line 282 in src/pages/settings/InitialSettingsPage.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

React Hook useMemo has a missing dependency: 'isActingAsDelegate'. Either include it or remove the dependency array

Check warning on line 282 in src/pages/settings/InitialSettingsPage.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

React Hook useMemo has a missing dependency: 'isActingAsDelegate'. Either include it or remove the dependency array

/**
* Retuns JSX.Element with menu items
Expand Down Expand Up @@ -435,6 +444,10 @@
onCancel={() => toggleSignoutConfirmModal(false)}
/>
</ScrollView>
<DelegateNoAccessModal
isNoDelegateAccessMenuVisible={isNoDelegateAccessMenuVisible}
onClose={() => setIsNoDelegateAccessMenuVisible(false)}
/>
</ScreenWrapper>
);
}
Expand Down
2 changes: 0 additions & 2 deletions src/pages/settings/Profile/Contacts/ContactMethodsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
import Text from '@components/Text';
import useDelegateUserDetails from '@hooks/useDelegateUserDetails';

Check failure on line 16 in src/pages/settings/Profile/Contacts/ContactMethodsPage.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'useDelegateUserDetails' is defined but never used

Check failure on line 16 in src/pages/settings/Profile/Contacts/ContactMethodsPage.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

'useDelegateUserDetails' is defined but never used
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
Expand All @@ -36,7 +36,6 @@
const [account] = useOnyx(ONYXKEYS.ACCOUNT);
const isActingAsDelegate = !!account?.delegatedAccess?.delegate;
const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false);
const {delegatorEmail} = useDelegateUserDetails();

// Sort the login names by placing the one corresponding to the default contact method as the first item before displaying the contact methods.
// The default contact method is determined by checking against the session email (the current login).
Expand Down Expand Up @@ -132,7 +131,6 @@
<DelegateNoAccessModal
isNoDelegateAccessMenuVisible={isNoDelegateAccessMenuVisible}
onClose={() => setIsNoDelegateAccessMenuVisible(false)}
delegatorEmail={delegatorEmail ?? ''}
/>
</ScreenWrapper>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import React, {useCallback, useEffect, useRef, useState} from 'react';
import {View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import DelegateNoAccessWrapper from '@components/DelegateNoAccessWrapper';
import DotIndicatorMessage from '@components/DotIndicatorMessage';
import FormProvider from '@components/Form/FormProvider';
import InputWrapper from '@components/Form/InputWrapper';
Expand All @@ -21,7 +22,7 @@
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
import {addSMSDomainIfPhoneNumber} from '@libs/PhoneNumber';
import * as UserUtils from '@libs/UserUtils';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';

Check failure on line 25 in src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'AccessOrNotFoundWrapper' is defined but never used

Check failure on line 25 in src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

'AccessOrNotFoundWrapper' is defined but never used
import * as User from '@userActions/User';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
Expand All @@ -43,7 +44,7 @@
const loginData = loginList?.[pendingContactAction?.contactMethod ?? contactMethod];
const validateLoginError = ErrorUtils.getLatestErrorField(loginData, 'addedLogin');
const [account] = useOnyx(ONYXKEYS.ACCOUNT);
const isActingAsDelegate = !!account?.delegatedAccess?.delegate;

Check failure on line 47 in src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'isActingAsDelegate' is assigned a value but never used

Check failure on line 47 in src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

'isActingAsDelegate' is assigned a value but never used

const navigateBackTo = route?.params?.backTo ?? ROUTES.SETTINGS_PROFILE;

Expand Down Expand Up @@ -110,7 +111,8 @@
}, [navigateBackTo]);

return (
<AccessOrNotFoundWrapper shouldBeBlocked={isActingAsDelegate}>
// <AccessOrNotFoundWrapper shouldBeBlocked={isActingAsDelegate}>
<DelegateNoAccessWrapper accessDeniedVariants={[CONST.DELEGATE.DENIED_ACCESS_VARIANTS.DELEGATE]}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DelegateNoAccessWrapper is wrapped within ScreenWrapper everywhere else except here. Any reason for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a mistake, It should be inside ScreenWrapper. Fixing...

<ScreenWrapper
onEntryTransitionEnd={() => loginInputRef.current?.focus()}
includeSafeAreaPaddingBottom={false}
Expand Down Expand Up @@ -174,7 +176,8 @@
description={translate('contacts.enterMagicCode', {contactMethod})}
/>
</ScreenWrapper>
</AccessOrNotFoundWrapper>
</DelegateNoAccessWrapper>
// </AccessOrNotFoundWrapper>
);
}

Expand Down
21 changes: 16 additions & 5 deletions src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {subYears} from 'date-fns';
import React, {useCallback} from 'react';
import React, {useCallback, useState} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import {useOnyx, withOnyx} from 'react-native-onyx';
import DatePicker from '@components/DatePicker';
import DelegateNoAccessModal from '@components/DelegateNoAccessModal';
import FormProvider from '@components/Form/FormProvider';
import InputWrapper from '@components/Form/InputWrapper';
import type {FormOnyxValues} from '@components/Form/types';
Expand All @@ -16,7 +17,7 @@ import * as ValidationUtils from '@libs/ValidationUtils';
import * as PersonalDetails from '@userActions/PersonalDetails';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import INPUT_IDS from '@src/types/form/DateOfBirthForm';
import INPUT_IDS, {DateOfBirthForm} from '@src/types/form/DateOfBirthForm';
import type {PrivatePersonalDetails} from '@src/types/onyx';

type DateOfBirthPageOnyxProps = {
Expand All @@ -30,6 +31,9 @@ type DateOfBirthPageProps = DateOfBirthPageOnyxProps;
function DateOfBirthPage({privatePersonalDetails, isLoadingApp = true}: DateOfBirthPageProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const [account] = useOnyx(ONYXKEYS.ACCOUNT);
const isActingAsDelegate = !!account?.delegatedAccess?.delegate;
const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false);

/**
* @returns An object containing the errors for each inputID
Expand All @@ -48,6 +52,13 @@ function DateOfBirthPage({privatePersonalDetails, isLoadingApp = true}: DateOfBi

return errors;
}, []);
// For delegates, modifying legal DOB is a restricted action.
// So, on pressing submit, skip validation and show delegateNoAccessModal

const skipValidation = isActingAsDelegate;
const handleSubmit = (DOB: DateOfBirthForm) => {
isActingAsDelegate ? setIsNoDelegateAccessMenuVisible(true) : PersonalDetails.updateDateOfBirth(DOB);
};

return (
<ScreenWrapper
Expand All @@ -64,8 +75,8 @@ function DateOfBirthPage({privatePersonalDetails, isLoadingApp = true}: DateOfBi
<FormProvider
style={[styles.flexGrow1, styles.ph5]}
formID={ONYXKEYS.FORMS.DATE_OF_BIRTH_FORM}
validate={validate}
onSubmit={PersonalDetails.updateDateOfBirth}
validate={skipValidation ? undefined : validate}
onSubmit={handleSubmit}
submitButtonText={translate('common.save')}
enabledWhenOffline
>
Expand Down
25 changes: 20 additions & 5 deletions src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, {useCallback} from 'react';
import React, {useCallback, useState} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import {useOnyx, withOnyx} from 'react-native-onyx';
import DelegateNoAccessModal from '@components/DelegateNoAccessModal';
import FormProvider from '@components/Form/FormProvider';
import InputWrapper from '@components/Form/InputWrapper';
import type {FormOnyxValues} from '@components/Form/types';
Expand Down Expand Up @@ -33,12 +34,14 @@ type LegalNamePageProps = LegalNamePageOnyxProps;
const updateLegalName = (values: PrivatePersonalDetails) => {
PersonalDetails.updateLegalName(values.legalFirstName?.trim() ?? '', values.legalLastName?.trim() ?? '');
};

function LegalNamePage({privatePersonalDetails, isLoadingApp = true}: LegalNamePageProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const legalFirstName = privatePersonalDetails?.legalFirstName ?? '';
const legalLastName = privatePersonalDetails?.legalLastName ?? '';
const [account] = useOnyx(ONYXKEYS.ACCOUNT);
const isActingAsDelegate = !!account?.delegatedAccess?.delegate;
const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false);

const validate = useCallback(
(values: FormOnyxValues<typeof ONYXKEYS.FORMS.LEGAL_NAME_FORM>) => {
Expand Down Expand Up @@ -83,6 +86,14 @@ function LegalNamePage({privatePersonalDetails, isLoadingApp = true}: LegalNameP
[translate],
);

// For delegates, modifying legal Name is a restricted action.
// So, on pressing submit, skip validation and show delegateNoAccessModal

const skipValidation = isActingAsDelegate;
const handleSubmit = (values: PrivatePersonalDetails) => {
isActingAsDelegate ? setIsNoDelegateAccessMenuVisible(true) : updateLegalName(values);
};

return (
<ScreenWrapper
includeSafeAreaPaddingBottom={false}
Expand All @@ -99,8 +110,8 @@ function LegalNamePage({privatePersonalDetails, isLoadingApp = true}: LegalNameP
<FormProvider
style={[styles.flexGrow1, styles.ph5]}
formID={ONYXKEYS.FORMS.LEGAL_NAME_FORM}
validate={validate}
onSubmit={updateLegalName}
validate={skipValidation ? undefined : validate}
onSubmit={handleSubmit}
submitButtonText={translate('common.save')}
enabledWhenOffline
>
Expand Down Expand Up @@ -130,6 +141,10 @@ function LegalNamePage({privatePersonalDetails, isLoadingApp = true}: LegalNameP
</View>
</FormProvider>
)}
<DelegateNoAccessModal
isNoDelegateAccessMenuVisible={isNoDelegateAccessMenuVisible}
onClose={() => setIsNoDelegateAccessMenuVisible(false)}
/>
</ScreenWrapper>
);
}
Expand Down
Loading
Loading