diff --git a/app/locales/en.json b/app/locales/en.json
index 6f285bca81..c4e7b52221 100644
--- a/app/locales/en.json
+++ b/app/locales/en.json
@@ -96,7 +96,7 @@
"notifications_off_subheader": "You will not receive notifications about possible exposures nor when new Health Departments are added in your area",
"select_authority_button": "Add Health Department",
"select_authority_header": "No local Health Department Selected",
- "select_authority_subheader": "Allow PathCheck to add your local Health Department or select one yourself to receive info about COVID-19 in your area"
+ "select_authority_subheader": "Select your local Health Department to receive info about COVID-19 in your area"
}
},
"import": {
diff --git a/app/store/actions/healthcareAuthorities/getHealthcareAuthoritiesAction.ts b/app/store/actions/healthcareAuthorities/getHealthcareAuthoritiesAction.ts
index 4fcb184590..850c1cd438 100644
--- a/app/store/actions/healthcareAuthorities/getHealthcareAuthoritiesAction.ts
+++ b/app/store/actions/healthcareAuthorities/getHealthcareAuthoritiesAction.ts
@@ -63,7 +63,10 @@ const getHealthcareAuthoritiesAction = (
dispatch(
toggleSelectedHealthcareAuthorityAction(
{ authority: localHealthAuthority, overrideValue: true },
- { triggerIntersect: false },
+ {
+ triggerIntersect: false,
+ autoSubscribed: !!autoSubscriptionLocation,
+ },
),
);
}
diff --git a/app/store/actions/healthcareAuthorities/toggleAutoSubscriptionBannerAction.ts b/app/store/actions/healthcareAuthorities/toggleAutoSubscriptionBannerAction.ts
new file mode 100644
index 0000000000..ad34b1aca3
--- /dev/null
+++ b/app/store/actions/healthcareAuthorities/toggleAutoSubscriptionBannerAction.ts
@@ -0,0 +1,12 @@
+import { createAction } from '@reduxjs/toolkit';
+
+const TOGGLE_AUTO_SUBSCRIPTION_BANNER = 'TOGGLE_AUTO_SUBSCRIPTION_BANNER';
+
+/**
+ * Enables / disables the auto-subscription banner from being shown
+ */
+const toggleAutoSubscriptionBannerAction = createAction<{
+ overrideValue: boolean;
+}>(TOGGLE_AUTO_SUBSCRIPTION_BANNER);
+
+export default toggleAutoSubscriptionBannerAction;
diff --git a/app/store/actions/healthcareAuthorities/toggleHealthcareAuthorityAutoSubscription.ts b/app/store/actions/healthcareAuthorities/toggleHealthcareAuthorityAutoSubscription.ts
deleted file mode 100644
index 31b5e984c9..0000000000
--- a/app/store/actions/healthcareAuthorities/toggleHealthcareAuthorityAutoSubscription.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { createAction } from '@reduxjs/toolkit';
-
-const TOGGLE_HEALTHCARE_AUTHORITY_AUTO_SUBSCRIPTION =
- 'TOGGLE_HEALTHCARE_AUTHORITY_AUTO_SUBSCRIPTION';
-
-const toggleHealthcareAuthorityAutoSubscription = createAction<{
- autoSubscriptionEnabled: boolean;
-}>(TOGGLE_HEALTHCARE_AUTHORITY_AUTO_SUBSCRIPTION);
-
-export default toggleHealthcareAuthorityAutoSubscription;
diff --git a/app/store/actions/healthcareAuthorities/toggleSelectedHealthcareAuthorityAction.ts b/app/store/actions/healthcareAuthorities/toggleSelectedHealthcareAuthorityAction.ts
index ac02a20807..374810f6bf 100644
--- a/app/store/actions/healthcareAuthorities/toggleSelectedHealthcareAuthorityAction.ts
+++ b/app/store/actions/healthcareAuthorities/toggleSelectedHealthcareAuthorityAction.ts
@@ -7,7 +7,8 @@ type Payload = {
};
type Meta = {
- triggerIntersect: boolean;
+ triggerIntersect?: boolean; // indicates that this action should trigger a recomputation of possible exposure notifications
+ autoSubscribed?: boolean; // indicates that this was triggered via geofencing auto subscription
};
const TOGGLE_SELECTED_HEALTHCARE_AUTHORITY =
@@ -15,9 +16,12 @@ const TOGGLE_SELECTED_HEALTHCARE_AUTHORITY =
const toggleSelectedHealthcareAuthorityAction = createAction(
TOGGLE_SELECTED_HEALTHCARE_AUTHORITY,
- ({ authority, overrideValue }: Payload, { triggerIntersect }: Meta) => ({
+ (
+ { authority, overrideValue }: Payload,
+ { triggerIntersect, autoSubscribed }: Meta,
+ ) => ({
payload: { authority, overrideValue },
- meta: { triggerIntersect },
+ meta: { triggerIntersect, autoSubscribed },
}),
);
diff --git a/app/store/index.ts b/app/store/index.ts
index a75cfd9548..39c07601d3 100644
--- a/app/store/index.ts
+++ b/app/store/index.ts
@@ -19,7 +19,7 @@ const enhancers = composeWithDevTools(
),
);
-export const STORE_VERSION = 1;
+export const STORE_VERSION = 2;
const persistConfig = {
key: 'root',
storage: AsyncStorage,
diff --git a/app/store/migrations/migrations.js b/app/store/migrations/migrations.js
index 3f7de0dab7..1e86e5ac13 100644
--- a/app/store/migrations/migrations.js
+++ b/app/store/migrations/migrations.js
@@ -8,6 +8,21 @@ const migrations = {
}
return prevState;
},
+ // Migration 2: Introduce auto-subscription
+ 2: (prevState) => {
+ if (prevState && prevState.healthcareAuthorities) {
+ prevState.healthcareAuthorities.autoSubscription = {
+ bannerDismissed: false,
+ selectedAuthority: null,
+ // only auto-subscribe if user has no HAs.
+ active:
+ !prevState.healthcareAuthorities.availableCustomAuthorities ||
+ prevState.healthcareAuthorities.availableCustomAuthorities.length ===
+ 0,
+ };
+ }
+ return prevState;
+ },
};
export default migrations;
diff --git a/app/store/reducers/healthcareAuthoritiesReducer.ts b/app/store/reducers/healthcareAuthoritiesReducer.ts
index bf386bf50e..0ec0b317f5 100644
--- a/app/store/reducers/healthcareAuthoritiesReducer.ts
+++ b/app/store/reducers/healthcareAuthoritiesReducer.ts
@@ -8,7 +8,7 @@ import {
getHealthcareAuthorities_success,
} from '../actions/healthcareAuthorities/getHealthcareAuthoritiesAction';
import toggleSelectedHealthcareAuthorityAction from '../actions/healthcareAuthorities/toggleSelectedHealthcareAuthorityAction';
-import toggleHealthcareAuthorityAutoSubscription from '../actions/healthcareAuthorities/toggleHealthcareAuthorityAutoSubscription';
+import toggleAutoSubscriptionBannerAction from '../actions/healthcareAuthorities/toggleAutoSubscriptionBannerAction';
type HealthCareReducerState = {
// Because we control this list to be super small and have type safety, we use the full models
@@ -16,19 +16,27 @@ type HealthCareReducerState = {
availableAuthorities: HealthcareAuthority[];
availableCustomAuthorities: HealthcareAuthority[];
selectedAuthorities: HealthcareAuthority[];
- autoSubscriptionEnabled: boolean;
request: ApiRequest;
+ autoSubscription: {
+ active: boolean; // controls firing. We set to false after any toggle so that auto-subscribe happens max of once, and before manual.
+ bannerDismissed: boolean; // independently show banner until dismissed
+ selectedAuthority: HealthcareAuthority | null;
+ };
};
const initialState: HealthCareReducerState = {
availableAuthorities: [],
availableCustomAuthorities: [], // For testing, from a custom uploaded YAML
selectedAuthorities: [],
- autoSubscriptionEnabled: true,
request: {
status: ApiStatus.INITIAL,
errorMessage: null,
},
+ autoSubscription: {
+ active: true,
+ bannerDismissed: false,
+ selectedAuthority: null,
+ },
};
// The 'request' property of this reducer is helpful metadata for showing loading / error cases
@@ -71,7 +79,10 @@ const healthcareAuthoritiesReducer = createReducer(initialState, (builder) =>
})
.addCase(
toggleSelectedHealthcareAuthorityAction,
- (state, { payload: { authority, overrideValue } }) => {
+ (
+ state,
+ { payload: { authority, overrideValue }, meta: { autoSubscribed } },
+ ) => {
// always remove
state.selectedAuthorities = state.selectedAuthorities.filter(
({ internal_id }) => internal_id !== authority.internal_id,
@@ -79,13 +90,20 @@ const healthcareAuthoritiesReducer = createReducer(initialState, (builder) =>
// add if needed
if (overrideValue) {
state.selectedAuthorities.push(authority);
+ state.autoSubscription.active = false; // after we subscribe, for any reason, prevent auto-subscribing
+ }
+
+ // Display banner that HA was auto-subscribed to
+ if (autoSubscribed) {
+ state.autoSubscription.bannerDismissed = false;
+ state.autoSubscription.selectedAuthority = authority;
}
},
)
.addCase(
- toggleHealthcareAuthorityAutoSubscription,
- (state, { payload: { autoSubscriptionEnabled } }) => {
- state.autoSubscriptionEnabled = autoSubscriptionEnabled;
+ toggleAutoSubscriptionBannerAction,
+ (state, { payload: { overrideValue } }) => {
+ state.autoSubscription.bannerDismissed = !overrideValue;
},
),
);
diff --git a/app/store/selectors/isAutoSubscriptionEnabledSelector.ts b/app/store/selectors/isAutoSubscriptionEnabledSelector.ts
deleted file mode 100644
index 9d632cbfdb..0000000000
--- a/app/store/selectors/isAutoSubscriptionEnabledSelector.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import type { RootState } from '../types';
-const isAutoSubscriptionEnabledSelector = (state: RootState): boolean =>
- state.healthcareAuthorities.autoSubscriptionEnabled;
-
-export default isAutoSubscriptionEnabledSelector;
diff --git a/app/views/Main.js b/app/views/Main.js
index 835e1c13e0..723c2b974b 100644
--- a/app/views/Main.js
+++ b/app/views/Main.js
@@ -8,14 +8,16 @@ import { AllServicesOnScreen } from './main/AllServicesOn';
import {
TracingOffScreen,
NotificationsOffScreen,
- // SelectAuthorityScreen,
+ SelectAuthorityScreen,
} from './main/ServiceOffScreens';
import PermissionsContext from '../gps/PermissionsContext';
import { PermissionStatus } from '../permissionStatus';
-import { useSelector } from 'react-redux';
+import { useSelector, useDispatch } from 'react-redux';
import selectedHealthcareAuthoritiesSelector from '../store/selectors/selectedHealthcareAuthoritiesSelector';
import { useStatusBarEffect } from '../navigation';
+import getHealthcareAuthoritiesAction from '../store/actions/healthcareAuthorities/getHealthcareAuthoritiesAction';
+import Geolocation from '@react-native-community/geolocation';
export const Main = () => {
useStatusBarEffect('light-content');
@@ -47,14 +49,35 @@ export const Main = () => {
};
}, [navigation, updateStateInfo]);
+ const dispatch = useDispatch();
+ const { autoSubscription } = useSelector(
+ (state) => state.healthcareAuthorities,
+ );
+
+ const autoSubscribe = useCallback(async () => {
+ if (autoSubscription.active) {
+ Geolocation.getCurrentPosition(({ coords }) => {
+ dispatch(
+ getHealthcareAuthoritiesAction({ autoSubscriptionLocation: coords }),
+ );
+ });
+ }
+ }, [autoSubscription, dispatch]);
+
+ useEffect(() => {
+ autoSubscribe();
+ }, [autoSubscribe]);
+
if (!canTrack) {
return ;
} else if (notification.status === PermissionStatus.DENIED) {
return ;
} else if (selectedAuthorities.length === 0) {
- // TODO: enable this for testing versions of app
- // return ;
- return ;
+ if (autoSubscription.active) {
+ return ;
+ } else {
+ return ;
+ }
} else {
return ;
}
diff --git a/app/views/Partners/PartnersOverview.tsx b/app/views/Partners/PartnersOverview.tsx
index 8fb9f8fc0d..1091af931d 100644
--- a/app/views/Partners/PartnersOverview.tsx
+++ b/app/views/Partners/PartnersOverview.tsx
@@ -21,11 +21,6 @@ import { Typography } from '../../components/Typography';
import { Images, Icons } from '../../assets';
import { Colors } from '../../styles';
-import { useSelector, useDispatch } from 'react-redux';
-import toggleHealthcareAuthorityAutoSubscription from '../../store/actions/healthcareAuthorities/toggleHealthcareAuthorityAutoSubscription';
-import isAutoSubscriptionEnabledSelector from '../../store/selectors/isAutoSubscriptionEnabledSelector';
-import { Switch } from 'react-native-gesture-handler';
-
// For fixing image width issues
const win = Dimensions.get('window');
@@ -71,20 +66,8 @@ const PartnersIllustration = (): JSX.Element => {
const PartnersScreen = ({ navigation }: PartnersScreenProps): JSX.Element => {
const { t } = useTranslation();
- const dispatch = useDispatch();
const navigateToViewHAs = () => navigation.navigate('PartnersEdit');
- const autoSubscriptionEnabled = useSelector(
- isAutoSubscriptionEnabledSelector,
- );
- const onToggleAutoSubscription = (value: boolean) => {
- dispatch(
- toggleHealthcareAuthorityAutoSubscription({
- autoSubscriptionEnabled: value,
- }),
- );
- };
-
return (
{
- {__DEV__ && (
-
-
- {t('authorities.automatically_follow')}
-
-
-
-
- )}
);
};
@@ -160,15 +123,6 @@ const styles = StyleSheet.create({
backgroundColor: Colors.primaryBackground,
flex: 1,
},
- bottomSheet: {
- backgroundColor: Colors.bottomSheetBackground,
- padding: 24,
- flexDirection: 'row',
- justifyContent: 'space-between',
- alignItems: 'center',
- borderTopWidth: StyleSheet.hairlineWidth,
- borderTopColor: Colors.formInputBorder,
- },
divider: {
height: 1,
backgroundColor: Colors.formInputBorder,
diff --git a/app/views/main/AllServicesOn.tsx b/app/views/main/AllServicesOn.tsx
index 30bdd67b38..85fb65f57c 100644
--- a/app/views/main/AllServicesOn.tsx
+++ b/app/views/main/AllServicesOn.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect, useCallback } from 'react';
+import React, { useEffect } from 'react';
import {
Dimensions,
ImageBackground,
@@ -9,75 +9,45 @@ import {
import { useTranslation } from 'react-i18next';
import Pulse from 'react-native-pulse';
import { SvgXml } from 'react-native-svg';
-import Geolocation from '@react-native-community/geolocation';
import { Icons, Images } from '../../assets';
import { Typography } from '../../components/Typography';
import { styles } from './style';
-import { Colors } from '../../styles';
+import { Colors, Spacing } from '../../styles';
import { Stacks, NavigationProp } from '../../navigation';
import { useSelector, useDispatch } from 'react-redux';
-import isAutoSubscriptionEnabledSelector from '../../store/selectors/isAutoSubscriptionEnabledSelector';
-import getHealthcareAuthorities from '../../store/actions/healthcareAuthorities/getHealthcareAuthoritiesAction';
import { RootState } from '../../store/types';
+import toggleAutoSubscriptionBanner from '../../store/actions/healthcareAuthorities/toggleAutoSubscriptionBannerAction';
type AllServicesOnProps = {
- noHaAvailable: boolean;
navigation: NavigationProp;
};
-const useAutoSubscriptionBanner = (
- showAutoSubscribeBanner: boolean,
- navigation: NavigationProp,
-) => {
- const [showBanner, setShowBanner] = useState(showAutoSubscribeBanner);
-
- useEffect(() => {
- const listener = navigation.addListener('blur', () => setShowBanner(false));
-
- return listener.remove;
- }, [navigation]);
-
- return {
- showBanner,
- };
-};
-
export const AllServicesOnScreen = ({
- noHaAvailable,
navigation,
}: AllServicesOnProps): JSX.Element => {
const size = Dimensions.get('window').height;
const { t } = useTranslation();
- const dispatch = useDispatch();
-
- const [userAutoSubscribed, setUserAutoSubscribed] = useState(false);
- const { showBanner } = useAutoSubscriptionBanner(true, navigation);
- const haName = useSelector(
- (state: RootState) =>
- state.healthcareAuthorities.selectedAuthorities[0]?.name,
+ const { autoSubscription, selectedAuthorities } = useSelector(
+ (state: RootState) => state.healthcareAuthorities,
);
- const autoSubscriptionEnabled = useSelector(
- isAutoSubscriptionEnabledSelector,
- );
-
- const autoSubscribe = useCallback(async () => {
- if (autoSubscriptionEnabled && noHaAvailable && !userAutoSubscribed) {
- Geolocation.getCurrentPosition(({ coords }) => {
- dispatch(
- getHealthcareAuthorities({ autoSubscriptionLocation: coords }),
- );
- setUserAutoSubscribed(true);
- });
- }
- }, [autoSubscriptionEnabled, noHaAvailable, userAutoSubscribed, dispatch]);
-
+ const dispatch = useDispatch();
useEffect(() => {
- autoSubscribe();
- }, [autoSubscribe]);
+ const listener = navigation.addListener('blur', () => {
+ if (
+ !autoSubscription.bannerDismissed &&
+ autoSubscription.selectedAuthority
+ ) {
+ dispatch(toggleAutoSubscriptionBanner({ overrideValue: false }));
+ }
+ });
+ return listener.remove;
+ }, [navigation, dispatch, autoSubscription]);
+
+ const { bannerDismissed, selectedAuthority } = autoSubscription;
return (
@@ -115,7 +85,7 @@ export const AllServicesOnScreen = ({
{t('home.gps.all_services_on_subheader')}
- {noHaAvailable && (
+ {selectedAuthorities.length === 0 && (
{t('home.gps.all_services_on_no_ha_available')}
@@ -123,29 +93,27 @@ export const AllServicesOnScreen = ({
- {showBanner && (
-
-
- <>
- {t('home.gps.auto_subscribe_text', {
- healthAuthorityName: haName,
- })}
- navigation.navigate(Stacks.Partners)}>
- {t('home.gps.auto_subscribe_link_text')}
-
- >
-
-
- navigation.navigate(Stacks.Partners)}>
-
-
-
+ {!bannerDismissed && !!selectedAuthority && (
+ navigation.navigate(Stacks.Partners)}>
+
+
+ <>
+ {t('home.gps.auto_subscribe_text', {
+ healthAuthorityName: selectedAuthority.name,
+ })}
+
+ {t('home.gps.auto_subscribe_link_text')}
+
+ >
+
+
+
+
)}
);
diff --git a/app/views/main/ServiceOffScreens/SelectAuthority.tsx b/app/views/main/ServiceOffScreens/SelectAuthority.tsx
index 51bd5bcb33..72da9442c5 100644
--- a/app/views/main/ServiceOffScreens/SelectAuthority.tsx
+++ b/app/views/main/ServiceOffScreens/SelectAuthority.tsx
@@ -3,14 +3,14 @@ import { useNavigation } from '@react-navigation/native';
import { useTranslation } from 'react-i18next';
import { ServiceOffScreen } from './Base';
-import { Screens } from '../../../navigation';
+import { Stacks } from '../../../navigation';
export const SelectAuthorityScreen = (): JSX.Element => {
const { t } = useTranslation();
const navigation = useNavigation();
const onPress = () => {
- navigation.navigate(Screens.PartnersEdit);
+ navigation.navigate(Stacks.Partners);
};
return (
diff --git a/app/views/main/ServiceOffScreens/__tests__/__snapshots__/SelectAuthority.spec.js.snap b/app/views/main/ServiceOffScreens/__tests__/__snapshots__/SelectAuthority.spec.js.snap
index fb747a138f..633137fd96 100644
--- a/app/views/main/ServiceOffScreens/__tests__/__snapshots__/SelectAuthority.spec.js.snap
+++ b/app/views/main/ServiceOffScreens/__tests__/__snapshots__/SelectAuthority.spec.js.snap
@@ -159,7 +159,7 @@ exports[`select authority screen matches snapshot 1`] = `
]
}
>
- Allow PathCheck to add your local Health Department or select one yourself to receive info about COVID-19 in your area
+ Select your local Health Department to receive info about COVID-19 in your area
PathCheck is saving the places you visit to create your private location diary
-
-
-
-
- You’ve been auto-subscribed to .
- Click here to change.
+ You will not receive exposure notifications while you are outside a region served by Health Department partners
-
-
-
-
-
-
-"
- />
-
+
diff --git a/app/views/main/style.ts b/app/views/main/style.ts
index cda0115395..53bf288473 100644
--- a/app/views/main/style.ts
+++ b/app/views/main/style.ts
@@ -75,6 +75,8 @@ export const styles = StyleSheet.create({
paddingLeft: 20,
},
bottomSheet: {
+ position: 'absolute',
+ bottom: 0,
backgroundColor: Colors.bottomSheetBackground,
padding: 24,
flexDirection: 'row',
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index cb37c2f933..99ef4153f0 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -522,4 +522,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: a70cd2a7867b1a342049fd907a0dace84082799b
-COCOAPODS: 1.9.3
+COCOAPODS: 1.9.1