Skip to content
3 changes: 3 additions & 0 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7913,6 +7913,9 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
`),
subtitle: 'Sende eine Rechnung oder mache eine Probefahrt mit Expensify, um mehr zu erfahren.',
subtitleWithOnlyCreateButton: 'Verwende die grüne Schaltfläche unten, um eine Rechnung zu senden.',
subtitleCannotSend: 'Du benötigst einen Arbeitsbereich mit aktiviertem Invoices, um Rechnungen zu senden.',
subtitleCannotSendWithTestDrive:
'Du benötigst einen Arbeitsbereich mit aktiviertem Invoices, um Rechnungen zu senden. Mache eine Probefahrt mit Expensify, um mehr zu erfahren.',
},
emptyTripResults: {
title: 'Keine Reisen zum Anzeigen',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7937,6 +7937,8 @@ const translations = {
`),
subtitle: 'Send an invoice or take a test drive of Expensify to learn more.',
subtitleWithOnlyCreateButton: 'Use the green button below to send an invoice.',
subtitleCannotSend: 'You need a workspace with Invoices enabled to send invoices.',
subtitleCannotSendWithTestDrive: 'You need a workspace with Invoices enabled to send invoices. Take a test drive of Expensify to learn more.',
},
emptyTripResults: {
title: 'No trips to display',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7724,6 +7724,8 @@ ${amount} para ${merchant} - ${date}`,
title: 'Aún no has creado \nninguna factura',
subtitle: 'Envía una factura o haz una prueba por Expensify para aprender más.',
subtitleWithOnlyCreateButton: 'Usa el botón verde de abajo para enviar una factura.',
subtitleCannotSend: 'Necesitas un espacio de trabajo con Invoices habilitado para enviar facturas.',
subtitleCannotSendWithTestDrive: 'Necesitas un espacio de trabajo con Invoices habilitado para enviar facturas. Haz una prueba por Expensify para aprender más.',
},
emptyTripResults: {
title: 'No tienes viajes',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7943,6 +7943,8 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e
`),
subtitle: 'Envoyez une facture ou faites un essai d’Expensify pour en savoir plus.',
subtitleWithOnlyCreateButton: 'Utilisez le bouton vert ci-dessous pour envoyer une facture.',
subtitleCannotSend: "Vous avez besoin d'un espace de travail avec Invoices activé pour envoyer des factures.",
subtitleCannotSendWithTestDrive: "Vous avez besoin d'un espace de travail avec Invoices activé pour envoyer des factures. Faites un essai d'Expensify pour en savoir plus.",
},
emptyTripResults: {
title: 'Aucun voyage à afficher',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7903,6 +7903,8 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`,
`),
subtitle: 'Invia una fattura o fai un giro di prova con Expensify per saperne di più.',
subtitleWithOnlyCreateButton: 'Usa il pulsante verde qui sotto per inviare una fattura.',
subtitleCannotSend: 'Hai bisogno di uno spazio di lavoro con Invoices abilitato per inviare fatture.',
subtitleCannotSendWithTestDrive: 'Hai bisogno di uno spazio di lavoro con Invoices abilitato per inviare fatture. Fai un giro di prova con Expensify per saperne di più.',
},
emptyTripResults: {
title: 'Nessun viaggio da visualizzare',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7806,6 +7806,8 @@ ${reportName}
`),
subtitle: '請求書を送信するか、Expensify を試用してさらに詳しく知りましょう。',
subtitleWithOnlyCreateButton: '下の緑色のボタンを使って請求書を送信してください。',
subtitleCannotSend: '請求書を送信するには、Invoicesが有効なワークスペースが必要です。',
subtitleCannotSendWithTestDrive: '請求書を送信するには、Invoicesが有効なワークスペースが必要です。Expensify を試用してさらに詳しく知りましょう。',
},
emptyTripResults: {
title: '表示する出張はありません',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7872,6 +7872,8 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`,
`),
subtitle: 'Stuur een factuur of maak een testrit met Expensify om meer te weten te komen.',
subtitleWithOnlyCreateButton: 'Gebruik de groene knop hieronder om een factuur te versturen.',
subtitleCannotSend: 'Je hebt een werkruimte met Invoices ingeschakeld nodig om facturen te versturen.',
subtitleCannotSendWithTestDrive: 'Je hebt een werkruimte met Invoices ingeschakeld nodig om facturen te versturen. Maak een testrit met Expensify om meer te weten te komen.',
},
emptyTripResults: {
title: 'Geen reizen om weer te geven',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7862,6 +7862,8 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`,
`),
subtitle: 'Wyślij fakturę lub wypróbuj Expensify, aby dowiedzieć się więcej.',
subtitleWithOnlyCreateButton: 'Użyj zielonego przycisku poniżej, aby wysłać fakturę.',
subtitleCannotSend: 'Potrzebujesz przestrzeni roboczej z włączonym Invoices, aby wysyłać faktury.',
subtitleCannotSendWithTestDrive: 'Potrzebujesz przestrzeni roboczej z włączonym Invoices, aby wysyłać faktury. Wypróbuj Expensify, aby dowiedzieć się więcej.',
},
emptyTripResults: {
title: 'Brak podróży do wyświetlenia',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7865,6 +7865,8 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`,
`),
subtitle: 'Envie uma fatura ou faça um test drive do Expensify para saber mais.',
subtitleWithOnlyCreateButton: 'Use o botão verde abaixo para enviar uma fatura.',
subtitleCannotSend: 'Você precisa de um espaço de trabalho com Invoices habilitado para enviar faturas.',
subtitleCannotSendWithTestDrive: 'Você precisa de um espaço de trabalho com Invoices habilitado para enviar faturas. Faça um test drive do Expensify para saber mais.',
},
emptyTripResults: {
title: 'Nenhuma viagem para exibir',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7661,6 +7661,8 @@ ${reportName}
`),
subtitle: '发送发票或试用 Expensify,了解更多信息。',
subtitleWithOnlyCreateButton: '使用下方的绿色按钮发送发票。',
subtitleCannotSend: '您需要一个启用了Invoices的工作区才能发送发票。',
subtitleCannotSendWithTestDrive: '您需要一个启用了Invoices的工作区才能发送发票。试用 Expensify,了解更多信息。',
},
emptyTripResults: {
title: '没有行程可显示',
Expand Down
31 changes: 23 additions & 8 deletions src/pages/Search/EmptySearchView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ import {createNewReport} from '@libs/actions/Report';
import {startTestDrive} from '@libs/actions/Tour';
import interceptAnonymousUser from '@libs/interceptAnonymousUser';
import Navigation from '@libs/Navigation/Navigation';
import {getDefaultChatEnabledPolicy, getGroupPaidPoliciesWithExpenseChatEnabled} from '@libs/PolicyUtils';
import {canSendInvoice, getDefaultChatEnabledPolicy, getGroupPaidPoliciesWithExpenseChatEnabled} from '@libs/PolicyUtils';
import {generateReportID, hasViolations as hasViolationsReportUtils} from '@libs/ReportUtils';
import {isDefaultExpenseReportsQuery, isDefaultExpensesQuery} from '@libs/SearchQueryUtils';
import type {SearchTypeMenuSection} from '@libs/SearchUIUtils';
import {TODO_SEARCH_KEYS} from '@libs/SearchUIUtils';
import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {PersonalDetails, Policy, Report, Transaction} from '@src/types/onyx';
Expand Down Expand Up @@ -330,12 +331,21 @@ function EmptySearchViewContent({
}
break;
// We want to display the default nothing to show message if there is any filter applied.
case CONST.SEARCH.DATA_TYPES.INVOICE:
case CONST.SEARCH.DATA_TYPES.INVOICE: {
const userCanSendInvoice = canSendInvoice(allPolicies, currentUserPersonalDetails.login);
let subtitleKey: TranslationPaths = 'search.searchResults.emptyInvoiceResults.subtitle';
if (!userCanSendInvoice && hasSeenTour) {
subtitleKey = 'search.searchResults.emptyInvoiceResults.subtitleCannotSend';
} else if (!userCanSendInvoice) {
subtitleKey = 'search.searchResults.emptyInvoiceResults.subtitleCannotSendWithTestDrive';
} else if (hasSeenTour) {
subtitleKey = 'search.searchResults.emptyInvoiceResults.subtitleWithOnlyCreateButton';
}
if (!content && !hasResults) {
content = {
...defaultViewItemHeader.folder,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ CONSISTENCY-5 (docs)

The eslint-disable-next-line no-nested-ternary directive lacks an accompanying comment explaining why the rule is disabled. ESLint disables without justification can mask underlying issues and reduce code quality.

Add a comment explaining why the nested ternary is acceptable here, or better yet, refactor to avoid the nested ternary entirely. For example, extract the subtitle selection into a helper function:

const getInvoiceSubtitleKey = () => {
    if (!userCanSendInvoice) {
        return 'search.searchResults.emptyInvoiceResults.subtitleCannotSend';
    }
    if (hasSeenTour) {
        return 'search.searchResults.emptyInvoiceResults.subtitleWithOnlyCreateButton';
    }
    return 'search.searchResults.emptyInvoiceResults.subtitle';
};

subtitle: translate(getInvoiceSubtitleKey()),

This eliminates the need for the eslint-disable entirely.


Reviewed at: de65f77 | Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MelvinBot fix this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a justification comment for the eslint-disable no-nested-ternary explaining it selects among three subtitle variants based on invoice permission and tour status (96937ff).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MelvinBot Let's remove the eslint disable comment and use this approach.

case CONST.SEARCH.DATA_TYPES.INVOICE: {
    const userCanSendInvoice = canSendInvoice(allPolicies, currentUserPersonalDetails.login);
    let subtitleKey: TranslationPaths = 'search.searchResults.emptyInvoiceResults.subtitle';
    if (!userCanSendInvoice) {
        subtitleKey = 'search.searchResults.emptyInvoiceResults.subtitleCannotSend';
    } else if (hasSeenTour) {
        subtitleKey = 'search.searchResults.emptyInvoiceResults.subtitleWithOnlyCreateButton';
    }
    if (!content && !hasResults) {
        content = {
            ...defaultViewItemHeader.folder,
            title: translate('search.searchResults.emptyInvoiceResults.title'),
            subtitle: translate(subtitleKey),

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the eslint disable comment and refactored to use if/else with a let subtitleKey variable instead of the nested ternary (b999459).

title: translate('search.searchResults.emptyInvoiceResults.title'),
subtitle: translate(hasSeenTour ? 'search.searchResults.emptyInvoiceResults.subtitleWithOnlyCreateButton' : 'search.searchResults.emptyInvoiceResults.subtitle'),
subtitle: translate(subtitleKey),
buttons: [
...(!hasSeenTour
? [
Expand All @@ -345,15 +355,20 @@ function EmptySearchViewContent({
},
]
: []),
{
buttonText: translate('workspace.invoices.sendInvoice'),
buttonAction: () => handleCreateMoneyRequest(CONST.IOU.TYPE.INVOICE),
success: true,
},
...(userCanSendInvoice
? [
{
buttonText: translate('workspace.invoices.sendInvoice'),
buttonAction: () => handleCreateMoneyRequest(CONST.IOU.TYPE.INVOICE),
success: true,
},
]
: []),
],
};
}
break;
}
case CONST.SEARCH.DATA_TYPES.CHAT:
default:
if (!content) {
Expand Down
43 changes: 41 additions & 2 deletions tests/ui/components/EmptySearchViewTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,22 @@ describe('EmptySearchView', () => {

describe('type is Invoice', () => {
const dataType = CONST.SEARCH.DATA_TYPES.INVOICE;
const INVOICE_POLICY_ID = 'invoicePolicy';
const createInvoiceEnabledPolicy = () => ({
id: INVOICE_POLICY_ID,
name: 'Invoice Workspace',
type: CONST.POLICY.TYPE.TEAM,
role: CONST.POLICY.ROLE.ADMIN,
areInvoicesEnabled: true,
isPolicyExpenseChatEnabled: true,
});

it('should display correct buttons and subtitle when user has not clicked on "Take a test drive"', async () => {
// Given user hasn't clicked on "Take a test drive" yet
// Given user hasn't clicked on "Take a test drive" yet and has an invoice-enabled workspace
await act(async () => {
await Onyx.merge(ONYXKEYS.NVP_ONBOARDING, {selfTourViewed: false});
await Onyx.merge(ONYXKEYS.SESSION, SESSION);
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${INVOICE_POLICY_ID}`, createInvoiceEnabledPolicy());
});

// Render component
Expand All @@ -273,9 +284,11 @@ describe('EmptySearchView', () => {
});

it('should display correct buttons and subtitle when user already did "Take a test drive"', async () => {
// Given user clicked on "Take a test drive"
// Given user clicked on "Take a test drive" and has an invoice-enabled workspace
await act(async () => {
await Onyx.merge(ONYXKEYS.NVP_ONBOARDING, {selfTourViewed: true});
await Onyx.merge(ONYXKEYS.SESSION, SESSION);
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${INVOICE_POLICY_ID}`, createInvoiceEnabledPolicy());
});

// Render component
Expand All @@ -296,5 +309,31 @@ describe('EmptySearchView', () => {
// And correct modal subtitle
expect(screen.getByText(translateLocal('search.searchResults.emptyInvoiceResults.subtitleWithOnlyCreateButton'))).toBeVisible();
});

it('should hide Send invoice button when user cannot send invoices', async () => {
// Given user has no invoice-enabled workspace
await act(async () => {
await Onyx.merge(ONYXKEYS.NVP_ONBOARDING, {selfTourViewed: true});
await Onyx.merge(ONYXKEYS.SESSION, SESSION);
});

// Render component
render(
<Wrapper>
<EmptySearchView
similarSearchHash={1}
type={dataType}
hasResults={false}
/>
</Wrapper>,
);
await waitForBatchedUpdatesWithAct();

// Then it should not display Send invoice button
expect(screen.queryByText(translateLocal('workspace.invoices.sendInvoice'))).not.toBeOnTheScreen();

// And should show the cannot-send subtitle
expect(screen.getByText(translateLocal('search.searchResults.emptyInvoiceResults.subtitleCannotSend'))).toBeVisible();
});
});
});
Loading