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

[No QA] Card flow screens #44376

Merged
merged 11 commits into from
Jun 28, 2024
10 changes: 8 additions & 2 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1243,7 +1243,13 @@ PODS:
- react-native-config (1.5.0):
- react-native-config/App (= 1.5.0)
- react-native-config/App (1.5.0):
- React-Core
- RCT-Folly
- RCTRequired
- RCTTypeSafety
- React
- React-Codegen
- React-RCTFabric
- ReactCommon/turbomodule/core
- react-native-document-picker (9.1.1):
Copy link
Contributor

Choose a reason for hiding this comment

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

are these changes necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

for sure not, reverting!

- RCT-Folly
- RCTRequired
Expand Down Expand Up @@ -2552,7 +2558,7 @@ SPEC CHECKSUMS:
react-native-airship: 38e2596999242b68c933959d6145512e77937ac0
react-native-blob-util: 1ddace5234c62e3e6e4e154d305ad07ef686599b
react-native-cameraroll: f373bebbe9f6b7c3fd2a6f97c5171cda574cf957
react-native-config: 5330c8258265c1e5fdb8c009d2cabd6badd96727
react-native-config: 5ce986133b07fc258828b20b9506de0e683efc1c
react-native-document-picker: 8532b8af7c2c930f9e202aac484ac785b0f4f809
react-native-geolocation: f9e92eb774cb30ac1e099f34b3a94f03b4db7eb3
react-native-image-picker: f8a13ff106bcc7eb00c71ce11fdc36aac2a44440
Expand Down
9 changes: 9 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1925,6 +1925,15 @@ const CONST = {
MONTHLY: 'monthly',
FIXED: 'fixed',
},
STEP_NAMES: ['1', '2', '3', '4', '5', '6'],
STEP: {
ASSIGNEE: 'Assignee',
CARD_TYPE: 'CardType',
LIMIT_TYPE: 'LimitType',
LIMIT: 'Limit',
CARD_NAME: 'CardName',
CONFIRMATION: 'Confirmation',
},
},
AVATAR_ROW_SIZE: {
DEFAULT: 4,
Expand Down
7 changes: 7 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,9 @@ const ONYXKEYS = {
/** Stores info during review duplicates flow */
REVIEW_DUPLICATES: 'reviewDuplicates',

/** Stores the information about the state of issuing a new card */
ISSUE_NEW_EXPENSIFY_CARD: 'issueNewExpensifyCard',
mountiny marked this conversation as resolved.
Show resolved Hide resolved

/** Collection Keys */
COLLECTION: {
DOWNLOAD: 'download_',
Expand Down Expand Up @@ -508,6 +511,8 @@ const ONYXKEYS = {
NEW_CHAT_NAME_FORM_DRAFT: 'newChatNameFormDraft',
SUBSCRIPTION_SIZE_FORM: 'subscriptionSizeForm',
SUBSCRIPTION_SIZE_FORM_DRAFT: 'subscriptionSizeFormDraft',
ISSUE_NEW_EXPENSIFY_CARD_FORM: 'issueNewExpensifyCardForm',
mountiny marked this conversation as resolved.
Show resolved Hide resolved
ISSUE_NEW_EXPENSIFY_CARD_FORM_DRAFT: 'issueNewExpensifyCardFormDraft',
mountiny marked this conversation as resolved.
Show resolved Hide resolved
},
} as const;

Expand Down Expand Up @@ -567,6 +572,7 @@ type OnyxFormValuesMapping = {
[ONYXKEYS.FORMS.WORKSPACE_TAX_VALUE_FORM]: FormTypes.WorkspaceTaxValueForm;
[ONYXKEYS.FORMS.NEW_CHAT_NAME_FORM]: FormTypes.NewChatNameForm;
[ONYXKEYS.FORMS.SUBSCRIPTION_SIZE_FORM]: FormTypes.SubscriptionSizeForm;
[ONYXKEYS.FORMS.ISSUE_NEW_EXPENSIFY_CARD_FORM]: FormTypes.IssueNewExpensifyCardForm;
};

type OnyxFormDraftValuesMapping = {
Expand Down Expand Up @@ -723,6 +729,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.POLICY_OWNERSHIP_CHANGE_CHECKS]: Record<string, OnyxTypes.PolicyOwnershipChangeChecks>;
[ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE]: OnyxTypes.QuickAction;
[ONYXKEYS.REVIEW_DUPLICATES]: OnyxTypes.ReviewDuplicates;
[ONYXKEYS.ISSUE_NEW_EXPENSIFY_CARD]: OnyxTypes.IssueNewCard;
[ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL]: string;
[ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL]: string;
[ONYXKEYS.NVP_BILLING_FUND_ID]: number;
Expand Down
11 changes: 11 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,17 @@ const ROUTES = {
route: 'settings/workspaces/:policyID/tax/:taxID/value',
getRoute: (policyID: string, taxID: string) => `settings/workspaces/${policyID}/tax/${encodeURIComponent(taxID)}/value` as const,
},
// TODO: uncomment after development is done
// WORKSPACE_EXPENSIFY_CARD: {
// route: 'settings/workspaces/:policyID/expensify-card',
// getRoute: (policyID: string) => `settings/workspaces/${policyID}/expensify-card` as const,
// },
// WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW: {
// route: 'settings/workspaces/:policyID/expensify-card/issues-new',
// getRoute: (policyID: string) => `settings/workspaces/${policyID}/expensify-card/issue-new` as const,
// },
// TODO: remove after development is done - this one is for testing purposes
WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW: 'settings/workspaces/expensify-card/issue-new',
mountiny marked this conversation as resolved.
Show resolved Hide resolved
WORKSPACE_DISTANCE_RATES: {
route: 'settings/workspaces/:policyID/distance-rates',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/distance-rates` as const,
Expand Down
2 changes: 2 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ const SCREENS = {
RATE_AND_UNIT: 'Workspace_RateAndUnit',
RATE_AND_UNIT_RATE: 'Workspace_RateAndUnit_Rate',
RATE_AND_UNIT_UNIT: 'Workspace_RateAndUnit_Unit',
EXPENSIFY_CARD: 'Workspace_ExpensifyCard',
EXPENSIFY_CARD_ISSUE_NEW: 'Workspace_ExpensifyCard_New',
BILLS: 'Workspace_Bills',
INVOICES: 'Workspace_Invoices',
TRAVEL: 'Workspace_Travel',
Expand Down
28 changes: 28 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2377,6 +2377,34 @@ export default {
benefit4: 'Customizable limits',
addWorkEmail: 'Add work email address',
checkingDomain: 'Hang tight! We are still working on enabling your Expensify Cards. Check back here in a few minutes.',
issueCard: 'Issue card',
Copy link
Contributor

Choose a reason for hiding this comment

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

@koko57 Did we confirm the translation with design team?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@DylanDylann translations are in the design doc

issueNewCard: {
whoNeedsCard: 'Who needs a card?',
findMember: 'Find member',
chooseCardType: 'Choose a card type',
physicalCard: 'Physical card',
physicalCardDescription: 'Great for the frequent spender',
virtualCard: 'Virtual card',
virtualCardDescription: 'Instant and flexible',
chooseLimitType: 'Choose a limit type',
smartLimit: 'Smart Limit',
smartLimitDescription: 'Spend up to a certain amount before requiring approval',
monthly: 'Monthly',
monthlyDescription: 'Spend up to a certain amount per month',
fixedAmount: 'Fixed amount',
fixedAmountDescription: 'Spend up to a certain amount once',
setLimit: 'Set a limit',
giveItName: 'Give it a name',
giveItNameInstruction: 'Make it unique enough to tell apart from the other. Specific use cases are even better!',
cardName: 'Card name',
letsDoubleCheck: 'Let’s double check that everything looks right.',
willBeReady: 'This card will be ready to use immediately.',
cardholder: 'Cardholder',
cardType: 'Card type',
limit: 'Limit',
limitType: 'Limit type',
name: 'Name',
},
},
reimburse: {
captureReceipts: 'Capture receipts',
Expand Down
28 changes: 28 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2581,6 +2581,34 @@ export default {
benefit4: 'Límites personalizables',
addWorkEmail: 'Añadir correo electrónico de trabajo',
checkingDomain: '¡Un momento! Estamos todavía trabajando para habilitar tu Tarjeta Expensify. Vuelve aquí en unos minutos.',
issueCard: 'Emitir tarjeta',
issueNewCard: {
whoNeedsCard: '¿Quién necesita una tarjeta?',
findMember: 'Buscar miembro',
chooseCardType: 'Elegir un tipo de tarjeta',
physicalCard: 'Tarjeta física',
physicalCardDescription: 'Ideal para los consumidores habituales',
virtualCard: 'Tarjeta virtual',
virtualCardDescription: 'Instantáneo y flexible',
chooseLimitType: 'Elegir un tipo de límite',
smartLimit: 'Límite inteligente',
smartLimitDescription: 'Gasta hasta una determinada cantidad antes de requerir aprobación',
monthly: 'Mensual',
monthlyDescription: 'Gasta hasta una determinada cantidad al mes',
fixedAmount: 'Cantidad fija',
fixedAmountDescription: 'Gasta hasta una determinada cantidad una vez',
setLimit: 'Establecer un límite',
giveItName: 'Dale un nombre',
giveItNameInstruction: 'Hazlo lo suficientemente único como para distinguirlo de los demás. Los casos de uso específicos son aún mejores.',
cardName: 'Nombre de la tarjeta',
letsDoubleCheck: 'Vuelve a comprobar que todo parece correcto. ',
willBeReady: 'Esta tarjeta estará lista para su uso inmediato.',
cardholder: 'Titular de la tarjeta',
cardType: 'Tipo de tarjeta',
limit: 'Limite',
limitType: 'Tipo de limite',
name: 'Nombre',
},
},
reimburse: {
captureReceipts: 'Captura recibos',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.WORKSPACE.TAX_NAME]: () => require('../../../../pages/workspace/taxes/NamePage').default as React.ComponentType,
[SCREENS.WORKSPACE.TAX_VALUE]: () => require('../../../../pages/workspace/taxes/ValuePage').default as React.ComponentType,
[SCREENS.WORKSPACE.TAX_CREATE]: () => require('../../../../pages/workspace/taxes/WorkspaceCreateTaxPage').default as React.ComponentType,
[SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW]: () => require('@pages/workspace/card/issueNew/IssueNewCardPage').default as React.ComponentType,
[SCREENS.SETTINGS.SAVE_THE_WORLD]: () => require('../../../../pages/TeachersUnite/SaveTheWorldPage').default as React.ComponentType,
[SCREENS.SETTINGS.SUBSCRIPTION.ADD_PAYMENT_CARD]: () => require('../../../../pages/settings/Subscription/PaymentCard/AddPaymentCard').default as React.ComponentType,
});
Expand Down
7 changes: 7 additions & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,13 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
[SCREENS.WORKSPACE.SHARE]: {
path: ROUTES.WORKSPACE_PROFILE_SHARE.route,
},
// TODO: uncomment after development
// [SCREENS.WORKSPACE.EXPENSIFY_CARD]: {
// path: ROUTES.WORKSPACE_EXPENSIFY_CARD,
// },
[SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW]: {
path: ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW,
},
[SCREENS.WORKSPACE.RATE_AND_UNIT]: {
path: ROUTES.WORKSPACE_RATE_AND_UNIT.route,
},
Expand Down
20 changes: 16 additions & 4 deletions src/libs/actions/Card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {ActivatePhysicalExpensifyCardParams, ReportVirtualExpensifyCardFrau
import {SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {ExpensifyCardDetails} from '@src/types/onyx/Card';
import type {ExpensifyCardDetails, IssueNewCardStep} from '@src/types/onyx/Card';

type ReplacementReason = 'damaged' | 'stolen';

Expand Down Expand Up @@ -44,7 +44,11 @@ function reportVirtualExpensifyCardFraud(cardID: number) {
cardID,
};

API.write(WRITE_COMMANDS.REPORT_VIRTUAL_EXPENSIFY_CARD_FRAUD, parameters, {optimisticData, successData, failureData});
API.write(WRITE_COMMANDS.REPORT_VIRTUAL_EXPENSIFY_CARD_FRAUD, parameters, {
optimisticData,
successData,
failureData,
});
}

/**
Expand Down Expand Up @@ -89,7 +93,11 @@ function requestReplacementExpensifyCard(cardID: number, reason: ReplacementReas
reason,
};

API.write(WRITE_COMMANDS.REQUEST_REPLACEMENT_EXPENSIFY_CARD, parameters, {optimisticData, successData, failureData});
API.write(WRITE_COMMANDS.REQUEST_REPLACEMENT_EXPENSIFY_CARD, parameters, {
optimisticData,
successData,
failureData,
});
}

/**
Expand Down Expand Up @@ -177,5 +185,9 @@ function revealVirtualCardDetails(cardID: number): Promise<ExpensifyCardDetails>
});
}

export {requestReplacementExpensifyCard, activatePhysicalExpensifyCard, clearCardListErrors, reportVirtualExpensifyCardFraud, revealVirtualCardDetails};
function setIssueNewCardStep(step: IssueNewCardStep | null) {
Onyx.merge(ONYXKEYS.ISSUE_NEW_EXPENSIFY_CARD, {currentStep: step});
}

export {requestReplacementExpensifyCard, activatePhysicalExpensifyCard, clearCardListErrors, reportVirtualExpensifyCardFraud, revealVirtualCardDetails, setIssueNewCardStep};
export type {ReplacementReason};
61 changes: 61 additions & 0 deletions src/pages/workspace/card/issueNew/AssigneeStep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react';
import {View} from 'react-native';
import FormProvider from '@components/Form/FormProvider';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import InteractiveStepSubHeader from '@components/InteractiveStepSubHeader';
import ScreenWrapper from '@components/ScreenWrapper';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@navigation/Navigation';
import * as Card from '@userActions/Card';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';

function AssigneeStep() {
const {translate} = useLocalize();
const styles = useThemeStyles();

const submit = () => {
// TODO: the logic will be created in https://github.com/Expensify/App/issues/44309
Card.setIssueNewCardStep(CONST.EXPENSIFY_CARD.STEP.CARD_TYPE);
};

const handleBackButtonPress = () => {
Navigation.goBack();
};

return (
<ScreenWrapper
testID={AssigneeStep.displayName}
includeSafeAreaPaddingBottom={false}
shouldEnablePickerAvoiding={false}
shouldEnableMaxHeight
>
<HeaderWithBackButton
title={translate('workspace.card.issueCard')}
onBackButtonPress={handleBackButtonPress}
/>
<View style={[styles.ph5, styles.mb5, styles.mt3, {height: CONST.BANK_ACCOUNT.STEPS_HEADER_HEIGHT}]}>
<InteractiveStepSubHeader
startStepIndex={0}
stepNames={CONST.EXPENSIFY_CARD.STEP_NAMES}
/>
</View>
<Text style={[styles.textHeadlineLineHeightXXL, styles.ph5, styles.mv3]}>{translate('workspace.card.issueNewCard.whoNeedsCard')}</Text>
<FormProvider
formID={ONYXKEYS.FORMS.ISSUE_NEW_EXPENSIFY_CARD_FORM}
submitButtonText={translate('common.next')}
onSubmit={submit}
style={[styles.mh5, styles.flexGrow1]}
>
{/* TODO: the content will be created in https://github.com/Expensify/App/issues/44309 */}
<View />
</FormProvider>
</ScreenWrapper>
);
}

AssigneeStep.displayName = 'AssigneeStep';

export default AssigneeStep;
60 changes: 60 additions & 0 deletions src/pages/workspace/card/issueNew/CardNameStep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from 'react';
import {View} from 'react-native';
import FormProvider from '@components/Form/FormProvider';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import InteractiveStepSubHeader from '@components/InteractiveStepSubHeader';
import ScreenWrapper from '@components/ScreenWrapper';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as Card from '@userActions/Card';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';

function CardNameStep() {
const {translate} = useLocalize();
const styles = useThemeStyles();

const submit = () => {
// TODO: the logic will be created in https://github.com/Expensify/App/issues/44309
Card.setIssueNewCardStep(CONST.EXPENSIFY_CARD.STEP.CONFIRMATION);
};

const handleBackButtonPress = () => {
Card.setIssueNewCardStep(CONST.EXPENSIFY_CARD.STEP.LIMIT);
};

return (
<ScreenWrapper
testID={CardNameStep.displayName}
includeSafeAreaPaddingBottom={false}
shouldEnablePickerAvoiding={false}
shouldEnableMaxHeight
>
<HeaderWithBackButton
title={translate('workspace.card.issueCard')}
onBackButtonPress={handleBackButtonPress}
/>
<View style={[styles.ph5, styles.mb5, styles.mt3, {height: CONST.BANK_ACCOUNT.STEPS_HEADER_HEIGHT}]}>
<InteractiveStepSubHeader
startStepIndex={4}
stepNames={CONST.EXPENSIFY_CARD.STEP_NAMES}
/>
</View>
<Text style={[styles.textHeadlineLineHeightXXL, styles.ph5, styles.mv3]}>{translate('workspace.card.issueNewCard.giveItName')}</Text>
<FormProvider
formID={ONYXKEYS.FORMS.ISSUE_NEW_EXPENSIFY_CARD_FORM}
submitButtonText={translate('common.next')}
onSubmit={submit}
style={[styles.mh5, styles.flexGrow1]}
>
{/* TODO: the content will be created in https://github.com/Expensify/App/issues/44309 */}
<View />
</FormProvider>
</ScreenWrapper>
);
}

CardNameStep.displayName = 'CardNameStep';

export default CardNameStep;
Loading
Loading