diff --git a/src/CONST.ts b/src/CONST.ts index d929a01e030a..1e161b7ece64 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -682,6 +682,9 @@ const CONST = { ACTIONABLE_TRACK_EXPENSE_WHISPER: 'ACTIONABLETRACKEXPENSEWHISPER', ADD_COMMENT: 'ADDCOMMENT', APPROVED: 'APPROVED', + CARD_MISSING_ADDRESS: 'CARDMISSINGADDRESS', + CARD_ISSUED: 'CARDISSUED', + CARD_ISSUED_VIRTUAL: 'CARDISSUEDVIRTUAL', CHANGE_FIELD: 'CHANGEFIELD', // OldDot Action CHANGE_POLICY: 'CHANGEPOLICY', // OldDot Action CHANGE_TYPE: 'CHANGETYPE', // OldDot Action diff --git a/src/components/ReportActionItem/IssueCardMessage.tsx b/src/components/ReportActionItem/IssueCardMessage.tsx new file mode 100644 index 000000000000..292b010cd851 --- /dev/null +++ b/src/components/ReportActionItem/IssueCardMessage.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import type {OnyxEntry} from 'react-native-onyx'; +import {useOnyx} from 'react-native-onyx'; +import Button from '@components/Button'; +import RenderHTML from '@components/RenderHTML'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import useEnvironment from '@hooks/useEnvironment'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import type {ReportAction} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; + +type IssueCardMessageProps = { + action: OnyxEntry<ReportAction>; +}; + +function IssueCardMessage({action}: IssueCardMessageProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const {environmentURL} = useEnvironment(); + // TODO: now mocking accountID with current user accountID instead of action.message.assigneeAccountID + const personalData = useCurrentUserPersonalDetails(); + const [privatePersonalDetails] = useOnyx(ONYXKEYS.PRIVATE_PERSONAL_DETAILS); + + // TODO: now mocking accountID with current user accountID instead of action.message.assigneeAccountID + const assignee = `<mention-user accountID=${personalData.accountID}></mention-user>`; + const link = `<a href='${environmentURL}/${ROUTES.SETTINGS_WALLET}'>${translate('cardPage.expensifyCard')}</a>`; + + const noMailingAddress = action?.actionName === CONST.REPORT.ACTIONS.TYPE.CARD_MISSING_ADDRESS && isEmptyObject(privatePersonalDetails?.address); + + const getTranslation = () => { + switch (action?.actionName) { + case CONST.REPORT.ACTIONS.TYPE.CARD_ISSUED: + return translate('workspace.expensifyCard.issuedCard', assignee); + case CONST.REPORT.ACTIONS.TYPE.CARD_ISSUED_VIRTUAL: + return translate('workspace.expensifyCard.issuedCardVirtual', {assignee, link}); + case CONST.REPORT.ACTIONS.TYPE.CARD_MISSING_ADDRESS: + return translate(`workspace.expensifyCard.${noMailingAddress ? 'issuedCardNoMailingAddress' : 'addedAddress'}`, assignee); + default: + return ''; + } + }; + + return ( + <> + <RenderHTML html={`<muted-text>${getTranslation()}</muted-text>`} /> + {noMailingAddress && ( + <Button + onPress={() => Navigation.navigate(ROUTES.SETTINGS_ADDRESS)} + success + medium + style={[styles.alignSelfStart, styles.mt3]} + text={translate('workspace.expensifyCard.addMailingAddress')} + /> + )} + </> + ); +} + +IssueCardMessage.displayName = 'IssueCardMessage'; + +export default IssueCardMessage; diff --git a/src/languages/en.ts b/src/languages/en.ts index cb5e0b76edef..f4239f301f36 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -36,6 +36,7 @@ import type { GoBackMessageParams, GoToRoomParams, InstantSummaryParams, + IssueVirtualCardParams, LocalTimeParams, LoggedInAsParams, LogSizeParams, @@ -2707,6 +2708,11 @@ export default { `If you change this card's limit type to Smart Limit, new transactions will be declined because the ${limit} unapproved limit has already been reached.`, changeCardMonthlyLimitTypeWarning: (limit: string) => `If you change this card's limit type to Monthly, new transactions will be declined because the ${limit} monthly limit has already been reached.`, + addMailingAddress: 'Add mailing address', + issuedCard: (assignee: string) => `issued ${assignee} an Expensify Card! The card will arrive in 2-3 business days.`, + issuedCardNoMailingAddress: (assignee: string) => `issued ${assignee} an Expensify Card! The card will be shipped once a mailing address is added.`, + issuedCardVirtual: ({assignee, link}: IssueVirtualCardParams) => `issued ${assignee} a virtual ${link}! The card can be used right away.`, + addedAddress: (assignee: string) => `${assignee} added the address. Expensify Card will arrive in 2-3 business days.`, }, categories: { deleteCategories: 'Delete categories', diff --git a/src/languages/es.ts b/src/languages/es.ts index 6f4ba907fc9c..9a42813cc0dd 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -35,6 +35,7 @@ import type { GoBackMessageParams, GoToRoomParams, InstantSummaryParams, + IssueVirtualCardParams, LocalTimeParams, LoggedInAsParams, LogSizeParams, @@ -2759,6 +2760,11 @@ export default { `Si cambias el tipo de límite de esta tarjeta a Límite inteligente, las nuevas transacciones serán rechazadas porque ya se ha alcanzado el límite de ${limit} no aprobado.`, changeCardMonthlyLimitTypeWarning: (limit: string) => `Si cambias el tipo de límite de esta tarjeta a Mensual, las nuevas transacciones serán rechazadas porque ya se ha alcanzado el límite de ${limit} mensual.`, + addMailingAddress: 'Añadir dirección de postal', + issuedCard: (assignee: string) => `¡emitió a ${assignee} una Tarjeta Expensify! La tarjeta llegará en 2-3 días laborables.`, + issuedCardNoMailingAddress: (assignee: string) => `¡emitió a ${assignee} una Tarjeta Expensify! La tarjeta se enviará una vez que se añada una dirección postal.`, + issuedCardVirtual: ({assignee, link}: IssueVirtualCardParams) => `¡emitió a ${assignee} una ${link} virtual! La tarjeta puede utilizarse inmediatamente.`, + addedAddress: (assignee: string) => `${assignee} ha añadido la dirección. Tarjeta Expensify llegará en 2-3 días hábiles.`, }, categories: { deleteCategories: 'Eliminar categorías', diff --git a/src/languages/types.ts b/src/languages/types.ts index 24117f257d8f..9e1e7113a9e6 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -348,6 +348,11 @@ type DeleteExpenseTranslationParams = { count: number; }; +type IssueVirtualCardParams = { + assignee: string; + link: string; +}; + export type { AddressLineParams, AdminCanceledRequestParams, @@ -376,6 +381,7 @@ export type { GoToRoomParams, HeldRequestParams, InstantSummaryParams, + IssueVirtualCardParams, LocalTimeParams, LogSizeParams, LoggedInAsParams, diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index c741be4ca3b4..051b19f4c7ae 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -22,6 +22,7 @@ import type {ActionableItem} from '@components/ReportActionItem/ActionableItemBu import ActionableItemButtons from '@components/ReportActionItem/ActionableItemButtons'; import ChronosOOOListActions from '@components/ReportActionItem/ChronosOOOListActions'; import ExportIntegration from '@components/ReportActionItem/ExportIntegration'; +import IssueCardMessage from '@components/ReportActionItem/IssueCardMessage'; import MoneyRequestAction from '@components/ReportActionItem/MoneyRequestAction'; import RenameAction from '@components/ReportActionItem/RenameAction'; import ReportPreview from '@components/ReportActionItem/ReportPreview'; @@ -653,6 +654,10 @@ function ReportActionItem({ children = <ReportActionItemBasicMessage message={ReportActionsUtils.getDismissedViolationMessageText(ReportActionsUtils.getOriginalMessage(action))} />; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.ADD_TAG) { children = <ReportActionItemBasicMessage message={PolicyUtils.getCleanedTagName(ReportActionsUtils.getReportActionMessage(action)?.text ?? '')} />; + } else if ( + ReportActionsUtils.isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.CARD_ISSUED, CONST.REPORT.ACTIONS.TYPE.CARD_ISSUED_VIRTUAL, CONST.REPORT.ACTIONS.TYPE.CARD_MISSING_ADDRESS) + ) { + children = <IssueCardMessage action={action} />; } else if (ReportActionsUtils.isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.EXPORTED_TO_INTEGRATION)) { children = <ExportIntegration action={action} />; } else { diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 06b31f242989..94c2059f1260 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -579,6 +579,12 @@ type OriginalMessageMap = { [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP]: never; /** */ [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_SETUP_REQUESTED]: never; + /** */ + [CONST.REPORT.ACTIONS.TYPE.CARD_ISSUED]: never; + /** */ + [CONST.REPORT.ACTIONS.TYPE.CARD_MISSING_ADDRESS]: never; + /** */ + [CONST.REPORT.ACTIONS.TYPE.CARD_ISSUED_VIRTUAL]: never; } & OldDotOriginalMessageMap & { [T in ValueOf<typeof CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG>]: OriginalMessageChangeLog; } & {