diff --git a/package.json b/package.json index dd2e15c0ce0..782c939e669 100644 --- a/package.json +++ b/package.json @@ -175,7 +175,7 @@ "ts-jest": "^25.1.0", "ts-node": "^7.0.1", "tslint": "5.20.0", - "typescript": "3.4.1" + "typescript": "^3.9.7" }, "resolutions": { "@types/react": "16.7.18", diff --git a/patches/@types+react-native-text-input-mask+0.7.2.patch b/patches/@types+react-native-text-input-mask+0.7.2.patch new file mode 100644 index 00000000000..d2928d810f3 --- /dev/null +++ b/patches/@types+react-native-text-input-mask+0.7.2.patch @@ -0,0 +1,23 @@ +diff --git a/node_modules/@types/react-native-text-input-mask/index.d.ts b/node_modules/@types/react-native-text-input-mask/index.d.ts +index 4cf4b39..8eacdbc 100644 +--- a/node_modules/@types/react-native-text-input-mask/index.d.ts ++++ b/node_modules/@types/react-native-text-input-mask/index.d.ts +@@ -4,6 +4,7 @@ + // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + // TypeScript Version: 2.8 + ++import {MutableRefObject} from "react"; + import * as React from "react"; + import * as ReactNative from "react-native"; + +@@ -221,6 +222,10 @@ export interface TextInputMaskProps extends ReactNative.ViewProps, ReactNative.T + * or set/update maxLength to prevent unwanted edits without flicker. + */ + value?: string; ++ ++ // Patch: Adding missing types ref and isNumericSecureKeyboard ++ ref?: ((instance: TextInputMask | null) => void) | MutableRefObject | null; ++ isNumericSecureKeyboard?: boolean, + } + + export default class TextInputMask extends React.Component { } diff --git a/patches/patches.md b/patches/patches.md index c81551db0c8..bc3116df7d1 100644 --- a/patches/patches.md +++ b/patches/patches.md @@ -68,3 +68,10 @@ Created on **12/08/2020** #### Reason: - Use TouchableHighlight instead of TouchableNativeFeedback on Android sdk < 19 to avoid crash. + + +### @types/react-native-text-input-mask+0.7.2 +Created on **13/08/2020** + +#### Reason: +- Add missing props types for TextInputMaskProps. diff --git a/ts/components/FlagSecure.tsx b/ts/components/FlagSecure.tsx index c313398fb86..d000f2035ac 100644 --- a/ts/components/FlagSecure.tsx +++ b/ts/components/FlagSecure.tsx @@ -32,7 +32,4 @@ const mapStateToProps = (state: GlobalState) => ({ isAllowedSnapshotCurrentScreen: isAllowedSnapshotCurrentScreen(state) }); -export default connect( - mapStateToProps, - null -)(FlagSecureComponent); +export default connect(mapStateToProps)(FlagSecureComponent); diff --git a/ts/components/screens/DarkLayout.tsx b/ts/components/screens/DarkLayout.tsx index 1ae4758d8a3..f59036b6d41 100644 --- a/ts/components/screens/DarkLayout.tsx +++ b/ts/components/screens/DarkLayout.tsx @@ -1,15 +1,15 @@ /** * A component to display a brandDarkGray background color on the screen using it */ -import { View } from "native-base"; +import { Content, View } from "native-base"; import * as React from "react"; import { + Animated, ImageSourcePropType, - RefreshControlProps, StyleProp, + StyleSheet, ViewStyle } from "react-native"; -import { StyleSheet } from "react-native"; import LinearGradient from "react-native-linear-gradient"; import { IconProps } from "react-native-vector-icons/Icon"; import customVariables from "../../theme/variables"; @@ -41,7 +41,7 @@ type Props = Readonly<{ footerContent?: React.ReactNode; contextualHelp?: ContextualHelpProps; contextualHelpMarkdown?: ContextualHelpPropsMarkdown; - contentRefreshControl?: React.ReactElement; + contentRefreshControl?: Animated.ComponentProps["refreshControl"]; faqCategories?: ReadonlyArray; customGoBack?: React.ReactNode; gradientHeader?: boolean; diff --git a/ts/components/screens/ScreenContent.tsx b/ts/components/screens/ScreenContent.tsx index 01a1cbb2b25..a1d0764dfac 100644 --- a/ts/components/screens/ScreenContent.tsx +++ b/ts/components/screens/ScreenContent.tsx @@ -1,8 +1,8 @@ import { Content } from "native-base"; import * as React from "react"; -import { NavigationEvents } from "react-navigation"; -import { RefreshControlProps, StyleProp, ViewStyle } from "react-native"; +import { StyleProp, ViewStyle } from "react-native"; +import { NavigationEvents } from "react-navigation"; import { ComponentProps } from "../../types/react"; import { ScreenContentHeader } from "./ScreenContentHeader"; @@ -10,7 +10,7 @@ interface OwnProps { hideHeader?: boolean; contentStyle?: StyleProp; bounces?: boolean; - contentRefreshControl?: React.ReactElement; + contentRefreshControl?: ComponentProps["refreshControl"]; } type Props = OwnProps & ComponentProps; diff --git a/ts/components/wallet/WalletLayout.tsx b/ts/components/wallet/WalletLayout.tsx index 124b16036e1..345388a858c 100644 --- a/ts/components/wallet/WalletLayout.tsx +++ b/ts/components/wallet/WalletLayout.tsx @@ -8,14 +8,9 @@ * footer with a button for starting a new payment */ -import { Text, View } from "native-base"; +import { Content, Text, View } from "native-base"; import * as React from "react"; -import { - RefreshControlProps, - StyleProp, - StyleSheet, - ViewStyle -} from "react-native"; +import { Animated, StyleProp, StyleSheet, ViewStyle } from "react-native"; import I18n from "../../i18n"; import customVariables from "../../theme/variables"; import { FAQsCategoriesType } from "../../utils/faq"; @@ -36,7 +31,7 @@ type Props = Readonly<{ hideHeader?: boolean; footerContent?: React.ReactNode; contentStyle?: StyleProp; - refreshControl?: React.ReactElement; + refreshControl?: Animated.ComponentProps["refreshControl"]; contextualHelp?: ContextualHelpProps; contextualHelpMarkdown?: ContextualHelpPropsMarkdown; faqCategories?: ReadonlyArray; diff --git a/ts/features/bonusVacanze/store/sagas/activation/getBonusActivationSaga.ts b/ts/features/bonusVacanze/store/sagas/activation/getBonusActivationSaga.ts index 29653ab2fbb..da4127bd0ee 100644 --- a/ts/features/bonusVacanze/store/sagas/activation/getBonusActivationSaga.ts +++ b/ts/features/bonusVacanze/store/sagas/activation/getBonusActivationSaga.ts @@ -36,7 +36,11 @@ function* getBonusActivation( typeof BackendBonusVacanze >["getLatestBonusVacanzeFromId"], bonusId: string -): IterableIterator, BonusActivationWithQrCode>> { +): Generator< + Effect, + Either, BonusActivationWithQrCode>, + SagaCallReturnType +> { try { const getLatestBonusVacanzeFromIdResult: SagaCallReturnType< typeof getLatestBonusVacanzeFromId @@ -49,24 +53,30 @@ function* getBonusActivation( switch (activation.status) { // processing -> polling should continue case BonusActivationStatusEnum.PROCESSING: - return left(none); + return left, BonusActivationWithQrCode>(none); case BonusActivationStatusEnum.FAILED: // blocking error - return left(some(new Error("Bonus Activation failed"))); + return left, BonusActivationWithQrCode>( + some(new Error("Bonus Activation failed")) + ); default: // active - return right(getLatestBonusVacanzeFromIdResult.value.value); + return right, BonusActivationWithQrCode>( + getLatestBonusVacanzeFromIdResult.value.value + ); } } // Request not found - polling must be stopped if (getLatestBonusVacanzeFromIdResult.value.status === 404) { - return left(some(new Error("Bonus Activation not found"))); + return left, BonusActivationWithQrCode>( + some(new Error("Bonus Activation not found")) + ); } // polling should continue - return left(none); + return left, BonusActivationWithQrCode>(none); } else { // we got some error on decoding, stop polling - return left( + return left, BonusActivationWithQrCode>( some( Error(readablePrivacyReport(getLatestBonusVacanzeFromIdResult.value)) ) @@ -74,7 +84,7 @@ function* getBonusActivation( } } catch (e) { // polling should continue - return left(none); + return left, BonusActivationWithQrCode>(none); } } @@ -87,8 +97,10 @@ export const bonusActivationSaga = ( typeof BackendBonusVacanze >["getLatestBonusVacanzeFromId"] ) => - function* startBonusActivationSaga(): IterableIterator< - Effect | ActionType + function* startBonusActivationSaga(): Generator< + Effect, + ActionType, + any > { try { const startBonusActivationProcedureResult: SagaCallReturnType< diff --git a/ts/features/bonusVacanze/store/sagas/eligibility/getBonusEligibilitySaga.ts b/ts/features/bonusVacanze/store/sagas/eligibility/getBonusEligibilitySaga.ts index 331bb0db573..0ccfb7fd7fd 100644 --- a/ts/features/bonusVacanze/store/sagas/eligibility/getBonusEligibilitySaga.ts +++ b/ts/features/bonusVacanze/store/sagas/eligibility/getBonusEligibilitySaga.ts @@ -58,7 +58,11 @@ function* getCheckBonusEligibilitySaga( getBonusEligibilityCheck: ReturnType< typeof BackendBonusVacanze >["getBonusEligibilityCheck"] -): IterableIterator, EligibilityCheck>> { +): Generator< + Effect, + Either, EligibilityCheck>, + SagaCallReturnType +> { try { const eligibilityCheckResult: SagaCallReturnType< typeof getBonusEligibilityCheck @@ -68,18 +72,18 @@ function* getCheckBonusEligibilitySaga( // 200 -> we got the check result, polling must be stopped if (eligibilityCheckResult.value.status === 200) { const check = eligibilityCheckResult.value.value; - return right(check); + return right, EligibilityCheck>(check); } // polling should continue - return left(none); + return left, EligibilityCheck>(none); } else { // we got some error on decoding, stop polling - return left( + return left, EligibilityCheck>( some(Error(readablePrivacyReport(eligibilityCheckResult.value))) ); } } catch (e) { - return left(none); + return left, EligibilityCheck>(none); } } @@ -105,8 +109,10 @@ export const bonusEligibilitySaga = ( typeof BackendBonusVacanze >["getBonusEligibilityCheck"] ) => - function* getBonusEligibilitySaga(): IterableIterator< - Effect | ActionType + function* getBonusEligibilitySaga(): Generator< + Effect, + ActionType, + any > { try { const startEligibilityResult: SagaCallReturnType< diff --git a/ts/sagas/backendInfo.ts b/ts/sagas/backendInfo.ts index 59169ab4e88..861374bcfcf 100644 --- a/ts/sagas/backendInfo.ts +++ b/ts/sagas/backendInfo.ts @@ -21,7 +21,11 @@ const BACKEND_INFO_LOAD_INTERVAL = 60 * 60 * 1000; // retry loading backend info every 10 seconds on error const BACKEND_INFO_RETRY_INTERVAL = 10 * 1000; -function* backendInfoWatcher(): IterableIterator { +function* backendInfoWatcher(): Generator< + Effect, + void, + SagaCallReturnType +> { const backendPublicClient = BackendPublicClient(apiUrlPrefix); function getServerInfo(): Promise< @@ -36,9 +40,7 @@ function* backendInfoWatcher(): IterableIterator { while (true) { try { - const backendInfoResponse: SagaCallReturnType< - typeof getServerInfo - > = yield call(getServerInfo); + const backendInfoResponse = yield call(getServerInfo); if ( backendInfoResponse.isRight() && backendInfoResponse.value.status === 200 diff --git a/ts/sagas/backendStatus.ts b/ts/sagas/backendStatus.ts index 5cd784ebd8f..6cad9269476 100644 --- a/ts/sagas/backendStatus.ts +++ b/ts/sagas/backendStatus.ts @@ -16,12 +16,9 @@ const BACKEND_SERVICES_STATUS_FAILURE_INTERVAL = (10 * 1000) as Millisecond; // Return true if it has information (200) false otherwise export function* backendStatusSaga( getServicesStatus: ReturnType["getStatus"] -): IterableIterator { +): Generator> { try { - const response: SagaCallReturnType = yield call( - getServicesStatus, - {} - ); + const response = yield call(getServicesStatus, {}); if (response.isRight() && response.value.status === 200) { yield put(backendStatusLoadSuccess(response.value.value)); return true; @@ -40,7 +37,7 @@ export function* backendStatusSaga( */ export function* backendStatusWatcherLoop( getStatus: ReturnType["getStatus"] -): IterableIterator { +) { // check backend status periodically while (true) { const response: SagaCallReturnType = yield call( diff --git a/ts/sagas/contentLoaders.ts b/ts/sagas/contentLoaders.ts index 58f44b833f7..8487881d99c 100644 --- a/ts/sagas/contentLoaders.ts +++ b/ts/sagas/contentLoaders.ts @@ -140,7 +140,11 @@ function* watchServiceMetadataLoadSaga( function* fetchMunicipalityMetadata( getMunicipality: ReturnType["getMunicipality"], codiceCatastale: CodiceCatastale -): IterableIterator> { +): Generator< + Effect, + Either, + SagaCallReturnType +> { try { const response: SagaCallReturnType = yield call( getMunicipality, @@ -153,9 +157,9 @@ function* fetchMunicipalityMetadata( if (response.value.status !== 200) { throw Error(`response status ${response.value.status}`); } - return right(response.value.value); + return right(response.value.value); } catch (error) { - return left(error); + return left(error); } } diff --git a/ts/sagas/identification.ts b/ts/sagas/identification.ts index 4e868528f1b..e9a14c2f581 100644 --- a/ts/sagas/identification.ts +++ b/ts/sagas/identification.ts @@ -47,7 +47,11 @@ type ResultAction = | ActionType | ActionType; // Wait the identification and return the result -function* waitIdentificationResult(): Iterator { +function* waitIdentificationResult(): Generator< + Effect, + void | IdentificationResult, + any +> { const resultAction: ResultAction = yield take([ getType(identificationCancel), getType(identificationPinReset), @@ -136,7 +140,7 @@ export function* startAndReturnIdentificationResult( function* startAndHandleIdentificationResult( pin: PinString, identificationRequestAction: ActionType -): IterableIterator { +) { yield put( identificationStart( pin, diff --git a/ts/sagas/instabug.ts b/ts/sagas/instabug.ts index 4fb5e5f30a0..34144627429 100644 --- a/ts/sagas/instabug.ts +++ b/ts/sagas/instabug.ts @@ -4,7 +4,6 @@ import { instabugUnreadMessagesLoaded, updateInstabugUnreadMessages } from "../store/actions/instabug"; -import { SagaCallReturnType } from "../types/utils"; const loadInstabugUnreadMessages = () => { return new Promise(resolve => { @@ -31,10 +30,8 @@ function* watchInstabugSaga(): IterableIterator { } } -function* updateInstabugBadgeSaga(): IterableIterator { - const repliesCount: SagaCallReturnType< - typeof loadInstabugUnreadMessages - > = yield call(loadInstabugUnreadMessages); +function* updateInstabugBadgeSaga(): Generator { + const repliesCount = yield call(loadInstabugUnreadMessages); yield put(instabugUnreadMessagesLoaded(repliesCount)); } diff --git a/ts/sagas/installation.ts b/ts/sagas/installation.ts index ecf9911d54c..8e453eedca2 100644 --- a/ts/sagas/installation.ts +++ b/ts/sagas/installation.ts @@ -12,8 +12,10 @@ import { deletePin } from "../utils/keychain"; * This generator function removes user data from previous application * installation */ -export function* previousInstallationDataDeleteSaga(): IterableIterator< - Effect +export function* previousInstallationDataDeleteSaga(): Generator< + Effect, + void, + boolean > { const isFirstRunAfterInstall: ReturnType< typeof isFirstRunAfterInstallSelector diff --git a/ts/sagas/messages/__tests__/messages.test.ts b/ts/sagas/messages/__tests__/messages.test.ts index 0dbc535d8a0..e36f4d4cf4b 100644 --- a/ts/sagas/messages/__tests__/messages.test.ts +++ b/ts/sagas/messages/__tests__/messages.test.ts @@ -1,7 +1,6 @@ import { left, right } from "fp-ts/lib/Either"; import * as t from "io-ts"; -import * as pot from "italia-ts-commons/lib/pot"; import { testSaga } from "redux-saga-test-plan"; import { CreatedMessageWithContentAndAttachments } from "../../../../definitions/backend/CreatedMessageWithContentAndAttachments"; @@ -65,20 +64,6 @@ describe("messages", () => { }); describe("loadMessage test plan", () => { - it("should return the cached message if the message is in the cache", () => { - const getMessage = jest.fn(); - testSaga(loadMessage, getMessage, testMessageWithContent1) - .next() - .next({ - message: pot.some(testMessageWithContent1) - }) - .returns( - right({ - message: pot.some(testMessageWithContent1) - }) - ); - }); - it("should call fetchMessage with the right parameters", () => { const getMessage = jest.fn(); testSaga(loadMessage, getMessage, testMessageWithContent1) diff --git a/ts/sagas/messages/messages.ts b/ts/sagas/messages/messages.ts index 9d498f4953d..895cd914ea8 100644 --- a/ts/sagas/messages/messages.ts +++ b/ts/sagas/messages/messages.ts @@ -17,11 +17,14 @@ import { readablePrivacyReport } from "../../utils/reporters"; /** * A saga to fetch a message from the Backend and save it in the redux store. */ + export function* loadMessage( getMessage: ReturnType["getMessage"], meta: CreatedMessageWithoutContent -): IterableIterator< - Effect | Either +): Generator< + Effect, + Either, + any > { // Load the messages already in the redux store const cachedMessage: ReturnType< @@ -30,7 +33,9 @@ export function* loadMessage( // If we already have the message in the store just return it if (cachedMessage !== undefined && pot.isSome(cachedMessage.message)) { - return right(cachedMessage); + return right( + cachedMessage.message.value + ); } try { // Fetch the message from the Backend @@ -53,7 +58,7 @@ export function* loadMessage( error }) ); - return left(error); + return left(error); } } @@ -63,8 +68,10 @@ export function* loadMessage( export function* fetchMessage( getMessage: ReturnType["getMessage"], meta: CreatedMessageWithoutContent -): IterableIterator< - Effect | Either +): Generator< + Effect, + Either, + any > { try { const response: SagaCallReturnType = yield call( @@ -80,12 +87,14 @@ export function* fetchMessage( ? response.value.value.title : `response status ${response.value.status}`; // Return the error - return left(Error(error)); + return left(Error(error)); } - return right(response.value.value); + return right( + response.value.value + ); } catch (error) { // Return the error - return left(error); + return left(error); } } diff --git a/ts/sagas/notifications.ts b/ts/sagas/notifications.ts index 87c5b1f6815..5d53f164db8 100644 --- a/ts/sagas/notifications.ts +++ b/ts/sagas/notifications.ts @@ -25,8 +25,10 @@ export function* updateInstallationSaga( createOrUpdateInstallation: ReturnType< typeof BackendClient >["createOrUpdateInstallation"] -): Iterator< - Effect | TypeOfApiResponseStatus | undefined +): Generator< + Effect, + TypeOfApiResponseStatus | undefined, + any > { // Get the notifications installation data from the store const notificationsInstallation: ReturnType< diff --git a/ts/sagas/preferences.ts b/ts/sagas/preferences.ts index f4a51b24385..b12a4fc8d15 100644 --- a/ts/sagas/preferences.ts +++ b/ts/sagas/preferences.ts @@ -8,10 +8,11 @@ import { SagaCallReturnType } from "../types/utils"; /** * A saga that retrieves the system languages */ -export function* loadSystemPreferencesSaga(): IterableIterator { - const languages: SagaCallReturnType = yield call( - getLanguages - ); - +export function* loadSystemPreferencesSaga(): Generator< + Effect, + void, + SagaCallReturnType +> { + const languages = yield call(getLanguages); yield put(preferencesLanguagesLoadSuccess(languages)); } diff --git a/ts/sagas/profile.ts b/ts/sagas/profile.ts index 5c5fbbe1cdb..977a239487b 100644 --- a/ts/sagas/profile.ts +++ b/ts/sagas/profile.ts @@ -25,12 +25,13 @@ import { SagaCallReturnType } from "../types/utils"; // A saga to load the Profile. export function* loadProfile( getProfile: ReturnType["getProfile"] -): Iterator> { +): Generator< + Effect, + Option, + SagaCallReturnType +> { try { - const response: SagaCallReturnType = yield call( - getProfile, - {} - ); + const response = yield call(getProfile, {}); // we got an error, throw it if (response.isLeft()) { throw Error(readableReport(response.value)); @@ -63,7 +64,7 @@ function* createOrUpdateProfileSaga( typeof BackendClient >["createOrUpdateProfile"], action: ActionType -): Iterator { +): Generator { // Get the current Profile from the state const profileState: ReturnType = yield select( profileSelector @@ -166,18 +167,19 @@ export function* startEmailValidationProcessSaga( startEmailValidationProcess: ReturnType< typeof BackendClient >["startEmailValidationProcess"] -): Iterator> { +): Generator< + Effect, + void, + SagaCallReturnType +> { try { - const response: SagaCallReturnType< - typeof startEmailValidationProcess - > = yield call(startEmailValidationProcess, {}); + const response = yield call(startEmailValidationProcess, {}); // we got an error, throw it if (response.isLeft()) { throw Error(readableReport(response.value)); } if (response.value.status === 202) { yield put(startEmailValidation.success()); - return some(response.value.value); } if (response.value.status === 401) { // in case we got an expired session while loading the profile, we reset @@ -190,7 +192,6 @@ export function* startEmailValidationProcessSaga( } catch (error) { yield put(startEmailValidation.failure(error)); } - return none; } // This function listens for request to send again the email validation to profile email and calls the needed saga. diff --git a/ts/sagas/startup.ts b/ts/sagas/startup.ts index b02ea05e119..64456fd48d0 100644 --- a/ts/sagas/startup.ts +++ b/ts/sagas/startup.ts @@ -96,7 +96,7 @@ const WAIT_INITIALIZE_SAGA = 3000 as Millisecond; * Handles the application startup and the main application logic loop */ // tslint:disable-next-line:cognitive-complexity no-big-function -export function* initializeApplicationSaga(): IterableIterator { +export function* initializeApplicationSaga(): Generator { // Remove explicitly previous session data. This is done as completion of two // use cases: // 1. Logout with data reset diff --git a/ts/sagas/startup/authenticationSaga.ts b/ts/sagas/startup/authenticationSaga.ts index 3acb958b9df..e0ebe63ea83 100644 --- a/ts/sagas/startup/authenticationSaga.ts +++ b/ts/sagas/startup/authenticationSaga.ts @@ -14,7 +14,7 @@ import { stopCieManager, watchCieAuthenticationSaga } from "../cie"; * A saga that makes the user go through the authentication process until * a SessionToken gets produced. */ -export function* authenticationSaga(): IterableIterator { +export function* authenticationSaga(): Generator { yield put(analyticsAuthenticationStarted()); // Watch for login by CIE diff --git a/ts/sagas/startup/checkAcceptedTosSaga.ts b/ts/sagas/startup/checkAcceptedTosSaga.ts index b66b0e804a4..e88f880891f 100644 --- a/ts/sagas/startup/checkAcceptedTosSaga.ts +++ b/ts/sagas/startup/checkAcceptedTosSaga.ts @@ -9,7 +9,12 @@ import { isProfileFirstOnBoarding } from "../../store/reducers/profile"; export function* checkAcceptedTosSaga( userProfile: InitializedProfile -): IterableIterator { +): Generator< + Effect, + void, + | ActionType + | ActionType +> { // The user has to explicitly accept the new version of ToS if: // - this is the first access // - the user profile stores the user accepted an old version of ToS @@ -37,9 +42,7 @@ export function* checkAcceptedTosSaga( */ if (userProfile.has_profile) { yield put(profileUpsert.request({ accepted_tos_version: tosVersion })); - const action: - | ActionType - | ActionType = yield take([ + const action = yield take([ getType(profileUpsert.success), getType(profileUpsert.failure) ]); diff --git a/ts/sagas/startup/checkAcknowledgedFingerprintSaga.ts b/ts/sagas/startup/checkAcknowledgedFingerprintSaga.ts index 453d86a7b29..980bd1d22ba 100644 --- a/ts/sagas/startup/checkAcknowledgedFingerprintSaga.ts +++ b/ts/sagas/startup/checkAcknowledgedFingerprintSaga.ts @@ -20,12 +20,14 @@ export type BiometrySimpleType = * All other cases are treated as a single umbrella case "Unavailable: Not * supported/Others". */ -function* onboardFingerprintIfAvailableSaga(): IterableIterator { +function* onboardFingerprintIfAvailableSaga(): Generator< + Effect, + void, + BiometrySimpleType +> { // Check if user device has biometric recognition feature by trying to // query data from TouchID library - const biometryTypeOrUnsupportedReason: BiometrySimpleType = yield call( - getFingerprintSettings - ); + const biometryTypeOrUnsupportedReason = yield call(getFingerprintSettings); if (biometryTypeOrUnsupportedReason !== "UNAVAILABLE") { // If biometric recognition is available, navigate to the Fingerprint @@ -67,12 +69,16 @@ function* onboardFingerprintIfAvailableSaga(): IterableIterator { * saga that prompts it, otherwise. Consider that, like ToS, this should happen * at first launch of the app ONLY. */ -export function* checkAcknowledgedFingerprintSaga(): IterableIterator { +export function* checkAcknowledgedFingerprintSaga(): Generator< + Effect, + void, + ReturnType +> { // Query system state and check whether the user has already acknowledged biometric // recognition Screen. Consider that, like ToS, this should be displayed once. - const isFingerprintAcknowledged: ReturnType< - typeof isFingerprintAcknowledgedSelector - > = yield select(isFingerprintAcknowledgedSelector); + const isFingerprintAcknowledged = yield select( + isFingerprintAcknowledgedSelector + ); if (!isFingerprintAcknowledged) { // Navigate to the FingerprintScreen and wait for acknowledgment diff --git a/ts/sagas/startup/checkConfiguredPinSaga.ts b/ts/sagas/startup/checkConfiguredPinSaga.ts index 4f9a9b56cd5..50eb099aca2 100644 --- a/ts/sagas/startup/checkConfiguredPinSaga.ts +++ b/ts/sagas/startup/checkConfiguredPinSaga.ts @@ -1,21 +1,17 @@ -import { Option } from "fp-ts/lib/Option"; -import { Effect } from "redux-saga/effects"; -import { call, put, take } from "redux-saga/effects"; +import { call, Effect, put, take } from "redux-saga/effects"; import { ActionType, getType } from "typesafe-actions"; -import { getPin } from "../../utils/keychain"; +import { navigateToOnboardingPinScreenAction } from "../../store/actions/navigation"; +import { createPinSuccess } from "../../store/actions/pinset"; import { PinString } from "../../types/PinString"; -import { navigateToOnboardingPinScreenAction } from "../../store/actions/navigation"; -import { createPinSuccess } from "../../store/actions/pinset"; +import { getPin } from "../../utils/keychain"; -export function* checkConfiguredPinSaga(): IterableIterator< - Effect | PinString -> { +export function* checkConfiguredPinSaga(): Generator { // We check whether the user has already created a unlock code by trying to retrieve // it from the Keychain - const pinCode: Option = yield call(getPin); + const pinCode = yield call(getPin); if (pinCode.isSome()) { return pinCode.value; diff --git a/ts/sagas/startup/checkEmailNotificationPreferencesSaga.ts b/ts/sagas/startup/checkEmailNotificationPreferencesSaga.ts index 6f73cdda807..171c7d71231 100644 --- a/ts/sagas/startup/checkEmailNotificationPreferencesSaga.ts +++ b/ts/sagas/startup/checkEmailNotificationPreferencesSaga.ts @@ -26,8 +26,10 @@ import { profileSelector, ProfileState } from "../../store/reducers/profile"; * A saga to match at the first startup if the user has customized settings related to the * forwarding of notifications on the verified email within previous installations */ -export function* watchEmailNotificationPreferencesSaga(): IterableIterator< - Effect +export function* watchEmailNotificationPreferencesSaga(): Generator< + Effect, + void, + any > { const isCustomEmailChannelEnabled: ReturnType< typeof isCustomEmailChannelEnabledSelector diff --git a/ts/sagas/startup/checkProfileEnabledSaga.ts b/ts/sagas/startup/checkProfileEnabledSaga.ts index 210ef65f776..b881c5a0680 100644 --- a/ts/sagas/startup/checkProfileEnabledSaga.ts +++ b/ts/sagas/startup/checkProfileEnabledSaga.ts @@ -12,7 +12,12 @@ import { export function* checkProfileEnabledSaga( profile: InitializedProfile -): IterableIterator { +): Generator< + Effect, + void, + | ActionType + | ActionType +> { if ( isProfileFirstOnBoarding(profile) && (!hasProfileEmail(profile) || @@ -26,9 +31,7 @@ export function* checkProfileEnabledSaga( is_webhook_enabled: true }) ); - const action: - | ActionType - | ActionType = yield take([ + const action = yield take([ getType(profileUpsert.success), getType(profileUpsert.failure) ]); diff --git a/ts/sagas/startup/loadServiceDetailRequestHandler.ts b/ts/sagas/startup/loadServiceDetailRequestHandler.ts index 475473c9d67..49f92b21a84 100644 --- a/ts/sagas/startup/loadServiceDetailRequestHandler.ts +++ b/ts/sagas/startup/loadServiceDetailRequestHandler.ts @@ -17,12 +17,9 @@ import { handleServiceReadabilitySaga } from "../services/handleServiceReadabili export function* loadServiceDetailRequestHandler( getService: ReturnType["getService"], action: ActionType -): IterableIterator { +): Generator> { try { - const response: SagaCallReturnType = yield call( - getService, - { service_id: action.payload } - ); + const response = yield call(getService, { service_id: action.payload }); if (response.isLeft()) { throw Error(readableReport(response.value)); diff --git a/ts/sagas/startup/loadSessionInformationSaga.ts b/ts/sagas/startup/loadSessionInformationSaga.ts index b433648d4f6..31e8f624363 100644 --- a/ts/sagas/startup/loadSessionInformationSaga.ts +++ b/ts/sagas/startup/loadSessionInformationSaga.ts @@ -22,13 +22,14 @@ import { SagaCallReturnType } from "../../types/utils"; */ export function* loadSessionInformationSaga( getSession: ReturnType["getSession"] -): IterableIterator> { +): Generator< + Effect, + Option, + SagaCallReturnType +> { try { // Call the Backend service - const response: SagaCallReturnType = yield call( - getSession, - {} - ); + const response = yield call(getSession, {}); // Ko we got an error if (response.isLeft()) { throw readableReport(response.value); diff --git a/ts/sagas/startup/loadVisibleServicesHandler.ts b/ts/sagas/startup/loadVisibleServicesHandler.ts index 5ccc1858fff..e29932f992b 100644 --- a/ts/sagas/startup/loadVisibleServicesHandler.ts +++ b/ts/sagas/startup/loadVisibleServicesHandler.ts @@ -16,12 +16,9 @@ import { removeUnusedStoredServices } from "../services/removeUnusedStoredServic */ export function* loadVisibleServicesRequestHandler( getVisibleServices: ReturnType["getVisibleServices"] -): IterableIterator { +): Generator> { try { - const response: SagaCallReturnType = yield call( - getVisibleServices, - {} - ); + const response = yield call(getVisibleServices, {}); if (response.isLeft()) { throw Error(readableReport(response.value)); } diff --git a/ts/sagas/startup/saveNavigationStateSaga.ts b/ts/sagas/startup/saveNavigationStateSaga.ts index 16071b2c475..a2f8832a1df 100644 --- a/ts/sagas/startup/saveNavigationStateSaga.ts +++ b/ts/sagas/startup/saveNavigationStateSaga.ts @@ -12,10 +12,12 @@ import { navigationStateSelector } from "../../store/reducers/navigation"; * navigation route. * Saving and restoring routes relies on the deep link mechanism. */ -export function* saveNavigationStateSaga(): IterableIterator { - const navigationState: ReturnType< - typeof navigationStateSelector - > = yield select(navigationStateSelector); +export function* saveNavigationStateSaga(): Generator< + Effect, + void, + ReturnType +> { + const navigationState = yield select(navigationStateSelector); const currentRoute = navigationState.routes[ navigationState.index ] as NavigationStateRoute; diff --git a/ts/sagas/startup/watchLoadMessageWithRelationsSaga.ts b/ts/sagas/startup/watchLoadMessageWithRelationsSaga.ts index eef2c6341bf..fa0e546e7f0 100644 --- a/ts/sagas/startup/watchLoadMessageWithRelationsSaga.ts +++ b/ts/sagas/startup/watchLoadMessageWithRelationsSaga.ts @@ -16,7 +16,7 @@ export function* loadMessageWithRelationsSaga( messageWithRelationsLoadRequest: ActionType< typeof loadMessageWithRelations["request"] > -): IterableIterator { +): Generator { // Extract the message id from the action payload const messageId = messageWithRelationsLoadRequest.payload; diff --git a/ts/sagas/startup/watchLoadMessagesSaga.ts b/ts/sagas/startup/watchLoadMessagesSaga.ts index 554e456aaa8..7d8eb704a3a 100644 --- a/ts/sagas/startup/watchLoadMessagesSaga.ts +++ b/ts/sagas/startup/watchLoadMessagesSaga.ts @@ -44,7 +44,7 @@ import { uniqueItem } from "../../utils/enumerables"; // tslint:disable-next-line: cognitive-complexity export function* loadMessages( getMessages: ReturnType["getMessages"] -): IterableIterator { +): Generator { // We are using try...finally to manage task cancellation // @https://redux-saga.js.org/docs/advanced/TaskCancellation.html try { @@ -184,7 +184,7 @@ export function* loadMessages( */ export function* watchMessagesLoadOrCancelSaga( getMessages: ReturnType["getMessages"] -): IterableIterator { +): Generator { // We store the latest task so we can also cancel it // tslint:disable-next-line:no-let let lastTask: Option = none; diff --git a/ts/sagas/user/userMetadata.ts b/ts/sagas/user/userMetadata.ts index 8f8e4ca921f..f284656976b 100644 --- a/ts/sagas/user/userMetadata.ts +++ b/ts/sagas/user/userMetadata.ts @@ -33,12 +33,13 @@ import { SagaCallReturnType } from "../../types/utils"; */ export function* fetchUserMetadata( getUserMetadata: ReturnType["getUserMetadata"] -): IterableIterator> { +): Generator< + Effect, + Either, + SagaCallReturnType +> { try { - const response: SagaCallReturnType = yield call( - getUserMetadata, - {} - ); + const response = yield call(getUserMetadata, {}); // Can't decode response if (response.isLeft()) { @@ -48,18 +49,18 @@ export function* fetchUserMetadata( if (response.value.status !== 200) { if (response.value.status === 204) { // Return an empty object cause profile has no metadata yet (204 === No Content) - return right(emptyUserMetadata); + return right(emptyUserMetadata); } const error = response.value.status === 500 ? response.value.value.title : undefined; // Return the error - return left(Error(error)); + return left(Error(error)); } - return right(response.value.value); + return right(response.value.value); } catch (error) { - return left(error); + return left(error); } } @@ -70,14 +71,19 @@ export function* fetchUserMetadata( export function* loadUserMetadata( getUserMetadata: ReturnType["getUserMetadata"], setLoading: boolean = false -): IterableIterator> { +): Generator< + Effect, + Option, + SagaCallReturnType +> { if (setLoading) { yield put(userMetadataLoad.request()); } - const backendUserMetadataOrError: SagaCallReturnType< - typeof fetchUserMetadata - > = yield call(fetchUserMetadata, getUserMetadata); + const backendUserMetadataOrError = yield call( + fetchUserMetadata, + getUserMetadata + ); if (backendUserMetadataOrError.isLeft()) { yield put(userMetadataLoad.failure(backendUserMetadataOrError.value)); @@ -130,11 +136,13 @@ export function* postUserMetadata( typeof BackendClient >["createOrUpdateUserMetadata"], backendUserMetadata: BackendUserMetadata -): IterableIterator> { +): Generator< + Effect, + Either, + SagaCallReturnType +> { try { - const response: SagaCallReturnType< - typeof createOrUpdateUserMetadata - > = yield call(createOrUpdateUserMetadata, { + const response = yield call(createOrUpdateUserMetadata, { userMetadata: backendUserMetadata }); @@ -147,12 +155,12 @@ export function* postUserMetadata( const error = response.value.status === 500 ? response.value.value.title : undefined; // Return the error - return left(Error(error)); + return left(Error(error)); } - return right(response.value.value); + return right(response.value.value); } catch (error) { - return left(error); + return left(error); } } @@ -166,7 +174,7 @@ export function* upsertUserMetadata( >["createOrUpdateUserMetadata"], userMetadata: UserMetadata, setLoading: boolean = false -): IterableIterator> { +): Generator, any> { if (setLoading) { yield put(userMetadataUpsert.request(userMetadata)); } diff --git a/ts/sagas/wallet.ts b/ts/sagas/wallet.ts index 1795c9df50c..16c70580603 100644 --- a/ts/sagas/wallet.ts +++ b/ts/sagas/wallet.ts @@ -146,7 +146,7 @@ function* startOrResumeAddCreditCardSaga( // prepare a new wallet (payment method) that describes the credit card we // want to add const creditCardWallet: NullableWallet = { - idWallet: null, + idWallet: undefined, type: TypeEnum.CREDIT_CARD, favourite: action.payload.setAsFavorite, creditCard: action.payload.creditCard, @@ -484,7 +484,7 @@ export function* watchWalletSaga( sessionToken: SessionToken, walletToken: string, paymentManagerUrlPrefix: string -): Iterator { +): Generator { // Builds a backend client specifically for the pagopa-proxy endpoints that // need a fetch instance that doesn't retry requests and have longer timeout const pagopaNodoClient = BackendClient( @@ -526,9 +526,7 @@ export function* watchWalletSaga( const pmSessionManager = new SessionManager(getPaymentManagerSession); // check if the current profile (this saga starts only when the user is logged in) // has an email address validated - const isEmailValidated: ReturnType< - typeof isProfileEmailValidatedSelector - > = yield select(isProfileEmailValidatedSelector); + const isEmailValidated = yield select(isProfileEmailValidatedSelector); yield call(pmSessionManager.setSessionEnabled, isEmailValidated); // // Sagas diff --git a/ts/sagas/wallet/pagopaApis.ts b/ts/sagas/wallet/pagopaApis.ts index e5345657421..3833d546a7b 100644 --- a/ts/sagas/wallet/pagopaApis.ts +++ b/ts/sagas/wallet/pagopaApis.ts @@ -63,7 +63,7 @@ function* checkSession(): IterableIterator { export function* fetchWalletsRequestHandler( pagoPaClient: PaymentManagerClient, pmSessionManager: SessionManager -): Iterator { +): Generator { yield call(checkSession); const request = pmSessionManager.withRefresh(pagoPaClient.getWallets); try { @@ -89,7 +89,7 @@ export function* fetchTransactionsRequestHandler( pagoPaClient: PaymentManagerClient, pmSessionManager: SessionManager, action: ActionType -): Iterator { +): Generator { yield call(checkSession); const request = pmSessionManager.withRefresh( pagoPaClient.getTransactions(action.payload.start) @@ -122,7 +122,7 @@ export function* fetchTransactionRequestHandler( pagoPaClient: PaymentManagerClient, pmSessionManager: SessionManager, action: ActionType -): Iterator { +): Generator { const request = pmSessionManager.withRefresh( pagoPaClient.getTransaction(action.payload) ); @@ -149,7 +149,7 @@ export function* fetchPspRequestHandler( pagoPaClient: PaymentManagerClient, pmSessionManager: SessionManager, action: ActionType -): Iterator { +): Generator { const request = pmSessionManager.withRefresh( pagoPaClient.getPsp(action.payload.idPsp) ); @@ -192,7 +192,7 @@ export function* setFavouriteWalletRequestHandler( pagoPaClient: PaymentManagerClient, pmSessionManager: SessionManager, action: ActionType -): Iterator { +): Generator { const favouriteWalletId = action.payload; if (favouriteWalletId === undefined) { // FIXME: currently there is no way to unset a favourite wallet @@ -306,7 +306,7 @@ export function* deleteWalletRequestHandler( pagoPaClient: PaymentManagerClient, pmSessionManager: SessionManager, action: ActionType -): Iterator { +): Generator { const deleteWalletApi = pagoPaClient.deleteWallet(action.payload.walletId); const deleteWalletWithRefresh = pmSessionManager.withRefresh(deleteWalletApi); @@ -508,7 +508,7 @@ export function* paymentCheckRequestHandler( pagoPaClient: PaymentManagerClient, pmSessionManager: SessionManager, action: ActionType -): Iterator { +): Generator { // FIXME: we should not use default pagopa client for checkpayment, need to // a client that doesn't retry on failure!!! checkpayment is NOT // idempotent, the 2nd time it will error! @@ -545,7 +545,7 @@ export function* paymentExecutePaymentRequestHandler( pagoPaClient: PaymentManagerClient, pmSessionManager: SessionManager, action: ActionType -): Iterator { +): Generator { const apiPostPayment = pagoPaClient.postPayment(action.payload.idPayment, { data: { tipo: "web", idWallet: action.payload.wallet.idWallet } }); @@ -581,7 +581,7 @@ export function* paymentDeletePaymentRequestHandler( pagoPaClient: PaymentManagerClient, pmSessionManager: SessionManager, action: ActionType -): Iterator { +): Generator { const apiPostPayment = pagoPaClient.deletePayment(action.payload.paymentId); const request = pmSessionManager.withRefresh(apiPostPayment); try { diff --git a/ts/screens/wallet/AddCardScreen.tsx b/ts/screens/wallet/AddCardScreen.tsx index 33417f340f3..5bae969e091 100644 --- a/ts/screens/wallet/AddCardScreen.tsx +++ b/ts/screens/wallet/AddCardScreen.tsx @@ -9,6 +9,7 @@ import { Content, Item, Text, View } from "native-base"; import * as React from "react"; import { FlatList, Image, ScrollView, StyleSheet } from "react-native"; import { Col, Grid } from "react-native-easy-grid"; +import TextInputMask from "react-native-text-input-mask"; import { NavigationInjectedProps } from "react-navigation"; import { connect } from "react-redux"; import { PaymentRequestsGetResponse } from "../../../definitions/backend/PaymentRequestsGetResponse"; @@ -17,7 +18,6 @@ import BaseScreenComponent, { ContextualHelpPropsMarkdown } from "../../components/screens/BaseScreenComponent"; import FooterWithButtons from "../../components/ui/FooterWithButtons"; -import MaskedInput from "../../components/ui/MaskedInput"; import { cardIcons } from "../../components/wallet/card/Logo"; import I18n from "../../i18n"; import { navigateToWalletConfirmCardDetails } from "../../store/actions/navigation"; @@ -147,9 +147,9 @@ const displayedCards: { [key: string]: any } = { }; class AddCardScreen extends React.Component { - private panRef = React.createRef(); - private expirationDateRef = React.createRef(); - private securityCodeRef = React.createRef(); + private panRef = React.createRef(); + private expirationDateRef = React.createRef(); + private securityCodeRef = React.createRef(); constructor(props: Props) { super(props); diff --git a/ts/types/pagopa.ts b/ts/types/pagopa.ts index 6c4a34d905e..37a58f1d919 100644 --- a/ts/types/pagopa.ts +++ b/ts/types/pagopa.ts @@ -108,7 +108,7 @@ export type Wallet = t.TypeOf; /** * A Wallet that has not being saved yet */ -export type NullableWallet = ReplaceProp1; +export type NullableWallet = ReplaceProp1; /** * A refined Transaction diff --git a/ts/types/utils.ts b/ts/types/utils.ts index 122c0d64a03..94245122a5a 100644 --- a/ts/types/utils.ts +++ b/ts/types/utils.ts @@ -7,11 +7,13 @@ import { PayloadAC, PayloadMetaAC } from "typesafe-actions/dist/type-helpers"; export type SagaCallReturnType< T extends (...args: any[]) => any, R = ReturnType -> = R extends Iterator - ? B - : R extends IterableIterator - ? B1 - : R extends Promise ? B2 : never; +> = R extends Generator + ? B0 + : R extends Iterator + ? B + : R extends IterableIterator + ? B1 + : R extends Promise ? B2 : never; /** * Extracts the type of the payload of a typesafe action diff --git a/yarn.lock b/yarn.lock index 0dbac88b4cf..4865ab87152 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11371,10 +11371,10 @@ typescript-tuple@^2.2.1: dependencies: typescript-compare "^0.0.2" -typescript@3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.1.tgz#b6691be11a881ffa9a05765a205cb7383f3b63c6" - integrity sha512-3NSMb2VzDQm8oBTLH6Nj55VVtUEpe/rgkIzMir0qVoLyjDZlnMBva0U6vDiV3IH+sl/Yu6oP5QwsAQtHPmDd2Q== +typescript@^3.9.7: + version "3.9.7" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" + integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== typestrict@^1.0.2: version "1.0.2"