Skip to content

Commit e9b6204

Browse files
authored
Merge pull request #57849 from callstack-internal/feat/step-6-logic
[NO QA] feat: Non USD VBA flow - step 6 logic
2 parents a4439ff + c5fa095 commit e9b6204

File tree

11 files changed

+173
-35
lines changed

11 files changed

+173
-35
lines changed

src/languages/en.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2710,11 +2710,14 @@ const translations = {
27102710
regulationRequiresUs: 'Regulation requires us to verify the identity of any individual who owns more than 25% of the business.',
27112711
iAmAuthorized: 'I am authorized to use the business bank account for business spend.',
27122712
iCertify: 'I certify that the information provided is true and accurate.',
2713-
termsAndConditions: 'terms and conditions.',
2713+
termsAndConditions: 'terms and conditions',
27142714
accept: 'Accept and add bank account',
2715+
iConsentToThe: 'I consent to the',
2716+
privacyNotice: 'privacy notice',
27152717
error: {
27162718
authorized: 'You must be a controlling officer with authorization to operate the business bank account',
27172719
certify: 'Please certify that the information is true and accurate',
2720+
consent: 'Please consent to the privacy notice',
27182721
},
27192722
},
27202723
finishStep: {

src/languages/es.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2733,11 +2733,14 @@ const translations = {
27332733
regulationRequiresUs: 'La normativa requiere que verifiquemos la identidad de cualquier individuo que posea más del 25% del negocio.',
27342734
iAmAuthorized: 'Estoy autorizado para usar la cuenta bancaria para gastos del negocio.',
27352735
iCertify: 'Certifico que la información proporcionada es verdadera y correcta.',
2736-
termsAndConditions: 'términos y condiciones.',
2736+
termsAndConditions: 'términos y condiciones',
27372737
accept: 'Agregar y aceptar cuenta bancaria',
2738+
iConsentToThe: 'Doy mi consentimiento para el',
2739+
privacyNotice: 'aviso de privacidad',
27382740
error: {
27392741
authorized: 'Debe ser un funcionario controlador con autorización para operar la cuenta bancaria comercial',
27402742
certify: 'Por favor certifique que la información es verdadera y exacta',
2743+
consent: 'Por favor, acepte el aviso de privacidad',
27412744
},
27422745
},
27432746
finishStep: {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
type FinishCorpayBankAccountOnboardingParams = {
2+
inputs: string;
3+
bankAccountID: number;
4+
};
5+
6+
export default FinishCorpayBankAccountOnboardingParams;

src/libs/API/parameters/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,3 +388,4 @@ export type {default as SetPolicyProhibitedExpensesParams} from './SetPolicyProh
388388
export type {default as GetEmphemeralTokenParams} from './GetEmphemeralTokenParams';
389389
export type {default as CreateAppleDigitalWalletParams} from './CreateAppleDigitalWalletParams';
390390
export type {default as CompleteConciergeCallParams} from './CompleteConciergeCallParams';
391+
export type {default as FinishCorpayBankAccountOnboardingParams} from './FinishCorpayBankAccountOnboardingParams';

src/libs/API/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ const WRITE_COMMANDS = {
468468
CHANGE_TRANSACTIONS_REPORT: 'ChangeTransactionsReport',
469469
SEND_RECAP_IN_ADMINS_ROOM: 'SendRecapInAdminsRoom',
470470
COMPLETE_CONCIERGE_CALL: 'CompleteConciergeCall',
471+
FINISH_CORPAY_BANK_ACCOUNT_ONBOARDING: 'FinishCorpayBankAccountOnboarding',
471472
} as const;
472473

473474
type WriteCommand = ValueOf<typeof WRITE_COMMANDS>;
@@ -811,6 +812,7 @@ type WriteCommandParameters = {
811812
[WRITE_COMMANDS.SEND_RECAP_IN_ADMINS_ROOM]: Parameters.SendRecapInAdminsRoomParams;
812813
[WRITE_COMMANDS.SET_POLICY_PROHIBITED_EXPENSES]: Parameters.SetPolicyProhibitedExpensesParams;
813814
[WRITE_COMMANDS.COMPLETE_CONCIERGE_CALL]: Parameters.CompleteConciergeCallParams;
815+
[WRITE_COMMANDS.FINISH_CORPAY_BANK_ACCOUNT_ONBOARDING]: Parameters.FinishCorpayBankAccountOnboardingParams;
814816

815817
[WRITE_COMMANDS.DELETE_MONEY_REQUEST_ON_SEARCH]: Parameters.DeleteMoneyRequestOnSearchParams;
816818
[WRITE_COMMANDS.HOLD_MONEY_REQUEST_ON_SEARCH]: Parameters.HoldMoneyRequestOnSearchParams;

src/libs/actions/BankAccounts.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
BankAccountHandlePlaidErrorParams,
88
ConnectBankAccountParams,
99
DeletePaymentBankAccountParams,
10+
FinishCorpayBankAccountOnboardingParams,
1011
OpenReimbursementAccountPageParams,
1112
SaveCorpayOnboardingBeneficialOwnerParams,
1213
ValidateBankAccountWithTransactionsParams,
@@ -585,6 +586,44 @@ function saveCorpayOnboardingDirectorInformation(parameters: SaveCorpayOnboardin
585586
return API.write(WRITE_COMMANDS.SAVE_CORPAY_ONBOARDING_DIRECTOR_INFORMATION, parameters, onyxData);
586587
}
587588

589+
function finishCorpayBankAccountOnboarding(parameters: FinishCorpayBankAccountOnboardingParams) {
590+
const onyxData: OnyxData = {
591+
optimisticData: [
592+
{
593+
onyxMethod: Onyx.METHOD.MERGE,
594+
key: ONYXKEYS.REIMBURSEMENT_ACCOUNT,
595+
value: {
596+
isFinishingCorpayBankAccountOnboarding: true,
597+
errors: null,
598+
},
599+
},
600+
],
601+
successData: [
602+
{
603+
onyxMethod: Onyx.METHOD.MERGE,
604+
key: ONYXKEYS.REIMBURSEMENT_ACCOUNT,
605+
value: {
606+
isFinishingCorpayBankAccountOnboarding: false,
607+
isSuccess: true,
608+
},
609+
},
610+
],
611+
failureData: [
612+
{
613+
onyxMethod: Onyx.METHOD.MERGE,
614+
key: ONYXKEYS.REIMBURSEMENT_ACCOUNT,
615+
value: {
616+
isFinishingCorpayBankAccountOnboarding: false,
617+
isSuccess: false,
618+
errors: getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'),
619+
},
620+
},
621+
],
622+
};
623+
624+
return API.write(WRITE_COMMANDS.FINISH_CORPAY_BANK_ACCOUNT_ONBOARDING, parameters, onyxData);
625+
}
626+
588627
function clearReimbursementAccount() {
589628
Onyx.set(ONYXKEYS.REIMBURSEMENT_ACCOUNT, null);
590629
}
@@ -609,6 +648,10 @@ function clearReimbursementAccoungSaveCorplayOnboardingDirectorInformation() {
609648
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {isSuccess: null, isSavingCorpayOnboardingDirectorInformation: null});
610649
}
611650

651+
function clearReimbursementAccountFinishCorpayBankAccountOnboarding() {
652+
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {isSuccess: null, isFinishingCorpayBankAccountOnboarding: null});
653+
}
654+
612655
/**
613656
* Function to display and fetch data for Reimbursement Account step
614657
* @param stepToOpen - current step to open
@@ -897,6 +940,8 @@ export {
897940
clearReimbursementAccountSaveCorpayOnboardingBeneficialOwners,
898941
clearReimbursementAccoungSaveCorplayOnboardingDirectorInformation,
899942
clearCorpayBankAccountFields,
943+
finishCorpayBankAccountOnboarding,
944+
clearReimbursementAccountFinishCorpayBankAccountOnboarding,
900945
};
901946

902947
export type {BusinessAddress, PersonalAddress};

src/pages/ReimbursementAccount/NonUSD/Agreements/index.tsx

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import type {ComponentType} from 'react';
2-
import React from 'react';
2+
import React, {useEffect, useMemo} from 'react';
3+
import {useOnyx} from 'react-native-onyx';
34
import InteractiveStepWrapper from '@components/InteractiveStepWrapper';
45
import useLocalize from '@hooks/useLocalize';
56
import useSubStep from '@hooks/useSubStep';
67
import type {SubStepProps} from '@hooks/useSubStep/types';
8+
import getSubStepValues from '@pages/ReimbursementAccount/utils/getSubStepValues';
9+
import {clearReimbursementAccountFinishCorpayBankAccountOnboarding, finishCorpayBankAccountOnboarding} from '@userActions/BankAccounts';
710
import CONST from '@src/CONST';
11+
import ONYXKEYS from '@src/ONYXKEYS';
12+
import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
813
import Confirmation from './subSteps/Confirmation';
914

1015
type AgreementsProps = {
@@ -17,13 +22,48 @@ type AgreementsProps = {
1722

1823
const bodyContent: Array<ComponentType<SubStepProps>> = [Confirmation];
1924

25+
const INPUT_KEYS = {
26+
PROVIDE_TRUTHFUL_INFORMATION: INPUT_IDS.ADDITIONAL_DATA.CORPAY.PROVIDE_TRUTHFUL_INFORMATION,
27+
AGREE_TO_TERMS_AND_CONDITIONS: INPUT_IDS.ADDITIONAL_DATA.CORPAY.AGREE_TO_TERMS_AND_CONDITIONS,
28+
CONSENT_TO_PRIVACY_NOTICE: INPUT_IDS.ADDITIONAL_DATA.CORPAY.CONSENT_TO_PRIVACY_NOTICE,
29+
AUTHORIZED_TO_BIND_CLIENT_TO_AGREEMENT: INPUT_IDS.ADDITIONAL_DATA.CORPAY.AUTHORIZED_TO_BIND_CLIENT_TO_AGREEMENT,
30+
};
31+
2032
function Agreements({onBackButtonPress, onSubmit}: AgreementsProps) {
2133
const {translate} = useLocalize();
34+
const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {canBeMissing: false});
35+
const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT, {canBeMissing: false});
36+
const agreementsStepValues = useMemo(() => getSubStepValues(INPUT_KEYS, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]);
37+
const bankAccountID = reimbursementAccount?.achData?.bankAccountID ?? CONST.DEFAULT_NUMBER_ID;
2238

2339
const submit = () => {
24-
onSubmit();
40+
finishCorpayBankAccountOnboarding({
41+
inputs: JSON.stringify({
42+
provideTruthfulInformation: agreementsStepValues.provideTruthfulInformation,
43+
agreeToTermsAndConditions: agreementsStepValues.agreeToTermsAndConditions,
44+
consentToPrivacyNotice: agreementsStepValues.consentToPrivacyNotice,
45+
authorizedToBindClientToAgreement: agreementsStepValues.authorizedToBindClientToAgreement,
46+
}),
47+
bankAccountID,
48+
});
2549
};
2650

51+
useEffect(() => {
52+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
53+
if (reimbursementAccount?.errors || reimbursementAccount?.isFinishingCorpayBankAccountOnboarding || !reimbursementAccount?.isSuccess) {
54+
return;
55+
}
56+
57+
if (reimbursementAccount?.isSuccess) {
58+
onSubmit();
59+
clearReimbursementAccountFinishCorpayBankAccountOnboarding();
60+
}
61+
62+
return () => {
63+
clearReimbursementAccountFinishCorpayBankAccountOnboarding();
64+
};
65+
}, [reimbursementAccount, onSubmit]);
66+
2767
const {componentToRender: SubStep, isEditing, screenIndex, nextScreen, prevScreen, moveTo, goToTheLastStep} = useSubStep({bodyContent, startFrom: 0, onFinished: submit});
2868

2969
const handleBackButtonPress = () => {

src/pages/ReimbursementAccount/NonUSD/Agreements/subSteps/Confirmation.tsx

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {useCallback} from 'react';
1+
import React, {useCallback, useMemo} from 'react';
22
import {useOnyx} from 'react-native-onyx';
33
import CheckboxWithLabel from '@components/CheckboxWithLabel';
44
import FormProvider from '@components/Form/FormProvider';
@@ -10,11 +10,12 @@ import useLocalize from '@hooks/useLocalize';
1010
import type {SubStepProps} from '@hooks/useSubStep/types';
1111
import useThemeStyles from '@hooks/useThemeStyles';
1212
import {getFieldRequiredErrors, isRequiredFulfilled} from '@libs/ValidationUtils';
13+
import getSubStepValues from '@pages/ReimbursementAccount/utils/getSubStepValues';
1314
import ONYXKEYS from '@src/ONYXKEYS';
1415
import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
1516

16-
const {AUTHORIZED_TO_BIND_CLIENT_TO_AGREEMENT, PROVIDE_TRUTHFUL_INFORMATION, AGREE_TO_TERMS_AND_CONDITIONS} = INPUT_IDS.ADDITIONAL_DATA.CORPAY;
17-
const STEP_FIELDS = [AUTHORIZED_TO_BIND_CLIENT_TO_AGREEMENT, PROVIDE_TRUTHFUL_INFORMATION, AGREE_TO_TERMS_AND_CONDITIONS];
17+
const {AUTHORIZED_TO_BIND_CLIENT_TO_AGREEMENT, PROVIDE_TRUTHFUL_INFORMATION, AGREE_TO_TERMS_AND_CONDITIONS, CONSENT_TO_PRIVACY_NOTICE} = INPUT_IDS.ADDITIONAL_DATA.CORPAY;
18+
const STEP_FIELDS = [AUTHORIZED_TO_BIND_CLIENT_TO_AGREEMENT, PROVIDE_TRUTHFUL_INFORMATION, AGREE_TO_TERMS_AND_CONDITIONS, CONSENT_TO_PRIVACY_NOTICE];
1819

1920
function IsAuthorizedToUseBankAccountLabel() {
2021
const {translate} = useLocalize();
@@ -31,24 +32,34 @@ function TermsAndConditionsLabel() {
3132
return (
3233
<Text>
3334
{translate('common.iAcceptThe')}
34-
<TextLink href="https://cross-border.corpay.com/tc/">{`${translate('agreementsStep.termsAndConditions')}`}</TextLink>
35+
<TextLink href="https://cross-border.corpay.com/tc/">{`${translate('agreementsStep.termsAndConditions')}`}</TextLink>.
3536
</Text>
3637
);
3738
}
3839

40+
function ConsentToPrivacyNoticeLabel() {
41+
const {translate} = useLocalize();
42+
return (
43+
<Text>
44+
{translate('agreementsStep.iConsentToThe')} <TextLink href="https://payments.corpay.com/compliance">{`${translate('agreementsStep.privacyNotice')}`}</TextLink>.
45+
</Text>
46+
);
47+
}
48+
49+
const INPUT_KEYS = {
50+
PROVIDE_TRUTHFUL_INFORMATION: INPUT_IDS.ADDITIONAL_DATA.CORPAY.PROVIDE_TRUTHFUL_INFORMATION,
51+
AGREE_TO_TERMS_AND_CONDITIONS: INPUT_IDS.ADDITIONAL_DATA.CORPAY.AGREE_TO_TERMS_AND_CONDITIONS,
52+
CONSENT_TO_PRIVACY_NOTICE: INPUT_IDS.ADDITIONAL_DATA.CORPAY.CONSENT_TO_PRIVACY_NOTICE,
53+
AUTHORIZED_TO_BIND_CLIENT_TO_AGREEMENT: INPUT_IDS.ADDITIONAL_DATA.CORPAY.AUTHORIZED_TO_BIND_CLIENT_TO_AGREEMENT,
54+
};
55+
3956
function Confirmation({onNext}: SubStepProps) {
4057
const {translate} = useLocalize();
4158
const styles = useThemeStyles();
4259

43-
const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT);
44-
const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT);
45-
46-
const defaultValues = {
47-
[AUTHORIZED_TO_BIND_CLIENT_TO_AGREEMENT]:
48-
!!reimbursementAccount?.achData?.corpay?.[AUTHORIZED_TO_BIND_CLIENT_TO_AGREEMENT] ?? reimbursementAccountDraft?.[AUTHORIZED_TO_BIND_CLIENT_TO_AGREEMENT] ?? '',
49-
[PROVIDE_TRUTHFUL_INFORMATION]: !!reimbursementAccount?.achData?.corpay?.[PROVIDE_TRUTHFUL_INFORMATION] ?? reimbursementAccountDraft?.[PROVIDE_TRUTHFUL_INFORMATION] ?? '',
50-
[AGREE_TO_TERMS_AND_CONDITIONS]: !!reimbursementAccount?.achData?.corpay?.[AGREE_TO_TERMS_AND_CONDITIONS] ?? reimbursementAccountDraft?.[AGREE_TO_TERMS_AND_CONDITIONS] ?? '',
51-
};
60+
const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {canBeMissing: false});
61+
const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT, {canBeMissing: false});
62+
const agreementsStepValues = useMemo(() => getSubStepValues(INPUT_KEYS, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]);
5263

5364
const validate = useCallback(
5465
(values: FormOnyxValues<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM>): FormInputErrors<typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM> => {
@@ -66,6 +77,10 @@ function Confirmation({onNext}: SubStepProps) {
6677
errors[AGREE_TO_TERMS_AND_CONDITIONS] = translate('common.error.acceptTerms');
6778
}
6879

80+
if (!isRequiredFulfilled(values[CONSENT_TO_PRIVACY_NOTICE])) {
81+
errors[CONSENT_TO_PRIVACY_NOTICE] = translate('agreementsStep.error.consent');
82+
}
83+
6984
return errors;
7085
},
7186
[translate],
@@ -79,6 +94,7 @@ function Confirmation({onNext}: SubStepProps) {
7994
submitButtonText={translate('agreementsStep.accept')}
8095
style={[styles.mh5, styles.flexGrow1]}
8196
enabledWhenOffline={false}
97+
isLoading={reimbursementAccount?.isFinishingCorpayBankAccountOnboarding}
8298
>
8399
<Text style={[styles.textHeadlineLineHeightXXL]}>{translate('agreementsStep.pleaseConfirm')}</Text>
84100
<Text style={[styles.pv3, styles.textSupporting]}>{translate('agreementsStep.regulationRequiresUs')}</Text>
@@ -88,7 +104,7 @@ function Confirmation({onNext}: SubStepProps) {
88104
inputID={AUTHORIZED_TO_BIND_CLIENT_TO_AGREEMENT}
89105
style={styles.mt6}
90106
LabelComponent={IsAuthorizedToUseBankAccountLabel}
91-
defaultValue={defaultValues[AUTHORIZED_TO_BIND_CLIENT_TO_AGREEMENT]}
107+
defaultValue={agreementsStepValues[AUTHORIZED_TO_BIND_CLIENT_TO_AGREEMENT]}
92108
shouldSaveDraft
93109
/>
94110
<InputWrapper
@@ -97,16 +113,25 @@ function Confirmation({onNext}: SubStepProps) {
97113
inputID={PROVIDE_TRUTHFUL_INFORMATION}
98114
style={styles.mt6}
99115
LabelComponent={CertifyTrueAndAccurateLabel}
100-
defaultValue={defaultValues[PROVIDE_TRUTHFUL_INFORMATION]}
116+
defaultValue={agreementsStepValues[PROVIDE_TRUTHFUL_INFORMATION]}
101117
shouldSaveDraft
102118
/>
103119
<InputWrapper
104120
InputComponent={CheckboxWithLabel}
105-
accessibilityLabel={`${translate('common.iAcceptThe')} ${translate('agreementsStep.termsAndConditions')}`}
121+
accessibilityLabel={`${translate('common.iAcceptThe')} ${translate('agreementsStep.termsAndConditions')}.`}
106122
inputID={AGREE_TO_TERMS_AND_CONDITIONS}
107123
style={styles.mt6}
108124
LabelComponent={TermsAndConditionsLabel}
109-
defaultValue={defaultValues[AGREE_TO_TERMS_AND_CONDITIONS]}
125+
defaultValue={agreementsStepValues[AGREE_TO_TERMS_AND_CONDITIONS]}
126+
shouldSaveDraft
127+
/>
128+
<InputWrapper
129+
InputComponent={CheckboxWithLabel}
130+
accessibilityLabel={`${translate('agreementsStep.iConsentToThe')} ${translate('agreementsStep.privacyNotice')}.`}
131+
inputID={CONSENT_TO_PRIVACY_NOTICE}
132+
style={styles.mt6}
133+
LabelComponent={ConsentToPrivacyNoticeLabel}
134+
defaultValue={agreementsStepValues[CONSENT_TO_PRIVACY_NOTICE]}
110135
shouldSaveDraft
111136
/>
112137
</FormProvider>

src/pages/ReimbursementAccount/NonUSD/NonUSDVerifiedBankAccountFlow.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import React from 'react';
2+
import {clearErrors} from '@userActions/FormActions';
23
import CONST from '@src/CONST';
4+
import ONYXKEYS from '@src/ONYXKEYS';
35
import Agreements from './Agreements';
46
import BankInfo from './BankInfo/BankInfo';
57
import BeneficialOwnerInfo from './BeneficialOwnerInfo/BeneficialOwnerInfo';
@@ -49,6 +51,7 @@ function NonUSDVerifiedBankAccountFlow({
4951
};
5052

5153
const nonUSDBankAccountsGoBack = () => {
54+
clearErrors(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM);
5255
switch (nonUSDBankAccountStep) {
5356
case CONST.NON_USD_BANK_ACCOUNT.STEP.COUNTRY:
5457
setNonUSDBankAccountStep(null);
@@ -69,6 +72,10 @@ function NonUSDVerifiedBankAccountFlow({
6972
case CONST.NON_USD_BANK_ACCOUNT.STEP.AGREEMENTS:
7073
setNonUSDBankAccountStep(CONST.NON_USD_BANK_ACCOUNT.STEP.SIGNER_INFO);
7174
break;
75+
case CONST.NON_USD_BANK_ACCOUNT.STEP.FINISH:
76+
setShouldShowContinueSetupButton(true);
77+
setNonUSDBankAccountStep(null);
78+
break;
7279
default:
7380
return null;
7481
}

0 commit comments

Comments
 (0)