From 07e6c61610d47328b0209f9dd4136c56528b0d8f Mon Sep 17 00:00:00 2001 From: I Nyoman Jyotisa Date: Wed, 17 Jul 2024 20:43:26 +0800 Subject: [PATCH 1/3] track-expense and submit-expense deep links --- .well-known/apple-app-site-association | 8 +++ android/app/src/main/AndroidManifest.xml | 4 ++ src/ROUTES.ts | 2 + src/SCREENS.ts | 2 + .../Navigation/AppNavigator/AuthScreens.tsx | 12 ++++ src/libs/Navigation/linkingConfig/config.ts | 2 + src/libs/Navigation/types.ts | 2 + src/pages/SubmitExpensePage.tsx | 56 +++++++++++++++ src/pages/TrackExpensePage.tsx | 71 +++++++++++++++++++ 9 files changed, 159 insertions(+) create mode 100644 src/pages/SubmitExpensePage.tsx create mode 100644 src/pages/TrackExpensePage.tsx diff --git a/.well-known/apple-app-site-association b/.well-known/apple-app-site-association index 394e45f8d9ae..dce724440adf 100644 --- a/.well-known/apple-app-site-association +++ b/.well-known/apple-app-site-association @@ -91,6 +91,14 @@ { "/": "/money2020/*", "comment": "Money 2020" + }, + { + "/": "/track-expense/*", + "comment": "Track Expense" + }, + { + "/": "/submit-expense/*", + "comment": "Submit Expense" } ] } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 520602a28a02..142d919a7a18 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -73,6 +73,8 @@ + + @@ -94,6 +96,8 @@ + + diff --git a/src/ROUTES.ts b/src/ROUTES.ts index f13724bf4322..b29e4d27dcb3 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -61,6 +61,8 @@ const ROUTES = { // This is a utility route used to go to the user's concierge chat, or the sign-in page if the user's not authenticated CONCIERGE: 'concierge', + TRACK_EXPENSE: 'track-expense', + SUBMIT_EXPENSE: 'submit-expense', FLAG_COMMENT: { route: 'flag/:reportID/:reportActionID', getRoute: (reportID: string, reportActionID: string) => `flag/${reportID}/${reportActionID}` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 3a0bb2248303..0b6e3e4c9c4f 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -8,6 +8,8 @@ const PROTECTED_SCREENS = { HOME: 'Home', CONCIERGE: 'Concierge', ATTACHMENTS: 'Attachments', + TRACK_EXPENSE: 'TrackExpense', + SUBMIT_EXPENSE: 'SubmitExpense', } as const; const SCREENS = { diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 0e40fa4d4037..dfc47d9bb342 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -71,6 +71,8 @@ const loadReportAttachments = () => require('../../../page const loadValidateLoginPage = () => require('../../../pages/ValidateLoginPage').default; const loadLogOutPreviousUserPage = () => require('../../../pages/LogOutPreviousUserPage').default; const loadConciergePage = () => require('../../../pages/ConciergePage').default; +const loadTrackExpensePage = () => require('../../../pages/TrackExpensePage').default; +const loadSubmitExpensePage = () => require('../../../pages/SubmitExpensePage').default; const loadProfileAvatar = () => require('../../../pages/settings/Profile/ProfileAvatar').default; const loadWorkspaceAvatar = () => require('../../../pages/workspace/WorkspaceAvatar').default; const loadReportAvatar = () => require('../../../pages/ReportAvatar').default; @@ -358,6 +360,16 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie options={defaultScreenOptions} getComponent={loadConciergePage} /> + + ['config'] = { [SCREENS.TRANSITION_BETWEEN_APPS]: ROUTES.TRANSITION_BETWEEN_APPS, [SCREENS.CONNECTION_COMPLETE]: ROUTES.CONNECTION_COMPLETE, [SCREENS.CONCIERGE]: ROUTES.CONCIERGE, + [SCREENS.TRACK_EXPENSE]: ROUTES.TRACK_EXPENSE, + [SCREENS.SUBMIT_EXPENSE]: ROUTES.SUBMIT_EXPENSE, [SCREENS.SIGN_IN_WITH_APPLE_DESKTOP]: ROUTES.APPLE_SIGN_IN, [SCREENS.SIGN_IN_WITH_GOOGLE_DESKTOP]: ROUTES.GOOGLE_SIGN_IN, [SCREENS.SAML_SIGN_IN]: ROUTES.SAML_SIGN_IN, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index c273b2db6a10..a628e4a4d1bf 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1208,6 +1208,8 @@ type PublicScreensParamList = SharedScreensParamList & { type AuthScreensParamList = CentralPaneScreensParamList & SharedScreensParamList & { [SCREENS.CONCIERGE]: undefined; + [SCREENS.TRACK_EXPENSE]: undefined; + [SCREENS.SUBMIT_EXPENSE]: undefined; [SCREENS.ATTACHMENTS]: { reportID: string; source: string; diff --git a/src/pages/SubmitExpensePage.tsx b/src/pages/SubmitExpensePage.tsx new file mode 100644 index 000000000000..7eb1fda045ad --- /dev/null +++ b/src/pages/SubmitExpensePage.tsx @@ -0,0 +1,56 @@ +import {useFocusEffect} from '@react-navigation/native'; +import React, {useEffect, useRef} from 'react'; +import {View} from 'react-native'; +import ReportActionsSkeletonView from '@components/ReportActionsSkeletonView'; +import ReportHeaderSkeletonView from '@components/ReportHeaderSkeletonView'; +import ScreenWrapper from '@components/ScreenWrapper'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import * as App from '@userActions/App'; +import * as IOU from '@userActions/IOU'; +import CONST from '@src/CONST'; +import * as ReportUtils from '@libs/ReportUtils'; +import interceptAnonymousUser from '@libs/interceptAnonymousUser'; + +/* + * This is a "utility page", that does this: + * - If the user is authenticated, start Submit Expense + * - Else re-route to the login page + */ +function SubmitExpensePage() { + const styles = useThemeStyles(); + const isUnmounted = useRef(false); + + useFocusEffect(() => { + interceptAnonymousUser(() => { + App.confirmReadyToOpenApp(); + Navigation.isNavigationReady().then(() => { + if (isUnmounted.current) { + return; + } + Navigation.goBack(); + IOU.startMoneyRequest(CONST.IOU.TYPE.SUBMIT, ReportUtils.generateReportID(),); + }); + }); + }); + + useEffect( + () => () => { + isUnmounted.current = true; + }, + [], + ); + + return ( + + + + + + + ); +} + +SubmitExpensePage.displayName = 'SubmitExpensePage'; + +export default SubmitExpensePage; \ No newline at end of file diff --git a/src/pages/TrackExpensePage.tsx b/src/pages/TrackExpensePage.tsx new file mode 100644 index 000000000000..854444de275c --- /dev/null +++ b/src/pages/TrackExpensePage.tsx @@ -0,0 +1,71 @@ +import {useFocusEffect} from '@react-navigation/native'; +import React, {useEffect, useRef} from 'react'; +import {View} from 'react-native'; +import ReportActionsSkeletonView from '@components/ReportActionsSkeletonView'; +import ReportHeaderSkeletonView from '@components/ReportHeaderSkeletonView'; +import ScreenWrapper from '@components/ScreenWrapper'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import * as App from '@userActions/App'; +import ONYXKEYS from '@src/ONYXKEYS'; +import * as IOU from '@userActions/IOU'; +import CONST from '@src/CONST'; +import * as ReportUtils from '@libs/ReportUtils'; +import interceptAnonymousUser from '@libs/interceptAnonymousUser'; +import ROUTES from '@src/ROUTES'; +import useNetwork from '@hooks/useNetwork'; +import { useOnyx } from "react-native-onyx"; + +/* + * This is a "utility page", that does this: + * - If the user is authenticated, find their self DM and and start a Track Expense + * - Else re-route to the login page + */ +function TrackExpensePage() { + const styles = useThemeStyles(); + const isUnmounted = useRef(false); + const {isOffline} = useNetwork(); + const [hasSeenTrackTraining] = useOnyx(ONYXKEYS.NVP_HAS_SEEN_TRACK_TRAINING); + + useFocusEffect(() => { + interceptAnonymousUser(() => { + App.confirmReadyToOpenApp(); + Navigation.isNavigationReady().then(() => { + if (isUnmounted.current) { + return; + } + Navigation.goBack(); + IOU.startMoneyRequest( + CONST.IOU.TYPE.TRACK, + ReportUtils.findSelfDMReportID() || ReportUtils.generateReportID(), + ) + + if (!hasSeenTrackTraining && !isOffline) { + setTimeout(() => { + Navigation.navigate(ROUTES.TRACK_TRAINING_MODAL); + }, CONST.ANIMATED_TRANSITION); + } + }); + }); + }); + + useEffect( + () => () => { + isUnmounted.current = true; + }, + [], + ); + + return ( + + + + + + + ); +} + +TrackExpensePage.displayName = 'TrackExpensePage'; + +export default TrackExpensePage; \ No newline at end of file From 2b8d4ba0000c62ca21661d8fcf67c63373c523f3 Mon Sep 17 00:00:00 2001 From: I Nyoman Jyotisa Date: Thu, 18 Jul 2024 19:54:54 +0800 Subject: [PATCH 2/3] lint --- src/pages/SubmitExpensePage.tsx | 8 ++++---- src/pages/TrackExpensePage.tsx | 15 ++++++++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/pages/SubmitExpensePage.tsx b/src/pages/SubmitExpensePage.tsx index 7eb1fda045ad..f4f6ea623c34 100644 --- a/src/pages/SubmitExpensePage.tsx +++ b/src/pages/SubmitExpensePage.tsx @@ -5,12 +5,12 @@ import ReportActionsSkeletonView from '@components/ReportActionsSkeletonView'; import ReportHeaderSkeletonView from '@components/ReportHeaderSkeletonView'; import ScreenWrapper from '@components/ScreenWrapper'; import useThemeStyles from '@hooks/useThemeStyles'; +import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import Navigation from '@libs/Navigation/Navigation'; +import * as ReportUtils from '@libs/ReportUtils'; import * as App from '@userActions/App'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; -import * as ReportUtils from '@libs/ReportUtils'; -import interceptAnonymousUser from '@libs/interceptAnonymousUser'; /* * This is a "utility page", that does this: @@ -29,7 +29,7 @@ function SubmitExpensePage() { return; } Navigation.goBack(); - IOU.startMoneyRequest(CONST.IOU.TYPE.SUBMIT, ReportUtils.generateReportID(),); + IOU.startMoneyRequest(CONST.IOU.TYPE.SUBMIT, ReportUtils.generateReportID()); }); }); }); @@ -53,4 +53,4 @@ function SubmitExpensePage() { SubmitExpensePage.displayName = 'SubmitExpensePage'; -export default SubmitExpensePage; \ No newline at end of file +export default SubmitExpensePage; diff --git a/src/pages/TrackExpensePage.tsx b/src/pages/TrackExpensePage.tsx index 854444de275c..71f2bf6c5d77 100644 --- a/src/pages/TrackExpensePage.tsx +++ b/src/pages/TrackExpensePage.tsx @@ -1,20 +1,20 @@ import {useFocusEffect} from '@react-navigation/native'; import React, {useEffect, useRef} from 'react'; import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; import ReportActionsSkeletonView from '@components/ReportActionsSkeletonView'; import ReportHeaderSkeletonView from '@components/ReportHeaderSkeletonView'; import ScreenWrapper from '@components/ScreenWrapper'; +import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; +import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import Navigation from '@libs/Navigation/Navigation'; +import * as ReportUtils from '@libs/ReportUtils'; import * as App from '@userActions/App'; -import ONYXKEYS from '@src/ONYXKEYS'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; -import * as ReportUtils from '@libs/ReportUtils'; -import interceptAnonymousUser from '@libs/interceptAnonymousUser'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import useNetwork from '@hooks/useNetwork'; -import { useOnyx } from "react-native-onyx"; /* * This is a "utility page", that does this: @@ -37,8 +37,9 @@ function TrackExpensePage() { Navigation.goBack(); IOU.startMoneyRequest( CONST.IOU.TYPE.TRACK, + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing ReportUtils.findSelfDMReportID() || ReportUtils.generateReportID(), - ) + ); if (!hasSeenTrackTraining && !isOffline) { setTimeout(() => { @@ -68,4 +69,4 @@ function TrackExpensePage() { TrackExpensePage.displayName = 'TrackExpensePage'; -export default TrackExpensePage; \ No newline at end of file +export default TrackExpensePage; From 40653d4b8b76de4f4c92647499484c963cb11a55 Mon Sep 17 00:00:00 2001 From: I Nyoman Jyotisa Date: Fri, 26 Jul 2024 23:28:22 +0800 Subject: [PATCH 3/3] fix track training always displayed --- src/pages/TrackExpensePage.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/TrackExpensePage.tsx b/src/pages/TrackExpensePage.tsx index 71f2bf6c5d77..2e08c49721be 100644 --- a/src/pages/TrackExpensePage.tsx +++ b/src/pages/TrackExpensePage.tsx @@ -15,6 +15,7 @@ import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; /* * This is a "utility page", that does this: @@ -25,13 +26,14 @@ function TrackExpensePage() { const styles = useThemeStyles(); const isUnmounted = useRef(false); const {isOffline} = useNetwork(); - const [hasSeenTrackTraining] = useOnyx(ONYXKEYS.NVP_HAS_SEEN_TRACK_TRAINING); + const [hasSeenTrackTraining, hasSeenTrackTrainingResult] = useOnyx(ONYXKEYS.NVP_HAS_SEEN_TRACK_TRAINING); + const isLoadingHasSeenTrackTraining = isLoadingOnyxValue(hasSeenTrackTrainingResult); useFocusEffect(() => { interceptAnonymousUser(() => { App.confirmReadyToOpenApp(); Navigation.isNavigationReady().then(() => { - if (isUnmounted.current) { + if (isUnmounted.current || isLoadingHasSeenTrackTraining) { return; } Navigation.goBack();