diff --git a/assets/images/companyCards/card-amex-blue.svg b/assets/images/companyCards/card-amex-blue.svg deleted file mode 100644 index 5282ca095760..000000000000 --- a/assets/images/companyCards/card-amex-blue.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/assets/images/companyCards/card-amex.svg b/assets/images/companyCards/card-amex.svg index 5282ca095760..0e8b2d22e9b4 100644 --- a/assets/images/companyCards/card-amex.svg +++ b/assets/images/companyCards/card-amex.svg @@ -1,39 +1,32 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + diff --git a/assets/images/companyCards/card-bofa.svg b/assets/images/companyCards/card-bofa.svg new file mode 100644 index 000000000000..469142e4d6ff --- /dev/null +++ b/assets/images/companyCards/card-bofa.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + diff --git a/assets/images/companyCards/card-brex.svg b/assets/images/companyCards/card-brex.svg index 068c9a054d39..dd19403d5837 100644 --- a/assets/images/companyCards/card-brex.svg +++ b/assets/images/companyCards/card-brex.svg @@ -1,35 +1,27 @@ - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + diff --git a/assets/images/companyCards/card-capitalone.svg b/assets/images/companyCards/card-capitalone.svg new file mode 100644 index 000000000000..95948992383b --- /dev/null +++ b/assets/images/companyCards/card-capitalone.svg @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/assets/images/companyCards/card-chase.svg b/assets/images/companyCards/card-chase.svg index 511453169813..7bea71bd66ec 100644 --- a/assets/images/companyCards/card-chase.svg +++ b/assets/images/companyCards/card-chase.svg @@ -1,32 +1,24 @@ - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + diff --git a/assets/images/companyCards/card-citi.svg b/assets/images/companyCards/card-citi.svg index 2d2bf71b1312..c8d71afd7798 100644 --- a/assets/images/companyCards/card-citi.svg +++ b/assets/images/companyCards/card-citi.svg @@ -1,43 +1,32 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + diff --git a/assets/images/companyCards/card-expensify.svg b/assets/images/companyCards/card-expensify.svg index d6b847d8f74f..9fd29b511c7b 100644 --- a/assets/images/companyCards/card-expensify.svg +++ b/assets/images/companyCards/card-expensify.svg @@ -1,72 +1,99 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/companyCards/card-mastercard.svg b/assets/images/companyCards/card-mastercard.svg index b1a698fe9acc..e8d3cf8f4096 100644 --- a/assets/images/companyCards/card-mastercard.svg +++ b/assets/images/companyCards/card-mastercard.svg @@ -1,40 +1,27 @@ - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + diff --git a/assets/images/companyCards/card-stripe.svg b/assets/images/companyCards/card-stripe.svg index e4c874452309..608f067a1854 100644 --- a/assets/images/companyCards/card-stripe.svg +++ b/assets/images/companyCards/card-stripe.svg @@ -1,45 +1,39 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + diff --git a/assets/images/companyCards/card-visa.svg b/assets/images/companyCards/card-visa.svg index 52d0f727a960..9e2eae97ba90 100644 --- a/assets/images/companyCards/card-visa.svg +++ b/assets/images/companyCards/card-visa.svg @@ -1,60 +1,73 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/companyCards/card-wellsfargo.svg b/assets/images/companyCards/card-wellsfargo.svg new file mode 100644 index 000000000000..086f66cc0423 --- /dev/null +++ b/assets/images/companyCards/card-wellsfargo.svg @@ -0,0 +1,57 @@ + + + + + + + + diff --git a/assets/images/companyCards/card=-generic.svg b/assets/images/companyCards/card=-generic.svg new file mode 100644 index 000000000000..61e4296f7779 --- /dev/null +++ b/assets/images/companyCards/card=-generic.svg @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/assets/images/companyCards/pendingstate_laptop-with-hourglass-and-cards.svg b/assets/images/companyCards/pendingstate_laptop-with-hourglass-and-cards.svg new file mode 100644 index 000000000000..0f40859c8839 --- /dev/null +++ b/assets/images/companyCards/pendingstate_laptop-with-hourglass-and-cards.svg @@ -0,0 +1,244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/EmptyStateComponent/types.ts b/src/components/EmptyStateComponent/types.ts index 7f3b375f9f75..a30a9222c01f 100644 --- a/src/components/EmptyStateComponent/types.ts +++ b/src/components/EmptyStateComponent/types.ts @@ -13,7 +13,7 @@ type MediaTypes = ValueOf; type SharedProps = { SkeletonComponent: ValidSkeletons; title: string; - subtitle: string; + subtitle: string | React.ReactNode; buttonText?: string; buttonAction?: () => void; containerStyles?: StyleProp; diff --git a/src/components/Icon/Illustrations.ts b/src/components/Icon/Illustrations.ts index 954f9fa5caa7..e3604dc5a86e 100644 --- a/src/components/Icon/Illustrations.ts +++ b/src/components/Icon/Illustrations.ts @@ -1,10 +1,10 @@ import AmexCompanyCards from '@assets/images/companyCards/amex.svg'; -import AmexBlueCompanyCards from '@assets/images/companyCards/card-amex-blue.svg'; import AmexCardCompanyCardDetail from '@assets/images/companyCards/card-amex.svg'; import MasterCardCompanyCardDetail from '@assets/images/companyCards/card-mastercard.svg'; import VisaCompanyCardDetail from '@assets/images/companyCards/card-visa.svg'; import CompanyCardsEmptyState from '@assets/images/companyCards/emptystate__card-pos.svg'; import MasterCardCompanyCards from '@assets/images/companyCards/mastercard.svg'; +import CompanyCardsPendingState from '@assets/images/companyCards/pendingstate_laptop-with-hourglass-and-cards.svg'; import VisaCompanyCards from '@assets/images/companyCards/visa.svg'; import EmptyCardState from '@assets/images/emptystate__expensifycard.svg'; import ExpensifyCardIllustration from '@assets/images/expensifyCard/cardIllustration.svg'; @@ -239,7 +239,7 @@ export { AmexCompanyCards, MasterCardCompanyCards, VisaCompanyCards, - AmexBlueCompanyCards, + CompanyCardsPendingState, VisaCompanyCardDetail, MasterCardCompanyCardDetail, AmexCardCompanyCardDetail, diff --git a/src/languages/en.ts b/src/languages/en.ts index a6c5f54bb9dd..5aecf780eb63 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2845,11 +2845,11 @@ export default { companyLabel: 'Company ID', }, amex: { - title: `What's the Amex delivery file name`, + title: `What's the Amex delivery file name?`, fileNameLabel: 'Delivery file name', }, mastercard: { - title: `What's the Mastercard distribution ID`, + title: `What's the Mastercard distribution ID?`, distributionLabel: 'Distribution ID', }, }, @@ -3062,6 +3062,8 @@ export default { setTransactionLiabilityDescription: 'When enabled, cardholders can delete card transactions. New transactions will follow this rule.', emptyAddedFeedTitle: 'Assign company cards', emptyAddedFeedDescription: 'Get started by assigning your first card to a member.', + pendingFeedTitle: `We're reviewing your request...`, + pendingFeedDescription: `We're currently reviewing your feed details. Once that's done we'll reach out to you via`, giveItNameInstruction: 'Give the card a name that sets it apart from the others.', updating: 'Updating...', noAccountsFound: 'No accounts found', diff --git a/src/languages/es.ts b/src/languages/es.ts index a8481ec305fc..5229beb16eca 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3111,7 +3111,9 @@ export default { 'Cuando está habilitada, los titulares de tarjetas pueden eliminar transacciones con tarjeta. Las transacciones nuevas seguirán esta regla.', emptyAddedFeedTitle: 'Asignar tarjetas de empresa', emptyAddedFeedDescription: 'Comienza asignando tu primera tarjeta a un miembro.', - giveItNameInstruction: 'Dale a la tarjeta un nombre que la distinga de las demás.', + pendingFeedTitle: `Estamos revisando tu solicitud...`, + pendingFeedDescription: `Actualmente estamos revisando los detalles de tu feed. Una vez hecho esto, nos pondremos en contacto contigo a través de`, + giveItNameInstruction: 'Nombra la tarjeta para distingirla de las demás.', updating: 'Actualizando...', noAccountsFound: 'No se han encontrado cuentas', noAccountsFoundDescription: (connection: string) => `Añade la cuenta en ${connection} y sincroniza la conexión de nuevo.`, diff --git a/src/libs/API/parameters/OpenPolicyCompanyCardsPageParams.ts b/src/libs/API/parameters/OpenPolicyCompanyCardsPageParams.ts new file mode 100644 index 000000000000..0fd101ab03b7 --- /dev/null +++ b/src/libs/API/parameters/OpenPolicyCompanyCardsPageParams.ts @@ -0,0 +1,6 @@ +type OpenPolicyCompanyCardsPageParams = { + policyID: string; + authToken: string | null | undefined; +}; + +export default OpenPolicyCompanyCardsPageParams; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 5c6102da81d8..2fa068c8a753 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -853,6 +853,7 @@ const READ_COMMANDS = { OPEN_POLICY_TAXES_PAGE: 'OpenPolicyTaxesPage', OPEN_POLICY_REPORT_FIELDS_PAGE: 'OpenPolicyReportFieldsPage', OPEN_POLICY_EXPENSIFY_CARDS_PAGE: 'OpenPolicyExpensifyCardsPage', + OPEN_POLICY_COMPANY_CARDS_PAGE: 'OpenPolicyCompanyCardsPage', OPEN_POLICY_EDIT_CARD_LIMIT_TYPE_PAGE: 'OpenPolicyEditCardLimitTypePage', OPEN_WORKSPACE_INVITE_PAGE: 'OpenWorkspaceInvitePage', OPEN_DRAFT_WORKSPACE_REQUEST: 'OpenDraftWorkspaceRequest', @@ -917,6 +918,7 @@ type ReadCommandParameters = { [READ_COMMANDS.OPEN_POLICY_MORE_FEATURES_PAGE]: Parameters.OpenPolicyMoreFeaturesPageParams; [READ_COMMANDS.OPEN_POLICY_ACCOUNTING_PAGE]: Parameters.OpenPolicyAccountingPageParams; [READ_COMMANDS.OPEN_POLICY_EXPENSIFY_CARDS_PAGE]: Parameters.OpenPolicyExpensifyCardsPageParams; + [READ_COMMANDS.OPEN_POLICY_COMPANY_CARDS_PAGE]: Parameters.OpenPolicyExpensifyCardsPageParams; [READ_COMMANDS.OPEN_POLICY_EDIT_CARD_LIMIT_TYPE_PAGE]: Parameters.OpenPolicyEditCardLimitTypePageParams; [READ_COMMANDS.OPEN_POLICY_PROFILE_PAGE]: Parameters.OpenPolicyProfilePageParams; [READ_COMMANDS.OPEN_POLICY_INITIAL_PAGE]: Parameters.OpenPolicyInitialPageParams; diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index e30ddaf97e1f..d73e2b8c4166 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -71,7 +71,6 @@ import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as PhoneNumber from '@libs/PhoneNumber'; import * as PolicyUtils from '@libs/PolicyUtils'; import {navigateWhenEnableFeature} from '@libs/PolicyUtils'; -import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; @@ -93,6 +92,7 @@ import type { } from '@src/types/onyx'; import type {Errors} from '@src/types/onyx/OnyxCommon'; import type {Attributes, CompanyAddress, CustomUnit, NetSuiteCustomList, NetSuiteCustomSegment, Rate, TaxRate, Unit} from '@src/types/onyx/Policy'; +import type {ReportActions} from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import {buildOptimisticPolicyCategories} from './Category'; @@ -165,6 +165,19 @@ Onyx.connect({ }, }); +let allReportActions: OnyxCollection; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT_ACTIONS, + waitForCollectionCallback: true, + callback: (actions) => { + if (!actions) { + return; + } + + allReportActions = actions; + }, +}); + let lastAccessedWorkspacePolicyID: OnyxEntry; Onyx.connect({ key: ONYXKEYS.LAST_ACCESSED_WORKSPACE_POLICY_ID, @@ -2119,6 +2132,47 @@ function openPolicyTaxesPage(policyID: string) { API.read(READ_COMMANDS.OPEN_POLICY_TAXES_PAGE, params); } +function openPolicyCompanyCardsPage(policyID: string, workspaceAccountID: number) { + const authToken = NetworkStore.getAuthToken(); + + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${workspaceAccountID}`, + value: { + isLoading: true, + }, + }, + ]; + + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${workspaceAccountID}`, + value: { + isLoading: false, + }, + }, + ]; + + const failureData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${workspaceAccountID}`, + value: { + isLoading: false, + }, + }, + ]; + + const params: OpenPolicyExpensifyCardsPageParams = { + policyID, + authToken, + }; + + API.read(READ_COMMANDS.OPEN_POLICY_COMPANY_CARDS_PAGE, params, {optimisticData, successData, failureData}); +} + function openPolicyExpensifyCardsPage(policyID: string, workspaceAccountID: number) { const authToken = NetworkStore.getAuthToken(); @@ -2578,7 +2632,11 @@ function createWorkspaceFromIOUPayment(iouReport: OnyxEntry): WorkspaceF }); // We need to move the report preview action from the DM to the workspace chat. - const reportPreview = ReportActionsUtils.getParentReportAction(iouReport); + const reportPreview = + iouReport?.parentReportID && iouReport.parentReportActionID + ? allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.parentReportID}`]?.[iouReport.parentReportActionID] + : undefined; + optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldChatReportID}`, @@ -4971,6 +5029,7 @@ export { setWorkspaceCompanyCardFeedName, deleteWorkspaceCompanyCardFeed, setWorkspaceCompanyCardTransactionLiability, + openPolicyCompanyCardsPage, unassignWorkspaceCompanyCard, updateWorkspaceCompanyCard, updateCompanyCardName, diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsFeedPendingPage.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsFeedPendingPage.tsx new file mode 100644 index 000000000000..f387de8c6f03 --- /dev/null +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsFeedPendingPage.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import EmptyStateComponent from '@components/EmptyStateComponent'; +import * as Illustrations from '@components/Icon/Illustrations'; +import TableListItemSkeleton from '@components/Skeletons/TableRowSkeleton'; +import TextLink from '@components/TextLink'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import colors from '@styles/theme/colors'; +import * as ReportInstance from '@userActions/Report'; +import CONST from '@src/CONST'; + +function WorkspaceCompanyCardsFeedPendingPage() { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + + const subtitle = ( + <> + {translate('workspace.moreFeatures.companyCards.pendingFeedDescription')} + ReportInstance.navigateToConciergeChat()}> {CONST?.CONCIERGE_CHAT_NAME} + + ); + + return ( + + ); +} + +WorkspaceCompanyCardsFeedPendingPage.displayName = 'WorkspaceCompanyCardsFeedPendingPage'; + +export default WorkspaceCompanyCardsFeedPendingPage; diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsListHeaderButtons.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsListHeaderButtons.tsx index 863ad7e2de5e..b71f6583e25a 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardsListHeaderButtons.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsListHeaderButtons.tsx @@ -1,5 +1,6 @@ import React from 'react'; import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import CaretWrapper from '@components/CaretWrapper'; import Icon from '@components/Icon'; @@ -10,16 +11,11 @@ import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import * as CardUtils from '@libs/CardUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; import variables from '@styles/variables'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {CardFeeds} from '@src/types/onyx'; - -const mockedFeeds = { - companyCardNicknames: { - cdfbmo: 'BMO MasterCard', - }, -} as unknown as CardFeeds; type WorkspaceCompanyCardsListHeaderButtonsProps = { /** Current policy id */ @@ -33,17 +29,16 @@ function WorkspaceCompanyCardsListHeaderButtons({policyID, selectedFeed}: Worksp const styles = useThemeStyles(); const {translate} = useLocalize(); const {shouldUseNarrowLayout, isMediumScreenWidth} = useResponsiveLayout(); - // TODO: use data form onyx instead of mocked one when API is implemented - // const [cardFeeds] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${workspaceAccountID}`); - const cardFeeds = mockedFeeds ?? {}; + const workspaceAccountID = PolicyUtils.getWorkspaceAccountID(policyID); + const [cardFeeds] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${workspaceAccountID}`); const shouldChangeLayout = isMediumScreenWidth || shouldUseNarrowLayout; return ( Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_SELECT_FEED.getRoute(policyID))} - style={[styles.flexRow, styles.alignItemsCenter, styles.gap3, styles.ml4, shouldChangeLayout && styles.mb3]} - accessibilityLabel={cardFeeds?.companyCardNicknames?.[selectedFeed]} + style={[styles.flexRow, styles.alignItemsCenter, styles.gap3, styles.ml4, shouldUseNarrowLayout && styles.mb3]} + accessibilityLabel={cardFeeds?.companyCardNicknames?.[selectedFeed] ?? ''} >