From e55f5a84c57a9bda3344964197e38cebf4ee4ec6 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Tue, 5 Nov 2024 17:44:15 +0300 Subject: [PATCH 01/11] updated EmptySearchView to show generic nothing to show message for empty search results --- src/components/Search/index.tsx | 6 ++++- src/pages/Search/EmptySearchView.tsx | 40 ++++++++++++++++------------ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 9238488361b0..8a54b1d14ed1 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -33,6 +33,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SearchResults from '@src/types/onyx/SearchResults'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import {useSearchContext} from './SearchContext'; import type {SearchColumnType, SearchQueryJSON, SearchStatus, SelectedTransactionInfo, SelectedTransactions, SortOrder} from './types'; @@ -307,7 +308,10 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr if (shouldShowEmptyState) { return ( - + ); } diff --git a/src/pages/Search/EmptySearchView.tsx b/src/pages/Search/EmptySearchView.tsx index 8e61978c169e..e274c981aa21 100644 --- a/src/pages/Search/EmptySearchView.tsx +++ b/src/pages/Search/EmptySearchView.tsx @@ -26,6 +26,7 @@ import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; type EmptySearchViewProps = { type: SearchDataTypes; + noExpensesCreatedYet?: boolean; }; const tripsFeatures: FeatureListItem[] = [ @@ -39,7 +40,7 @@ const tripsFeatures: FeatureListItem[] = [ }, ]; -function EmptySearchView({type}: EmptySearchViewProps) { +function EmptySearchView({type, noExpensesCreatedYet = false}: EmptySearchViewProps) { const theme = useTheme(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); @@ -114,21 +115,26 @@ function EmptySearchView({type}: EmptySearchViewProps) { ], }; case CONST.SEARCH.DATA_TYPES.EXPENSE: - return { - headerMedia: LottieAnimations.GenericEmptyState, - headerStyles: [StyleUtils.getBackgroundColorStyle(theme.emptyFolderBG)], - title: translate('search.searchResults.emptyExpenseResults.title'), - subtitle: translate('search.searchResults.emptyExpenseResults.subtitle'), - buttons: [ - {buttonText: translate('emptySearchView.takeATour'), buttonAction: () => Link.openExternalLink(navatticLink)}, - { - buttonText: translate('iou.createExpense'), - buttonAction: () => interceptAnonymousUser(() => IOU.startMoneyRequest(CONST.IOU.TYPE.CREATE, ReportUtils.generateReportID())), - success: true, - }, - ], - headerContentStyles: styles.emptyStateFolderWebStyles, - }; + if (noExpensesCreatedYet) { + return { + headerMedia: LottieAnimations.GenericEmptyState, + headerStyles: [StyleUtils.getBackgroundColorStyle(theme.emptyFolderBG)], + title: translate('search.searchResults.emptyExpenseResults.title'), + subtitle: translate('search.searchResults.emptyExpenseResults.subtitle'), + buttons: [ + {buttonText: translate('emptySearchView.takeATour'), buttonAction: () => Link.openExternalLink(navatticLink)}, + { + buttonText: translate('iou.createExpense'), + buttonAction: () => interceptAnonymousUser(() => IOU.startMoneyRequest(CONST.IOU.TYPE.CREATE, ReportUtils.generateReportID())), + success: true, + }, + ], + headerContentStyles: styles.emptyStateFolderWebStyles, + }; + } + // We want to display the default nothing to show message if the user has expenses created + // but the current search filter result is empty. + // eslint-disable-next-line no-fallthrough case CONST.SEARCH.DATA_TYPES.CHAT: case CONST.SEARCH.DATA_TYPES.INVOICE: default: @@ -140,7 +146,7 @@ function EmptySearchView({type}: EmptySearchViewProps) { headerContentStyles: styles.emptyStateFolderWebStyles, }; } - }, [type, StyleUtils, translate, theme, styles, subtitleComponent, ctaErrorMessage, navatticLink]); + }, [type, StyleUtils, translate, theme, styles, subtitleComponent, ctaErrorMessage, navatticLink, noExpensesCreatedYet]); return ( Date: Fri, 8 Nov 2024 23:22:02 +0300 Subject: [PATCH 02/11] rename variable --- src/components/Search/index.tsx | 2 +- src/pages/Search/EmptySearchView.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 8a54b1d14ed1..9cbc0b2052bc 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -310,7 +310,7 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr ); diff --git a/src/pages/Search/EmptySearchView.tsx b/src/pages/Search/EmptySearchView.tsx index e274c981aa21..539da3d34c2a 100644 --- a/src/pages/Search/EmptySearchView.tsx +++ b/src/pages/Search/EmptySearchView.tsx @@ -26,7 +26,7 @@ import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; type EmptySearchViewProps = { type: SearchDataTypes; - noExpensesCreatedYet?: boolean; + hasNoExpensesCreatedYet?: boolean; }; const tripsFeatures: FeatureListItem[] = [ @@ -40,7 +40,7 @@ const tripsFeatures: FeatureListItem[] = [ }, ]; -function EmptySearchView({type, noExpensesCreatedYet = false}: EmptySearchViewProps) { +function EmptySearchView({type, hasNoExpensesCreatedYet = false}: EmptySearchViewProps) { const theme = useTheme(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); @@ -115,7 +115,7 @@ function EmptySearchView({type, noExpensesCreatedYet = false}: EmptySearchViewPr ], }; case CONST.SEARCH.DATA_TYPES.EXPENSE: - if (noExpensesCreatedYet) { + if (hasNoExpensesCreatedYet) { return { headerMedia: LottieAnimations.GenericEmptyState, headerStyles: [StyleUtils.getBackgroundColorStyle(theme.emptyFolderBG)], @@ -146,7 +146,7 @@ function EmptySearchView({type, noExpensesCreatedYet = false}: EmptySearchViewPr headerContentStyles: styles.emptyStateFolderWebStyles, }; } - }, [type, StyleUtils, translate, theme, styles, subtitleComponent, ctaErrorMessage, navatticLink, noExpensesCreatedYet]); + }, [type, StyleUtils, translate, theme, styles, subtitleComponent, ctaErrorMessage, navatticLink, hasNoExpensesCreatedYet]); return ( Date: Tue, 12 Nov 2024 16:26:40 +0300 Subject: [PATCH 03/11] updated comment --- src/pages/Search/EmptySearchView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Search/EmptySearchView.tsx b/src/pages/Search/EmptySearchView.tsx index 2bf541e45907..dfb691da37b6 100644 --- a/src/pages/Search/EmptySearchView.tsx +++ b/src/pages/Search/EmptySearchView.tsx @@ -135,8 +135,8 @@ function EmptySearchView({type, hasNoExpensesCreatedYet = false}: EmptySearchVie headerContentStyles: styles.emptyStateFolderWebStyles, }; } - // We want to display the default nothing to show message if the user has expenses created - // but the current search filter result is empty. + // We want to display the default nothing to show message if the current expense type search + // result is empty but the user already has some expenses created. // eslint-disable-next-line no-fallthrough case CONST.SEARCH.DATA_TYPES.CHAT: case CONST.SEARCH.DATA_TYPES.INVOICE: From 267e219b4fc47f47a29e5348c20a7f3858818872 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 13 Nov 2024 00:43:01 +0300 Subject: [PATCH 04/11] updated noExpenseCreated logic --- src/components/Search/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 9f43934a247f..187a6979b144 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -309,13 +309,14 @@ function Search({queryJSON, onSearchListScroll, isSearchScreenFocused, contentCo }); const shouldShowEmptyState = !isDataLoaded || data.length === 0; + const hasNoExpensesCreatedYet = shouldShowEmptyState && isEmptyObject(queryJSON.filters) && queryJSON.status === CONST.SEARCH.STATUS.EXPENSE.ALL && !queryJSON.policyID; if (shouldShowEmptyState) { return ( ); From 13edffd10c2d403da4c5b58d2dcaab9d0aa4f52c Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 13 Nov 2024 01:19:24 +0300 Subject: [PATCH 05/11] added no invoices created yet variant --- src/components/Search/index.tsx | 4 ++-- src/languages/en.ts | 4 ++++ src/pages/Search/EmptySearchView.tsx | 31 +++++++++++++++++++++------- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 187a6979b144..cdf9b936eb78 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -309,14 +309,14 @@ function Search({queryJSON, onSearchListScroll, isSearchScreenFocused, contentCo }); const shouldShowEmptyState = !isDataLoaded || data.length === 0; - const hasNoExpensesCreatedYet = shouldShowEmptyState && isEmptyObject(queryJSON.filters) && queryJSON.status === CONST.SEARCH.STATUS.EXPENSE.ALL && !queryJSON.policyID; + const hasNoFilterApplied = isEmptyObject(queryJSON.filters) && queryJSON.status === CONST.SEARCH.STATUS.EXPENSE.ALL && !queryJSON.policyID; if (shouldShowEmptyState) { return ( ); diff --git a/src/languages/en.ts b/src/languages/en.ts index 7f05ea436837..a4fd2db805ab 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -4392,6 +4392,10 @@ const translations = { title: "You haven't created any expenses yet", subtitle: 'Use the green button below to create an expense or take a tour of Expensify to learn more.', }, + emptyInvoiceResults: { + title: "You haven't created any invoices yet", + subtitle: 'Use the green button below to send an invoice or take a tour of Expensify to learn more.', + }, emptyTripResults: { title: 'No trips to display', subtitle: 'Get started by booking your first trip below.', diff --git a/src/pages/Search/EmptySearchView.tsx b/src/pages/Search/EmptySearchView.tsx index dfb691da37b6..45ffe4638fc2 100644 --- a/src/pages/Search/EmptySearchView.tsx +++ b/src/pages/Search/EmptySearchView.tsx @@ -28,7 +28,7 @@ import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; type EmptySearchViewProps = { type: SearchDataTypes; - hasNoExpensesCreatedYet?: boolean; + hasNoFilterApplied?: boolean; }; const tripsFeatures: FeatureListItem[] = [ @@ -42,7 +42,7 @@ const tripsFeatures: FeatureListItem[] = [ }, ]; -function EmptySearchView({type, hasNoExpensesCreatedYet = false}: EmptySearchViewProps) { +function EmptySearchView({type, hasNoFilterApplied = false}: EmptySearchViewProps) { const theme = useTheme(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); @@ -118,7 +118,7 @@ function EmptySearchView({type, hasNoExpensesCreatedYet = false}: EmptySearchVie ], }; case CONST.SEARCH.DATA_TYPES.EXPENSE: - if (hasNoExpensesCreatedYet) { + if (hasNoFilterApplied) { return { headerMedia: LottieAnimations.GenericEmptyState, headerStyles: [StyleUtils.getBackgroundColorStyle(theme.emptyFolderBG)], @@ -135,11 +135,28 @@ function EmptySearchView({type, hasNoExpensesCreatedYet = false}: EmptySearchVie headerContentStyles: styles.emptyStateFolderWebStyles, }; } - // We want to display the default nothing to show message if the current expense type search - // result is empty but the user already has some expenses created. + // We want to display the default nothing to show message if there is any filter applied. // eslint-disable-next-line no-fallthrough - case CONST.SEARCH.DATA_TYPES.CHAT: case CONST.SEARCH.DATA_TYPES.INVOICE: + if (hasNoFilterApplied) { + return { + headerMedia: LottieAnimations.GenericEmptyState, + headerStyles: [StyleUtils.getBackgroundColorStyle(theme.emptyFolderBG)], + title: translate('search.searchResults.emptyInvoiceResults.title'), + subtitle: translate('search.searchResults.emptyInvoiceResults.subtitle'), + buttons: [ + {buttonText: translate('emptySearchView.takeATour'), buttonAction: () => Link.openExternalLink(navatticURL)}, + { + buttonText: translate('workspace.invoices.sendInvoice'), + buttonAction: () => interceptAnonymousUser(() => IOU.startMoneyRequest(CONST.IOU.TYPE.INVOICE, ReportUtils.generateReportID())), + success: true, + }, + ], + headerContentStyles: styles.emptyStateFolderWebStyles, + }; + } + // eslint-disable-next-line no-fallthrough + case CONST.SEARCH.DATA_TYPES.CHAT: default: return { headerMedia: LottieAnimations.GenericEmptyState, @@ -149,7 +166,7 @@ function EmptySearchView({type, hasNoExpensesCreatedYet = false}: EmptySearchVie headerContentStyles: styles.emptyStateFolderWebStyles, }; } - }, [type, StyleUtils, translate, theme, styles, subtitleComponent, ctaErrorMessage, navatticURL, hasNoExpensesCreatedYet]); + }, [type, StyleUtils, translate, theme, styles, subtitleComponent, ctaErrorMessage, navatticURL, hasNoFilterApplied]); return ( Date: Wed, 13 Nov 2024 14:51:48 +0300 Subject: [PATCH 06/11] broke down the copy to two lines --- src/languages/en.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index a4fd2db805ab..3e0d3aafc586 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -4393,7 +4393,7 @@ const translations = { subtitle: 'Use the green button below to create an expense or take a tour of Expensify to learn more.', }, emptyInvoiceResults: { - title: "You haven't created any invoices yet", + title: "You haven't created any \ninvoices yet", subtitle: 'Use the green button below to send an invoice or take a tour of Expensify to learn more.', }, emptyTripResults: { From 9e59246ea489393c2e2529b72d35fc448a38def6 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 13 Nov 2024 19:23:12 +0300 Subject: [PATCH 07/11] add spanish translation --- src/languages/es.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/languages/es.ts b/src/languages/es.ts index 92ffd8728d97..c3a5c095c889 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -4439,6 +4439,10 @@ const translations = { title: 'Aún no has creado ningún gasto', subtitle: 'Usa el botón verde de abajo para crear un gasto o haz un tour por Expensify para aprender más.', }, + emptyInvoiceResults: { + title: 'Aún no has creado ninguna factura', + subtitle: 'Usa el botón verde de abajo para crear una factura o haz un tour por Expensify para aprender más.', + }, emptyTripResults: { title: 'No tienes viajes', subtitle: 'Reserva tu primer viaje a continuación.', From 35973092aaa4865ec8e0a59ec2aa9bd4b32111ac Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 13 Nov 2024 19:24:37 +0300 Subject: [PATCH 08/11] added new line --- src/languages/es.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index c3a5c095c889..3bab2a102d67 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -4440,7 +4440,7 @@ const translations = { subtitle: 'Usa el botón verde de abajo para crear un gasto o haz un tour por Expensify para aprender más.', }, emptyInvoiceResults: { - title: 'Aún no has creado ninguna factura', + title: 'Aún no has creado \nninguna factura', subtitle: 'Usa el botón verde de abajo para crear una factura o haz un tour por Expensify para aprender más.', }, emptyTripResults: { From f5ceb035f021a76e4841dca0cfa06fa747c8cd10 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Tue, 19 Nov 2024 20:13:49 +0300 Subject: [PATCH 09/11] added redirect to expensify classic same as for create expense --- src/pages/Search/EmptySearchView.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/pages/Search/EmptySearchView.tsx b/src/pages/Search/EmptySearchView.tsx index e9716d91a87b..10869a53bb16 100644 --- a/src/pages/Search/EmptySearchView.tsx +++ b/src/pages/Search/EmptySearchView.tsx @@ -164,7 +164,14 @@ function EmptySearchView({type, hasNoFilterApplied = false}: EmptySearchViewProp {buttonText: translate('emptySearchView.takeATour'), buttonAction: () => Link.openExternalLink(navatticURL)}, { buttonText: translate('workspace.invoices.sendInvoice'), - buttonAction: () => interceptAnonymousUser(() => IOU.startMoneyRequest(CONST.IOU.TYPE.INVOICE, ReportUtils.generateReportID())), + buttonAction: () => + interceptAnonymousUser(() => { + if (shouldRedirectToExpensifyClassic) { + setModalVisible(true); + return; + } + IOU.startMoneyRequest(CONST.IOU.TYPE.INVOICE, ReportUtils.generateReportID()); + }), success: true, }, ], From ce1abbc42867f9ec369135cd51b1b302a73d0081 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Thu, 5 Dec 2024 22:05:20 +0300 Subject: [PATCH 10/11] implemented with hasResults --- src/components/Search/index.tsx | 3 +-- src/pages/Search/EmptySearchView.tsx | 10 +++++----- src/types/onyx/SearchResults.ts | 4 ++++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 793b41cee51b..35ea91e6489c 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -340,14 +340,13 @@ function Search({queryJSON, onSearchListScroll, isSearchScreenFocused, contentCo }); const shouldShowEmptyState = !isDataLoaded || data.length === 0; - const hasNoFilterApplied = isEmptyObject(queryJSON.filters) && queryJSON.status === CONST.SEARCH.STATUS.EXPENSE.ALL && !queryJSON.policyID; if (shouldShowEmptyState) { return ( ); diff --git a/src/pages/Search/EmptySearchView.tsx b/src/pages/Search/EmptySearchView.tsx index b19f1ef5652e..16d72818f936 100644 --- a/src/pages/Search/EmptySearchView.tsx +++ b/src/pages/Search/EmptySearchView.tsx @@ -35,7 +35,7 @@ import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; type EmptySearchViewProps = { type: SearchDataTypes; - hasNoFilterApplied?: boolean; + hasResults: boolean; }; const tripsFeatures: FeatureListItem[] = [ @@ -49,7 +49,7 @@ const tripsFeatures: FeatureListItem[] = [ }, ]; -function EmptySearchView({type, hasNoFilterApplied = false}: EmptySearchViewProps) { +function EmptySearchView({type, hasResults}: EmptySearchViewProps) { const theme = useTheme(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); @@ -136,7 +136,7 @@ function EmptySearchView({type, hasNoFilterApplied = false}: EmptySearchViewProp lottieWebViewStyles: {backgroundColor: theme.travelBG, ...styles.emptyStateFolderWebStyles}, }; case CONST.SEARCH.DATA_TYPES.EXPENSE: - if (hasNoFilterApplied) { + if (!hasResults) { return { headerMedia: LottieAnimations.GenericEmptyState, title: translate('search.searchResults.emptyExpenseResults.title'), @@ -174,7 +174,7 @@ function EmptySearchView({type, hasNoFilterApplied = false}: EmptySearchViewProp // We want to display the default nothing to show message if there is any filter applied. // eslint-disable-next-line no-fallthrough case CONST.SEARCH.DATA_TYPES.INVOICE: - if (hasNoFilterApplied) { + if (!hasResults) { return { headerMedia: LottieAnimations.GenericEmptyState, title: translate('search.searchResults.emptyInvoiceResults.title'), @@ -233,7 +233,7 @@ function EmptySearchView({type, hasNoFilterApplied = false}: EmptySearchViewProp ctaErrorMessage, navatticURL, shouldRedirectToExpensifyClassic, - hasNoFilterApplied, + hasResults, viewTourTaskReport, ]); diff --git a/src/types/onyx/SearchResults.ts b/src/types/onyx/SearchResults.ts index bd5502e76a5f..9a72574ab0a7 100644 --- a/src/types/onyx/SearchResults.ts +++ b/src/types/onyx/SearchResults.ts @@ -54,6 +54,10 @@ type SearchResultsInfo = { /** Whether the user can fetch more search results */ hasMoreResults: boolean; + /** Whether the user has any valid data on the current search type, for instance, + * whether they have created any invoice yet when the search type is invoice */ + hasResults: boolean; + /** Whether the search results are currently loading */ isLoading: boolean; From 4eb86b4435761c97f4c7257dd7e03ac565274d53 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Thu, 5 Dec 2024 22:07:51 +0300 Subject: [PATCH 11/11] remove unwanted import --- src/components/Search/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 35ea91e6489c..07f23a96424d 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -33,7 +33,6 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SearchResults from '@src/types/onyx/SearchResults'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; import {useSearchContext} from './SearchContext'; import type {SearchColumnType, SearchQueryJSON, SearchStatus, SelectedTransactionInfo, SelectedTransactions, SortOrder} from './types';