diff --git a/.babelrc b/.babelrc index 8df53fe430a..a9ce1369e61 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,3 @@ { -"presets": ["react-native"] -} \ No newline at end of file + "presets": ["react-native"] +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..35c4d207a6a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# From https://github.com/facebook/react-native/blob/master/.editorconfig +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 diff --git a/.flowconfig b/.flowconfig index 52426e27184..1dd3eff6987 100644 --- a/.flowconfig +++ b/.flowconfig @@ -26,8 +26,6 @@ emoji=true module.system=haste -experimental.strict_type_args=true - munge_underscores=true module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' @@ -36,12 +34,12 @@ suppress_type=$FlowIssue suppress_type=$FlowFixMe suppress_type=$FixMe -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-0]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) -suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-0]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-7]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-7]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError unsafe.enable_getters_and_setters=true [version] -^0.44.0 +^0.47.0 diff --git a/android/app/build.gradle b/android/app/build.gradle index c301ccb1349..08b26515dd3 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -33,6 +33,13 @@ import com.android.build.OutputFile * // 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: "../../", * @@ -58,7 +65,7 @@ import com.android.build.OutputFile * inputExcludes: ["android/**", "ios/**"], * * // override which node gets called and with what additional arguments - * nodeExecutableAndArgs: ["node"] + * nodeExecutableAndArgs: ["node"], * * // supply additional arguments to the packager * extraPackagerArgs: [] diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro index 48361a9015d..6e8516c8d6d 100644 --- a/android/app/proguard-rules.pro +++ b/android/app/proguard-rules.pro @@ -50,6 +50,10 @@ -dontwarn com.facebook.react.** +# TextLayoutBuilder uses a non-public Android constructor within StaticLayout. +# See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. +-dontwarn android.text.StaticLayout + # okhttp -keepattributes Signature diff --git a/ios/ItaliaApp.xcodeproj/project.pbxproj b/ios/ItaliaApp.xcodeproj/project.pbxproj index 96f0a47cfc5..b4ae25ecab6 100644 --- a/ios/ItaliaApp.xcodeproj/project.pbxproj +++ b/ios/ItaliaApp.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; }; 5F80C0C2BA7C7139E0A5497D /* libPods-ItaliaApp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BEB90DCEBDEADAD0062F2238 /* libPods-ItaliaApp.a */; }; 63AA5202B969492B8CD3AD06 /* Rubik-BlackItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = BABA34511F8142DABAC64DD9 /* Rubik-BlackItalic.ttf */; }; + 63DDE52BC03543388B897EAF /* libreact-native-sha256.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F1400122219F4FA8AA1B26C1 /* libreact-native-sha256.a */; }; 6453A140D4E54760AE4F2C5A /* Rubik-Italic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 683538EBA6C941FF94273106 /* Rubik-Italic.ttf */; }; 661EF081C4614BB8AB5611FD /* Octicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 322B328CD28841989C582D07 /* Octicons.ttf */; }; 68F6F3B39D0C48E78D89CA25 /* Courier New.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 2BEADD26C56E4BCF85FB2742 /* Courier New.ttf */; }; @@ -339,6 +340,8 @@ D5F6B2E2DEEE4D6CBBCDEDB6 /* Rubik-Regular.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Rubik-Regular.ttf"; path = "../node_modules/native-base/Fonts/Rubik-Regular.ttf"; sourceTree = ""; }; DA80BC2F4FDB4E7B98F95C3D /* Arial.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Arial.ttf; path = "../node_modules/native-base/Fonts/Arial.ttf"; sourceTree = ""; }; EEA222FBF70B4D0385257B7E /* TitilliumWeb-ExtraLightItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "TitilliumWeb-ExtraLightItalic.ttf"; path = "../assets/fonts/TitilliumWeb/TitilliumWeb-ExtraLightItalic.ttf"; sourceTree = ""; }; + F1400122219F4FA8AA1B26C1 /* libreact-native-sha256.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = archive.ar; name = "libreact-native-sha256.a"; path = "libreact-native-sha256.a"; sourceTree = ""; }; + F752D8F6CC3242A2A8D3DD25 /* react-native-sha256.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = "react-native-sha256.xcodeproj"; path = "../node_modules/react-native-sha256/ios/react-native-sha256.xcodeproj"; sourceTree = ""; }; FFE68AEA5A7D43B2AFFEAE55 /* Zocial.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Zocial.ttf; path = "../node_modules/native-base/Fonts/Zocial.ttf"; sourceTree = ""; }; F752D8F6CC3242A2A8D3DD25 /* react-native-sha256.xcodeproj */ = {isa = PBXFileReference; name = "react-native-sha256.xcodeproj"; path = "../node_modules/react-native-sha256/ios/react-native-sha256.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; }; F1400122219F4FA8AA1B26C1 /* libreact-native-sha256.a */ = {isa = PBXFileReference; name = "libreact-native-sha256.a"; path = "libreact-native-sha256.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; }; diff --git a/ios/ItaliaAppTests/ItaliaAppTests.m b/ios/ItaliaAppTests/ItaliaAppTests.m index 22b9861db65..f521c4d3d3c 100644 --- a/ios/ItaliaAppTests/ItaliaAppTests.m +++ b/ios/ItaliaAppTests/ItaliaAppTests.m @@ -37,7 +37,7 @@ - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test - (void)testRendersWelcomeScreen { - UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; + UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; BOOL foundElement = NO; diff --git a/js/actions/appState.js b/js/actions/appState.js index 4885f21c028..7f71fcd5604 100644 --- a/js/actions/appState.js +++ b/js/actions/appState.js @@ -11,7 +11,7 @@ const APPLICATION_STATE_CHANGE_ACTION = 'APPLICATION_STATE_CHANGE_ACTION' function appStateChange(appState: ApplicationState): ApplicationStateAction { return { type: APPLICATION_STATE_CHANGE_ACTION, - name: appState, + name: (appState).toUpperCase(), } } diff --git a/js/actions/login.js b/js/actions/login.js index 1b031c55cdf..ec3e48c6255 100644 --- a/js/actions/login.js +++ b/js/actions/login.js @@ -7,15 +7,48 @@ 'use strict' import type { Action, ThunkAction, Dispatch, GetState } from './types' +import type { IdentityProvider } from '../utils/api' import { requestUserProfile } from './user' +// The User is about to Login (taps on the SPID Login button) +const USER_WILL_LOGIN_ACTION = 'USER_WILL_LOGIN_ACTION' +// The User selects the SPID Provider from the list +const USER_SELECTED_SPID_PROVIDER_ACTION = 'USER_SELECTED_SPID_PROVIDER_ACTION' +// The User successfully performs a proper Login +const USER_LOGGED_IN_ACTION = 'USER_LOGGED_IN_ACTION' +// An error is returned from the Login Webview +const USER_LOGIN_ERROR_ACTION = 'USER_LOGIN_ERROR_ACTION' +// The User successfully performs a proper Logout +const USER_LOGGED_OUT_ACTION = 'USER_LOGGED_OUT_ACTION' + +/** + * Dispatched when the user taps on SPID Login + */ +function logInIntent(): Action { + return { + type: USER_WILL_LOGIN_ACTION, + } +} + +/** + * Dispatched when the user selects the SPID provider + */ +function selectIdp(idp: IdentityProvider): Action { + return { + type: USER_SELECTED_SPID_PROVIDER_ACTION, + data: { + idp + } + } +} + /** * Logs the user in, setting the provided auth token and SPID IdP */ function logIn(token: string, idpId: string): ThunkAction { return (dispatch: Dispatch, getState: GetState) => { dispatch({ - type: 'LOGGED_IN', + type: USER_LOGGED_IN_ACTION, data: { token, idpId, @@ -25,16 +58,33 @@ function logIn(token: string, idpId: string): ThunkAction { } } +function logInError(error: string): Action { + return { + type: USER_LOGIN_ERROR_ACTION, + data: { + error, + } + } +} + /** * Logs the user out */ function logOut(): Action { return { - type: 'LOGGED_OUT', + type: USER_LOGGED_OUT_ACTION, } } module.exports = { + logInIntent, + selectIdp, logIn, - logOut + logInError, + logOut, + + USER_WILL_LOGIN_ACTION, + USER_SELECTED_SPID_PROVIDER_ACTION, + USER_LOGGED_IN_ACTION, + USER_LOGIN_ERROR_ACTION, } diff --git a/js/actions/types.js b/js/actions/types.js index 361ad30db88..119b28d75a0 100644 --- a/js/actions/types.js +++ b/js/actions/types.js @@ -6,13 +6,21 @@ 'use strict' -import type { ApiUserProfile } from '../utils/api' +import type { ApiUserProfile, IdentityProvider } from '../utils/api' export type Action = - | { type: 'LOGGED_IN', data: { token: string, idpId: string } } - | { type: 'LOGGED_OUT' } - | { type: 'REQUEST_USER_PROFILE' } - | { type: 'RECEIVE_USER_PROFILE', profile: ApiUserProfile, receivedAt: number } + | { type: 'USER_WILL_LOGIN_ACTION' } + | { type: 'USER_SELECTED_SPID_PROVIDER_ACTION', data: { idp: IdentityProvider } } + | { type: 'USER_LOGGED_IN_ACTION', data: { token: string, idpId: string } } + | { type: 'USER_LOGIN_ERROR_ACTION', data: { error: string } } + | { type: 'USER_LOGGED_OUT_ACTION' } + | { type: 'REQUEST_USER_PROFILE_ACTION' } + | { type: 'RECEIVE_USER_PROFILE_ACTION', profile: ApiUserProfile, receivedAt: number } + +export type ApplicationState = 'background' | 'inactive' | 'active' + +export type ApplicationStateAction = + { type: 'APPLICATION_STATE_CHANGE_ACTION', name: ApplicationState } export type ApplicationState = 'background' | 'inactive' | 'active' diff --git a/js/actions/user.js b/js/actions/user.js index 6ad4454bf77..bf3e75f756d 100644 --- a/js/actions/user.js +++ b/js/actions/user.js @@ -10,6 +10,9 @@ import type { ThunkAction, Dispatch, GetState } from './types' import type { ApiUserProfile } from '../utils/api' import { getUserProfile } from '../utils/api' +const REQUEST_USER_PROFILE_ACTION = 'REQUEST_USER_PROFILE_ACTION' +const RECEIVE_USER_PROFILE_ACTION = 'RECEIVE_USER_PROFILE_ACTION' + /** * Begins an API requests for the user profile to the backend. */ @@ -17,7 +20,7 @@ function requestUserProfile(): ThunkAction { return (dispatch: Dispatch, getState: GetState) => { // first we dispatch the request action dispatch({ - type: 'REQUEST_USER_PROFILE', + type: REQUEST_USER_PROFILE_ACTION, }) // then we make the API call to the backend const { apiUrlPrefix, token } = getState().user @@ -34,7 +37,7 @@ function requestUserProfile(): ThunkAction { function receiveUserProfile(profile: ApiUserProfile): ThunkAction { return (dispatch: Dispatch) => { dispatch({ - type: 'RECEIVE_USER_PROFILE', + type: RECEIVE_USER_PROFILE_ACTION, profile: profile, receivedAt: Date.now(), }) @@ -43,4 +46,6 @@ function receiveUserProfile(profile: ApiUserProfile): ThunkAction { module.exports = { requestUserProfile, + REQUEST_USER_PROFILE_ACTION, + RECEIVE_USER_PROFILE_ACTION } diff --git a/js/components/LoginScreen.js b/js/components/LoginScreen.js index 068b7788c18..d54606c13a7 100644 --- a/js/components/LoginScreen.js +++ b/js/components/LoginScreen.js @@ -28,9 +28,9 @@ import type { Dispatch } from '../actions/types' import { SpidLoginButton } from './SpidLoginButton' import SpidSubscribeComponent from './SpidSubscribeComponent' -const { - logIn, -} = require('../actions') +import { logInIntent, selectIdp, logIn, logInError } from '../actions' + +import { ROUTES } from '../utils/constants' import { ROUTES } from '../utils/constants' @@ -123,10 +123,17 @@ class LoginScreen extends React.Component {

