From 16fc382808da6673e3a9af4a391f7de5ca7bf714 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Sun, 17 Aug 2025 22:06:04 +0700 Subject: [PATCH 1/4] implement front-end onboarding message --- src/hooks/useOnboardingMessages/index.ts | 5 +- src/languages/de.ts | 6 +- src/languages/en.ts | 6 +- src/languages/es.ts | 6 +- src/languages/fr.ts | 6 +- src/languages/it.ts | 6 +- src/languages/ja.ts | 6 +- src/languages/nl.ts | 6 +- src/languages/pl.ts | 6 +- src/languages/pt-BR.ts | 6 +- src/languages/zh-hans.ts | 6 +- src/libs/ReportUtils.ts | 60 ++++++++----------- src/libs/actions/IOU.ts | 2 +- src/libs/actions/Policy/Policy.ts | 2 +- src/libs/actions/Report.ts | 2 +- src/libs/actions/Welcome/OnboardingFlow.ts | 4 +- .../BaseOnboardingInterestedFeatures.tsx | 2 +- .../home/report/PureReportActionItem.tsx | 1 + 18 files changed, 75 insertions(+), 63 deletions(-) diff --git a/src/hooks/useOnboardingMessages/index.ts b/src/hooks/useOnboardingMessages/index.ts index 4e4eecbda4032..71e21f7689795 100644 --- a/src/hooks/useOnboardingMessages/index.ts +++ b/src/hooks/useOnboardingMessages/index.ts @@ -1,9 +1,12 @@ import {useMemo} from 'react'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import {getOnboardingMessages} from '@libs/actions/Welcome/OnboardingFlow'; +import ONYXKEYS from '@src/ONYXKEYS'; export default function useOnboardingMessages() { const {preferredLocale} = useLocalize(); - const onboardingMessages = useMemo(() => getOnboardingMessages(preferredLocale), [preferredLocale]); + const [hasIntroSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {canBeMissing: true, selector: (introSelected) => !!introSelected?.choice}); + const onboardingMessages = useMemo(() => getOnboardingMessages(hasIntroSelected, preferredLocale), [hasIntroSelected, preferredLocale]); return onboardingMessages; } diff --git a/src/languages/de.ts b/src/languages/de.ts index ebda7505ac791..1033a3a23f5ba 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -2454,8 +2454,10 @@ const translations = { messages: { onboardingEmployerOrSubmitMessage: 'Erstattungen zu erhalten ist so einfach wie eine Nachricht zu senden. Lass uns die Grundlagen durchgehen.', onboardingPersonalSpendMessage: 'So verfolgst du deine Ausgaben mit nur wenigen Klicks.', - onboardingManageTeamMessage: - '# Deine kostenlose Testversion hat begonnen! Lass uns mit der Einrichtung loslegen.\n👋 Hallo, ich bin dein Expensify-Einrichtungsassistent. Jetzt, da du einen Workspace erstellt hast, hole das Beste aus deiner 30-tägigen kostenlosen Testphase heraus, indem du die folgenden Schritte befolgst!', + onboardingManageTeamMessage: ({hasIntroSelected}: {hasIntroSelected: boolean}) => + hasIntroSelected + ? '# Deine kostenlose Testphase hat begonnen! Lass uns alles einrichten.\n👋 Hallo, ich bin dein Expensify-Einrichtungsspezialist. Da du nun einen Workspace erstellt hast, nutze deine 30-tägige kostenlose Testphase optimal, indem du die folgenden Schritte befolgst!' + : '# Deine kostenlose Testphase hat begonnen! Lass uns alles einrichten.\n👋 Hallo, ich bin dein Expensify-Einrichtungsspezialist. Ich habe bereits einen Workspace erstellt, um die Belege und Ausgaben deines Teams zu verwalten. Um deine 30-tägige kostenlose Testphase optimal zu nutzen, folge einfach den verbleibenden Einrichtungsschritten unten!', onboardingTrackWorkspaceMessage: '# Lass uns loslegen\n👋 Ich helfe dir! Ich habe deine Workspace-Einstellungen für Einzelunternehmer und ähnliche Unternehmen angepasst. Du kannst sie über den folgenden Link anpassen!\n\nSo verfolgst du deine Ausgaben mit nur wenigen Klicks:', onboardingChatSplitMessage: 'Rechnungen mit Freunden zu teilen ist so einfach wie eine Nachricht zu senden. So funktioniert’s.', diff --git a/src/languages/en.ts b/src/languages/en.ts index 53ee0ec45d934..e9c0f300afc56 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2460,8 +2460,10 @@ const translations = { messages: { onboardingEmployerOrSubmitMessage: 'Getting paid back is as easy as sending a message. Let’s go over the basics.', onboardingPersonalSpendMessage: 'Here’s how to track your spend in a few clicks.', - onboardingManageTeamMessage: - "# Your free trial has started! Let's get you set up.\n👋 Hey there, I'm your Expensify setup specialist. Now that you've created a workspace, make the most of your 30-day free trial by following the steps below!", + onboardingManageTeamMessage: ({hasIntroSelected}: {hasIntroSelected: boolean}) => + hasIntroSelected + ? "# Your free trial has started! Let's get you set up.\n👋 Hey there, I'm your Expensify setup specialist. Now that you've created a workspace, make the most of your 30-day free trial by following the steps below!" + : "# Your free trial has started! Let's get you set up.\n👋 Hey there, I'm your Expensify setup specialist. I've already created a workspace to help manage your team's receipts and expenses. To make the most of your 30-day free trial, just follow the remaining setup steps below!", onboardingTrackWorkspaceMessage: '# Let’s get you set up\n👋 I’m here to help! To get you started, I’ve tailored your workspace settings for sole proprietors and similar businesses. You can adjust your workspace by clicking the link below!\n\nHere’s how to track your spend in a few clicks:', onboardingChatSplitMessage: 'Splitting bills with friends is as easy as sending a message. Here’s how.', diff --git a/src/languages/es.ts b/src/languages/es.ts index 748af2fb4c092..ee1986419321d 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2427,8 +2427,10 @@ const translations = { messages: { onboardingEmployerOrSubmitMessage: 'Que te reembolsen es tan fácil como enviar un mensaje. Repasemos lo básico.', onboardingPersonalSpendMessage: 'Aquí tienes cómo organizar tus gastos en unos pocos clics.', - onboardingManageTeamMessage: - '# ¡Tu prueba gratuita ha comenzado! Vamos a poner todo a punto.\n👋 Hola, soy tu especialista de configuración de Expensify. Ahora que has creado un espacio de trabajo, aprovecha al máximo tus 30 días de prueba gratuita siguiendo los pasos que aparecen a continuación.', + onboardingManageTeamMessage: ({hasIntroSelected}: {hasIntroSelected: boolean}) => + hasIntroSelected + ? '# ¡Tu prueba gratuita ha comenzado! Vamos a poner todo a punto.\n👋 Hola, soy tu especialista de configuración de Expensify. Ahora que has creado un espacio de trabajo, aprovecha al máximo tus 30 días de prueba gratuita siguiendo los pasos que aparecen a continuación.' + : '# ¡Tu prueba gratuita ha comenzado! Vamos a configurarlo.\n👋 Hola, soy tu especialista asignado de Expensify. Ya he creado un espacio de trabajo para ayudarte a gestionar los recibos y gastos de tu equipo. Para aprovechar al máximo tu prueba gratuita de 30 días, solo sigue los pasos de configuración restantes a continuación.', onboardingTrackWorkspaceMessage: '# Vamos a configurarte\n👋 ¡Estoy aquí para ayudarte! Para comenzar, he personalizado la configuración de tu espacio de trabajo para propietarios únicos y negocios similares. Puedes ajustar tu espacio de trabajo haciendo clic en el enlace de abajo.\n\nAsí es como puedes organizar tus gastos en unos pocos clics:', onboardingChatSplitMessage: 'Dividir cuentas con amigos es tan fácil como enviar un mensaje. Así se hace.', diff --git a/src/languages/fr.ts b/src/languages/fr.ts index b3e58a9c21b1b..7e540ad79baa6 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -2457,8 +2457,10 @@ const translations = { messages: { onboardingEmployerOrSubmitMessage: 'Se faire rembourser est aussi simple que d’envoyer un message. Voici les bases.', onboardingPersonalSpendMessage: 'Voici comment suivre vos dépenses en quelques clics.', - onboardingManageTeamMessage: - '# Votre essai gratuit a commencé ! Passons à la configuration.\n👋 Bonjour, je suis votre spécialiste de configuration Expensify. Maintenant que vous avez créé un espace de travail, profitez pleinement de vos 30 jours d’essai gratuit en suivant les étapes ci-dessous !', + onboardingManageTeamMessage: ({hasIntroSelected}: {hasIntroSelected: boolean}) => + hasIntroSelected + ? '# Votre essai gratuit a commencé ! Configurons tout cela.\n👋 Bonjour, je suis votre spécialiste de configuration Expensify. Maintenant que vous avez créé un espace de travail, profitez pleinement de votre essai gratuit de 30 jours en suivant les étapes ci-dessous.' + : '# Votre essai gratuit a commencé ! Configurons tout cela.\n👋 Bonjour, je suis votre spécialiste de configuration Expensify. J’ai déjà créé un espace de travail pour vous aider à gérer les reçus et dépenses de votre équipe. Pour profiter pleinement de votre essai gratuit de 30 jours, suivez simplement les étapes de configuration ci-dessous.', onboardingTrackWorkspaceMessage: '# Configurons votre espace\n👋 Je suis là pour vous aider ! J’ai personnalisé votre espace pour les entrepreneurs individuels et entreprises similaires. Vous pouvez le modifier via le lien ci-dessous.\n\nVoici comment suivre vos dépenses rapidement :', onboardingChatSplitMessage: 'Partager des dépenses entre amis est aussi simple qu’un message. Voici comment faire.', diff --git a/src/languages/it.ts b/src/languages/it.ts index f4e0c9921ab1c..e7b2ec1f1d0e9 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -2470,8 +2470,10 @@ const translations = { messages: { onboardingEmployerOrSubmitMessage: 'Ricevere un rimborso è facile come inviare un messaggio. Vediamo le basi.', onboardingPersonalSpendMessage: 'Ecco come monitorare le tue spese in pochi clic.', - onboardingManageTeamMessage: - '# La tua prova gratuita è iniziata! Procediamo con la configurazione.\n👋 Ciao, sono il tuo specialista di configurazione Expensify. Ora che hai creato uno spazio di lavoro, sfrutta al massimo i tuoi 30 giorni di prova gratuita seguendo i passaggi indicati di seguito!', + onboardingManageTeamMessage: ({hasIntroSelected}: {hasIntroSelected: boolean}) => + hasIntroSelected + ? '# La tua prova gratuita è iniziata! Configuriamo tutto.\n👋 Ciao, sono il tuo specialista di configurazione Expensify. Ora che hai creato uno spazio di lavoro, sfrutta al massimo la tua prova gratuita di 30 giorni seguendo i passaggi qui sotto!' + : '# La tua prova gratuita è iniziata! Configuriamo tutto.\n👋 Ciao, sono il tuo specialista di configurazione Expensify. Ho già creato uno spazio di lavoro per aiutarti a gestire le ricevute e le spese del tuo team. Per sfruttare al massimo la tua prova gratuita di 30 giorni, segui semplicemente i restanti passaggi di configurazione qui sotto!', onboardingTrackWorkspaceMessage: '# Iniziamo\n👋 Sono qui per aiutarti! Per iniziare, ho personalizzato le impostazioni dello spazio di lavoro per ditte individuali e aziende simili. Puoi modificarle cliccando il link qui sotto!\n\nEcco come monitorare le tue spese in pochi clic:', onboardingChatSplitMessage: 'Dividere le spese con gli amici è facile come inviare un messaggio. Ecco come.', diff --git a/src/languages/ja.ts b/src/languages/ja.ts index fb88cd275a8f8..5025133da8143 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -2475,8 +2475,10 @@ const translations = { '\u652F\u6255\u3044\u3092\u53D7\u3051\u53D6\u308B\u306E\u306F\u3001\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u9001\u308B\u306E\u3068\u540C\u3058\u304F\u3089\u3044\u7C21\u5358\u3067\u3059\u3002\u57FA\u672C\u3092\u78BA\u8A8D\u3057\u307E\u3057\u3087\u3046\u3002', onboardingPersonalSpendMessage: '\u6570\u56DE\u30AF\u30EA\u30C3\u30AF\u3059\u308B\u3060\u3051\u3067\u3042\u306A\u305F\u306E\u652F\u51FA\u3092\u8FFD\u8DE1\u3059\u308B\u65B9\u6CD5\u306F\u6B21\u306E\u3068\u304A\u308A\u3067\u3059\u3002', - onboardingManageTeamMessage: - '\u0023 \u7121\u6599\u30c8\u30e9\u30a4\u30a2\u30eb\u304c\u958b\u59cb\u3057\u307e\u3057\u305f\uff01\u8a2d\u5b9a\u3092\u59cb\u3081\u307e\u3057\u3087\u3046\u3002\n\ud83d\udc4b \u3053\u3093\u306b\u3061\u306f\u3001\u79c1\u306f\u3042\u306a\u305f\u306eExpensify\u8a2d\u5b9a\u30b9\u30da\u30b7\u30e3\u30ea\u30b9\u30c8\u3067\u3059\u3002\u4eca\u3001\u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9\u3092\u4f5c\u6210\u3057\u305f\u306e\u3067\u300130\u65e5\u9593\u306e\u7121\u6599\u30c8\u30e9\u30a4\u30a2\u30eb\u3092\u6700\u5927\u9650\u6d3b\u7528\u3057\u3001\u4e0b\u8a18\u306e\u30b9\u30c6\u30c3\u30d7\u306b\u5f93\u3063\u3066\u304f\u3060\u3055\u3044\uff01', + onboardingManageTeamMessage: ({hasIntroSelected}: {hasIntroSelected: boolean}) => + hasIntroSelected + ? '\u0023 \u7121\u6599\u30c8\u30e9\u30a4\u30a2\u30eb\u304c\u958b\u59cb\u3057\u307e\u3057\u305f\uff01\u3055\u3041\u3001\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u3092\u59cb\u3081\u307e\u3057\u3087\u3046\u3002\n\ud83d\udc4b \u3053\u3093\u306b\u3061\u306f\u3001Expensify \u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u30b9\u30da\u30b7\u30e3\u30ea\u30b9\u30c8\u306e\u79c1\u3067\u3059\u3002\u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9\u3092\u4f5c\u6210\u3057\u305f\u306e\u3067\u300130\u65e5\u9593\u306e\u7121\u6599\u30c8\u30e9\u30a4\u30a2\u30eb\u3092\u6700\u5927\u9650\u5229\u7528\u3057\u3001\u4e0b\u8a18\u306e\u624b\u9806\u306b\u5f93\u3063\u3066\u304f\u3060\u3055\u3044\u3002' + : '\u0023 \u7121\u6599\u30c8\u30e9\u30a4\u30a2\u30eb\u304c\u958b\u59cb\u3057\u307e\u3057\u305f\uff01\u3055\u3041\u3001\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u3092\u59cb\u3081\u307e\u3057\u3087\u3046\u3002\n\ud83d\udc4b \u3053\u3093\u306b\u3061\u306f\u3001Expensify \u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u30b9\u30da\u30b7\u30e3\u30ea\u30b9\u30c8\u306e\u79c1\u3067\u3059\u3002\u30c1\u30fc\u30e0\u306e\u9818\u53ce\u66f8\u3084\u7d4c\u8cbb\u3092\u7ba1\u7406\u3059\u308b\u305f\u3081\u306b\u3001\u3059\u3067\u306b\u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9\u3092\u4f5c\u6210\u3057\u307e\u3057\u305f\u300230\u65e5\u9593\u306e\u7121\u6599\u30c8\u30e9\u30a4\u30a2\u30eb\u3092\u6700\u5927\u9650\u5229\u7528\u3059\u308b\u305f\u3081\u306b\u3001\u4e0b\u8a18\u306e\u6b8b\u308a\u306e\u624b\u9806\u306b\u5f93\u3063\u3066\u304f\u3060\u3055\u3044\u3002', onboardingTrackWorkspaceMessage: '# \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3057\u307E\u3057\u3087\u3046\n\u3063\u3066\u3001\u304A\u624B\u4F1D\u3044\u3057\u307E\u3059\uFF01\u958B\u59CB\u306B\u3042\u305F\u3063\u3066\u3001\u3042\u306A\u305F\u306E\u30ef\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u8A2D\u5B9A\u3092\u500B\u4EBA\u4E8B\u696D\u4E3B\u3084\u985E\u4F3C\u306E\u4F01\u696D\u306B\u5408\u308F\u305B\u3066\u8ABF\u6574\u3057\u307E\u3057\u305F\u3002\u4EE5\u4E0B\u306E\u30EA\u30F3\u30AF\u3092\u30AF\u30EA\u30C3\u30AF\u3059\u308B\u3068\u3001\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u3092\u8ABF\u6574\u3067\u304D\u307E\u3059\uFF01\n\n\u6570\u56DE\u30AF\u30EA\u30C3\u30AF\u3059\u308B\u3060\u3051\u3067\u3042\u306A\u305F\u306E\u652F\u51FA\u3092\u8FFD\u8DE1\u3059\u308B\u65B9\u6CD5\u306F\u6B21\u306E\u3068\u304A\u308A\u3067\u3059\u3002', onboardingChatSplitMessage: diff --git a/src/languages/nl.ts b/src/languages/nl.ts index c724913923158..f9465da2a8036 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -2477,8 +2477,10 @@ const translations = { messages: { onboardingEmployerOrSubmitMessage: 'Terugbetaald krijgen is net zo eenvoudig als een bericht sturen. Laten we de basis doornemen.', onboardingPersonalSpendMessage: 'Zo volgt u uw uitgaven in een paar klikken.', - onboardingManageTeamMessage: - '# Je gratis proefperiode is begonnen! Laten we aan de slag gaan met de installatie.\n👋 Hallo, ik ben je Expensify-installatiespecialist. Nu je een workspace hebt gemaakt, haal het meeste uit je 30 dagen gratis proefperiode door de onderstaande stappen te volgen!', + onboardingManageTeamMessage: ({hasIntroSelected}: {hasIntroSelected: boolean}) => + hasIntroSelected + ? '# Je gratis proefperiode is gestart! Laten we aan de slag gaan.\n👋 Hoi, ik ben je Expensify-instellingsspecialist. Nu je een werkruimte hebt gemaakt, haal het meeste uit je 30 dagen gratis proefperiode door de onderstaande stappen te volgen!' + : '# Je gratis proefperiode is gestart! Laten we aan de slag gaan.\n👋 Hoi, ik ben je Expensify-instellingsspecialist. Ik heb al een werkruimte gemaakt om je te helpen met het beheren van de bonnetjes en uitgaven van je team. Haal het meeste uit je 30 dagen gratis proefperiode door eenvoudig de resterende instellingsstappen hieronder te volgen!', onboardingTrackWorkspaceMessage: '# Laten we u instellen\n👋 Ik ben hier om te helpen! Om u op weg te helpen, heb ik uw werkruimte-instellingen afgestemd op eenmanszaken en soortgelijke bedrijven. U kunt uw werkruimte aanpassen door op de onderstaande link te klikken!\n\nZo volgt u uw uitgaven in een paar klikken:', onboardingChatSplitMessage: 'Rekeningen splitsen met vrienden is net zo eenvoudig als een bericht sturen. Zo doet u dat.', diff --git a/src/languages/pl.ts b/src/languages/pl.ts index 9317c68564071..bb95627c89678 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -2472,8 +2472,10 @@ const translations = { messages: { onboardingEmployerOrSubmitMessage: 'Terugbetaald krijgen is net zo eenvoudig als een bericht sturen. Laten we de basis doornemen.', onboardingPersonalSpendMessage: 'Zo volgt u uw uitgaven in een paar klikken.', - onboardingManageTeamMessage: - '# Twój bezpłatny okres próbny właśnie się rozpoczął! Zacznijmy konfigurację.\n👋 Cześć, jestem Twoim specjalistą ds. konfiguracji Expensify. Teraz, gdy utworzyłeś przestrzeń roboczą, wykorzystaj w pełni swoje 30 dni bezpłatnego okresu próbnego, postępując zgodnie z poniższymi krokami!', + onboardingManageTeamMessage: ({hasIntroSelected}: {hasIntroSelected: boolean}) => + hasIntroSelected + ? '# Twój bezpłatny okres próbny właśnie się rozpoczął! Skonfigurujmy wszystko.\n👋 Cześć, jestem twoim specjalistą ds. konfiguracji Expensify. Teraz, gdy utworzyłeś przestrzeń roboczą, w pełni wykorzystaj 30-dniowy bezpłatny okres próbny, wykonując poniższe kroki!' + : '# Twój bezpłatny okres próbny właśnie się rozpoczął! Skonfigurujmy wszystko.\n👋 Cześć, jestem twoim specjalistą ds. konfiguracji Expensify. Już utworzyłem przestrzeń roboczą, aby pomóc w zarządzaniu paragonami i wydatkami twojego zespołu. Aby w pełni wykorzystać 30-dniowy bezpłatny okres próbny, po prostu wykonaj poniższe pozostałe kroki konfiguracji!', onboardingTrackWorkspaceMessage: '# Laten we u instellen\n👋 Ik ben hier om te helpen! Om u op weg te helpen, heb ik uw werkruimte-instellingen afgestemd op eenmanszaken en soortgelijke bedrijven. U kunt uw werkruimte aanpassen door op de onderstaande link te klikken!\n\nZo volgt u uw uitgaven in een paar klikken:', onboardingChatSplitMessage: 'Rekeningen splitsen met vrienden is net zo eenvoudig als een bericht sturen. Zo doet u dat.', diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index c67680318bb02..c9613f14f0f65 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -2476,8 +2476,10 @@ const translations = { messages: { onboardingEmployerOrSubmitMessage: 'Ser reembolsado é tão fácil quanto enviar uma mensagem. Vamos ver o básico.', onboardingPersonalSpendMessage: 'Veja como rastrear seus gastos em poucos cliques.', - onboardingManageTeamMessage: - '# Seu teste gratuito começou! Vamos configurar tudo.\n👋 Olá, sou seu especialista de configuração da Expensify. Agora que você criou um workspace, aproveite ao máximo seus 30 dias de teste gratuito seguindo as etapas abaixo!', + onboardingManageTeamMessage: ({hasIntroSelected}: {hasIntroSelected: boolean}) => + hasIntroSelected + ? '# Seu teste gratuito começou! Vamos configurar tudo.\n👋 Olá, sou seu especialista de configuração da Expensify. Agora que você criou um workspace, aproveite ao máximo seus 30 dias de teste gratuito seguindo as etapas abaixo!' + : '# Seu teste gratuito começou! Vamos configurar tudo.\n👋 Olá, sou seu especialista de configuração da Expensify. Já criei um workspace para ajudar a gerenciar os recibos e despesas da sua equipe. Para aproveitar ao máximo seus 30 dias de teste gratuito, basta seguir as etapas restantes de configuração abaixo!', onboardingTrackWorkspaceMessage: '# Vamos configurar você\n👋 Estou aqui para ajudar! Para você começar, adaptei as configurações do seu espaço de trabalho para microempreendedores individuais e empresas semelhantes. Você pode ajustar seu espaço de trabalho clicando no link abaixo!\n\nVeja como rastrear seus gastos em poucos cliques:', onboardingChatSplitMessage: 'Dividir contas com amigos é tão fácil quanto enviar uma mensagem. Veja como.', diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 72cf43dc60006..c76fc9f06aa6d 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -2446,8 +2446,10 @@ const translations = { onboardingEmployerOrSubmitMessage: '\u62a5\u9500\u5c31\u50cf\u53d1\u9001\u6d88\u606f\u4e00\u6837\u7b80\u5355\u3002\u8ba9\u6211\u4eec\u6765\u770b\u770b\u57fa\u672c\u77e5\u8bc6\u3002', onboardingPersonalSpendMessage: '\u4ee5\u4e0b\u662f\u5982\u4f55\u5728\u51e0\u6b21\u70b9\u51fb\u4e2d\u8ddf\u8e2a\u60a8\u7684\u652f\u51fa\u3002', - onboardingManageTeamMessage: - '\u0023 \u60a8\u7684\u514d\u8d39\u8bd5\u7528\u5df2\u7ecf\u5f00\u59cb\uff01\u8ba9\u6211\u4eec\u5e2e\u60a8\u5b8c\u6210\u8bbe\u7f6e\u3002\n\ud83d\udc4b \u60a8\u597d\uff0c\u6211\u662f\u60a8\u7684 Expensify \u8bbe\u7f6e\u4e13\u5458\u3002\u73b0\u5728\u60a8\u5df2\u7ecf\u521b\u5efa\u4e86\u4e00\u4e2a\u5de5\u4f5c\u533a\uff0c\u8bf7\u5145\u5206\u5229\u7528 30 \u5929\u514d\u8d39\u8bd5\u7528\uff0c\u5e76\u6309\u7167\u4e0b\u9762\u7684\u6b65\u9aa4\u64cd\u4f5c\uff01', + onboardingManageTeamMessage: ({hasIntroSelected}: {hasIntroSelected: boolean}) => + hasIntroSelected + ? '\u0023 \u60a8\u7684\u514d\u8d39\u8bd5\u7528\u5df2\u7ecf\u5f00\u59cb\uff01\u8ba9\u6211\u4eec\u5e2e\u60a8\u5b8c\u6210\u8bbe\u7f6e\u3002\n\ud83d\udc4b \u60a8\u597d\uff0c\u6211\u662f\u60a8\u7684 Expensify \u8bbe\u7f6e\u4e13\u5458\u3002\u73b0\u5728\u60a8\u5df2\u7ecf\u521b\u5efa\u4e86\u4e00\u4e2a\u5de5\u4f5c\u533a\uff0c\u8bf7\u5145\u5206\u5229\u7528 30 \u5929\u514d\u8d39\u8bd5\u7528\uff0c\u5e76\u6309\u7167\u4e0b\u9762\u7684\u6b65\u9aa4\u64cd\u4f5c\uff01' + : '\u0023 \u60a8\u7684\u514d\u8d39\u8bd5\u7528\u5df2\u7ecf\u5f00\u59cb\uff01\u8ba9\u6211\u4eec\u5e2e\u60a8\u5b8c\u6210\u8bbe\u7f6e\u3002\n\ud83d\udc4b \u60a8\u597d\uff0c\u6211\u662f\u60a8\u7684 Expensify \u8bbe\u7ece\u4e13\u5458\u3002\u6211\u5df2\u7ecf\u521b\u5efa\u4e86\u4e00\u4e2a\u5de5\u4f5c\u533a\uff0c\u7528\u4e8e\u5e2e\u52a9\u7ba1\u7406\u60a8\u56e2\u961f\u7684\u6536\u636e\u548c\u8d39\u7528\u3002\u4e3a\u4e86\u5145\u5206\u5229\u7528 30 \u5929\u514d\u8d39\u8bd5\u7528\uff0c\u8bf7\u6309\u7167\u4e0b\u9762\u7684\u5269\u4f59\u6b65\u9aa4\u64cd\u4f5c\uff01', onboardingTrackWorkspaceMessage: '# \u8ba9\u6211\u4eec\u6765\u8bbe\u7f6e\u60a8\u7684\u5e10\u6237\n\u00f0\u009f\u0091\u008b \u6211\u6765\u5e2e\u5fd9\u4e86\uff01\u4e3a\u4e86\u5e2e\u52a9\u60a8\u5f00\u59cb\uff0c\u6211\u5df2\u4e3a\u4e2a\u4f53\u7ecf\u8425\u8005\u548c\u7c7b\u4f3c\u4f01\u4e1a\u91cf\u8eab\u5b9a\u5236\u4e86\u60a8\u7684\u5de5\u4f5c\u533a\u8bbe\u7f6e\u3002\u60a8\u53ef\u4ee5\u901a\u8fc7\u70b9\u51fb\u4e0b\u9762\u7684\u94fe\u63a5\u6765\u8c03\u6574\u60a8\u7684\u5de5\u4f5c\u533a\uff01\n\n\u4ee5\u4e0b\u662f\u5982\u4f55\u5728\u51e0\u6b21\u70b9\u51fb\u4e2d\u8ddf\u8e2a\u60a8\u7684\u652f\u51fa\uff1a', onboardingChatSplitMessage: '\u4e0e\u670b\u53cb\u5206\u644a\u8d26\u5355\u5c31\u50cf\u53d1\u9001\u6d88\u606f\u4e00\u6837\u7b80\u5355\u3002\u4ee5\u4e0b\u662f\u65b9\u6cd5\u3002', diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 526ee5d678966..f6b40fbe86049 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -10544,16 +10544,13 @@ function prepareOnboardingOnyxData( }, ); - // If we post tasks in the #admins room and introSelected?.choice does not exist, it means that a guide is assigned and all messages except tasks are handled by the backend - if (!shouldPostTasksInAdminsRoom || !!introSelected?.choice) { - optimisticData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [textCommentAction.reportActionID]: textCommentAction as ReportAction, - }, - }); - } + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [textCommentAction.reportActionID]: textCommentAction as ReportAction, + }, + }); if (!wasInvited) { optimisticData.push({ @@ -10565,16 +10562,13 @@ function prepareOnboardingOnyxData( const successData: OnyxUpdate[] = [...tasksForSuccessData]; - // If we post tasks in the #admins room and introSelected?.choice does not exist, it means that a guide is assigned and all messages except tasks are handled by the backend - if (!shouldPostTasksInAdminsRoom || !!introSelected?.choice) { - successData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [textCommentAction.reportActionID]: {pendingAction: null, isOptimisticAction: null}, - }, - }); - } + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [textCommentAction.reportActionID]: {pendingAction: null, isOptimisticAction: null}, + }, + }); let failureReport: Partial = { lastMessageText: '', @@ -10612,18 +10606,15 @@ function prepareOnboardingOnyxData( }, }, ); - // If we post tasks in the #admins room and introSelected?.choice does not exist, it means that a guide is assigned and all messages except tasks are handled by the backend - if (!shouldPostTasksInAdminsRoom || !!introSelected?.choice) { - failureData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [textCommentAction.reportActionID]: { - errors: getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), - } as ReportAction, - }, - }); - } + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [textCommentAction.reportActionID]: { + errors: getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), + } as ReportAction, + }, + }); if (!wasInvited) { failureData.push({ @@ -10674,12 +10665,9 @@ function prepareOnboardingOnyxData( }); } - // If we post tasks in the #admins room and introSelected?.choice does not exist, it means that a guide is assigned and all messages except tasks are handled by the backend const guidedSetupData: GuidedSetupData = []; - if (!shouldPostTasksInAdminsRoom || !!introSelected?.choice) { - guidedSetupData.push({type: 'message', ...textMessage}); - } + guidedSetupData.push({type: 'message', ...textMessage}); let selfDMParameters: SelfDMParameters = {}; if (engagementChoice === CONST.ONBOARDING_CHOICES.PERSONAL_SPEND) { diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 002c522d2b72f..adc5ac44ccef1 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -10404,7 +10404,7 @@ function completePaymentOnboarding(paymentSelected: ValueOf (task.type === 'startChat' ? {...task, autoCompleted: true} : task)); onboardingMessage.tasks = updatedTasks; diff --git a/src/libs/actions/Welcome/OnboardingFlow.ts b/src/libs/actions/Welcome/OnboardingFlow.ts index fb5de1aaeb12b..454aa04aa9fbb 100644 --- a/src/libs/actions/Welcome/OnboardingFlow.ts +++ b/src/libs/actions/Welcome/OnboardingFlow.ts @@ -151,7 +151,7 @@ function getOnboardingInitialPath(getOnboardingInitialPathParams: GetOnboardingI return onboardingInitialPath; } -const getOnboardingMessages = (locale?: Locale) => { +const getOnboardingMessages = (hasIntroSelected = false, locale?: Locale) => { const resolvedLocale = locale ?? IntlStore.getCurrentLocale(); const testDrive = { ONBOARDING_TASK_NAME: translate(resolvedLocale, 'onboarding.testDrive.name', {}), @@ -337,7 +337,7 @@ const getOnboardingMessages = (locale?: Locale) => { }; const onboardingManageTeamMessage: OnboardingMessage = { - message: translate(resolvedLocale, 'onboarding.messages.onboardingManageTeamMessage'), + message: translate(resolvedLocale, 'onboarding.messages.onboardingManageTeamMessage', {hasIntroSelected}), tasks: [createWorkspaceTask, testDriveAdminTask, addAccountingIntegrationTask, connectCorporateCardTask, inviteTeamTask, setupCategoriesAndTags, setupCategoriesTask, setupTagsTask], }; diff --git a/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx b/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx index 0760657f66269..4624d6f043259 100644 --- a/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx +++ b/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx @@ -360,7 +360,7 @@ function BaseOnboardingInterestedFeatures({shouldUseNativeStyles}: BaseOnboardin text={translate('common.continue')} onPress={handleContinue} isLoading={isLoading} - isDisabled={isOffline} + // isDisabled={isOffline} pressOnEnter /> diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 4fe86a3196a2e..afd2b613ea21c 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -1452,6 +1452,7 @@ function PureReportActionItem({ ); }; + console.log(action); return ( Date: Sun, 17 Aug 2025 22:08:18 +0700 Subject: [PATCH 2/4] remove the hardcode --- .../BaseOnboardingInterestedFeatures.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx b/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx index 4624d6f043259..0760657f66269 100644 --- a/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx +++ b/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx @@ -360,7 +360,7 @@ function BaseOnboardingInterestedFeatures({shouldUseNativeStyles}: BaseOnboardin text={translate('common.continue')} onPress={handleContinue} isLoading={isLoading} - // isDisabled={isOffline} + isDisabled={isOffline} pressOnEnter /> From fa0b5b3b57b5efa86874ffe55fc081421978bc8a Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Sun, 17 Aug 2025 22:08:48 +0700 Subject: [PATCH 3/4] remove consolog --- src/pages/home/report/PureReportActionItem.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index afd2b613ea21c..4fe86a3196a2e 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -1452,7 +1452,6 @@ function PureReportActionItem({ ); }; - console.log(action); return ( Date: Mon, 25 Aug 2025 15:42:29 +0700 Subject: [PATCH 4/4] fix duplicate free trial message --- src/CONST/index.ts | 2 ++ src/libs/ReportActionsUtils.ts | 9 ++++++++- src/libs/SearchUIUtils.ts | 20 +++++++++++++++++--- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 8c19cbb6e3cc7..804f511c2521f 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -421,6 +421,8 @@ const CONST = { NEW_EXPENSIFY_URL: ACTIVE_EXPENSIFY_URL, UBER_CONNECT_URL, + FREE_TRIAL_MARKDOWN: + "# Your free trial has started! Let's get you set up.\n👋 Hey there, I'm your Expensify setup specialist. I've already created a workspace to help manage your team's receipts and expenses. To make the most of your 30-day free trial, just follow the remaining setup steps below!", APP_DOWNLOAD_LINKS: { ANDROID: `https://play.google.com/store/apps/details?id=${ANDROID_PACKAGE_NAME}`, IOS: 'https://apps.apple.com/us/app/expensify-travel-expense/id471713959', diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 182671bf9f3be..8f3ee6cfb56b2 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -1043,7 +1043,14 @@ function isVisiblePreviewOrMoneyRequest(action: ReportAction): boolean { * Delegates visibility logic to isVisiblePreviewOrMoneyRequest. */ function getFilteredReportActionsForReportView(actions: ReportAction[]) { - return actions.filter(isVisiblePreviewOrMoneyRequest); + // The free trial message can be duplicated due to this change https://github.com/Expensify/App/pull/68630 without the backend change + // So we need to filter out the duplicate free trial message + const freeTrialMessages = actions.filter((action) => { + const html = getReportActionHtml(action); + return Parser.htmlToMarkdown(html) === CONST.FREE_TRIAL_MARKDOWN; + }); + const isDuplicateFreeTrialMessage = freeTrialMessages.length > 1; + return actions.filter(isVisiblePreviewOrMoneyRequest).filter((action) => !isDuplicateFreeTrialMessage || action.reportActionID !== freeTrialMessages.at(0)?.reportActionID); } /** diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 379fa082c0d21..42b2eb3bb6072 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -69,7 +69,15 @@ import Navigation from './Navigation/Navigation'; import Parser from './Parser'; import {getDisplayNameOrDefault} from './PersonalDetailsUtils'; import {arePaymentsEnabled, canSendInvoice, getActivePolicy, getGroupPaidPoliciesWithExpenseChatEnabled, getPolicy, isPaidGroupPolicy, isPolicyPayer} from './PolicyUtils'; -import {getOriginalMessage, isCreatedAction, isDeletedAction, isMoneyRequestAction, isResolvedActionableWhisper, isWhisperActionTargetedToOthers} from './ReportActionsUtils'; +import { + getOriginalMessage, + getReportActionHtml, + isCreatedAction, + isDeletedAction, + isMoneyRequestAction, + isResolvedActionableWhisper, + isWhisperActionTargetedToOthers, +} from './ReportActionsUtils'; import {canReview} from './ReportPreviewActionUtils'; import {isExportAction} from './ReportPrimaryActionUtils'; import { @@ -1237,8 +1245,14 @@ function getReportActionsSections(data: OnyxTypes.SearchResults['data']): Report for (const key in data) { if (isReportActionEntry(key)) { - const reportActions = data[key]; - for (const reportAction of Object.values(reportActions)) { + const reportActions = Object.values(data[key]); + const freeTrialMessages = reportActions.filter((action) => { + const html = getReportActionHtml(action); + return Parser.htmlToMarkdown(html) === CONST.FREE_TRIAL_MARKDOWN; + }); + const isDuplicateFreeTrialMessage = freeTrialMessages.length > 1; + const filteredReportActions = reportActions.filter((action) => !isDuplicateFreeTrialMessage || action.reportActionID !== freeTrialMessages.at(0)?.reportActionID); + for (const reportAction of filteredReportActions) { const from = data.personalDetailsList?.[reportAction.accountID]; const report = data[`${ONYXKEYS.COLLECTION.REPORT}${reportAction.reportID}`] ?? {}; const policy = data[`${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`] ?? {};