Skip to content

Commit

Permalink
Merge pull request #44376 from koko57/feat/card-flow
Browse files Browse the repository at this point in the history
[No QA] Card flow screens
  • Loading branch information
MariaHCD authored Jun 28, 2024
2 parents e78c38e + a660189 commit 3622deb
Show file tree
Hide file tree
Showing 20 changed files with 542 additions and 6 deletions.
9 changes: 9 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1926,6 +1926,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 @@ -353,6 +353,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',

/** Collection Keys */
COLLECTION: {
DOWNLOAD: 'download_',
Expand Down Expand Up @@ -521,6 +524,8 @@ const ONYXKEYS = {
NEW_CHAT_NAME_FORM_DRAFT: 'newChatNameFormDraft',
SUBSCRIPTION_SIZE_FORM: 'subscriptionSizeForm',
SUBSCRIPTION_SIZE_FORM_DRAFT: 'subscriptionSizeFormDraft',
ISSUE_NEW_EXPENSIFY_CARD_FORM: 'issueNewExpensifyCardForm',
ISSUE_NEW_EXPENSIFY_CARD_FORM_DRAFT: 'issueNewExpensifyCardFormDraft',
},
} as const;

Expand Down Expand Up @@ -581,6 +586,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 @@ -743,6 +749,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE]: OnyxTypes.QuickAction;
[ONYXKEYS.NVP_TRAVEL_SETTINGS]: OnyxTypes.TravelSettings;
[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 @@ -783,6 +783,17 @@ const ROUTES = {
route: 'settings/workspaces/:policyID/reportFields',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/reportFields` 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',
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 @@ -281,6 +281,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 @@ -2408,6 +2408,34 @@ export default {
benefit4: 'Customizable limits and spend controls',
addWorkEmail: 'Add work email address',
checkingDomain: "Hang tight! We're still working on enabling your Expensify Cards. Check back here in a few minutes.",
issueCard: 'Issue card',
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 @@ -2603,6 +2603,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<ReactComponentModule>('../../../../pages/workspace/taxes/NamePage').default,
[SCREENS.WORKSPACE.TAX_VALUE]: () => require<ReactComponentModule>('../../../../pages/workspace/taxes/ValuePage').default,
[SCREENS.WORKSPACE.TAX_CREATE]: () => require<ReactComponentModule>('../../../../pages/workspace/taxes/WorkspaceCreateTaxPage').default,
[SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW]: () => require<ReactComponentModule>('../../../../pages/workspace/card/issueNew/IssueNewCardPage').default,
[SCREENS.SETTINGS.SAVE_THE_WORLD]: () => require<ReactComponentModule>('../../../../pages/TeachersUnite/SaveTheWorldPage').default,
[SCREENS.SETTINGS.SUBSCRIPTION.CHANGE_PAYMENT_CURRENCY]: () => require<ReactComponentModule>('../../../../pages/settings/PaymentCard/ChangeCurrency').default,
[SCREENS.SETTINGS.SUBSCRIPTION.CHANGE_BILLING_CURRENCY]: () => require<ReactComponentModule>('../../../../pages/settings/Subscription/PaymentCard/ChangeBillingCurrency').default,
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 @@ -366,6 +366,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;
60 changes: 60 additions & 0 deletions src/pages/workspace/card/issueNew/CardTypeStep.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 CardTypeStep() {
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.LIMIT_TYPE);
};

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

return (
<ScreenWrapper
testID={CardTypeStep.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={1}
stepNames={CONST.EXPENSIFY_CARD.STEP_NAMES}
/>
</View>
<Text style={[styles.textHeadlineLineHeightXXL, styles.ph5, styles.mv3]}>{translate('workspace.card.issueNewCard.chooseCardType')}</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>
);
}

CardTypeStep.displayName = 'CardTypeStep';

export default CardTypeStep;
Loading

0 comments on commit 3622deb

Please sign in to comment.