benvenuto nella tua

Cittadinanza Digitale

- { - this.props.dispatch(logIn(token, idpId)) - this.props.navigation.navigate(ROUTES.PROFILE) - }} /> + this.props.dispatch(selectIdp(idp))} + onSpidLoginIntent={() => this.props.dispatch(logInIntent())} + onSpidLogin={(token, idpId) => { + this.props.dispatch(logIn(token, idpId)) + this.props.navigation.navigate(ROUTES.PROFILE) + }} + onSpidLoginError={(error) => { + this.props.dispatch(logInError(error)) + }} + /> diff --git a/js/components/ProfileComponent.js b/js/components/ProfileComponent.js index e061c163512..9e7cee98d85 100644 --- a/js/components/ProfileComponent.js +++ b/js/components/ProfileComponent.js @@ -140,7 +140,7 @@ class ProfileComponent extends React.Component { DOMICILIO PEC { - this.props.navigation.navigate(ROUTES.DIGITALADDRESS) + this.props.navigation.navigate(ROUTES.DIGITAL_ADDRESS) }}> pinco@pec.italia.it @@ -154,7 +154,7 @@ class ProfileComponent extends React.Component { AVVISI E SCADENZE { - this.props.navigation.navigate(ROUTES.SENDERSELECTION) + this.props.navigation.navigate(ROUTES.SENDER_SELECTION) }}> Enti abilitati @@ -165,7 +165,7 @@ class ProfileComponent extends React.Component { { - this.props.navigation.navigate(ROUTES.TOPICSSELECTION) + this.props.navigation.navigate(ROUTES.TOPICS_SELECTION) }}> Tipologie diff --git a/js/components/SpidLoginButton.js b/js/components/SpidLoginButton.js index 0dbd4b84c9a..3b56ac19b58 100644 --- a/js/components/SpidLoginButton.js +++ b/js/components/SpidLoginButton.js @@ -31,13 +31,7 @@ import { Icon, } from 'native-base' -export type IdentityProvider = { - id: string, - logo: mixed, - name: string, - entityID: string, - profileUrl: string, -}; +import type { IdentityProvider } from '../utils/api' // prefix for recognizing auth token const TOKEN_PATH_PREFIX = '/app/token/get/' @@ -169,7 +163,9 @@ class IdpSelectionScreen extends React.Component { props: { closeModal: () => void, + onSelectIdp: (IdentityProvider) => void, onSpidLogin: (string, string) => void, + onSpidLoginError: (string) => void, } state: { @@ -178,6 +174,9 @@ class IdpSelectionScreen extends React.Component { constructor(props) { super(props) + + this.createButtons = this.createButtons.bind(this) + this.state = { selectedIdp: null, } @@ -199,6 +198,7 @@ class IdpSelectionScreen extends React.Component { return idps.map((idp: IdentityProvider) => { return (