diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 7a78b2695dc2..72e62e3d9998 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -7724,6 +7724,7 @@ const CONST = { ACCOUNT_SWITCHER: 'accountSwitcher', SCAN_TEST_DRIVE_CONFIRMATION: 'scanTestDriveConfirmation', MULTI_SCAN_EDUCATIONAL_MODAL: 'multiScanEducationalModal', + GPS_TOOLTIP: 'gpsTooltip', }, CHANGE_POLICY_TRAINING_MODAL: 'changePolicyModal', SMART_BANNER_HEIGHT: 152, diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 3205cb49523a..d75858614ffb 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -286,9 +286,6 @@ const ONYXKEYS = { /** This NVP contains personal expense rules */ NVP_EXPENSE_RULES: 'nvp_expensify_expenseRules', - /** A timestamp of when the user created a GPS expense for the first time */ - NVP_FIRST_CREATED_GPS_EXPENSE_DATE_NEW_DOT: 'nvp_firstCreatedGpsExpenseDateNewDot', - /** Plaid data (access tokens, bank accounts ...) */ PLAID_DATA: 'plaidData', @@ -1383,7 +1380,6 @@ type OnyxValuesMapping = { [ONYXKEYS.HYBRID_APP]: OnyxTypes.HybridApp; [ONYXKEYS.NVP_CSV_EXPORT_LAYOUTS]: Record; [ONYXKEYS.NVP_EXPENSE_RULES]: OnyxTypes.ExpenseRule[]; - [ONYXKEYS.NVP_FIRST_CREATED_GPS_EXPENSE_DATE_NEW_DOT]: string; [ONYXKEYS.NVP_LAST_DISTANCE_EXPENSE_TYPE]: DistanceExpenseType; [ONYXKEYS.NVP_REPORT_LAYOUT_GROUP_BY]: string; [ONYXKEYS.HAS_DENIED_CONTACT_IMPORT_PROMPT]: boolean | undefined; diff --git a/src/components/ProductTrainingContext/TOOLTIPS.ts b/src/components/ProductTrainingContext/TOOLTIPS.ts index 3e9cfb979e7b..4619267bd01c 100644 --- a/src/components/ProductTrainingContext/TOOLTIPS.ts +++ b/src/components/ProductTrainingContext/TOOLTIPS.ts @@ -3,8 +3,17 @@ import {dismissProductTraining} from '@libs/actions/Welcome'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; -const {CONCIERGE_LHN_GBR, RENAME_SAVED_SEARCH, SCAN_TEST_TOOLTIP, SCAN_TEST_TOOLTIP_MANAGER, SCAN_TEST_CONFIRMATION, OUTSTANDING_FILTER, ACCOUNT_SWITCHER, SCAN_TEST_DRIVE_CONFIRMATION} = - CONST.PRODUCT_TRAINING_TOOLTIP_NAMES; +const { + CONCIERGE_LHN_GBR, + RENAME_SAVED_SEARCH, + SCAN_TEST_TOOLTIP, + SCAN_TEST_TOOLTIP_MANAGER, + SCAN_TEST_CONFIRMATION, + OUTSTANDING_FILTER, + ACCOUNT_SWITCHER, + SCAN_TEST_DRIVE_CONFIRMATION, + GPS_TOOLTIP, +} = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES; type ProductTrainingTooltipName = Exclude, typeof CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.MULTI_SCAN_EDUCATIONAL_MODAL>; @@ -85,6 +94,13 @@ const TOOLTIPS: Record = { priority: 1200, shouldShow: () => true, }, + [GPS_TOOLTIP]: { + content: 'productTrainingTooltip.gpsTooltip', + onHideTooltip: (isDismissedUsingCloseButton = false) => dismissProductTraining(GPS_TOOLTIP, isDismissedUsingCloseButton), + name: GPS_TOOLTIP, + priority: 800, + shouldShow: () => true, + }, }; export default TOOLTIPS; diff --git a/src/components/ProductTrainingContext/index.tsx b/src/components/ProductTrainingContext/index.tsx index 29b880a8387e..3461cef7e4a0 100644 --- a/src/components/ProductTrainingContext/index.tsx +++ b/src/components/ProductTrainingContext/index.tsx @@ -153,6 +153,7 @@ function ProductTrainingContextProvider({children}: ChildrenProps) { tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP_MANAGER && tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_CONFIRMATION && tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_DRIVE_CONFIRMATION && + tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GPS_TOOLTIP && isModalVisible ) { return false; diff --git a/src/languages/de.ts b/src/languages/de.ts index c9531841315e..cee2f44b033b 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -7858,6 +7858,7 @@ Fordere Spesendetails wie Belege und Beschreibungen an, lege Limits und Standard }, outstandingFilter: 'Nach Ausgaben filtern,\ndie genehmigt werden müssen', scanTestDriveTooltip: 'Quittung senden, um\ndie Probefahrt abzuschließen!', + gpsTooltip: 'GPS-Verfolgung läuft! Wenn du fertig bist, stoppe die Verfolgung unten.', }, discardChangesConfirmation: { title: 'Änderungen verwerfen?', @@ -8036,7 +8037,6 @@ Hier ist ein *Testbeleg*, um dir zu zeigen, wie es funktioniert:`, domainAdmins: 'Domain-Admins', }, gps: { - tooltip: 'GPS-Verfolgung läuft! Wenn du fertig bist, stoppe die Verfolgung unten.', disclaimer: 'Benutze GPS, um eine Ausgabe von deiner Reise zu erstellen. Tippe unten auf „Start“, um mit der Aufzeichnung zu beginnen.', error: {failedToStart: 'Standortverfolgung konnte nicht gestartet werden.', failedToGetPermissions: 'Die erforderlichen Standortberechtigungen konnten nicht abgerufen werden.'}, trackingDistance: 'Strecke wird verfolgt...', diff --git a/src/languages/en.ts b/src/languages/en.ts index 4d0b71df0d2b..0d2345ec031d 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -7110,7 +7110,6 @@ const translations = { }, }, gps: { - tooltip: "GPS tracking in progress! When you're done, stop tracking below.", disclaimer: 'Use GPS to create an expense from your journey. Tap Start below to begin tracking.', error: { failedToStart: 'Failed to start location tracking.', @@ -7796,6 +7795,7 @@ const translations = { }, outstandingFilter: 'Filter for expenses\nthat need approval', scanTestDriveTooltip: 'Send this receipt to\ncomplete the test drive!', + gpsTooltip: "GPS tracking in progress! When you're done, stop tracking below.", }, discardChangesConfirmation: { title: 'Discard changes?', diff --git a/src/languages/es.ts b/src/languages/es.ts index 64bf4fb47ad2..ebb2ad89fd58 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -7954,6 +7954,7 @@ ${amount} para ${merchant} - ${date}`, }, outstandingFilter: 'Filtra los gastos\nque necesitan aprobación', scanTestDriveTooltip: '¡Envía este recibo para\ncompletar la prueba!', + gpsTooltip: '¡Seguimiento por GPS en curso! Cuando termines, detén el seguimiento a continuación.', }, discardChangesConfirmation: { title: '¿Descartar cambios?', @@ -8138,7 +8139,6 @@ ${amount} para ${merchant} - ${date}`, }, }, gps: { - tooltip: '¡Seguimiento por GPS en curso! Cuando termines, detén el seguimiento a continuación.', disclaimer: 'Utiliza el GPS para crear un gasto a partir de tu trayecto. Toca Iniciar a continuación para comenzar el seguimiento.', error: { failedToStart: 'No se pudo iniciar el seguimiento de la ubicación.', diff --git a/src/languages/fr.ts b/src/languages/fr.ts index 4915aea38b9d..a623ca6c91a5 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -7868,6 +7868,7 @@ Exigez des informations de dépense comme les reçus et les descriptions, défin }, outstandingFilter: 'Filtrer les dépenses\nqui doivent être approuvées', scanTestDriveTooltip: 'Envoyez ce reçu pour\nterminer l’essai !', + gpsTooltip: 'Suivi GPS en cours ! Quand vous avez terminé, arrêtez le suivi ci-dessous.', }, discardChangesConfirmation: { title: 'Annuler les modifications ?', @@ -8042,7 +8043,6 @@ Voici un *reçu test* pour vous montrer comment cela fonctionne :`, domainAdmins: 'Administrateurs de domaine', }, gps: { - tooltip: 'Suivi GPS en cours ! Quand vous avez terminé, arrêtez le suivi ci-dessous.', disclaimer: 'Utilisez le GPS pour créer une dépense à partir de votre trajet. Touchez Démarrer ci-dessous pour commencer le suivi.', error: {failedToStart: 'Impossible de démarrer le suivi de la localisation.', failedToGetPermissions: 'Échec de l’obtention des autorisations de localisation requises.'}, trackingDistance: 'Suivi de la distance...', diff --git a/src/languages/it.ts b/src/languages/it.ts index 0576e890726b..38e92be37e06 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -7848,6 +7848,7 @@ Richiedi dettagli di spesa come ricevute e descrizioni, imposta limiti e valori }, outstandingFilter: 'Filtra per le spese\nche necessitano di approvazione', scanTestDriveTooltip: 'Invia questa ricevuta per\ncompletare la prova!', + gpsTooltip: 'Monitoraggio GPS in corso! Quando hai finito, interrompi il monitoraggio qui sotto.', }, discardChangesConfirmation: { title: 'Scartare le modifiche?', @@ -8024,7 +8025,6 @@ Ecco una *ricevuta di prova* per mostrarti come funziona:`, domainAdmins: 'Amministratori di dominio', }, gps: { - tooltip: 'Monitoraggio GPS in corso! Quando hai finito, interrompi il monitoraggio qui sotto.', disclaimer: 'Usa il GPS per creare una spesa dal tuo viaggio. Tocca Avvia qui sotto per iniziare il tracciamento.', error: {failedToStart: 'Impossibile avviare il tracciamento della posizione.', failedToGetPermissions: 'Impossibile ottenere le autorizzazioni di localizzazione richieste.'}, trackingDistance: 'Tracciamento distanza...', diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 10ac8f278862..0ec563f215bc 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -7786,6 +7786,7 @@ ${reportName} }, outstandingFilter: '承認が必要な経費を絞り込む', scanTestDriveTooltip: 'このレシートを送信して\n試用を完了しましょう!', + gpsTooltip: 'GPS 追跡を進行中です!完了したら、下で追跡を停止してください。', }, discardChangesConfirmation: { title: '変更を破棄しますか?', @@ -7958,7 +7959,6 @@ Expensify の使い方をお見せするための*テストレシート*がこ domainAdmins: 'ドメイン管理者', }, gps: { - tooltip: 'GPS 追跡を進行中です!完了したら、下で追跡を停止してください。', disclaimer: '移動中の経路から、GPS を使って経費を作成しましょう。下の「開始」をタップして追跡を始めてください。', error: {failedToStart: '位置情報の追跡を開始できませんでした。', failedToGetPermissions: '必要な位置情報の権限を取得できませんでした。'}, trackingDistance: '距離を追跡中...', diff --git a/src/languages/nl.ts b/src/languages/nl.ts index 3d0bc2f48bf6..b74f938e5fd2 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -7828,6 +7828,7 @@ Vraag verplichte uitgavedetails zoals bonnetjes en beschrijvingen, stel limieten }, outstandingFilter: 'Filter voor uitgaven\ndie goedgekeurd moeten worden', scanTestDriveTooltip: 'Stuur dit bonnetje om\nde proefrit te voltooien!', + gpsTooltip: 'GPS-tracking bezig! Als je klaar bent, stop dan hieronder met tracken.', }, discardChangesConfirmation: { title: 'Wijzigingen negeren?', @@ -8005,7 +8006,6 @@ Hier is een *testbon* om je te laten zien hoe het werkt:`, domainAdmins: 'Domeinbeheerders', }, gps: { - tooltip: 'GPS-tracking bezig! Als je klaar bent, stop dan hieronder met tracken.', disclaimer: 'Gebruik GPS om een uitgave van je reis te maken. Tik hieronder op Start om het volgen te beginnen.', error: {failedToStart: 'Locatiebijhouding starten is mislukt.', failedToGetPermissions: 'Verkrijgen van vereiste locatierechten mislukt.'}, trackingDistance: 'Afstand bijhouden...', diff --git a/src/languages/pl.ts b/src/languages/pl.ts index 9265cf21a9c1..7a9aa50d6595 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -7816,6 +7816,7 @@ Wymagaj szczegółów wydatków, takich jak paragony i opisy, ustawiaj limity i }, outstandingFilter: 'Filtruj wydatki,\nktóre wymagają zatwierdzenia', scanTestDriveTooltip: 'Wyślij ten paragon, aby\nukończyć jazdę próbną!', + gpsTooltip: 'Śledzenie GPS w toku! Gdy skończysz, zatrzymaj śledzenie poniżej.', }, discardChangesConfirmation: { title: 'Odrzucić zmiany?', @@ -7990,7 +7991,6 @@ Oto *paragon testowy*, który pokazuje, jak to działa:`, domainAdmins: 'Administratorzy domeny', }, gps: { - tooltip: 'Śledzenie GPS w toku! Gdy skończysz, zatrzymaj śledzenie poniżej.', disclaimer: 'Użyj GPS, aby utworzyć wydatek z Twojej podróży. Stuknij „Start” poniżej, aby rozpocząć śledzenie.', error: {failedToStart: 'Nie udało się uruchomić śledzenia lokalizacji.', failedToGetPermissions: 'Nie udało się uzyskać wymaganych uprawnień do lokalizacji.'}, trackingDistance: 'Śledzenie dystansu…', diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index 0e7a3fa95b1d..fd49d82e4c97 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -7818,6 +7818,7 @@ Exija detalhes de despesas como recibos e descrições, defina limites e padrõe }, outstandingFilter: 'Filtrar despesas\nque precisam de aprovação', scanTestDriveTooltip: 'Envie este recibo para\nconcluir o test drive!', + gpsTooltip: 'Rastreamento por GPS em andamento! Quando terminar, pare o rastreamento abaixo.', }, discardChangesConfirmation: { title: 'Descartar alterações?', @@ -7995,7 +7996,6 @@ Aqui está um *recibo de teste* para mostrar como funciona:`, domainAdmins: 'Administradores de domínio', }, gps: { - tooltip: 'Rastreamento por GPS em andamento! Quando terminar, pare o rastreamento abaixo.', disclaimer: 'Use o GPS para criar uma despesa a partir da sua viagem. Toque em Iniciar abaixo para começar o rastreamento.', error: {failedToStart: 'Falha ao iniciar o rastreamento de localização.', failedToGetPermissions: 'Falha ao obter as permissões de localização necessárias.'}, trackingDistance: 'Acompanhando a distância...', diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index c4218ae09533..8831c9166d68 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -7642,6 +7642,7 @@ ${reportName} }, outstandingFilter: '筛选需要批准的报销', scanTestDriveTooltip: '发送此收据以\n完成试用体验!', + gpsTooltip: 'GPS 跟踪进行中!完成后,请在下方停止跟踪。', }, discardChangesConfirmation: { title: '放弃更改?', @@ -7800,7 +7801,6 @@ ${reportName} domainAdmins: '域管理员', }, gps: { - tooltip: 'GPS 跟踪进行中!完成后,请在下方停止跟踪。', disclaimer: '使用 GPS 根据您的行程创建报销。点击下方的“开始”以开始跟踪。', error: {failedToStart: '启动位置跟踪失败。', failedToGetPermissions: '获取必需的位置权限失败。'}, trackingDistance: '正在跟踪距离…', diff --git a/src/pages/iou/request/step/IOURequestStepDistanceGPS/Waypoints/index.tsx b/src/pages/iou/request/step/IOURequestStepDistanceGPS/Waypoints/index.tsx index 198e10d4dc2c..de7459a9f17c 100644 --- a/src/pages/iou/request/step/IOURequestStepDistanceGPS/Waypoints/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepDistanceGPS/Waypoints/index.tsx @@ -1,18 +1,17 @@ -import React, {useState} from 'react'; +import React from 'react'; import {View} from 'react-native'; -import Icon from '@components/Icon'; +import type {OnyxEntry} from 'react-native-onyx'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; -import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; -import Text from '@components/Text'; +import {useProductTrainingContext} from '@components/ProductTrainingContext'; import EducationalTooltip from '@components/Tooltip/EducationalTooltip'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {GpsDraftDetails} from '@src/types/onyx'; function Waypoints() { const styles = useThemeStyles(); @@ -64,50 +63,23 @@ export default Waypoints; const GPS_TOOLTIP_HORIZONTAL_PADDING = 40; -function GPSTooltip({children}: React.PropsWithChildren) { - const [hasUserClosedTooltip, setHasUserClosedTooltip] = useState(false); +const isTrackingSelector = (gpsDraftDetails: OnyxEntry) => gpsDraftDetails?.isTracking; - const [gpsDraftDetails] = useOnyx(ONYXKEYS.GPS_DRAFT_DETAILS, {canBeMissing: true}); - const [firstCreatedGPSExpenseDate] = useOnyx(ONYXKEYS.NVP_FIRST_CREATED_GPS_EXPENSE_DATE_NEW_DOT, {canBeMissing: true}); +function GPSTooltip({children}: React.PropsWithChildren) { + const [isTracking] = useOnyx(ONYXKEYS.GPS_DRAFT_DETAILS, {canBeMissing: true, selector: isTrackingSelector}); const styles = useThemeStyles(); const {windowWidth} = useWindowDimensions(); - const theme = useTheme(); - const {translate} = useLocalize(); - const icons = useMemoizedLazyExpensifyIcons(['Close', 'Lightbulb']); - - const showEducationalTooltip = !hasUserClosedTooltip && !firstCreatedGPSExpenseDate && gpsDraftDetails?.isTracking; - const renderTooltipContent = () => ( - - - {translate('gps.tooltip')} - - setHasUserClosedTooltip(true)} - role={CONST.ROLE.BUTTON} - accessibilityLabel={translate('common.close')} - > - - - - ); + const {renderProductTrainingTooltip, shouldShowProductTrainingTooltip} = useProductTrainingContext(CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GPS_TOOLTIP, !!isTracking); return ( {children} diff --git a/src/types/onyx/DismissedProductTraining.ts b/src/types/onyx/DismissedProductTraining.ts index 1478176edf12..041b5155861a 100644 --- a/src/types/onyx/DismissedProductTraining.ts +++ b/src/types/onyx/DismissedProductTraining.ts @@ -10,6 +10,7 @@ const { ACCOUNT_SWITCHER, SCAN_TEST_DRIVE_CONFIRMATION, MULTI_SCAN_EDUCATIONAL_MODAL, + GPS_TOOLTIP, } = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES; /** @@ -82,6 +83,11 @@ type DismissedProductTraining = { * When user dismisses the ChangeReportPolicy feature training modal, we store the timestamp here. */ [CONST.CHANGE_POLICY_TRAINING_MODAL]: DismissedProductTrainingElement; + + /** + * When user dismisses the GPS tooltip, we store the timestamp here. + */ + [GPS_TOOLTIP]: DismissedProductTrainingElement; }; export default DismissedProductTraining; diff --git a/tests/utils/TestHelper.ts b/tests/utils/TestHelper.ts index a7eac85292f6..09515f43e709 100644 --- a/tests/utils/TestHelper.ts +++ b/tests/utils/TestHelper.ts @@ -115,6 +115,10 @@ function getNvpDismissedProductTraining(): OnyxEntry { timestamp: '', dismissedMethod: 'click', }, + [CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GPS_TOOLTIP]: { + timestamp: '', + dismissedMethod: 'click', + }, }; }