From eb1a18d1fff2efac4db67ef099a3f0199d23b471 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 3 Sep 2024 17:42:29 +0200 Subject: [PATCH 01/24] new asset --- ...gstate_laptop-with-hourglass-and-cards.svg | 244 ++++++++++++++++++ src/components/Icon/Illustrations.ts | 2 + 2 files changed, 246 insertions(+) create mode 100644 assets/images/companyCards/pendingstate_laptop-with-hourglass-and-cards.svg 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/Icon/Illustrations.ts b/src/components/Icon/Illustrations.ts index e30fc8bce7b7..670ab18fbd41 100644 --- a/src/components/Icon/Illustrations.ts +++ b/src/components/Icon/Illustrations.ts @@ -1,6 +1,7 @@ import AmexCompanyCards from '@assets/images/companyCards/amex.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'; @@ -230,4 +231,5 @@ export { AmexCompanyCards, MasterCardCompanyCards, VisaCompanyCards, + CompanyCardsPendingState, }; From d08cfcb97426fbfb9858228bd40075955ec15ec0 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 3 Sep 2024 17:42:48 +0200 Subject: [PATCH 02/24] add support for reactNode for the subtitle --- src/components/EmptyStateComponent/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/EmptyStateComponent/types.ts b/src/components/EmptyStateComponent/types.ts index 80fac980864f..3c9c24cf6ed2 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; headerStyles?: StyleProp; From de98cdc58a5a6279eab71e5d037f6c5cf9455b39 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 3 Sep 2024 17:43:00 +0200 Subject: [PATCH 03/24] new translations --- src/languages/en.ts | 2 ++ src/languages/es.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/languages/en.ts b/src/languages/en.ts index 30e2dad391d9..996d84dfe1cb 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2922,6 +2922,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.', + pendingNoFeedTitle: `We're reviewing your request...`, + pendingNoFeedDescription: `We're currently reviewing your feed details. Once that's done we'll reach out to you via`, }, workflows: { title: 'Workflows', diff --git a/src/languages/es.ts b/src/languages/es.ts index 16b8f6f42ed2..6fa1377f187f 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2967,6 +2967,8 @@ 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.', + pendingNoFeedTitle: `Estamos revisando tu solicitud...`, + pendingNoFeedDescription: `Actualmente estamos revisando los detalles de tu feed. Una vez hecho esto, nos pondremos en contacto contigo a través de Concierge.`, }, distanceRates: { title: 'Tasas de distancia', From 99d0bde7bfe2b2aedf80b298a238462c5b323860 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 3 Sep 2024 17:43:26 +0200 Subject: [PATCH 04/24] add openPolicyCompanyCardsPage API --- .../OpenPolicyCompanyCardsPageParams.ts | 6 +++ src/libs/API/types.ts | 2 + src/libs/actions/Policy/Policy.ts | 42 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 src/libs/API/parameters/OpenPolicyCompanyCardsPageParams.ts 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 42cfc8d01aa1..79d8a99d16f5 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -752,6 +752,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', @@ -816,6 +817,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 3ccbb7873cef..fb5e091d99c0 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -2073,6 +2073,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(); @@ -3913,6 +3954,7 @@ export { setWorkspaceCompanyCardFeedName, deleteWorkspaceCompanyCardFeed, setWorkspaceCompanyCardTransactionLiability, + openPolicyCompanyCardsPage, }; export type {NewCustomUnit}; From 5920205f3fa0022321fb52620cb01775ad26c6ba Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 3 Sep 2024 17:43:41 +0200 Subject: [PATCH 05/24] new pending page --- ...spaceCompanyCardsFeedNoFeedPendingPage.tsx | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/pages/workspace/companyCards/WorkspaceCompanyCardsFeedNoFeedPendingPage.tsx diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsFeedNoFeedPendingPage.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsFeedNoFeedPendingPage.tsx new file mode 100644 index 000000000000..26dd1b6771ea --- /dev/null +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsFeedNoFeedPendingPage.tsx @@ -0,0 +1,38 @@ +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 WorkspaceCompanyCardsFeedNoFeedPendingPage() { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + + const subtitle = ( + <> + {translate('workspace.moreFeatures.companyCards.pendingNoFeedDescription')} + ReportInstance.navigateToConciergeChat()}> {CONST?.CONCIERGE_CHAT_NAME} + + ); + + return ( + + ); +} + +WorkspaceCompanyCardsFeedNoFeedPendingPage.displayName = 'WorkspaceCompanyCardsFeedNoFeedPendingPage'; + +export default WorkspaceCompanyCardsFeedNoFeedPendingPage; From 498cf13d62eef94e34d2157d92326ef8a0da1db2 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 3 Sep 2024 17:44:08 +0200 Subject: [PATCH 06/24] update main page --- .../WorkspaceCompanyCardsPage.tsx | 63 ++++++++++--------- src/types/onyx/CardFeeds.ts | 3 + 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx index 201f64e7681c..c52bd22c10eb 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx @@ -1,59 +1,60 @@ +import {useFocusEffect} from '@react-navigation/native'; import type {StackScreenProps} from '@react-navigation/stack'; -import React from 'react'; +import React, {useCallback} from 'react'; import {View} from 'react-native'; -// import Onyx from 'react-native-onyx'; +import {ActivityIndicator} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; import useLocalize from '@hooks/useLocalize'; -// import usePolicy from '@hooks/usePolicy'; +import usePolicy from '@hooks/usePolicy'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; import Navigation from '@navigation/Navigation'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections'; +import * as Policy from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; -// import ONYXKEYS from '@src/ONYXKEYS'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import WorkspaceCompanyCardPageEmptyState from './WorkspaceCompanyCardPageEmptyState'; import WorkspaceCompanyCardsFeedAddedEmptyPage from './WorkspaceCompanyCardsFeedAddedEmptyPage'; +import WorkspaceCompanyCardsFeedNoFeedPendingPage from './WorkspaceCompanyCardsFeedNoFeedPendingPage'; type WorkspaceCompanyCardPageProps = StackScreenProps; function WorkspaceCompanyCardPage({route}: WorkspaceCompanyCardPageProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); + const theme = useTheme(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const policyID = route.params.policyID; - // const policy = usePolicy(policyID); - // const workspaceAccountID = policy?.workspaceAccountID ?? -1; + const policy = usePolicy(policyID); + const workspaceAccountID = policy?.workspaceAccountID ?? -1; + const [cardFeeds] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${workspaceAccountID.toString()}`); + const fetchCompanyCards = useCallback(() => { + Policy.openPolicyCompanyCardsPage(policyID, workspaceAccountID); + }, [policyID, workspaceAccountID]); - // useEffect(() => { - // Onyx.set(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${workspaceAccountID}`, { - // companyCards: { - // cdfbmo: { - // pending: false, - // asrEnabled: true, - // forceReimbursable: 'force_no', - // liabilityType: 'corporate', - // preferredPolicy: '', - // reportTitleFormat: '{report:card}{report:bank}{report:submit:from}{report:total}{report:enddate:MMMM}', - // statementPeriodEndDay: 'LAST_DAY_OF_MONTH', - // }, - // }, - // companyCardNicknames: { - // cdfbmo: 'BMO MasterCard', - // }, - // }); - // }, [workspaceAccountID]); + useFocusEffect(fetchCompanyCards); + + const companyCards = cardFeeds?.companyCards; + const companyCardsLength = Object.keys(companyCards ?? {}).length; + const isNoFeed = companyCardsLength === 0; + const isFeedAdded = companyCardsLength > 0 && !Object.values(companyCards ?? {})[0].pending; + const isPending = companyCardsLength === 1 && Object.values(companyCards ?? {})[0].pending; + const isLoading = !cardFeeds || cardFeeds.isLoading; const getHeaderButtons = () => (