From 60ba12aeab8b2e6e0b2e950388b721d967c788a9 Mon Sep 17 00:00:00 2001
From: gijoe0295 <153004152+gijoe0295@users.noreply.github.com>
Date: Fri, 29 May 2026 00:55:50 +0700
Subject: [PATCH 01/44] feat: ai feature promo modal navigation, basic
component and guards
---
src/CONST/index.ts | 8 +
src/NAVIGATORS.ts | 1 +
src/ROUTES.ts | 5 +
src/SCREENS.ts | 4 +
src/components/AIFeaturesPromoModal/index.tsx | 34 ++++
.../Navigation/AppNavigator/AuthScreens.tsx | 6 +
.../AIFeaturesPromoModalNavigator.tsx | 26 +++
.../Navigation/guards/AIFeaturesPromoGuard.ts | 174 ++++++++++++++++++
src/libs/Navigation/guards/index.ts | 4 +
src/libs/Navigation/linkingConfig/config.ts | 9 +
src/libs/Navigation/types.ts | 6 +
src/types/onyx/DismissedProductTraining.ts | 5 +
12 files changed, 282 insertions(+)
create mode 100644 src/components/AIFeaturesPromoModal/index.tsx
create mode 100644 src/libs/Navigation/AppNavigator/Navigators/AIFeaturesPromoModalNavigator.tsx
create mode 100644 src/libs/Navigation/guards/AIFeaturesPromoGuard.ts
diff --git a/src/CONST/index.ts b/src/CONST/index.ts
index 78b741d7aec0..12eecd80e920 100644
--- a/src/CONST/index.ts
+++ b/src/CONST/index.ts
@@ -9000,6 +9000,14 @@ const CONST = {
MIGRATED_USER_WELCOME_MODAL: 'migratedUserWelcomeModal',
+ AI_FEATURES_PROMO_MODAL: 'aiFeaturesPromoModal',
+
+ AI_FEATURES_PROMO_LEARN_MORE_URLS: {
+ SPEND_ANALYSIS: 'https://help.expensify.com/articles/new-expensify/concierge-ai/How-Concierge-Analyzes-Spend',
+ EXPENSE_ASSISTANT: 'https://help.expensify.com/articles/new-expensify/concierge-ai/Expense-Assistant',
+ BUILD_AGENTS: 'https://help.expensify.com/articles/new-expensify/concierge-ai/Expense-Assistant',
+ },
+
BASE_LIST_ITEM_TEST_ID: 'base-list-item-',
SELECTION_BUTTON_TEST_ID: 'selection-button-',
PRODUCT_TRAINING_TOOLTIP_NAMES: {
diff --git a/src/NAVIGATORS.ts b/src/NAVIGATORS.ts
index 23f0755290cc..6e93648f621a 100644
--- a/src/NAVIGATORS.ts
+++ b/src/NAVIGATORS.ts
@@ -9,6 +9,7 @@ export default {
FEATURE_TRAINING_MODAL_NAVIGATOR: 'FeatureTrainingModalNavigator',
EXPLANATION_MODAL_NAVIGATOR: 'ExplanationModalNavigator',
MIGRATED_USER_MODAL_NAVIGATOR: 'MigratedUserModalNavigator',
+ AI_FEATURES_PROMO_MODAL_NAVIGATOR: 'AIFeaturesPromoModalNavigator',
TEST_DRIVE_MODAL_NAVIGATOR: 'TestDriveModalNavigator',
TEST_DRIVE_DEMO_NAVIGATOR: 'TestDriveDemoNavigator',
REPORTS_SPLIT_NAVIGATOR: 'ReportsSplitNavigator',
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index 3966b0b9e5a8..0d51153b9588 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -3328,6 +3328,11 @@ const ROUTES = {
getRoute: (backTo?: string) => getUrlWithBackToParam('onboarding/migrated-user-welcome', backTo, false),
},
+ AI_FEATURES_PROMO_MODAL: {
+ route: 'ai-features-promo',
+
+ getRoute: (backTo?: string) => getUrlWithBackToParam('ai-features-promo', backTo, false),
+ },
TRANSACTION_RECEIPT: {
route: 'r/:reportID/transaction/:transactionID/receipt/:action?/:iouType?',
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index 8eaebf73b0d1..0db9cd64ef75 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -960,6 +960,10 @@ const SCREENS = {
ROOT: 'MigratedUserWelcomeModal_Root',
},
+ AI_FEATURES_PROMO_MODAL: {
+ ROOT: 'AIFeaturesPromoModal_Root',
+ },
+
TEST_DRIVE_MODAL: {
ROOT: 'TestDrive_Modal_Root',
},
diff --git a/src/components/AIFeaturesPromoModal/index.tsx b/src/components/AIFeaturesPromoModal/index.tsx
new file mode 100644
index 000000000000..1dda5ecb0ca6
--- /dev/null
+++ b/src/components/AIFeaturesPromoModal/index.tsx
@@ -0,0 +1,34 @@
+import React from 'react';
+import FeatureTrainingModal from '@components/FeatureTrainingModal';
+import LottieAnimations from '@components/LottieAnimations';
+import useLocalize from '@hooks/useLocalize';
+import {dismissProductTraining} from '@libs/actions/Welcome';
+import Log from '@libs/Log';
+import CONST from '@src/CONST';
+
+function AIFeaturesPromoModal() {
+ const {translate} = useLocalize();
+
+ const onClose = () => {
+ Log.hmmm('[AIFeaturesPromoModal] onClose called, dismissing product training');
+ dismissProductTraining(CONST.AI_FEATURES_PROMO_MODAL, true);
+ };
+
+ const onConfirm = () => {
+ Log.hmmm('[AIFeaturesPromoModal] onConfirm called, dismissing product training');
+ dismissProductTraining(CONST.AI_FEATURES_PROMO_MODAL);
+ };
+
+ return (
+
+ );
+}
+
+export default AIFeaturesPromoModal;
diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx
index 721f8814fc15..072b627776fd 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx
@@ -55,6 +55,7 @@ import DelegatorConnectGuard from './DelegatorConnectGate';
import hideKeyboardOnSwipe from './hideKeyboardOnSwipe';
import KeyboardShortcutsHandler from './KeyboardShortcutsHandler';
import {ShareModalStackNavigator} from './ModalStackNavigators';
+import AIFeaturesPromoModalNavigator from './Navigators/AIFeaturesPromoModalNavigator';
import ExplanationModalNavigator from './Navigators/ExplanationModalNavigator';
import FeatureTrainingModalNavigator from './Navigators/FeatureTrainingModalNavigator';
import MigratedUserWelcomeModalNavigator from './Navigators/MigratedUserWelcomeModalNavigator';
@@ -309,6 +310,11 @@ function AuthScreens() {
options={rootNavigatorScreenOptions.basicModalNavigator}
component={MigratedUserWelcomeModalNavigator}
/>
+
();
+
+function AIFeaturesPromoModalNavigator() {
+ return (
+
+
+
+
+
+
+
+ );
+}
+
+export default AIFeaturesPromoModalNavigator;
diff --git a/src/libs/Navigation/guards/AIFeaturesPromoGuard.ts b/src/libs/Navigation/guards/AIFeaturesPromoGuard.ts
new file mode 100644
index 000000000000..192b89324c0e
--- /dev/null
+++ b/src/libs/Navigation/guards/AIFeaturesPromoGuard.ts
@@ -0,0 +1,174 @@
+import type {NavigationAction, NavigationState} from '@react-navigation/native';
+import {findFocusedRoute} from '@react-navigation/native';
+import {hasCompletedGuidedSetupFlowSelector, tryNewDotOnyxSelector} from '@selectors/Onboarding';
+import Onyx from 'react-native-onyx';
+import type {OnyxEntry} from 'react-native-onyx';
+import Log from '@libs/Log';
+import Navigation from '@libs/Navigation/Navigation';
+import isProductTrainingElementDismissed from '@libs/TooltipUtils';
+import CONST from '@src/CONST';
+import NAVIGATORS from '@src/NAVIGATORS';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
+import type {DismissedProductTraining, Onboarding, Session} from '@src/types/onyx';
+import type {GuardResult, NavigationGuard} from './types';
+
+let session: OnyxEntry;
+let isLoadingApp = true;
+
+let dismissedProductTraining: OnyxEntry;
+let isDismissedProductTrainingLoaded = false;
+
+let hasBeenAddedToNudgeMigration = false;
+let isTryNewDotLoaded = false;
+
+let onboarding: OnyxEntry;
+let isOnboardingLoaded = false;
+
+let hasRedirectedToAIFeaturesPromoModal = false;
+
+/**
+ * Same-session protection.
+ *
+ * Per the issue requirements, the AI features promo modal must not appear in the same
+ * session as the migration welcome modal or the onboarding flow. These flags trip when
+ * we observe either of those modals being "active" (pending dismissal / not yet
+ * completed) at any point during this process lifetime, and suppress the AI promo for
+ * the rest of the session.
+ */
+let observedActiveMigrationModalThisSession = false;
+let observedActiveOnboardingThisSession = false;
+
+function resetSessionFlag() {
+ hasRedirectedToAIFeaturesPromoModal = false;
+ observedActiveMigrationModalThisSession = false;
+ observedActiveOnboardingThisSession = false;
+}
+
+/**
+ * Proactively navigate to the AI features promo modal when all conditions are met.
+ * Waits for the gating NVPs to load to avoid racing with the migration / onboarding guards.
+ */
+function navigateToAIFeaturesPromoModalIfReady() {
+ if (
+ !session?.authToken ||
+ isLoadingApp ||
+ hasRedirectedToAIFeaturesPromoModal ||
+ !isDismissedProductTrainingLoaded ||
+ !isTryNewDotLoaded ||
+ !isOnboardingLoaded ||
+ isProductTrainingElementDismissed(CONST.AI_FEATURES_PROMO_MODAL, dismissedProductTraining) ||
+ observedActiveMigrationModalThisSession ||
+ observedActiveOnboardingThisSession
+ ) {
+ return;
+ }
+
+ Log.info('[AIFeaturesPromoGuard] Proactively navigating to AI features promo modal');
+ hasRedirectedToAIFeaturesPromoModal = true;
+ Navigation.navigate(ROUTES.AI_FEATURES_PROMO_MODAL.getRoute());
+}
+
+/**
+ * Called by guards/index.ts when session or loading app state changes.
+ * Reuses the shared Onyx subscriptions from guards/index.ts to avoid duplicate connections.
+ */
+function onSessionOrLoadingAppChanged(sessionValue: OnyxEntry, isLoadingAppValue: boolean) {
+ session = sessionValue;
+ isLoadingApp = isLoadingAppValue;
+ navigateToAIFeaturesPromoModalIfReady();
+}
+
+Onyx.connectWithoutView({
+ key: ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING,
+ callback: (value) => {
+ dismissedProductTraining = value;
+ isDismissedProductTrainingLoaded = true;
+ if (isProductTrainingElementDismissed(CONST.AI_FEATURES_PROMO_MODAL, value)) {
+ hasRedirectedToAIFeaturesPromoModal = false;
+ }
+ // If the migration welcome modal is currently still pending, suppress AI promo this session.
+ if (hasBeenAddedToNudgeMigration && !isProductTrainingElementDismissed(CONST.MIGRATED_USER_WELCOME_MODAL, value)) {
+ observedActiveMigrationModalThisSession = true;
+ }
+ navigateToAIFeaturesPromoModalIfReady();
+ },
+});
+
+Onyx.connectWithoutView({
+ key: ONYXKEYS.NVP_TRY_NEW_DOT,
+ callback: (value) => {
+ const result = value ? tryNewDotOnyxSelector(value) : undefined;
+ hasBeenAddedToNudgeMigration = result?.hasBeenAddedToNudgeMigration ?? false;
+ isTryNewDotLoaded = true;
+ if (hasBeenAddedToNudgeMigration && !isProductTrainingElementDismissed(CONST.MIGRATED_USER_WELCOME_MODAL, dismissedProductTraining)) {
+ observedActiveMigrationModalThisSession = true;
+ }
+ navigateToAIFeaturesPromoModalIfReady();
+ },
+});
+
+Onyx.connectWithoutView({
+ key: ONYXKEYS.NVP_ONBOARDING,
+ callback: (value) => {
+ onboarding = value;
+ isOnboardingLoaded = true;
+ if (!hasCompletedGuidedSetupFlowSelector(onboarding)) {
+ observedActiveOnboardingThisSession = true;
+ }
+ navigateToAIFeaturesPromoModalIfReady();
+ },
+});
+
+/**
+ * Block navigation while the AI features promo modal is active (on top of the stack).
+ * Mirrors the pattern from MigratedUserWelcomeModalGuard.
+ */
+function shouldBlockWhileModalActive(state: NavigationState, action: NavigationAction): boolean {
+ const isAllowedAction = action.type === CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL || action.type === CONST.NAVIGATION.ACTION_TYPE.GO_BACK;
+ return (
+ hasRedirectedToAIFeaturesPromoModal &&
+ !isProductTrainingElementDismissed(CONST.AI_FEATURES_PROMO_MODAL, dismissedProductTraining) &&
+ state.routes.at(-1)?.name === NAVIGATORS.AI_FEATURES_PROMO_MODAL_NAVIGATOR &&
+ !isAllowedAction
+ );
+}
+
+/** Prevents redirect loops by detecting when we're already on or resetting to the modal. */
+function isNavigatingToAIFeaturesPromoModal(state: NavigationState, action: NavigationAction): boolean {
+ const isOnModal = findFocusedRoute(state)?.name === SCREENS.AI_FEATURES_PROMO_MODAL.ROOT;
+ const isResettingToModal = action.type === 'RESET' && !!action.payload && findFocusedRoute(action.payload as NavigationState)?.name === SCREENS.AI_FEATURES_PROMO_MODAL.ROOT;
+
+ return isOnModal || isResettingToModal;
+}
+
+/**
+ * AIFeaturesPromoGuard surfaces the one-time AI features promo modal.
+ *
+ * This guard relies on the proactive Onyx-driven path (navigateToAIFeaturesPromoModalIfReady)
+ * rather than redirecting from evaluate(), because it needs to wait for higher-priority guards
+ * (Onboarding, MigratedUserWelcomeModal) to settle before deciding whether to fire.
+ */
+const AIFeaturesPromoGuard: NavigationGuard = {
+ name: 'AIFeaturesPromoGuard',
+
+ evaluate: (state: NavigationState, action: NavigationAction, context): GuardResult => {
+ if (context.isLoading) {
+ return {type: 'ALLOW'};
+ }
+
+ if (shouldBlockWhileModalActive(state, action)) {
+ return {type: 'BLOCK', reason: '[AIFeaturesPromoGuard] Blocking navigation while AI features promo modal is active'};
+ }
+
+ if (isNavigatingToAIFeaturesPromoModal(state, action) || hasRedirectedToAIFeaturesPromoModal) {
+ return {type: 'ALLOW'};
+ }
+
+ return {type: 'ALLOW'};
+ },
+};
+
+export default AIFeaturesPromoGuard;
+export {resetSessionFlag, onSessionOrLoadingAppChanged};
diff --git a/src/libs/Navigation/guards/index.ts b/src/libs/Navigation/guards/index.ts
index fdc43fd6440a..e60ba997d016 100644
--- a/src/libs/Navigation/guards/index.ts
+++ b/src/libs/Navigation/guards/index.ts
@@ -4,6 +4,7 @@ import type {OnyxEntry} from 'react-native-onyx';
import getCurrentUrl from '@libs/Navigation/currentUrl';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Session} from '@src/types/onyx';
+import AIFeaturesPromoGuard, {onSessionOrLoadingAppChanged as onAIFeaturesPromoSessionOrLoadingAppChanged} from './AIFeaturesPromoGuard';
import MigratedUserWelcomeModalGuard, {onSessionOrLoadingAppChanged} from './MigratedUserWelcomeModalGuard';
import OnboardingGuard from './OnboardingGuard';
import type {GuardContext, GuardResult, NavigationGuard} from './types';
@@ -20,6 +21,7 @@ Onyx.connectWithoutView({
callback: (value) => {
session = value;
onSessionOrLoadingAppChanged(session, isLoadingApp);
+ onAIFeaturesPromoSessionOrLoadingAppChanged(session, isLoadingApp);
},
});
@@ -28,6 +30,7 @@ Onyx.connectWithoutView({
callback: (value) => {
isLoadingApp = value ?? true;
onSessionOrLoadingAppChanged(session, isLoadingApp);
+ onAIFeaturesPromoSessionOrLoadingAppChanged(session, isLoadingApp);
},
});
@@ -103,5 +106,6 @@ function clearGuards(): void {
registerGuard(OnboardingGuard);
registerGuard(MigratedUserWelcomeModalGuard);
+registerGuard(AIFeaturesPromoGuard);
export {registerGuard, createGuardContext, evaluateGuards, getRegisteredGuards, clearGuards};
diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts
index f1a5498123d7..6ec8c9a3f6f6 100644
--- a/src/libs/Navigation/linkingConfig/config.ts
+++ b/src/libs/Navigation/linkingConfig/config.ts
@@ -67,6 +67,15 @@ const config: LinkingOptions['config'] = {
},
},
+ [NAVIGATORS.AI_FEATURES_PROMO_MODAL_NAVIGATOR]: {
+ screens: {
+ [SCREENS.AI_FEATURES_PROMO_MODAL.ROOT]: {
+ path: ROUTES.AI_FEATURES_PROMO_MODAL.route,
+ exact: true,
+ },
+ },
+ },
+
[NAVIGATORS.TEST_DRIVE_MODAL_NAVIGATOR]: {
screens: {
[SCREENS.TEST_DRIVE_MODAL.ROOT]: {
diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts
index 675cff9a5059..12be8b30c30f 100644
--- a/src/libs/Navigation/types.ts
+++ b/src/libs/Navigation/types.ts
@@ -2916,6 +2916,10 @@ type MigratedUserModalNavigatorParamList = {
[SCREENS.MIGRATED_USER_WELCOME_MODAL.ROOT]: undefined;
};
+type AIFeaturesPromoModalNavigatorParamList = {
+ [SCREENS.AI_FEATURES_PROMO_MODAL.ROOT]: undefined;
+};
+
type TestDriveModalNavigatorParamList = {
[SCREENS.TEST_DRIVE_MODAL.ROOT]: {
bossEmail?: string;
@@ -3092,6 +3096,7 @@ type AuthScreensParamList = SharedScreensParamList &
[NAVIGATORS.FEATURE_TRAINING_MODAL_NAVIGATOR]: NavigatorScreenParams;
[NAVIGATORS.EXPLANATION_MODAL_NAVIGATOR]: NavigatorScreenParams;
[NAVIGATORS.MIGRATED_USER_MODAL_NAVIGATOR]: NavigatorScreenParams;
+ [NAVIGATORS.AI_FEATURES_PROMO_MODAL_NAVIGATOR]: NavigatorScreenParams;
[NAVIGATORS.TEST_DRIVE_MODAL_NAVIGATOR]: NavigatorScreenParams;
[NAVIGATORS.TEST_DRIVE_DEMO_NAVIGATOR]: NavigatorScreenParams;
[SCREENS.CONNECTION_COMPLETE]: undefined;
@@ -3368,6 +3373,7 @@ export type {
WorkspaceSplitNavigatorParamList,
WorkspaceNavigatorParamList,
MigratedUserModalNavigatorParamList,
+ AIFeaturesPromoModalNavigatorParamList,
WorkspaceConfirmationNavigatorParamList,
WorkspaceDuplicateNavigatorParamList,
PolicyCopySettingsNavigatorParamList,
diff --git a/src/types/onyx/DismissedProductTraining.ts b/src/types/onyx/DismissedProductTraining.ts
index 7cfb6f999011..17c13e6c9112 100644
--- a/src/types/onyx/DismissedProductTraining.ts
+++ b/src/types/onyx/DismissedProductTraining.ts
@@ -22,6 +22,11 @@ type DismissedProductTraining = {
*/
[CONST.MIGRATED_USER_WELCOME_MODAL]: DismissedProductTrainingElement;
+ /**
+ * When user dismisses the AI features promo modal, we store the timestamp here.
+ */
+ [CONST.AI_FEATURES_PROMO_MODAL]: DismissedProductTrainingElement;
+
// TODO: CONCIERGE_LHN_GBR tooltip will be replaced by a tooltip in the #admins room
// https://github.com/Expensify/App/issues/57045#issuecomment-2701455668
/**
From 3b61e1e0ed926ba0dff7361c5c20f4d1d5d3c6d6 Mon Sep 17 00:00:00 2001
From: gijoe0295 <153004152+gijoe0295@users.noreply.github.com>
Date: Fri, 29 May 2026 00:58:32 +0700
Subject: [PATCH 02/44] add English terms
---
src/languages/en.ts | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/src/languages/en.ts b/src/languages/en.ts
index 2c964abfbbee..f10457e74c74 100644
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -9231,6 +9231,28 @@ const translations = {
chat: 'Chat on any expense to resolve questions quickly',
},
},
+ aiFeaturesPromoModal: {
+ title: 'Meet Concierge AI',
+ description: 'Your new AI-powered Expensify assistant.',
+ letsGo: "Let's go",
+ learnMore: 'Learn more',
+ next: 'Next',
+ back: 'Back',
+ screens: {
+ spendAnalysis: {
+ title: 'Interactive spend analysis',
+ description: 'Ask Concierge to break down your spending however you want — by category, person, project, or time.',
+ },
+ expenseAssistant: {
+ title: 'Meet your new expense assistant',
+ description: 'Concierge can categorize expenses, fill in details, and follow up on missing receipts for you.',
+ },
+ buildAgents: {
+ title: 'Build your own agents',
+ description: 'Create custom AI agents to automate the workflows that matter most to your team.',
+ },
+ },
+ },
productTrainingTooltip: {
// TODO: CONCIERGE_LHN_GBR tooltip will be replaced by a tooltip in the #admins room
// https://github.com/Expensify/App/issues/57045#issuecomment-2701455668
From 847a4fbfe6265c51319b9724d6bb3e54d3b96556 Mon Sep 17 00:00:00 2001
From: gijoe0295 <153004152+gijoe0295@users.noreply.github.com>
Date: Tue, 2 Jun 2026 00:14:30 +0700
Subject: [PATCH 03/44] run translation script
---
src/languages/de.ts | 22 ++++++++++++++++++++++
src/languages/es.ts | 16 ++++++++++++++++
src/languages/fr.ts | 19 +++++++++++++++++++
src/languages/it.ts | 19 +++++++++++++++++++
src/languages/ja.ts | 16 ++++++++++++++++
src/languages/nl.ts | 19 +++++++++++++++++++
src/languages/pl.ts | 19 +++++++++++++++++++
src/languages/pt-BR.ts | 16 ++++++++++++++++
src/languages/zh-hans.ts | 13 +++++++++++++
9 files changed, 159 insertions(+)
diff --git a/src/languages/de.ts b/src/languages/de.ts
index 57b6dfb756eb..0efacdba3fbc 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -9594,5 +9594,27 @@ Hier ist ein *Testbeleg*, um dir zu zeigen, wie es funktioniert:`,
negativeButton: 'Nicht wirklich',
},
monthPickerPage: {month: 'Monat', selectMonth: 'Bitte wählen Sie einen Monat aus'},
+ aiFeaturesPromoModal: {
+ title: 'Lernen Sie Concierge AI kennen',
+ description: 'Ihr neuer KI-gestützter Expensify-Assistent.',
+ letsGo: "Los geht's",
+ learnMore: 'Mehr erfahren',
+ next: 'Weiter',
+ back: 'Zurück',
+ screens: {
+ spendAnalysis: {
+ title: 'Interaktive Ausgabenanalyse',
+ description: 'Bitten Sie Concierge, Ihre Ausgaben ganz nach Ihren Wünschen aufzuschlüsseln – nach Kategorie, Person, Projekt oder Zeitraum.',
+ },
+ expenseAssistant: {
+ title: 'Lernen Sie Ihre neue Spesenassistenz kennen',
+ description: 'Concierge kann Ausgaben kategorisieren, Details ausfüllen und fehlenden Belegen für Sie nachgehen.',
+ },
+ buildAgents: {
+ title: 'Erstellen Sie Ihre eigenen Agents',
+ description: 'Erstellen Sie benutzerdefinierte KI-Agenten, um die Workflows zu automatisieren, die für Ihr Team am wichtigsten sind.',
+ },
+ },
+ },
};
export default translations;
diff --git a/src/languages/es.ts b/src/languages/es.ts
index f94ab5bdd7e5..20b26c068662 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -9839,5 +9839,21 @@ ${amount} para ${merchant} - ${date}`,
lockScreenTrackingText: 'Siguiendo...',
},
},
+ aiFeaturesPromoModal: {
+ title: 'Conoce Concierge AI',
+ description: 'Tu nuevo asistente de Expensify potenciado por IA.',
+ letsGo: 'Vamos allá',
+ learnMore: 'Más información',
+ next: 'Siguiente',
+ back: 'Atrás',
+ screens: {
+ spendAnalysis: {title: 'Análisis interactivo del gasto', description: 'Pídele a Concierge que desglosE tus gastos como quieras: por categoría, persona, proyecto o periodo.'},
+ expenseAssistant: {
+ title: 'Conoce a tu nuevo asistente de gastos',
+ description: 'Concierge puede categorizar gastos, completar detalles y hacer seguimiento de los recibos que falten por ti.',
+ },
+ buildAgents: {title: 'Crea tus propios agentes', description: 'Crea agentes de IA personalizados para automatizar los flujos de trabajo que más le importan a tu equipo.'},
+ },
+ },
};
export default translations;
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index ffe8fe432ab7..e26aab6249bf 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -9629,5 +9629,24 @@ Voici un *reçu test* pour vous montrer comment ça fonctionne :`,
negativeButton: 'Pas vraiment',
},
monthPickerPage: {month: 'Mois', selectMonth: 'Veuillez sélectionner un mois'},
+ aiFeaturesPromoModal: {
+ title: 'Découvrez Concierge IA',
+ description: 'Votre nouvel assistant Expensify, optimisé par l’IA.',
+ letsGo: 'Allons-y',
+ learnMore: 'En savoir plus',
+ next: 'Suivant',
+ back: 'Retour',
+ screens: {
+ spendAnalysis: {
+ title: 'Analyse interactive des dépenses',
+ description: 'Demandez à Concierge de ventiler vos dépenses comme vous le souhaitez — par catégorie, personne, projet ou période.',
+ },
+ expenseAssistant: {
+ title: 'Découvrez votre nouvel assistant de dépenses',
+ description: 'Concierge peut catégoriser les dépenses, renseigner les détails et faire le suivi des reçus manquants pour vous.',
+ },
+ buildAgents: {title: 'Créez vos propres agents', description: 'Créez des agents IA personnalisés pour automatiser les workflows qui comptent le plus pour votre équipe.'},
+ },
+ },
};
export default translations;
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 14a51b1a27a3..55b42c0d0b53 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -9583,5 +9583,24 @@ Ecco una *ricevuta di prova* per mostrarti come funziona:`,
negativeButton: 'Non proprio',
},
monthPickerPage: {month: 'Mese', selectMonth: 'Seleziona un mese'},
+ aiFeaturesPromoModal: {
+ title: 'Incontra Concierge AI',
+ description: 'Il tuo nuovo assistente Expensify con tecnologia AI.',
+ letsGo: 'Andiamo',
+ learnMore: 'Scopri di più',
+ next: 'Avanti',
+ back: 'Indietro',
+ screens: {
+ spendAnalysis: {
+ title: 'Analisi interattiva delle spese',
+ description: 'Chiedi a Concierge di suddividere le tue spese come vuoi tu — per categoria, persona, progetto o periodo.',
+ },
+ expenseAssistant: {
+ title: 'Scopri il tuo nuovo assistente per le spese',
+ description: 'Concierge può categorizzare le spese, compilare i dettagli e sollecitare le ricevute mancanti per te.',
+ },
+ buildAgents: {title: 'Crea i tuoi agenti', description: 'Crea agenti IA personalizzati per automatizzare i flussi di lavoro più importanti per il tuo team.'},
+ },
+ },
};
export default translations;
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 979a87f17b04..4118c5aa3e4c 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -9458,5 +9458,21 @@ ${reportName}
negativeButton: 'そうでもありません',
},
monthPickerPage: {month: '月', selectMonth: '月を選択してください'},
+ aiFeaturesPromoModal: {
+ title: 'Concierge AI を紹介します',
+ description: '新しい AI 搭載の Expensify アシスタントです。',
+ letsGo: '始めましょう',
+ learnMore: '詳細はこちら',
+ next: '次へ',
+ back: '戻る',
+ screens: {
+ spendAnalysis: {title: 'インタラクティブな支出分析', description: 'カテゴリ、人、プロジェクト、期間など、必要な切り口で支出を分解するよう Concierge に依頼できます。'},
+ expenseAssistant: {
+ title: '新しい経費アシスタントをご紹介します',
+ description: 'Concierge は、経費のカテゴリ分けや詳細の入力、不足しているレシートのフォローアップを代わりに行います。',
+ },
+ buildAgents: {title: '独自のエージェントを作成する', description: 'チームにとって最も重要なワークフローを自動化するカスタム AI エージェントを作成しましょう。'},
+ },
+ },
};
export default translations;
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 8540c1d87bdb..a0ceaa0758ba 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -9549,5 +9549,24 @@ Hier is een *proefbon* om je te laten zien hoe het werkt:`,
negativeButton: 'Niet echt',
},
monthPickerPage: {month: 'Maand', selectMonth: 'Selecteer een maand'},
+ aiFeaturesPromoModal: {
+ title: 'Maak kennis met Concierge AI',
+ description: 'Je nieuwe door AI aangestuurde Expensify-assistent.',
+ letsGo: 'Laten we gaan',
+ learnMore: 'Meer informatie',
+ next: 'Volgende',
+ back: 'Terug',
+ screens: {
+ spendAnalysis: {
+ title: 'Interactieve uitgavenanalyse',
+ description: 'Vraag Concierge om je uitgaven op elke gewenste manier op te splitsen — per categorie, persoon, project of tijd.',
+ },
+ expenseAssistant: {
+ title: 'Maak kennis met je nieuwe onkostenassistent',
+ description: 'Concierge kan uitgaven categoriseren, details invullen en ontbrekende bonnen voor je opvolgen.',
+ },
+ buildAgents: {title: 'Bouw je eigen agents', description: 'Maak aangepaste AI-agents om de workflows te automatiseren die het belangrijkst zijn voor je team.'},
+ },
+ },
};
export default translations;
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index bdbaf80e8efa..d0c90d123127 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -9528,5 +9528,24 @@ Oto *paragon testowy*, żeby pokazać Ci, jak to działa:`,
negativeButton: 'Niekoniecznie',
},
monthPickerPage: {month: 'Miesiąc', selectMonth: 'Wybierz miesiąc'},
+ aiFeaturesPromoModal: {
+ title: 'Poznaj Concierge AI',
+ description: 'Twój nowy asystent Expensify zasilany AI.',
+ letsGo: 'Zaczynajmy',
+ learnMore: 'Dowiedz się więcej',
+ next: 'Dalej',
+ back: 'Wstecz',
+ screens: {
+ spendAnalysis: {
+ title: 'Interaktywna analiza wydatków',
+ description: 'Poproś Concierge o rozbicie swoich wydatków tak, jak chcesz — według kategorii, osoby, projektu lub czasu.',
+ },
+ expenseAssistant: {
+ title: 'Poznaj swojego nowego asystenta wydatków',
+ description: 'Concierge może kategoryzować wydatki, uzupełniać szczegóły i śledzić brakujące paragony za ciebie.',
+ },
+ buildAgents: {title: 'Zbuduj własne agentów', description: 'Twórz własne agentki AI, żeby automatyzować procesy, które są dla twojego zespołu najważniejsze.'},
+ },
+ },
};
export default translations;
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index cdfe462ac026..6713140189f4 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -9539,5 +9539,21 @@ Aqui está um *comprovante de teste* para mostrar como funciona:`,
negativeButton: 'Na verdade, não',
},
monthPickerPage: {month: 'Mês', selectMonth: 'Selecione um mês por favor'},
+ aiFeaturesPromoModal: {
+ title: 'Conheça a Concierge AI',
+ description: 'Seu novo assistente Expensify com tecnologia de IA.',
+ letsGo: 'Vamos lá',
+ learnMore: 'Saiba mais',
+ next: 'Próximo',
+ back: 'Voltar',
+ screens: {
+ spendAnalysis: {title: 'Análise interativa de gastos', description: 'Peça ao Concierge para detalhar seus gastos como você quiser — por categoria, pessoa, projeto ou período.'},
+ expenseAssistant: {
+ title: 'Conheça seu novo assistente de despesas',
+ description: 'O Concierge pode categorizar despesas, preencher detalhes e acompanhar recibos ausentes para você.',
+ },
+ buildAgents: {title: 'Crie seus próprios agentes', description: 'Crie agentes de IA personalizados para automatizar os fluxos de trabalho que mais importam para a sua equipe.'},
+ },
+ },
};
export default translations;
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index 95a993c47bf1..dbdfd8e0cce6 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -9277,5 +9277,18 @@ ${reportName}
},
proactiveAppReview: {title: '喜欢全新的 Expensify 吗?', description: '请告诉我们,这样我们就能帮助您让报销体验变得更好。', positiveButton: '太棒了!', negativeButton: '不太是'},
monthPickerPage: {month: '月份', selectMonth: '请选择月份'},
+ aiFeaturesPromoModal: {
+ title: '了解 Concierge AI',
+ description: '您全新的 AI 驱动 Expensify 助理。',
+ letsGo: '开始使用',
+ learnMore: '了解详情',
+ next: '下一步',
+ back: '返回',
+ screens: {
+ spendAnalysis: {title: '交互式支出分析', description: '让 Concierge 按你想要的方式细分支出——按类别、人员、项目或时间。'},
+ expenseAssistant: {title: '认识你的新报销助手', description: 'Concierge 可以帮你分类报销、填写详情,并跟进缺失的收据。'},
+ buildAgents: {title: '构建你自己的代理', description: '创建自定义 AI 代理,自动化对你的团队最重要的工作流程。'},
+ },
+ },
};
export default translations;
From dc884962769efc7bd09137638b0f9c83ca649c48 Mon Sep 17 00:00:00 2001
From: gijoe0295 <153004152+gijoe0295@users.noreply.github.com>
Date: Tue, 2 Jun 2026 23:39:34 +0700
Subject: [PATCH 04/44] remove deprecated getUrlWithBackToParam
---
src/ROUTES.ts | 6 +-----
src/libs/Navigation/guards/AIFeaturesPromoGuard.ts | 2 +-
src/libs/Navigation/linkingConfig/config.ts | 2 +-
3 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index b58efd3b6367..4e6ece62015c 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -3375,11 +3375,7 @@ const ROUTES = {
getRoute: (backTo?: string) => getUrlWithBackToParam('onboarding/migrated-user-welcome', backTo, false),
},
- AI_FEATURES_PROMO_MODAL: {
- route: 'ai-features-promo',
-
- getRoute: (backTo?: string) => getUrlWithBackToParam('ai-features-promo', backTo, false),
- },
+ AI_FEATURES_PROMO_MODAL: 'ai-features-promo',
TRANSACTION_RECEIPT: {
route: 'r/:reportID/transaction/:transactionID/receipt/:action?/:iouType?',
diff --git a/src/libs/Navigation/guards/AIFeaturesPromoGuard.ts b/src/libs/Navigation/guards/AIFeaturesPromoGuard.ts
index 192b89324c0e..3a8df06ead97 100644
--- a/src/libs/Navigation/guards/AIFeaturesPromoGuard.ts
+++ b/src/libs/Navigation/guards/AIFeaturesPromoGuard.ts
@@ -67,7 +67,7 @@ function navigateToAIFeaturesPromoModalIfReady() {
Log.info('[AIFeaturesPromoGuard] Proactively navigating to AI features promo modal');
hasRedirectedToAIFeaturesPromoModal = true;
- Navigation.navigate(ROUTES.AI_FEATURES_PROMO_MODAL.getRoute());
+ Navigation.navigate(ROUTES.AI_FEATURES_PROMO_MODAL);
}
/**
diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts
index d6c4cbd3b396..3079af6ec200 100644
--- a/src/libs/Navigation/linkingConfig/config.ts
+++ b/src/libs/Navigation/linkingConfig/config.ts
@@ -65,7 +65,7 @@ const config: LinkingOptions['config'] = {
[NAVIGATORS.AI_FEATURES_PROMO_MODAL_NAVIGATOR]: {
screens: {
[SCREENS.AI_FEATURES_PROMO_MODAL.ROOT]: {
- path: ROUTES.AI_FEATURES_PROMO_MODAL.route,
+ path: ROUTES.AI_FEATURES_PROMO_MODAL,
exact: true,
},
},
From e9738ef72c6486c50149e027c821b4f8b5fb12ef Mon Sep 17 00:00:00 2001
From: gijoe0295 <153004152+gijoe0295@users.noreply.github.com>
Date: Mon, 8 Jun 2026 13:21:06 +0700
Subject: [PATCH 05/44] improve navigation guard to account for explanation
modal
---
.../Navigation/guards/AIFeaturesPromoGuard.ts | 20 ++++++++++++++-----
src/libs/Navigation/guards/index.ts | 6 +++---
2 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/src/libs/Navigation/guards/AIFeaturesPromoGuard.ts b/src/libs/Navigation/guards/AIFeaturesPromoGuard.ts
index 3a8df06ead97..041234a4053c 100644
--- a/src/libs/Navigation/guards/AIFeaturesPromoGuard.ts
+++ b/src/libs/Navigation/guards/AIFeaturesPromoGuard.ts
@@ -6,6 +6,7 @@ import type {OnyxEntry} from 'react-native-onyx';
import Log from '@libs/Log';
import Navigation from '@libs/Navigation/Navigation';
import isProductTrainingElementDismissed from '@libs/TooltipUtils';
+import CONFIG from '@src/CONFIG';
import CONST from '@src/CONST';
import NAVIGATORS from '@src/NAVIGATORS';
import ONYXKEYS from '@src/ONYXKEYS';
@@ -21,6 +22,7 @@ let dismissedProductTraining: OnyxEntry;
let isDismissedProductTrainingLoaded = false;
let hasBeenAddedToNudgeMigration = false;
+let isHybridAppOnboardingCompleted: boolean | undefined;
let isTryNewDotLoaded = false;
let onboarding: OnyxEntry;
@@ -32,18 +34,20 @@ let hasRedirectedToAIFeaturesPromoModal = false;
* Same-session protection.
*
* Per the issue requirements, the AI features promo modal must not appear in the same
- * session as the migration welcome modal or the onboarding flow. These flags trip when
- * we observe either of those modals being "active" (pending dismissal / not yet
- * completed) at any point during this process lifetime, and suppress the AI promo for
- * the rest of the session.
+ * session as the migration welcome modal, the onboarding flow, or the HybridApp
+ * explanation modal. These flags trip when we observe any of those modals being
+ * "active" (pending dismissal / not yet completed) at any point during this process
+ * lifetime, and suppress the AI promo for the rest of the session.
*/
let observedActiveMigrationModalThisSession = false;
let observedActiveOnboardingThisSession = false;
+let observedActiveExplanationModalThisSession = false;
function resetSessionFlag() {
hasRedirectedToAIFeaturesPromoModal = false;
observedActiveMigrationModalThisSession = false;
observedActiveOnboardingThisSession = false;
+ observedActiveExplanationModalThisSession = false;
}
/**
@@ -60,7 +64,8 @@ function navigateToAIFeaturesPromoModalIfReady() {
!isOnboardingLoaded ||
isProductTrainingElementDismissed(CONST.AI_FEATURES_PROMO_MODAL, dismissedProductTraining) ||
observedActiveMigrationModalThisSession ||
- observedActiveOnboardingThisSession
+ observedActiveOnboardingThisSession ||
+ observedActiveExplanationModalThisSession
) {
return;
}
@@ -101,10 +106,15 @@ Onyx.connectWithoutView({
callback: (value) => {
const result = value ? tryNewDotOnyxSelector(value) : undefined;
hasBeenAddedToNudgeMigration = result?.hasBeenAddedToNudgeMigration ?? false;
+ isHybridAppOnboardingCompleted = result?.isHybridAppOnboardingCompleted;
isTryNewDotLoaded = true;
if (hasBeenAddedToNudgeMigration && !isProductTrainingElementDismissed(CONST.MIGRATED_USER_WELCOME_MODAL, dismissedProductTraining)) {
observedActiveMigrationModalThisSession = true;
}
+ // The HybridApp explanation modal shows when the user is transitioning from OldDot to NewDot.
+ if (CONFIG.IS_HYBRID_APP && isHybridAppOnboardingCompleted === false) {
+ observedActiveExplanationModalThisSession = true;
+ }
navigateToAIFeaturesPromoModalIfReady();
},
});
diff --git a/src/libs/Navigation/guards/index.ts b/src/libs/Navigation/guards/index.ts
index e60ba997d016..783b8be533b3 100644
--- a/src/libs/Navigation/guards/index.ts
+++ b/src/libs/Navigation/guards/index.ts
@@ -5,7 +5,7 @@ import getCurrentUrl from '@libs/Navigation/currentUrl';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Session} from '@src/types/onyx';
import AIFeaturesPromoGuard, {onSessionOrLoadingAppChanged as onAIFeaturesPromoSessionOrLoadingAppChanged} from './AIFeaturesPromoGuard';
-import MigratedUserWelcomeModalGuard, {onSessionOrLoadingAppChanged} from './MigratedUserWelcomeModalGuard';
+import MigratedUserWelcomeModalGuard, {onSessionOrLoadingAppChanged as onMigratedUserWelcomeModalSessionOrLoadingAppChanged} from './MigratedUserWelcomeModalGuard';
import OnboardingGuard from './OnboardingGuard';
import type {GuardContext, GuardResult, NavigationGuard} from './types';
@@ -20,7 +20,7 @@ Onyx.connectWithoutView({
key: ONYXKEYS.SESSION,
callback: (value) => {
session = value;
- onSessionOrLoadingAppChanged(session, isLoadingApp);
+ onMigratedUserWelcomeModalSessionOrLoadingAppChanged(session, isLoadingApp);
onAIFeaturesPromoSessionOrLoadingAppChanged(session, isLoadingApp);
},
});
@@ -29,7 +29,7 @@ Onyx.connectWithoutView({
key: ONYXKEYS.IS_LOADING_APP,
callback: (value) => {
isLoadingApp = value ?? true;
- onSessionOrLoadingAppChanged(session, isLoadingApp);
+ onMigratedUserWelcomeModalSessionOrLoadingAppChanged(session, isLoadingApp);
onAIFeaturesPromoSessionOrLoadingAppChanged(session, isLoadingApp);
},
});
From d78c768b2a85f891ec954deed77a87427d7a584b Mon Sep 17 00:00:00 2001
From: gijoe0295 <153004152+gijoe0295@users.noreply.github.com>
Date: Mon, 8 Jun 2026 13:21:43 +0700
Subject: [PATCH 06/44] add lottie files
---
assets/animations/CustomAgents.lottie | Bin 0 -> 38277 bytes
assets/animations/ExpenseAssistant.lottie | Bin 0 -> 28766 bytes
assets/animations/SpendAnalysis.lottie | Bin 0 -> 20112 bytes
src/components/LottieAnimations/index.tsx | 16 ++++++++++++++++
4 files changed, 16 insertions(+)
create mode 100644 assets/animations/CustomAgents.lottie
create mode 100644 assets/animations/ExpenseAssistant.lottie
create mode 100644 assets/animations/SpendAnalysis.lottie
diff --git a/assets/animations/CustomAgents.lottie b/assets/animations/CustomAgents.lottie
new file mode 100644
index 0000000000000000000000000000000000000000..8210c757e7a027bfb36841b1b60c0024149afc06
GIT binary patch
literal 38277
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
literal 0
HcmV?d00001
diff --git a/assets/animations/ExpenseAssistant.lottie b/assets/animations/ExpenseAssistant.lottie
new file mode 100644
index 0000000000000000000000000000000000000000..99e64a64cede3e17f2b38cc4c4285971d86cc8c2
GIT binary patch
literal 28766
zcmZ_UL$D~YvMA7P+qP}nw(YZR+qP|=ZQHhO+vY#_zBhS;UzH3}8FVJ;O81I_G%yGX
z00004z=QOdPJ