Skip to content

Commit

Permalink
feat(Firma con IO): [SFEQS-1378] Update main app navigator stack to e…
Browse files Browse the repository at this point in the history
…nable FCI deeplink (#4568)

### ⚠️ This PR depends on #4152 

## Short description
This PR updates main app navigator stack adding FCI deep linking
support. This PR remove some checks related to FCI feat flag to avoid an
error during startup when backendStatus remote info not yet
synchronised. The logic is moved in FciRouterScreen.tsx.

[refs.
[https://reactnavigation.org/docs/5.x/deep-linking](https://reactnavigation.org/docs/5.x/deep-linking)]

## List of changes proposed in this pull request
- Update FciRouterScreen
- Update AppStackNavigator
- Update startup saga

## How to test
Using `io-dev-api-server` try to start a signing flow via deeplink. To
do this we have to know the ID of a signature request. This should be
read using tools like reacttotron navigating under the
features.fci.signatureRequest state after starting a signing flow from a
WAIT_FOR_SIGNATURE message. With the SIGNATURE_REQUEST_ID it should be
possibile to start a signing flow via deeplink launching from terminal:
```bash
xcrun simctl openurl booted "ioit://fci/main?signatureRequestId=01GX8RW869W2CFXCKKET4M6ZK9"
```
The test should be done with:
- app opened
- app closed
- app terminated

---------

Co-authored-by: Cristiano Tofani <[email protected]>
Co-authored-by: Andrea Piai <[email protected]>
Co-authored-by: Luca Cavallaro <[email protected]>
  • Loading branch information
4 people authored May 3, 2023
1 parent 080aecc commit 0326230
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 26 deletions.
20 changes: 10 additions & 10 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,7 @@
<!-- Required for local notifications -->
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />

<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:usesCleartextTraffic="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:requestLegacyExternalStorage="true"
android:theme="@style/AppTheme">
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:usesCleartextTraffic="true" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:requestLegacyExternalStorage="true" android:theme="@style/AppTheme">

<!-- START Required by react-native-push-notification -->

Expand Down Expand Up @@ -111,7 +103,7 @@
<!-- END Zendesk -->

<activity android:name=".MainActivity" android:launchMode="singleTask" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:windowSoftInputMode="adjustResize" android:exported="true">
<intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Expand All @@ -122,6 +114,14 @@
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="ioit" android:host="ioit" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
<data android:host="continua.io.pagopa.it" />
</intent-filter>
</activity>
</application>

Expand Down
7 changes: 7 additions & 0 deletions ios/ItaliaApp/AppDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,11 @@ - (BOOL)application:(UIApplication *)application
{
return [RCTLinkingManager application:application openURL:url options:options];
}
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
return [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
@end
12 changes: 8 additions & 4 deletions ios/ItaliaApp/ItaliaApp.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:continua.io.pagopa.it</string>
</array>
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>TAG</string>
<string>NDEF</string>
</array>
<array>
<string>TAG</string>
<string>NDEF</string>
</array>
</dict>
</plist>
21 changes: 19 additions & 2 deletions ts/features/fci/screens/FciRouterScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { LoadingErrorComponent } from "../../bonus/bonusVacanze/components/loadi
import SuccessComponent from "../components/SuccessComponent";
import GenericErrorComponent from "../components/GenericErrorComponent";
import { withValidatedEmail } from "../../../components/helpers/withValidatedEmail";
import { isFciEnabledSelector } from "../../../store/reducers/backendStatus";
import { isTestEnv } from "../../../utils/environment";
import {
NetworkError,
getErrorFromNetworkError,
Expand All @@ -33,10 +35,25 @@ const FciSignatureScreen = (
const signatureRequestId = props.route.params.signatureRequestId;
const dispatch = useIODispatch();
const fciSignatureRequest = useIOSelector(fciSignatureRequestSelector);
const fciEnabledSelector = useIOSelector(isFciEnabledSelector);
const fciEnabled = isTestEnv || fciEnabledSelector;

React.useEffect(() => {
dispatch(fciSignatureRequestFromId.request(signatureRequestId));
}, [dispatch, signatureRequestId]);
if (fciEnabled) {
dispatch(fciSignatureRequestFromId.request(signatureRequestId));
}
}, [dispatch, signatureRequestId, fciEnabled]);

if (!fciEnabled) {
return (
<GenericErrorComponent
title={I18n.t("features.fci.errors.generic.update.title")}
subTitle={I18n.t("features.fci.errors.generic.update.subTitle")}
onPress={() => dispatch(fciEndRequest())}
testID="GenericErrorComponentTestID"
/>
);
}

const LoadingComponent = () => (
<LoadingErrorComponent
Expand Down
11 changes: 6 additions & 5 deletions ts/navigation/AppStackNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ import { trackScreen } from "../store/middlewares/navigation";
import {
bpdRemoteConfigSelector,
isCGNEnabledSelector,
isFciEnabledSelector,
isIdPayEnabledSelector,
isFIMSEnabledSelector
} from "../store/reducers/backendStatus";
import { isTestEnv } from "../utils/environment";
import { startApplicationInitialization } from "../store/actions/application";
import { StartupStatusEnum, isStartupLoaded } from "../store/reducers/startup";
import { IO_INTERNAL_LINK_PREFIX } from "../utils/navigation";
import {
IO_INTERNAL_LINK_PREFIX,
IO_UNIVERSAL_LINK_PREFIX
} from "../utils/navigation";
import NavigationService, { navigationRef } from "./NavigationService";
import ROUTES from "./routes";
import AuthenticatedStackNavigator from "./AuthenticatedStackNavigator";
Expand Down Expand Up @@ -77,7 +79,6 @@ const InnerNavigationContainer = (props: { children: React.ReactElement }) => {

const cgnEnabled = useIOSelector(isCGNEnabledSelector);
const isFimsEnabled = useIOSelector(isFIMSEnabledSelector) && fimsEnabled;
const isFciEnabled = useIOSelector(isFciEnabledSelector);
const isIdPayEnabled = useIOSelector(isIdPayEnabledSelector);

const bpdRemoteConfig = useIOSelector(bpdRemoteConfigSelector);
Expand All @@ -86,7 +87,7 @@ const InnerNavigationContainer = (props: { children: React.ReactElement }) => {

const linking: LinkingOptions = {
enabled: !isTestEnv, // disable linking in test env
prefixes: [IO_INTERNAL_LINK_PREFIX],
prefixes: [IO_INTERNAL_LINK_PREFIX, IO_UNIVERSAL_LINK_PREFIX],
config: {
initialRouteName: ROUTES.MAIN,
screens: {
Expand Down Expand Up @@ -139,9 +140,9 @@ const InnerNavigationContainer = (props: { children: React.ReactElement }) => {
...(svEnabled && svLinkingOptions)
}
},
...fciLinkingOptions,
...(isFimsEnabled ? fimsLinkingOptions : {}),
...(cgnEnabled ? cgnLinkingOptions : {}),
...(isFciEnabled ? fciLinkingOptions : {}),
...(isIdPayEnabled ? idPayLinkingOptions : {}),
[UADONATION_ROUTES.WEBVIEW]: "uadonations-webview",
[ROUTES.WORKUNIT_GENERIC_FAILURE]: "*"
Expand Down
1 change: 1 addition & 0 deletions ts/navigation/AuthenticatedStackNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ const AuthenticatedStackNavigator = () => {
component={IDPayConfigurationNavigator}
options={{ gestureEnabled: isGestureEnabled }}
/>

<Stack.Screen
name={IDPayUnsubscriptionRoutes.IDPAY_UNSUBSCRIPTION_MAIN}
component={IDPayUnsubscriptionNavigator}
Expand Down
2 changes: 2 additions & 0 deletions ts/sagas/__tests__/initializeApplicationSaga.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ describe("initializeApplicationSaga", () => {
.next()
.next()
.next()
.next()
.select(sessionInfoSelector)
.next(O.none)
.next(O.none) // loadSessionInformationSaga
Expand Down Expand Up @@ -188,6 +189,7 @@ describe("initializeApplicationSaga", () => {
.next()
.next()
.next()
.next()
.select(sessionInfoSelector)
.next(
O.some({
Expand Down
9 changes: 4 additions & 5 deletions ts/sagas/startup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {
bpdEnabled,
cdcEnabled,
euCovidCertificateEnabled,
fciEnabled,
mvlEnabled,
pagoPaApiUrlPrefix,
pagoPaApiUrlPrefixTest,
Expand Down Expand Up @@ -302,6 +301,9 @@ export function* initializeApplicationSaga(): Generator<
backendClient.upsertMessageStatusAttributes
);

// watch FCI saga
yield* fork(watchFciSaga, sessionToken, keyInfo);

// whether we asked the user to login again
const isSessionRefreshed = previousSessionToken !== sessionToken;

Expand Down Expand Up @@ -519,10 +521,6 @@ export function* initializeApplicationSaga(): Generator<
yield* fork(watchIDPaySaga, maybeSessionInformation.value.bpdToken);
}

if (fciEnabled) {
yield* fork(watchFciSaga, sessionToken, keyInfo);
}

// Load the user metadata
yield* call(loadUserMetadata, backendClient.getUserMetadata, true);

Expand Down Expand Up @@ -599,6 +597,7 @@ export function* initializeApplicationSaga(): Generator<
loadUserDataProcessing.request(UserDataProcessingChoiceEnum.DELETE)
);
}

// Load visible services and service details from backend when requested
yield* fork(watchLoadServicesSaga, backendClient);

Expand Down
2 changes: 2 additions & 0 deletions ts/utils/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { Platform } from "react-native";
export const IO_INTERNAL_LINK_PROTOCOL = "ioit:";
export const IO_INTERNAL_LINK_PREFIX = IO_INTERNAL_LINK_PROTOCOL + "//";

export const IO_UNIVERSAL_LINK_PREFIX = "https://continua.io.pagopa.it";

export const convertUrlToNavigationLink = (path: string) =>
path.replace(IO_INTERNAL_LINK_PREFIX, "/");

Expand Down

0 comments on commit 0326230

Please sign in to comment.