From 9d1ce9f5c78aacb9ce9901cdf3f1dc3c8b1f8158 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 19 Aug 2024 21:37:14 -0700 Subject: [PATCH 01/60] Pass scope param to login page --- .../gov/va/mobileapp/native_modules/CustomTabsIntentModule.kt | 1 + VAMobile/ios/RNAuthSession.swift | 1 + 2 files changed, 2 insertions(+) diff --git a/VAMobile/android/app/src/main/java/gov/va/mobileapp/native_modules/CustomTabsIntentModule.kt b/VAMobile/android/app/src/main/java/gov/va/mobileapp/native_modules/CustomTabsIntentModule.kt index 4f9827e73b9..a61312e8a4b 100644 --- a/VAMobile/android/app/src/main/java/gov/va/mobileapp/native_modules/CustomTabsIntentModule.kt +++ b/VAMobile/android/app/src/main/java/gov/va/mobileapp/native_modules/CustomTabsIntentModule.kt @@ -47,6 +47,7 @@ class CustomTabsIntentModule(private val context: ReactApplicationContext) : appendQueryParameter("code_challenge", codeChallenge) appendQueryParameter("application", "vamobile") appendQueryParameter("oauth", "true") + appendQueryParameter("scope", "device_sso") } } .build() diff --git a/VAMobile/ios/RNAuthSession.swift b/VAMobile/ios/RNAuthSession.swift index efc30a76718..9c38c303c45 100644 --- a/VAMobile/ios/RNAuthSession.swift +++ b/VAMobile/ios/RNAuthSession.swift @@ -36,6 +36,7 @@ class RNAuthSession: NSObject, RCTBridgeModule, ASWebAuthenticationPresentationC URLQueryItem(name: "code_challenge", value: codeChallenge), URLQueryItem(name: "application", value: "vamobile"), URLQueryItem(name: "oauth", value: "true"), + URLQueryItem(name: "scope", value: "device_sso"), ] guard var comps = URLComponents(string: authUrl) else { From 53f6add425add1d347e1a4f071a6892ec929b6a6 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 19 Aug 2024 21:38:01 -0700 Subject: [PATCH 02/60] Add storage for device secret --- VAMobile/src/store/api/api.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/VAMobile/src/store/api/api.ts b/VAMobile/src/store/api/api.ts index 79b932d7235..b107b3b66ea 100644 --- a/VAMobile/src/store/api/api.ts +++ b/VAMobile/src/store/api/api.ts @@ -12,6 +12,7 @@ const { API_ROOT } = getEnv() let _token: string | undefined let _refresh_token: string | undefined +let _device_secret: string | undefined let refreshPromise: Promise | undefined let _demoMode = false let _store: ReduxToolkitStore | undefined @@ -35,6 +36,14 @@ export const getRefreshToken = (): string | undefined => { return _refresh_token } +export const setDeviceSecret = (secret?: string): void => { + _device_secret = secret +} + +export const getDeviceSecret = (): string | undefined => { + return _device_secret +} + export const setDemoMode = (demoMode: boolean): void => { _demoMode = demoMode } From b727be8e4d3d266b8410af5e91cc22f1e416b256 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 19 Aug 2024 21:38:25 -0700 Subject: [PATCH 03/60] Add device_secret type --- VAMobile/src/store/api/types/auth.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/VAMobile/src/store/api/types/auth.ts b/VAMobile/src/store/api/types/auth.ts index d68f7a55aa9..1da969d49b4 100644 --- a/VAMobile/src/store/api/types/auth.ts +++ b/VAMobile/src/store/api/types/auth.ts @@ -34,6 +34,7 @@ export const AuthParamsLoadingStateTypeConstants: { export type AuthCredentialData = { access_token?: string refresh_token?: string + device_secret?: string accessTokenExpirationDate?: string token_type?: string id_token?: string From 856bd5d0ff51127217ff87cf80daaa9b618026ec Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 19 Aug 2024 21:38:59 -0700 Subject: [PATCH 04/60] Store device secret --- VAMobile/src/store/slices/authSlice.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/VAMobile/src/store/slices/authSlice.ts b/VAMobile/src/store/slices/authSlice.ts index c3f83f2fae3..936da9e8036 100644 --- a/VAMobile/src/store/slices/authSlice.ts +++ b/VAMobile/src/store/slices/authSlice.ts @@ -389,6 +389,7 @@ const processAuthResponse = async (response: Response): Promise Date: Mon, 19 Aug 2024 21:39:38 -0700 Subject: [PATCH 05/60] Add feature toggle for sso --- VAMobile/src/utils/remoteConfig.test.ts | 1 + VAMobile/src/utils/remoteConfig.ts | 3 +++ 2 files changed, 4 insertions(+) diff --git a/VAMobile/src/utils/remoteConfig.test.ts b/VAMobile/src/utils/remoteConfig.test.ts index 18dbea85793..91dbae8fa39 100644 --- a/VAMobile/src/utils/remoteConfig.test.ts +++ b/VAMobile/src/utils/remoteConfig.test.ts @@ -31,6 +31,7 @@ const mockOverrides = { patientCheckInWaygate: true, preferredNameGenderWaygate: false, prescriptions: true, + sso: false, testFeature: false, whatsNewUI: false, } diff --git a/VAMobile/src/utils/remoteConfig.ts b/VAMobile/src/utils/remoteConfig.ts index f668624e9bd..a146c8529bd 100644 --- a/VAMobile/src/utils/remoteConfig.ts +++ b/VAMobile/src/utils/remoteConfig.ts @@ -29,6 +29,7 @@ export type FeatureToggleType = | 'patientCheckInWaygate' | 'preferredNameGenderWaygate' | 'prescriptions' + | 'sso' | 'testFeature' | 'whatsNewUI' @@ -46,6 +47,7 @@ type FeatureToggleValues = { patientCheckInWaygate: boolean preferredNameGenderWaygate: boolean prescriptions: boolean + sso: boolean testFeature: boolean whatsNewUI: boolean } @@ -64,6 +66,7 @@ export const defaults: FeatureToggleValues = { patientCheckInWaygate: true, preferredNameGenderWaygate: true, prescriptions: true, + sso: true, testFeature: false, whatsNewUI: true, } From ee9aeeb5748590fb533bd66f5751802ba0625ded Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 19 Aug 2024 21:42:04 -0700 Subject: [PATCH 06/60] Add logic to WebViewScreen for SSO authentication --- .../screens/WebviewScreen/WebviewScreen.tsx | 57 ++++++++++++++++++- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx index bb1037b39bc..000a4af8464 100644 --- a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx +++ b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx @@ -9,8 +9,11 @@ import { Box, BoxProps, LoadingComponent } from 'components' import { BackButton } from 'components/BackButton' import { BackButtonLabelConstants } from 'constants/backButtonLabels' import { NAMESPACE } from 'constants/namespaces' +import * as api from 'store/api' import { a11yLabelVA } from 'utils/a11yLabel' import { testIdProps } from 'utils/accessibility' +import { logNonFatalErrorToFirebase } from 'utils/analytics' +import getEnv from 'utils/env' import { useTheme } from 'utils/hooks' import { isIOS } from 'utils/platform' @@ -18,6 +21,8 @@ import WebviewControlButton from './WebviewControlButton' import WebviewControls, { WebviewControlsProps } from './WebviewControls' import WebviewTitle from './WebviewTitle' +const { AUTH_SIS_TOKEN_EXCHANGE_URL } = getEnv() + type ReloadButtonProps = { reloadPressed: () => void } @@ -78,11 +83,17 @@ export type WebviewStackParams = { displayTitle: string /** Text to appear with a lock icon in the header */ loadingMessage?: string + /** Use SSO to authenticate webview */ + useSSO?: boolean } } type WebviewScreenProps = StackScreenProps +type Cookies = { + [key: string]: string +} + /** * Screen for displaying web content within the app. Provides basic navigation and controls */ @@ -93,8 +104,10 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { const [canGoBack, setCanGoBack] = useState(false) const [canGoForward, setCanGoForward] = useState(false) const [currentUrl, setCurrentUrl] = useState('') + const [loading, setLoading] = useState(true) + const [headers, setHeaders] = useState() - const { url, displayTitle, loadingMessage } = route.params + const { url, displayTitle, loadingMessage, useSSO } = route.params const onReloadPressed = (): void => { webviewRef?.current.reload() @@ -116,6 +129,42 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { }) }) + useEffect(() => { + const fetchSSOCookies = async () => { + try { + const response = await fetch(AUTH_SIS_TOKEN_EXCHANGE_URL, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ + grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange', + subject_token: api.getAccessToken() || '', + subject_token_type: 'urn:ietf:params:oauth:token-type:access_token', + actor_token: api.getDeviceSecret() || '', + actor_token_type: 'urn:x-oath:params:oauth:token-type:device-secret', + client_id: 'vaweb', + }).toString(), + }) + + const cookieHeaders = response.headers.get('Set-Cookie') + const cookiesObj = cookieHeaders?.split(';').reduce((cookies: Cookies, cookie) => { + const [key, value] = cookie.split('=') + cookies[key.trim()] = value ? value.trim() : '' + return cookies + }, {}) + + setHeaders(cookiesObj) + } catch (error) { + logNonFatalErrorToFirebase(error, `Error fetching SSO cookies: ${error}`) + } finally { + setLoading(false) + } + } + + useSSO && fetchSSOCookies() + }, []) + const backPressed = (): void => { webviewRef?.current.goBack() } @@ -156,7 +205,9 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { bottom: 0, } - return ( + return useSSO && loading ? ( + + ) : ( } - source={{ uri: url }} + source={{ uri: url, headers }} injectedJavaScript={INJECTED_JAVASCRIPT} ref={webviewRef} // onMessage is required to be present for injected javascript to work on iOS From 67ae19e4a76c4a73a201180aaaccbdfcc775f237 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 19 Aug 2024 21:42:45 -0700 Subject: [PATCH 07/60] Always return NoAppointments component for testing --- .../Appointments/UpcomingAppointments/UpcomingAppointments.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VAMobile/src/screens/HealthScreen/Appointments/UpcomingAppointments/UpcomingAppointments.tsx b/VAMobile/src/screens/HealthScreen/Appointments/UpcomingAppointments/UpcomingAppointments.tsx index f2ab11fddd6..3b7b397dd1d 100644 --- a/VAMobile/src/screens/HealthScreen/Appointments/UpcomingAppointments/UpcomingAppointments.tsx +++ b/VAMobile/src/screens/HealthScreen/Appointments/UpcomingAppointments/UpcomingAppointments.tsx @@ -45,7 +45,7 @@ function UpcomingAppointments({ appointmentsData, loading, page, setPage, scroll return } - if (!appointmentsData || appointmentsData.data.length < 1) { + if (true) { return ( Date: Mon, 19 Aug 2024 21:44:01 -0700 Subject: [PATCH 08/60] Add feature flagged WebView --- VAMobile/env/constant.env | 1 - VAMobile/env/env.sh | 8 +++- .../NoAppointments/NoAppointments.tsx | 38 ++++++++++++++----- VAMobile/src/translations/en/common.json | 1 + 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/VAMobile/env/constant.env b/VAMobile/env/constant.env index 77d1e60e503..89dc941e463 100644 --- a/VAMobile/env/constant.env +++ b/VAMobile/env/constant.env @@ -6,7 +6,6 @@ LINK_URL_IN_APP_RECRUITMENT=https://docs.google.com/forms/d/e/1FAIpQLSfRb0OtW34q LINK_URL_VETERAN_USABILITY_PROJECT=https://veteranusability.us/ LINK_URL_VETERANS_CRISIS_LINE=https://www.veteranscrisisline.net/ LINK_URL_VETERANS_CRISIS_LINE_GET_HELP=https://www.veteranscrisisline.net/get-help/chat -LINK_URL_SCHEDULE_APPOINTMENTS=https://www.va.gov/health-care/schedule-view-va-appointments/ LINK_URL_PRIVACY_POLICY=https://www.va.gov/privacy-policy/ LINK_URL_DECISION_REVIEWS=https://www.va.gov/decision-reviews/ LINK_URL_ABOUT_DISABILITY_RATINGS=https://www.va.gov/disability/about-disability-ratings/ diff --git a/VAMobile/env/env.sh b/VAMobile/env/env.sh index a535026880f..53878600a7e 100755 --- a/VAMobile/env/env.sh +++ b/VAMobile/env/env.sh @@ -15,7 +15,7 @@ echo "" > .env if [[ $environment == 'staging' ]] then echo "Setting up Staging environment" - AUTH_SIS_PREFIX="staging." + WEBSITE_PREFIX="staging." API_PREFIX="staging-api." else echo "Setting up Production environment" @@ -27,7 +27,7 @@ echo "ENVIRONMENT=$environment" >> .env echo "API_ROOT=https://${API_PREFIX}va.gov/mobile" >> .env # set SIS vars -AUTH_SIS_ROOT="https://${AUTH_SIS_PREFIX}va.gov" +AUTH_SIS_ROOT="https://${WEBSITE_PREFIX}va.gov" echo "AUTH_SIS_ENDPOINT=${AUTH_SIS_ROOT}/sign-in" >> .env echo "AUTH_SIS_TOKEN_EXCHANGE_URL=https://${API_PREFIX}va.gov/v0/sign_in/token" >> .env echo "AUTH_SIS_TOKEN_REFRESH_URL=https://${API_PREFIX}va.gov/v0/sign_in/refresh" >> .env @@ -50,6 +50,10 @@ else fi # set demo mode password echo "DEMO_PASSWORD=${DEMO_PASSWORD}" >> .env + +# set website URLs +echo "LINK_URL_SCHEDULE_APPOINTMENTS=https://${WEBSITE_PREFIX}va.gov/health-care/schedule-view-va-appointments" >> .env + # Get all vars that are the same across environments while read p; do echo "$p" >> .env diff --git a/VAMobile/src/screens/HealthScreen/Appointments/NoAppointments/NoAppointments.tsx b/VAMobile/src/screens/HealthScreen/Appointments/NoAppointments/NoAppointments.tsx index 1734d20f2c8..80c689443bb 100644 --- a/VAMobile/src/screens/HealthScreen/Appointments/NoAppointments/NoAppointments.tsx +++ b/VAMobile/src/screens/HealthScreen/Appointments/NoAppointments/NoAppointments.tsx @@ -6,7 +6,8 @@ import { NAMESPACE } from 'constants/namespaces' import { a11yLabelVA } from 'utils/a11yLabel' import { testIdProps } from 'utils/accessibility' import getEnv from 'utils/env' -import { useTheme } from 'utils/hooks' +import { useRouteNavigation, useTheme } from 'utils/hooks' +import { featureEnabled } from 'utils/remoteConfig' const { LINK_URL_SCHEDULE_APPOINTMENTS } = getEnv() @@ -19,6 +20,7 @@ type NoAppointmentsProps = { export function NoAppointments({ subText, subTextA11yLabel, showVAGovLink = true }: NoAppointmentsProps) { const { t } = useTranslation(NAMESPACE.COMMON) const theme = useTheme() + const navigateTo = useRouteNavigation() return ( - {showVAGovLink && ( - - )} + {showVAGovLink && + (featureEnabled('sso') ? ( + + navigateTo('Webview', { + url: LINK_URL_SCHEDULE_APPOINTMENTS, + displayTitle: t('webview.vagov'), + loadingMessage: t('webview.appointments.loading'), + useSSO: true, + }) + } + text={t('noAppointments.visitVA')} + a11yLabel={a11yLabelVA(t('noAppointments.visitVA'))} + a11yHint={t('mobileBodyLink.a11yHint')} + /> + ) : ( + + ))} ) } diff --git a/VAMobile/src/translations/en/common.json b/VAMobile/src/translations/en/common.json index c8025b2fd63..340523ca915 100644 --- a/VAMobile/src/translations/en/common.json +++ b/VAMobile/src/translations/en/common.json @@ -1515,6 +1515,7 @@ "viewMoreDetails": "Review more details", "waygateEditScreen.title": "Waygate Edit Screen", "waygateManagement.title": "Waygate Management", + "webview.appointments.loading": "Loading appointments page...", "webview.changeLegalName.loading": "Loading how to change your legal name...", "webview.vagov": "va.gov", "webview.valocation.loading": "Loading VA location finder...", From cdc035672716afff2ec21ffbf8998905ab0fada1 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 19 Aug 2024 22:03:55 -0700 Subject: [PATCH 09/60] Update dependency array --- VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx index 000a4af8464..b03999d08ea 100644 --- a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx +++ b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx @@ -163,7 +163,7 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { } useSSO && fetchSSOCookies() - }, []) + }, [useSSO]) const backPressed = (): void => { webviewRef?.current.goBack() From 3b5545eece6f4546c2a552aea7fe297e14ab8282 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 9 Sep 2024 10:58:32 -0700 Subject: [PATCH 10/60] Add react-natie-cookies package --- VAMobile/ios/Podfile.lock | 20 +++++++++++++------- VAMobile/package.json | 3 ++- VAMobile/yarn.lock | 38 ++++++++++---------------------------- 3 files changed, 25 insertions(+), 36 deletions(-) diff --git a/VAMobile/ios/Podfile.lock b/VAMobile/ios/Podfile.lock index 4ed8052270c..dd16e33a2fe 100644 --- a/VAMobile/ios/Podfile.lock +++ b/VAMobile/ios/Podfile.lock @@ -1044,6 +1044,8 @@ PODS: - React-debug - react-native-blob-util (0.19.9): - React-Core + - react-native-cookies (6.2.1): + - React-Core - react-native-document-picker (8.2.2): - React-Core - react-native-image-picker (7.1.1): @@ -1052,7 +1054,7 @@ PODS: - React-Core - react-native-notifications (5.1.0): - React-Core - - react-native-safe-area-context (4.10.4): + - react-native-safe-area-context (4.10.8): - React-Core - react-native-webview (13.10.4): - glog @@ -1265,7 +1267,7 @@ PODS: - glog - RCT-Folly (= 2022.05.16.00) - React-Core - - RNKeychain (8.1.2): + - RNKeychain (8.2.0): - React-Core - RNLocalize (3.1.0): - React-Core @@ -1276,7 +1278,7 @@ PODS: - RCT-Folly (= 2022.05.16.00) - React-Core - React-RCTImage - - RNSVG (14.1.0): + - RNSVG (14.2.0): - React-Core - SDWebImage/Core (5.19.1) - SDWebImageWebPCoder (0.14.5): @@ -1325,6 +1327,7 @@ DEPENDENCIES: - React-logger (from `../node_modules/react-native/ReactCommon/logger`) - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`) - react-native-blob-util (from `../node_modules/react-native-blob-util`) + - "react-native-cookies (from `../node_modules/@react-native-cookies/cookies`)" - react-native-document-picker (from `../node_modules/react-native-document-picker`) - react-native-image-picker (from `../node_modules/react-native-image-picker`) - react-native-notifications (from `../node_modules/react-native-notifications`) @@ -1458,6 +1461,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon" react-native-blob-util: :path: "../node_modules/react-native-blob-util" + react-native-cookies: + :path: "../node_modules/@react-native-cookies/cookies" react-native-document-picker: :path: "../node_modules/react-native-document-picker" react-native-image-picker: @@ -1597,10 +1602,11 @@ SPEC CHECKSUMS: React-logger: 60afd40b183e8e6642bfd0108f1a1ad360cc665e React-Mapbuffer: 672a9342eb75a4d0663306e94d4dfc88aee73b93 react-native-blob-util: 18b510205c080a453574a7d2344d64673d0ad9af + react-native-cookies: f54fcded06bb0cda05c11d86788020b43528a26c react-native-document-picker: cd4d6b36a5207ad7a9e599ebb9eb0c2e84fa0b87 react-native-image-picker: b3ba58c691bc503b33480cef8ab987f78e310c15 react-native-notifications: 4601a5a8db4ced6ae7cfc43b44d35fe437ac50c4 - react-native-safe-area-context: 399a5859f6acbdf67f671c69b53113f535f3b5b0 + react-native-safe-area-context: b7daa1a8df36095a032dff095a1ea8963cb48371 react-native-webview: dbc8171113daa2abb2499da5f327a8d0cdfcd61c React-nativeconfig: 2e44d0d2dd222b12a5183f4bcaa4a91881497acb React-NativeModulesApple: 8aa032fe6c92c1a3c63e4809d42816284a56a9b0 @@ -1633,15 +1639,15 @@ SPEC CHECKSUMS: RNFBRemoteConfig: bfb9f6a04a0269038a352d8386e5c77f4ff98125 RNFileViewer: ce7ca3ac370e18554d35d6355cffd7c30437c592 RNGestureHandler: 67d3f1f69d4d0c98d6e83f4229e3bbf997d1dc72 - RNKeychain: a65256b6ca6ba6976132cc4124b238a5b13b3d9c + RNKeychain: bfe3d12bf4620fe488771c414530bf16e88f3678 RNLocalize: e8694475db034bf601e17bd3dfa8986565e769eb RNReactNativeHapticFeedback: ec56a5f81c3941206fd85625fa669ffc7b4545f9 RNScreens: e842cdccb23c0a084bd6307f6fa83fd1c1738029 - RNSVG: ba3e7232f45e34b7b47e74472386cf4e1a676d0a + RNSVG: 963a95f1f5d512a13d11ffd50d351c87fb5c6890 SDWebImage: 40b0b4053e36c660a764958bff99eed16610acbb SDWebImageWebPCoder: c94f09adbca681822edad9e532ac752db713eabf SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 - Yoga: e5b887426cee15d2a326bdd34afc0282fc0486ad + Yoga: 2a16e58450c48e110211dae1159fb114bbcdcfc0 PODFILE CHECKSUM: a2aca3d0b349c3f3445211d8f84e40a1584a8947 diff --git a/VAMobile/package.json b/VAMobile/package.json index 1690cea2e23..0ee4a92d385 100644 --- a/VAMobile/package.json +++ b/VAMobile/package.json @@ -38,10 +38,11 @@ }, "dependencies": { "@department-of-veterans-affairs/mobile-assets": "0.12.0", - "@department-of-veterans-affairs/mobile-tokens": "0.12.0", "@department-of-veterans-affairs/mobile-component-library": "0.19.1", + "@department-of-veterans-affairs/mobile-tokens": "0.12.0", "@expo/react-native-action-sheet": "^4.1.0", "@react-native-async-storage/async-storage": "^1.23.1", + "@react-native-cookies/cookies": "^6.2.1", "@react-native-firebase/analytics": "^18.9.0", "@react-native-firebase/app": "^18.9.0", "@react-native-firebase/crashlytics": "^18.9.0", diff --git a/VAMobile/yarn.lock b/VAMobile/yarn.lock index d12518e03e8..b4c253de905 100644 --- a/VAMobile/yarn.lock +++ b/VAMobile/yarn.lock @@ -2095,6 +2095,13 @@ prompts "^2.4.2" semver "^7.5.2" +"@react-native-cookies/cookies@^6.2.1": + version "6.2.1" + resolved "https://registry.yarnpkg.com/@react-native-cookies/cookies/-/cookies-6.2.1.tgz#54d50b9496400bbdc19e43c155f70f8f918999e3" + integrity sha512-D17wCA0DXJkGJIxkL74Qs9sZ3sA+c+kCoGmXVknW7bVw/W+Vv1m/7mWTNi9DLBZSRddhzYw8SU0aJapIaM/g5w== + dependencies: + invariant "^2.2.4" + "@react-native-firebase/analytics@^18.9.0": version "18.9.0" resolved "https://registry.yarnpkg.com/@react-native-firebase/analytics/-/analytics-18.9.0.tgz#15defe1052b01975e8b9dd487aff4041b5e42c1d" @@ -10249,7 +10256,7 @@ string-natural-compare@^3.0.1: resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -10266,15 +10273,6 @@ string-width@^2.0.0, string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -10404,7 +10402,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -10425,13 +10423,6 @@ strip-ansi@^5.0.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -11298,7 +11289,7 @@ word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f" integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -11316,15 +11307,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From f9bdd42dbae5898cc1e334bfb090c13fecbc15c7 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 9 Sep 2024 11:19:20 -0700 Subject: [PATCH 11/60] Set cookies in CookieManager --- .../screens/WebviewScreen/WebviewScreen.tsx | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx index b03999d08ea..5214fde3f2a 100644 --- a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx +++ b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx @@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next' import { Linking, StatusBar, ViewStyle } from 'react-native' import { WebView } from 'react-native-webview' +import CookieManager from '@react-native-cookies/cookies' import { StackScreenProps } from '@react-navigation/stack' import { Box, BoxProps, LoadingComponent } from 'components' @@ -90,10 +91,6 @@ export type WebviewStackParams = { type WebviewScreenProps = StackScreenProps -type Cookies = { - [key: string]: string -} - /** * Screen for displaying web content within the app. Provides basic navigation and controls */ @@ -105,7 +102,6 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { const [canGoForward, setCanGoForward] = useState(false) const [currentUrl, setCurrentUrl] = useState('') const [loading, setLoading] = useState(true) - const [headers, setHeaders] = useState() const { url, displayTitle, loadingMessage, useSSO } = route.params @@ -147,14 +143,13 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { }).toString(), }) - const cookieHeaders = response.headers.get('Set-Cookie') - const cookiesObj = cookieHeaders?.split(';').reduce((cookies: Cookies, cookie) => { - const [key, value] = cookie.split('=') - cookies[key.trim()] = value ? value.trim() : '' - return cookies - }, {}) + const cookieHeaders = response.headers.get('set-cookie') || '' + console.log('Cookie headers', cookieHeaders) - setHeaders(cookiesObj) + await CookieManager.clearAll() + await CookieManager.setFromResponse(AUTH_SIS_TOKEN_EXCHANGE_URL, cookieHeaders).then((success) => { + console.log('CookieManager.setFromResponse =>', success) + }) } catch (error) { logNonFatalErrorToFirebase(error, `Error fetching SSO cookies: ${error}`) } finally { @@ -162,8 +157,8 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { } } - useSSO && fetchSSOCookies() - }, [useSSO]) + fetchSSOCookies() + }, []) const backPressed = (): void => { webviewRef?.current.goBack() @@ -217,8 +212,12 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { } - source={{ uri: url, headers }} + source={{ + uri: 'https://staging-api.va.gov/v0/user', + }} injectedJavaScript={INJECTED_JAVASCRIPT} + sharedCookiesEnabled={true} + thirdPartyCookiesEnabled ref={webviewRef} // onMessage is required to be present for injected javascript to work on iOS onMessage={(): void => { From 0c8456728d3f247777fda1f020bdf5552647f2b3 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 9 Sep 2024 11:36:27 -0700 Subject: [PATCH 12/60] Revoke SSO session on logout --- VAMobile/src/store/slices/authSlice.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/VAMobile/src/store/slices/authSlice.ts b/VAMobile/src/store/slices/authSlice.ts index 936da9e8036..e3bb3ac0221 100644 --- a/VAMobile/src/store/slices/authSlice.ts +++ b/VAMobile/src/store/slices/authSlice.ts @@ -541,7 +541,10 @@ export const logout = (): AppThunk => async (dispatch, getState) => { const tokenMatchesServiceType = await refreshTokenMatchesLoginService() if (tokenMatchesServiceType) { - const queryString = new URLSearchParams({ refresh_token: refreshToken ?? '' }).toString() + const queryString = new URLSearchParams({ + refresh_token: refreshToken ?? '', + device_secret: api.getDeviceSecret() ?? '', + }).toString() const response = await fetch(AUTH_SIS_REVOKE_URL, { method: 'POST', From ffeddce7f26f86e4e7d74c134006f6fbcad47359 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 9 Sep 2024 11:54:51 -0700 Subject: [PATCH 13/60] Clear cookie manager cookies on logout --- VAMobile/src/store/slices/authSlice.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/VAMobile/src/store/slices/authSlice.ts b/VAMobile/src/store/slices/authSlice.ts index e3bb3ac0221..3f763ee422f 100644 --- a/VAMobile/src/store/slices/authSlice.ts +++ b/VAMobile/src/store/slices/authSlice.ts @@ -1,6 +1,7 @@ import * as Keychain from 'react-native-keychain' import AsyncStorage from '@react-native-async-storage/async-storage' +import CookieManager from '@react-native-cookies/cookies' import analytics from '@react-native-firebase/analytics' import { utils } from '@react-native-firebase/app' import crashlytics from '@react-native-firebase/crashlytics' @@ -538,6 +539,7 @@ export const logout = (): AppThunk => async (dispatch, getState) => { } await clearCookies() + await CookieManager.clearAll() const tokenMatchesServiceType = await refreshTokenMatchesLoginService() if (tokenMatchesServiceType) { From 39dbbf11bed341434c110b118000ca66c563c9bf Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 9 Sep 2024 11:55:25 -0700 Subject: [PATCH 14/60] Add feature togge logic to Webview SSO --- VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx index 5214fde3f2a..57139cd7234 100644 --- a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx +++ b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx @@ -17,6 +17,7 @@ import { logNonFatalErrorToFirebase } from 'utils/analytics' import getEnv from 'utils/env' import { useTheme } from 'utils/hooks' import { isIOS } from 'utils/platform' +import { featureEnabled } from 'utils/remoteConfig' import WebviewControlButton from './WebviewControlButton' import WebviewControls, { WebviewControlsProps } from './WebviewControls' @@ -95,15 +96,16 @@ type WebviewScreenProps = StackScreenProps * Screen for displaying web content within the app. Provides basic navigation and controls */ function WebviewScreen({ navigation, route }: WebviewScreenProps) { + const { url, displayTitle, loadingMessage, useSSO } = route.params + const isSSOSession = featureEnabled('sso') && useSSO + const theme = useTheme() const webviewRef = useRef() as MutableRefObject const [canGoBack, setCanGoBack] = useState(false) const [canGoForward, setCanGoForward] = useState(false) const [currentUrl, setCurrentUrl] = useState('') - const [loading, setLoading] = useState(true) - - const { url, displayTitle, loadingMessage, useSSO } = route.params + const [loading, setLoading] = useState(isSSOSession) const onReloadPressed = (): void => { webviewRef?.current.reload() @@ -157,7 +159,7 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { } } - fetchSSOCookies() + isSSOSession && fetchSSOCookies() }, []) const backPressed = (): void => { From 930b720b6ed5d5f92c79b4798e2d9eb45b00c402 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 9 Sep 2024 12:34:13 -0700 Subject: [PATCH 15/60] Always display Webview link for testing --- .../HealthScreen/Appointments/NoAppointments/NoAppointments.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VAMobile/src/screens/HealthScreen/Appointments/NoAppointments/NoAppointments.tsx b/VAMobile/src/screens/HealthScreen/Appointments/NoAppointments/NoAppointments.tsx index 80c689443bb..d3aafa98f26 100644 --- a/VAMobile/src/screens/HealthScreen/Appointments/NoAppointments/NoAppointments.tsx +++ b/VAMobile/src/screens/HealthScreen/Appointments/NoAppointments/NoAppointments.tsx @@ -40,7 +40,7 @@ export function NoAppointments({ subText, subTextA11yLabel, showVAGovLink = true {showVAGovLink && - (featureEnabled('sso') ? ( + (true ? ( From a9d10c3beb2281c8d3dc6eedd9627bd627e6422b Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 9 Sep 2024 14:49:33 -0700 Subject: [PATCH 16/60] Set hasSession local storage in Webview --- VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx index 57139cd7234..7e355fddd82 100644 --- a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx +++ b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx @@ -179,6 +179,7 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { } const INJECTED_JAVASCRIPT = `(function() { + localStorage.setItem('hasSession', true); document.getElementsByClassName("header")[0].style.display='none'; document.getElementsByClassName("va-nav-breadcrumbs")[0].style.display='none'; document.getElementsByClassName("footer")[0].style.display='none'; @@ -215,7 +216,7 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { startInLoadingState renderLoading={(): ReactElement => } source={{ - uri: 'https://staging-api.va.gov/v0/user', + uri: url, }} injectedJavaScript={INJECTED_JAVASCRIPT} sharedCookiesEnabled={true} From 7c8e0a2cbb08603f90f8c706d0cd4072e1762ee3 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 9 Sep 2024 15:02:14 -0700 Subject: [PATCH 17/60] Update loading logic --- VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx index 7e355fddd82..22312c0bcde 100644 --- a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx +++ b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx @@ -203,7 +203,7 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { bottom: 0, } - return useSSO && loading ? ( + return loading ? ( ) : ( From c38719baf7b86606a255a862cff9ab1f0fe1e82f Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Tue, 10 Sep 2024 19:59:18 -0700 Subject: [PATCH 18/60] Prevent fetching cookies if already set --- .../screens/WebviewScreen/WebviewScreen.tsx | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx index 22312c0bcde..eadc7ad5fc8 100644 --- a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx +++ b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx @@ -129,6 +129,16 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { useEffect(() => { const fetchSSOCookies = async () => { + // Check if any cookies are present + const ssoCookies = await CookieManager.get(AUTH_SIS_TOKEN_EXCHANGE_URL) + const cookiesArray = Object.values(ssoCookies) + const hasCookies = cookiesArray.some((cookie) => cookie.name) + + if (hasCookies) { + setLoading(false) + return + } + try { const response = await fetch(AUTH_SIS_TOKEN_EXCHANGE_URL, { method: 'POST', @@ -145,13 +155,8 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { }).toString(), }) - const cookieHeaders = response.headers.get('set-cookie') || '' - console.log('Cookie headers', cookieHeaders) - - await CookieManager.clearAll() - await CookieManager.setFromResponse(AUTH_SIS_TOKEN_EXCHANGE_URL, cookieHeaders).then((success) => { - console.log('CookieManager.setFromResponse =>', success) - }) + const cookieHeaders = response.headers.get('set-cookie') + cookieHeaders && (await CookieManager.setFromResponse(AUTH_SIS_TOKEN_EXCHANGE_URL, cookieHeaders)) } catch (error) { logNonFatalErrorToFirebase(error, `Error fetching SSO cookies: ${error}`) } finally { @@ -215,12 +220,9 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { } - source={{ - uri: url, - }} + source={{ uri: url }} injectedJavaScript={INJECTED_JAVASCRIPT} sharedCookiesEnabled={true} - thirdPartyCookiesEnabled ref={webviewRef} // onMessage is required to be present for injected javascript to work on iOS onMessage={(): void => { From 2502cb5047e007f914d1c2878eb18f6d43adedef Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Tue, 10 Sep 2024 20:00:21 -0700 Subject: [PATCH 19/60] Update logic --- .../HealthScreen/Appointments/NoAppointments/NoAppointments.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VAMobile/src/screens/HealthScreen/Appointments/NoAppointments/NoAppointments.tsx b/VAMobile/src/screens/HealthScreen/Appointments/NoAppointments/NoAppointments.tsx index d3aafa98f26..80c689443bb 100644 --- a/VAMobile/src/screens/HealthScreen/Appointments/NoAppointments/NoAppointments.tsx +++ b/VAMobile/src/screens/HealthScreen/Appointments/NoAppointments/NoAppointments.tsx @@ -40,7 +40,7 @@ export function NoAppointments({ subText, subTextA11yLabel, showVAGovLink = true {showVAGovLink && - (true ? ( + (featureEnabled('sso') ? ( From 2a2199e4d88551a9576313297f452999b6e3c794 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Tue, 10 Sep 2024 20:29:54 -0700 Subject: [PATCH 20/60] Revert testing changes and slight refactor --- .../UpcomingAppointments/UpcomingAppointments.tsx | 2 +- VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/VAMobile/src/screens/HealthScreen/Appointments/UpcomingAppointments/UpcomingAppointments.tsx b/VAMobile/src/screens/HealthScreen/Appointments/UpcomingAppointments/UpcomingAppointments.tsx index 3b7b397dd1d..f2ab11fddd6 100644 --- a/VAMobile/src/screens/HealthScreen/Appointments/UpcomingAppointments/UpcomingAppointments.tsx +++ b/VAMobile/src/screens/HealthScreen/Appointments/UpcomingAppointments/UpcomingAppointments.tsx @@ -45,7 +45,7 @@ function UpcomingAppointments({ appointmentsData, loading, page, setPage, scroll return } - if (true) { + if (!appointmentsData || appointmentsData.data.length < 1) { return ( { const fetchSSOCookies = async () => { - // Check if any cookies are present - const ssoCookies = await CookieManager.get(AUTH_SIS_TOKEN_EXCHANGE_URL) - const cookiesArray = Object.values(ssoCookies) - const hasCookies = cookiesArray.some((cookie) => cookie.name) + const cookies = await CookieManager.get(AUTH_SIS_TOKEN_EXCHANGE_URL) + const cookiesArray = Object.values(cookies) + const hasSSOCookies = cookiesArray.some((cookie) => cookie.name === 'vagov_access_token') - if (hasCookies) { + if (hasSSOCookies) { setLoading(false) return } From 6ab3be4f3accf6040a29e05fc15681c61b8df078 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Tue, 10 Sep 2024 21:32:50 -0700 Subject: [PATCH 21/60] Fix linting errors --- VAMobile/ios/Podfile.lock | 4 ++-- VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VAMobile/ios/Podfile.lock b/VAMobile/ios/Podfile.lock index dd16e33a2fe..abbe4915ebb 100644 --- a/VAMobile/ios/Podfile.lock +++ b/VAMobile/ios/Podfile.lock @@ -1054,7 +1054,7 @@ PODS: - React-Core - react-native-notifications (5.1.0): - React-Core - - react-native-safe-area-context (4.10.8): + - react-native-safe-area-context (4.10.9): - React-Core - react-native-webview (13.10.4): - glog @@ -1606,7 +1606,7 @@ SPEC CHECKSUMS: react-native-document-picker: cd4d6b36a5207ad7a9e599ebb9eb0c2e84fa0b87 react-native-image-picker: b3ba58c691bc503b33480cef8ab987f78e310c15 react-native-notifications: 4601a5a8db4ced6ae7cfc43b44d35fe437ac50c4 - react-native-safe-area-context: b7daa1a8df36095a032dff095a1ea8963cb48371 + react-native-safe-area-context: ab8f4a3d8180913bd78ae75dd599c94cce3d5e9a react-native-webview: dbc8171113daa2abb2499da5f327a8d0cdfcd61c React-nativeconfig: 2e44d0d2dd222b12a5183f4bcaa4a91881497acb React-NativeModulesApple: 8aa032fe6c92c1a3c63e4809d42816284a56a9b0 diff --git a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx index 2dfad433447..f81bf818a32 100644 --- a/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx +++ b/VAMobile/src/screens/WebviewScreen/WebviewScreen.tsx @@ -164,7 +164,7 @@ function WebviewScreen({ navigation, route }: WebviewScreenProps) { } isSSOSession && fetchSSOCookies() - }, []) + }, [isSSOSession]) const backPressed = (): void => { webviewRef?.current.goBack() From fc4bcd3c9edd724cb1e4ba21c79591ce6415acb6 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Wed, 11 Sep 2024 01:23:08 -0700 Subject: [PATCH 22/60] Mock cookies library for unit tests --- VAMobile/jest/testSetup.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/VAMobile/jest/testSetup.ts b/VAMobile/jest/testSetup.ts index 85f3dc8834b..8466f949420 100644 --- a/VAMobile/jest/testSetup.ts +++ b/VAMobile/jest/testSetup.ts @@ -200,6 +200,14 @@ jest.mock('react-native-file-viewer', () => { } }) +jest.mock('@react-native-cookies/cookies', () => { + return { + clearAll: jest.fn(), + get: jest.fn(), + setFromResponse: jest.fn(), + } +}) + jest.mock('@react-native-firebase/analytics', () => { return jest.fn(() => { return { From 909d78095f2c680d02e618d7e589511ab24f3a27 Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Wed, 11 Sep 2024 09:45:27 -0700 Subject: [PATCH 23/60] Update failing unit tests --- VAMobile/jest/testSetup.ts | 2 ++ VAMobile/src/store/slices/authSlice.sis.test.ts | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/VAMobile/jest/testSetup.ts b/VAMobile/jest/testSetup.ts index 8466f949420..acb9de03e34 100644 --- a/VAMobile/jest/testSetup.ts +++ b/VAMobile/jest/testSetup.ts @@ -59,6 +59,8 @@ jest.mock('../src/store/api', () => ({ setAccessToken: jest.fn(), getAccessToken: jest.fn(), setRefreshToken: jest.fn(), + getDeviceSecret: jest.fn(), + setDeviceSecret: jest.fn(), })) jest.mock('../src/utils/hooks', () => { diff --git a/VAMobile/src/store/slices/authSlice.sis.test.ts b/VAMobile/src/store/slices/authSlice.sis.test.ts index 57fd6cbdf36..e2db0d8d9da 100644 --- a/VAMobile/src/store/slices/authSlice.sis.test.ts +++ b/VAMobile/src/store/slices/authSlice.sis.test.ts @@ -82,13 +82,16 @@ const defaultEnvParams = { const sampleIdToken = 'TEST_TOKEN' const getItemMock = AsyncStorage.getItem as jest.Mock -let mockedAuthResponse: { data: { access_token: string; refresh_token: string; id_token: string } } +let mockedAuthResponse: { + data: { access_token: string; refresh_token: string; device_secret: string; id_token: string } +} context('authAction SIS', () => { let testAccessToken: string let encryptedComponent: string let nonce: string let testRefreshToken: string + let testDeviceSecret: string afterEach(() => { jest.clearAllMocks() }) @@ -101,6 +104,7 @@ context('authAction SIS', () => { data: { access_token: testAccessToken, refresh_token: testRefreshToken, + device_secret: testDeviceSecret, id_token: sampleIdToken, }, } From f200c1e06105b1fea4d6530f9b5758a40a1f52ed Mon Sep 17 00:00:00 2001 From: Theo Bentum Date: Mon, 16 Sep 2024 09:26:37 -0700 Subject: [PATCH 24/60] Merge develop --- .../detox_nightly_build_failure.md | 15 + .github/workflows/e2e_android.yml | 57 +- .github/workflows/e2e_ios.yml | 58 +- VAMobile/.detoxrc.json | 2 +- VAMobile/android/Gemfile.lock | 8 +- VAMobile/android/app/build.gradle | 90 +- .../android/app/src/main/AndroidManifest.xml | 1 + .../java/gov/va/mobileapp/MainApplication.kt | 2 +- .../res/drawable/rn_edit_text_material.xml | 3 +- VAMobile/android/build.gradle | 6 +- .../android/en-US/changelogs/default.txt | 2 +- .../en-US/images/phoneScreenshots/2_en-US.png | Bin 115944 -> 111646 bytes .../images/sevenInchScreenshots/2_en-US.png | Bin 115944 -> 111646 bytes VAMobile/android/gradle.properties | 2 - .../gradle/wrapper/gradle-wrapper.properties | 4 +- VAMobile/android/settings.gradle | 4 +- .../Alerts and progress/LoadingIndicator.md | 23 +- VAMobile/documentation/yarn.lock | 199 ++- VAMobile/e2e/tests/Claims.e2e.ts | 44 +- VAMobile/e2e/tests/Messages.e2e.ts | 26 +- VAMobile/e2e/tests/SettingsScreen.e2e.ts | 7 +- VAMobile/env/constant.env | 1 + VAMobile/env/test.env.ts | 1 + VAMobile/ios/Gemfile | 4 +- VAMobile/ios/Gemfile.lock | 8 +- VAMobile/ios/Podfile | 3 +- VAMobile/ios/Podfile.lock | 1484 ++++++++++++----- VAMobile/ios/PrivacyInfo.xcprivacy | 65 +- .../ios/VAMobile.xcodeproj/project.pbxproj | 45 +- VAMobile/ios/VAMobile/AppDelegate.mm | 4 +- VAMobile/ios/VAMobile/Info.plist | 2 +- .../fastlane/metadata/en-US/release_notes.txt | 2 +- .../screenshots/en-US/ipadPro129-screen-2.png | Bin 92368 -> 88749 bytes .../screenshots/en-US/iphone55-screen-2.png | Bin 163481 -> 156242 bytes .../screenshots/en-US/iphone67-screen-2.png | Bin 217185 -> 208830 bytes VAMobile/metro.config.js | 20 +- VAMobile/package.json | 20 +- .../src/components/AccordionCollapsible.tsx | 3 +- VAMobile/src/components/BackButton.tsx | 4 +- VAMobile/src/components/BaseListItem.tsx | 8 +- VAMobile/src/components/Box.tsx | 4 +- .../components/Carousel/CarouselTabBar.tsx | 10 +- VAMobile/src/components/CollapsibleView.tsx | 4 +- .../CommonErrorComponents/BasicError.tsx | 3 +- .../FormWrapper/FormFields/VASelector.tsx | 15 +- VAMobile/src/components/List.tsx | 13 +- VAMobile/src/components/NavigationTabBar.tsx | 5 +- VAMobile/src/components/Pagination.tsx | 3 +- VAMobile/src/components/VABulletList.tsx | 3 +- VAMobile/src/components/VAImage/VAImage.tsx | 4 +- .../AppealIssues/AppealIssues.tsx | 3 +- .../ClaimDetailsScreen/ClaimDetailsScreen.tsx | 8 +- .../ClaimFileUpload/TakePhotos/TakePhotos.tsx | 3 +- .../ClaimStatus/ClaimStatus.test.tsx | 18 +- .../ClaimTimeline/ClaimPhase.test.tsx | 27 +- .../ClaimStatus/ClaimTimeline/ClaimPhase.tsx | 4 +- .../ClaimTimeline/ClaimTimeline.test.tsx | 18 +- .../ClaimTimeline/DEPRECATED_ClaimPhase.tsx | 7 +- .../ConsolidatedClaimsNote.test.tsx | 2 +- .../ConsolidatedClaimsNote.tsx | 2 +- .../EstimatedDecisionDate.tsx | 11 +- .../WhatDoIDoIfDisagreement.test.tsx | 2 +- .../WhatDoIDoIfDisagreement.tsx | 8 +- .../ClaimsAndAppealsListView.tsx | 4 +- .../DEPRECATED_ClaimsAndAppealsListView.tsx | 4 +- .../NeedHelpData/NeedHelpData.tsx | 6 +- .../NoClaimsAndAppeals/NoClaimsAndAppeals.tsx | 24 +- .../NoClaimsAndAppealsAccess.tsx | 3 +- .../NoDisabilityRatings.tsx | 7 +- .../GenericLetter/GenericLetter.test.tsx | 1 - .../Letters/GenericLetter/GenericLetter.tsx | 7 +- .../Letters/LettersListScreen.tsx | 4 +- .../Letters/LettersOverviewScreen.tsx | 2 - .../NoLettersScreen/NoLettersScreen.tsx | 3 +- .../BiometricsPreferenceScreen.tsx | 5 +- .../NoAppointments/NoAppointments.tsx | 23 +- .../NoMatchInRecords/NoMatchInRecords.tsx | 3 +- .../PrescriptionHistory.tsx | 2 +- .../SecureMessaging/Folders/Folders.tsx | 3 +- .../NoInboxMessages/NoInboxMessages.tsx | 2 - .../NotEnrolledSM/NotEnrolledSM.tsx | 9 +- .../TermsAndConditions/TermsAndConditions.tsx | 11 +- .../NoMilitaryInformationAccess.tsx | 3 +- .../NotificationsSettingsScreen.test.tsx | 11 +- .../NotificationsSettingsScreen.tsx | 19 +- .../GenericOnboarding/GenericOnboarding.tsx | 3 +- .../src/screens/SplashScreen/SplashScreen.tsx | 3 +- .../src/screens/SyncScreen/SyncScreen.tsx | 3 +- .../WebviewScreen/WebviewControlButton.tsx | 22 +- .../screens/WebviewScreen/WebviewControls.tsx | 10 +- .../screens/WebviewScreen/WebviewScreen.tsx | 6 +- .../screens/WebviewScreen/WebviewTitle.tsx | 3 +- .../screens/auth/LoginScreen/LoginScreen.tsx | 11 +- VAMobile/src/translations/en/common.json | 18 +- VAMobile/src/utils/accessibility.tsx | 23 - VAMobile/src/utils/env.ts | 3 + VAMobile/yarn.lock | 783 ++++++--- 97 files changed, 2275 insertions(+), 1173 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/detox_nightly_build_failure.md diff --git a/.github/ISSUE_TEMPLATE/detox_nightly_build_failure.md b/.github/ISSUE_TEMPLATE/detox_nightly_build_failure.md new file mode 100644 index 00000000000..2f654b51763 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/detox_nightly_build_failure.md @@ -0,0 +1,15 @@ +--- +name: Detox Nightly Build Failure Template +about: Template for reporting a detox nightly build failure +title: "Bug - Detox - Fix Overnight Failures" +labels: bug, QA and Release +assignees: rbontrager + +--- + +## What failed? +Some detox tests have failed in the overnight build. Failures can be found [here](https://github.com/department-of-veterans-affairs/va-mobile-app/actions/workflows/e2e_ios.yml) for iOS and [here](https://github.com/department-of-veterans-affairs/va-mobile-app/actions/workflows/e2e_android.yml) for Android. Please look at the following list for what might be failing: + +- {{env.dateOfIssue}} {{env.OS}}: {{issues}} + + diff --git a/.github/workflows/e2e_android.yml b/.github/workflows/e2e_android.yml index 8577daba4c3..d733a1a0c86 100644 --- a/.github/workflows/e2e_android.yml +++ b/.github/workflows/e2e_android.yml @@ -251,7 +251,7 @@ jobs: if: steps.run_e2e_tests.outcome == 'failure' run: exit 1 - output-slack-results: + output-slack-results-and-update-detox-failure-ticket: if: (!cancelled()) && github.event_name == 'schedule' needs: [matrix-e2e-android, start_slack_thread] runs-on: macos-latest-xl @@ -259,11 +259,14 @@ jobs: - uses: actions/checkout@v3 with: ref: ${{ github.ref }} + - name: Download results uses: actions/download-artifact@v4 with: path: VAMobile/e2e/test_reports + - name: Inform Slack + id: inform_slack shell: bash run: | if grep -rq "" .; then @@ -281,6 +284,58 @@ jobs: https://slack.com/api/chat.postMessage| jq -r '.ts') fi + + - name: Find failing tests + id: failing_tests + shell: bash + run: | + failing_tests_list=$(grep -rl "") + failing_tests="" + for i in ${failing_tests_list[@]}; do + remove_before=${i%.ts*} + remove_after=${remove_before#*test_reports/} + echo "$remove_after" + if [ -z "${failing_tests}" ]; then + failing_tests=$(echo $failing_tests"$remove_after") + else + failing_tests=$(echo $failing_tests", ""$remove_after") + fi + done + echo "FAILING_TEST=$failing_tests" >> "$GITHUB_OUTPUT" + + - name: Github CLI Authentication + run: | + echo "${{ secrets.GITHUB_TOKEN }}" >> token.txt + gh auth login --with-token < token.txt + + - name: Update a ticket on failure (if needed) + id: find_if_ticket_already_exists + run: | + old_body=$(gh issue list --json body --jq '.[] | .body' --state open --search "Bug - Detox - Fix Overnight Failures in:title") + if [[ "$old_body" != '' ]]; then + ticket_number=$(gh issue list --json number --jq '.[] | .number' --state open --search "Bug - Detox - Fix Overnight Failures in:title") + new_body=$(echo "$old_body"$'\n'"- "${{ env.DATE_OF_ISSUE}}" on Android: "${{steps.failing_tests.outputs.FAILING_TEST}}) + echo "$new_body" + echo "TICKET_EXISTS=true" >> "$GITHUB_OUTPUT" + gh issue edit $ticket_number -b "$new_body" + else + echo "TICKET_EXISTS=false" >> "$GITHUB_OUTPUT" + fi + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Make a ticket on failure (if needed) + if: steps.inform_slack.outputs.TEST_FAILURE != '' && steps.find_if_ticket_already_exists.outputs.TICKET_EXISTS == '' + uses: JasonEtco/create-an-issue@v2 + with: + filename: .github/ISSUE_TEMPLATE/detox_nightly_build_failure.md + update_existing: true + search_existing: open + env: + dateOfIssue: ${{ env.DATE_OF_ISSUE }} + OS: "Android" + issues: ${{steps.failing_tests.outputs.FAILING_TEST}} + id: create-issue matrix-send_test_results_to_testrail: if: (!cancelled()) && github.event.inputs.run_testRail == 'true' diff --git a/.github/workflows/e2e_ios.yml b/.github/workflows/e2e_ios.yml index ae4757ee543..be004173938 100644 --- a/.github/workflows/e2e_ios.yml +++ b/.github/workflows/e2e_ios.yml @@ -228,7 +228,7 @@ jobs: if: steps.run_e2e_tests.outcome == 'failure' && steps.rerun_e2e_tests.outcome == 'failure' run: exit 1 - output-slack-results: + output-slack-results-and-update-detox-failure-ticket: if: (!cancelled()) && github.event_name == 'schedule' needs: [matrix-e2e-ios, start_slack_thread] runs-on: macos-latest-xl @@ -236,11 +236,14 @@ jobs: - uses: actions/checkout@v3 with: ref: ${{ github.ref }} + - name: Download results uses: actions/download-artifact@v4 with: path: VAMobile/e2e/test_reports + - name: Inform Slack + id: inform_slack shell: bash run: | if grep -rq "" .; then @@ -251,6 +254,8 @@ jobs: https://slack.com/api/chat.postMessage| jq -r '.ts') echo SLACK_THREAD_TS=${ts} >> $GITHUB_OUTPUT + echo "DATE_OF_ISSUE=$(date -d '+%A %b %d, %Y')" >> $GITHUB_ENV + echo TEST_FAILURE="true" >> $GITHUB_OUTPUT else ts=$(curl -X POST -H 'Authorization: Bearer '"$SLACK_API_TOKEN"' ' \ -H 'Content-type: application/json' \ @@ -259,6 +264,57 @@ jobs: jq -r '.ts') fi + - name: Find failing tests + id: failing_tests + shell: bash + run: | + failing_tests_list=$(grep -rl "") + failing_tests="" + for i in ${failing_tests_list[@]}; do + remove_before=${i%.ts*} + remove_after=${remove_before#*test_reports/} + echo "$remove_after" + if [ -z "${failing_tests}" ]; then + failing_tests=$(echo $failing_tests"$remove_after") + else + failing_tests=$(echo $failing_tests", ""$remove_after") + fi + done + echo "FAILING_TEST=$failing_tests" >> "$GITHUB_OUTPUT" + + - name: Github CLI Authentication + run: | + echo "${{ secrets.GITHUB_TOKEN }}" >> token.txt + gh auth login --with-token < token.txt + + - name: Update a ticket on failure (if needed) + id: find_if_ticket_already_exists + run: | + old_body=$(gh issue list --json body --jq '.[] | .body' --state open --search "Bug - Detox - Fix Overnight Failures in:title") + if [[ "$old_body" != '' ]]; then + ticket_number=$(gh issue list --json number --jq '.[] | .number' --state open --search "Bug - Detox - Fix Overnight Failures in:title") + new_body=$(echo "$old_body"$'\n'"- "${{ env.DATE_OF_ISSUE}}" on iOS: "${{steps.failing_tests.outputs.FAILING_TEST}}) + echo "$new_body" + echo "TICKET_EXISTS=true" >> "$GITHUB_OUTPUT" + gh issue edit $ticket_number -b "$new_body" + else + echo "TICKET_EXISTS=false" >> "$GITHUB_OUTPUT" + fi + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Make a ticket on failure (if needed) + if: steps.inform_slack.outputs.TEST_FAILURE != '' && steps.find_if_ticket_already_exists.outputs.TICKET_EXISTS == '' + uses: JasonEtco/create-an-issue@v2 + with: + filename: .github/ISSUE_TEMPLATE/detox_nightly_build_failure.md + search_existing: open + env: + dateOfIssue: ${{ env.DATE_OF_ISSUE }} + OS: "iOS" + issues: ${{steps.failing_tests.outputs.FAILING_TEST}} + id: create-issue + matrix-send_test_results_to_testrail: if: (!cancelled()) && github.event.inputs.run_testRail == 'true' needs: [matrix-e2e-ios, output_detox_tests_to_run] diff --git a/VAMobile/.detoxrc.json b/VAMobile/.detoxrc.json index b307913691d..fd6d707132b 100644 --- a/VAMobile/.detoxrc.json +++ b/VAMobile/.detoxrc.json @@ -20,7 +20,7 @@ "android": { "type": "android.apk", "binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk", - "build": "cd android ; ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug; cd .." + "build": "cd android ; ./gradlew app:assembleDebug app:assembleAndroidTest -DtestBuildType=debug; cd .." } }, "devices": { diff --git a/VAMobile/android/Gemfile.lock b/VAMobile/android/Gemfile.lock index 63429b8bf67..d260d6032d4 100644 --- a/VAMobile/android/Gemfile.lock +++ b/VAMobile/android/Gemfile.lock @@ -10,16 +10,16 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.970.0) - aws-sdk-core (3.203.0) + aws-partitions (1.973.0) + aws-sdk-core (3.204.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.9) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.89.0) + aws-sdk-kms (1.90.0) aws-sdk-core (~> 3, >= 3.203.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.160.0) + aws-sdk-s3 (1.161.0) aws-sdk-core (~> 3, >= 3.203.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) diff --git a/VAMobile/android/app/build.gradle b/VAMobile/android/app/build.gradle index 8ea0eb22bc2..2b7655c0e89 100644 --- a/VAMobile/android/app/build.gradle +++ b/VAMobile/android/app/build.gradle @@ -13,72 +13,26 @@ apply plugin: 'com.google.firebase.firebase-perf' * bundle directly from the development server. Below you can see all the possible configurations * and their defaults. If you decide to add a configuration block, make sure to add it before the * `apply from: "../../node_modules/react-native/react.gradle"` line. - * - * project.ext.react = [ - * // the name of the generated asset file containing your JS bundle - * bundleAssetName: "index.android.bundle", - * - * // the entry file for bundle generation. If none specified and - * // "index.android.js" exists, it will be used. Otherwise "index.js" is - * // default. Can be overridden with ENTRY_FILE environment variable. - * entryFile: "index.android.js", - * - * // https://reactnative.dev/docs/performance#enable-the-ram-format - * bundleCommand: "ram-bundle", - * - * // whether to bundle JS and assets in debug mode - * bundleInDebug: false, - * - * // whether to bundle JS and assets in release mode - * bundleInRelease: true, - * - * // whether to bundle JS and assets in another build variant (if configured). - * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants - * // The configuration property can be in the following formats - * // 'bundleIn${productFlavor}${buildType}' - * // 'bundleIn${buildType}' - * // bundleInFreeDebug: true, - * // bundleInPaidRelease: true, - * // bundleInBeta: true, - * - * // whether to disable dev mode in custom build variants (by default only disabled in release) - * // for example: to disable dev mode in the staging build type (if configured) - * devDisabledInStaging: true, - * // The configuration property can be in the following formats - * // 'devDisabledIn${productFlavor}${buildType}' - * // 'devDisabledIn${buildType}' - * - * // the root of your project, i.e. where "package.json" lives - * root: "../../", - * - * // where to put the JS bundle asset in debug mode - * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", - * - * // where to put the JS bundle asset in release mode - * jsBundleDirRelease: "$buildDir/intermediates/assets/release", - * - * // where to put drawable resources / React Native assets, e.g. the ones you use via - * // require('./image.png')), in debug mode - * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", - * - * // where to put drawable resources / React Native assets, e.g. the ones you use via - * // require('./image.png')), in release mode - * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", - * - * // by default the gradle tasks are skipped if none of the JS files or assets change; this means - * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to - * // date; if you have any other folders that you want to ignore for performance reasons (gradle - * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ - * // for example, you might want to remove it from here. - * inputExcludes: ["android/**", "ios/**"], - * - * // override which node gets called and with what additional arguments - * nodeExecutableAndArgs: ["node"], - * - * // supply additional arguments to the packager - * extraPackagerArgs: [] - * ] - */ + **/ +react { + // The root of your project, i.e. where "package.json" lives. Default is '../..' + // root = file("../../") + // The folder where the react-native NPM package is. Default is ../../node_modules/react-native + // reactNativeDir = file("../../node_modules/react-native") + // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen + // codegenDir = file("../../node_modules/@react-native/codegen") + // The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js + // cliFile = file("../../node_modules/react-native/cli.js") + + /* Variants */ + // The list of variants to that are debuggable. For those we're going to + // + // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" + // hermesFlags = ["-O", "-output-source-map"] + + /* Autolinking */ + autolinkLibrariesWithApp() +} project.ext.react = [ enableHermes: true, // clean and rebuild if changing @@ -215,7 +169,7 @@ dependencies { implementation jscFlavor } - implementation 'com.android.support:multidex:2.0.1' + implementation "androidx.multidex:multidex:2.0.1" implementation fileTree(dir: "libs", include: ["*.jar"]) @@ -264,8 +218,6 @@ task copyDownloadableDepsToLibs(type: Copy) { into 'libs' } -apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) - // fastlane build tasks and defs def readVersion() { def versionFile = new File(project.rootDir, 'version.properties') diff --git a/VAMobile/android/app/src/main/AndroidManifest.xml b/VAMobile/android/app/src/main/AndroidManifest.xml index d3061790723..9deb2da55bd 100644 --- a/VAMobile/android/app/src/main/AndroidManifest.xml +++ b/VAMobile/android/app/src/main/AndroidManifest.xml @@ -42,6 +42,7 @@ android:label="@string/app_name" android:roundIcon="@mipmap/${appIconRound}" android:theme="@style/AppTheme" + android:supportsRtl="true" android:networkSecurityConfig="@xml/network_security_config"> + android:insetBottom="@dimen/abc_edit_text_inset_bottom_material" + >