diff --git a/.circleci/config.yml b/.circleci/config.yml index 759fc03c364..261bff91731 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -121,7 +121,7 @@ jobs: - run: "bash <(curl -s https://codecov.io/bash)" # Runs Danger checks on PR - lint-typescript: + eslint: <<: *defaults_js steps: @@ -466,7 +466,7 @@ workflows: - run-tests - - lint-typescript + - eslint - run-danger: filters: @@ -519,7 +519,7 @@ workflows: branches: ignore: /.*/ - - lint-typescript: + - eslint: filters: tags: only: *release_tag @@ -538,7 +538,7 @@ workflows: requires: - compile-typescript - run-tests - - lint-typescript + - eslint filters: tags: only: *release_tag diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000000..92effe8471b --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +locales/locales.ts +ts/utils/__tests__/xss.test.ts +definitions/* diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000000..f845a6c209a --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,93 @@ +module.exports = { + root: true, + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "plugin:sonarjs/recommended", + "prettier", + "prettier/@typescript-eslint" + ], + parser: "@typescript-eslint/parser", + parserOptions: { + project: "tsconfig.json", + sourceType: "module" + }, + plugins: ["@typescript-eslint", "react", "import", "functional", "sonarjs"], + rules: { + "no-case-declarations": "off", + "no-inner-declarations": "off", + "prefer-const": "error", + curly: "error", + "spaced-comment": ["error", "always", { block: { balanced: true } }], + radix: "error", + "one-var": ["error", "never"], + "object-shorthand": "error", + "no-var": "error", + "no-param-reassign": "error", + "no-underscore-dangle": "error", + "no-undef-init": "error", + "no-throw-literal": "error", + "no-new-wrappers": "error", + "no-eval": "error", + "no-console": "error", + "no-caller": "error", + "no-bitwise": "error", + eqeqeq: ["error", "smart"], + "max-classes-per-file": ["error", 1], + "guard-for-in": "error", + complexity: "error", + "arrow-body-style": "error", + "import/order": "error", + "@typescript-eslint/no-unused-vars": "off", + // Enable if we want to enforce the return type for all the functions + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-inferrable-types": "off", + // TODO: added for compatibility. Removing this line we have to remove all the any usage in the code + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/array-type": [ + "error", + { + default: "generic" + } + ], + "@typescript-eslint/await-thenable": "error", + "@typescript-eslint/consistent-type-assertions": "error", + "@typescript-eslint/dot-notation": "error", + "@typescript-eslint/member-delimiter-style": [ + "error", + { + multiline: { + delimiter: "semi", + requireLast: true + }, + singleline: { + delimiter: "semi", + requireLast: false + } + } + ], + "@typescript-eslint/no-floating-promises": "error", + "no-unused-expressions": "off", + "@typescript-eslint/no-unused-expressions": ["error"], + "@typescript-eslint/prefer-function-type": "error", + "@typescript-eslint/restrict-plus-operands": "error", + semi: "off", + "@typescript-eslint/semi": ["error"], + "@typescript-eslint/unified-signatures": "error", + "react/prop-types": "off", + "react/display-name": "off", + "react/jsx-key": "error", + "react/jsx-no-bind": ["error", { allowArrowFunctions: true }], + "functional/no-let": "error", + "functional/immutable-data": "error", + "sonarjs/no-small-switch": "off", + "sonarjs/no-duplicate-string": "off" + }, + settings: { + react: { + version: "detect" + } + } +}; diff --git a/.node-version b/.node-version index db24ab967fb..06c9b9d3063 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -10.13.0 +10.18.0 diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 2340e06ca9a..00000000000 --- a/.prettierrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parser": "typescript" -} diff --git a/.prettierrc.js b/.prettierrc.js index 5c4de1a4f65..0e77b17fabd 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,6 +1,5 @@ module.exports = { - bracketSpacing: false, - jsxBracketSameLine: true, - singleQuote: true, - trailingComma: 'all', + trailingComma: "none", + arrowParens: "avoid", + parser: "typescript" }; diff --git a/Dangerfile.ts b/Dangerfile.ts index 9a6b6b6099d..b7296f0b7aa 100644 --- a/Dangerfile.ts +++ b/Dangerfile.ts @@ -4,16 +4,15 @@ import { warn } from "danger"; // See https://github.com/teamdigitale/danger-plugin-digitalcitizenship/ import checkDangers from "danger-plugin-digitalcitizenship"; import { DangerDSLType } from "danger/distribution/dsl/DangerDSL"; -import { none } from "fp-ts/lib/Option"; +import {fromNullable, none} from "fp-ts/lib/Option"; import { allStoriesSameType, getChangelogPrefixByStories, getChangelogScope, - getPivotalStoriesFromPrTitle, - getRawTitle + getPivotalStoriesFromPrTitle } from "./scripts/changelog/ts/changelog"; -declare var danger: DangerDSLType; +declare const danger: DangerDSLType; const multipleTypesWarning = "Multiple stories with different types are associated with this Pull request.\n" + @@ -41,19 +40,22 @@ const updatePrTitleForChangelog = async () => { .map(s => `(${s})`) .getOrElse(""); - const rawTitle = getRawTitle(danger.github.pr.title); + const cleanChangelogRegex = /^(fix(\(.+\))?!?: |feat(\(.+\))?!?: |chore(\(.+\))?!?: )?(.*)$/; + const title = fromNullable(danger.github.pr.title.match(cleanChangelogRegex)) + .map(matches => matches.pop() || danger.github.pr.title) + .getOrElse(danger.github.pr.title); maybePrTag.map(tag => danger.github.api.pulls.update({ owner: danger.github.thisPR.owner, repo: danger.github.thisPR.repo, pull_number: danger.github.thisPR.number, - title: `${tag}${scope}: ${rawTitle}` + title: `${tag}${scope}: ${title}` }) ); }; checkDangers(); -updatePrTitleForChangelog() +void updatePrTitleForChangelog() .then() .catch(); diff --git a/package.json b/package.json index 3e4fa1ab433..0edce3c8f9a 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ "packager:clear": "rm -rf $TMPDIR/react-native-packager-cache-* && rm -rf $TMPDIR/metro-bundler-cache-*", "bundle:android": "node node_modules/react-native/local-cli/cli.js bundle --platform android --dev true --entry-file index.js --bundle-output ./bundles/index.android.bundle", "tsc:noemit": "tsc --noemit", - "lint": "tslint -p . -c tslint.json -t verbose", - "lint-autofix": "tslint -p . -c tslint.json -t verbose --fix", + "lint": "eslint . -c .eslintrc.js --ext .ts,.tsx", + "lint-autofix": "eslint . -c .eslintrc.js --ext .ts,.tsx --fix", "check_urls": "python3 scripts/check_urls.py", "generate:pagopa-api-definitions": "rimraf definitions/pagopa && mkdir -p definitions/pagopa && gen-api-models --api-spec $npm_package_pagopa_api --out-dir ./definitions/pagopa --no-strict --request-types --response-decoders --default-error-type undefined", "generate:mock-google-services-json": "cp mock-google-services.json ./android/app/google-services.json", @@ -41,11 +41,15 @@ "@react-native-community/async-storage": "^1.6.1", "@react-native-community/cameraroll": "^4.0.0", "@redux-saga/testing-utils": "^1.1.3", + "@typescript-eslint/eslint-plugin": "^3.10.1", "abort-controller": "^1.0.2", "async-mutex": "^0.1.3", "buffer": "^4.9.1", "color": "^3.0.0", "date-fns": "^1.29.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-functional": "^3.0.2", + "eslint-plugin-sonarjs": "^0.5.0", "fp-ts": "1.12.0", "front-matter": "^4.0.2", "hoist-non-react-statics": "^3.0.1", @@ -151,6 +155,7 @@ "@types/stacktrace-js": "^0.0.32", "@types/uuid": "^3.4.4", "@types/validator": "^9.4.2", + "@typescript-eslint/parser": "^3.10.1", "abortcontroller-polyfill": "1.3.0", "babel-jest": "^25.1.0", "babel-preset-react-native": "^4.0.1", @@ -158,8 +163,9 @@ "danger": "^10.3.0", "danger-plugin-digitalcitizenship": "^0.3.1", "eslint": "^6.5.1", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-react": "^7.20.6", "fs-extra": "^7.0.0", - "italia-tslint-rules": "^1.1.0", "italia-utils": "^4.1.1", "jest": "^25.1.0", "js-yaml": "^3.13.1", @@ -171,14 +177,13 @@ "pivotaljs": "^1.0.3", "plist": "^3.0.1", "postinstall-postinstall": "^1.0.0", - "prettier": "1.14.2", + "prettier": "2.1.0", "react-test-renderer": "16.13.1", "redux-saga-test-plan": "4.0.0-rc.3", "rn-nodeify": "^10.0.1", "standard-version": "^8.0.2", "ts-jest": "^25.1.0", "ts-node": "^7.0.1", - "tslint": "5.20.0", "typescript": "^3.9.7" }, "resolutions": { diff --git a/scripts/changelog/ts/changelog.ts b/scripts/changelog/ts/changelog.ts index 0b876c3a148..6c84794a719 100644 --- a/scripts/changelog/ts/changelog.ts +++ b/scripts/changelog/ts/changelog.ts @@ -119,9 +119,7 @@ export const getStoryChangelogScope = ( if (maybeChangelogScopeTag.length > 1) { return left( new Error( - `Multiple labels match the expression \`${regex}\` for the story [#${ - story.id - }].\n + `Multiple labels match the expression \`${regex}\` for the story [#${story.id}].\n It is not possible to assign a single scope to this pull request!` ) ); @@ -130,11 +128,7 @@ export const getStoryChangelogScope = ( if (maybeProjectScope.isSome() && maybeChangelogScopeTag.length >= 1) { return left( new Error( - `The story [#${story.id}] have the project_id ${ - story.project_id - } associated with the scope ${ - maybeProjectScope.value - } but also have labels matching the expression \`${regex}\`.\n + `The story [#${story.id}] have the project_id ${story.project_id} associated with the scope ${maybeProjectScope.value} but also have labels matching the expression \`${regex}\`.\n It is not possible to assign a single scope to this pull request!` ) ); @@ -180,9 +174,10 @@ export const getChangelogScope = ( // if there is some error, forward the errors if (eitherChangelogScopes.some(scope => scope.isLeft())) { return left( - eitherChangelogScopes.reduce>((acc, val) => { - return val.isLeft() ? [...acc, val.value] : acc; - }, []) + eitherChangelogScopes.reduce>( + (acc, val) => (val.isLeft() ? [...acc, val.value] : acc), + [] + ) ); } const scopesList = eitherChangelogScopes diff --git a/scripts/make-locales.ts b/scripts/make-locales.ts index b75b7754dd0..9a1b42ca166 100644 --- a/scripts/make-locales.ts +++ b/scripts/make-locales.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ /** * This script converts the translations from the "locales" * directory into a typescript file that can be bundled with @@ -13,12 +14,11 @@ * I18N_IGNORE_LOCALE_ERRORS=1 Ignore locale validation errors. * I18N_MASTER_LOCALE=it Sets a different master locale. */ -// tslint:disable:no-console +import * as path from "path"; import chalk from "chalk"; import * as fs from "fs-extra"; import * as yaml from "js-yaml"; -import * as path from "path"; import * as prettier from "prettier"; interface LocaleDoc { @@ -44,26 +44,20 @@ const IncludeYamlType = (includeRoot: string) => new yaml.Type("!include", { kind: "scalar", - resolve: (data: any) => { - return ( + resolve: (data: any) => ( data !== null && typeof data === "string" && path // included file must be under includeRoot .normalize(path.join(includeRoot, data)) .startsWith(path.normalize(includeRoot)) && fs.statSync(path.join(includeRoot, data)).isFile() - ); - }, + ), - construct: data => { - return fs.readFileSync(path.join(includeRoot, data)).toString(); - }, + construct: data => fs.readFileSync(path.join(includeRoot, data)).toString(), instanceOf: String, - represent: (data: any) => { - return String(data); - } + represent: (data: any) => String(data) }); /** @@ -234,12 +228,12 @@ async function run(rootPath: string): Promise { // compare keys of locales with master keys console.log(chalk.gray("[3/4]"), "Comparing keys..."); - const checkedLocaleKeys: ReadonlyArray< - LocaleDocWithCheckedKeys - > = otherLocaleKeys.map(l => ({ - ...l, - ...compareLocaleKeys(masterKeys.keys, l.keys) - })); + const checkedLocaleKeys: ReadonlyArray = otherLocaleKeys.map( + l => ({ + ...l, + ...compareLocaleKeys(masterKeys.keys, l.keys) + }) + ); // look for locales that have missing or extra keys const badLocales = checkedLocaleKeys.filter( @@ -248,7 +242,7 @@ async function run(rootPath: string): Promise { if (badLocales.length > 0) { badLocales.forEach(reportBadLocale); - if (!Boolean(process.env.I18N_IGNORE_LOCALE_ERRORS)) { + if (!process.env.I18N_IGNORE_LOCALE_ERRORS) { throw Error("bad locales detected"); } } @@ -264,4 +258,7 @@ async function run(rootPath: string): Promise { } } -run(root).then(() => console.log("done"), () => process.exit(1)); +run(root).then( + () => console.log("done"), + () => process.exit(1) +); diff --git a/scripts/unused-locales.ts b/scripts/unused-locales.ts index 63ce349d377..7fe9715faad 100644 --- a/scripts/unused-locales.ts +++ b/scripts/unused-locales.ts @@ -1,12 +1,12 @@ -import chalk from "chalk"; +/* eslint-disable no-console */ import { exec } from "child_process"; import * as path from "path"; +import chalk from "chalk"; import { extractKeys, readLocaleDoc } from "./make-locales"; // tslint:disable:no-console -const isUnused = (input: string): Promise => { - return new Promise(res => { +const isUnused = (input: string): Promise => new Promise(res => { exec( `grep -F -r "${input}" ${path.join(__dirname, "../ts")}`, (err, stdout, _) => { @@ -17,7 +17,6 @@ const isUnused = (input: string): Promise => { } ); }); -}; const run = async (root: string, locale: string) => { const d = await readLocaleDoc(root, locale); diff --git a/ts/@types/detox.d.ts b/ts/@types/detox.d.ts index 4d3fa35470e..d6e28a519f6 100644 --- a/ts/@types/detox.d.ts +++ b/ts/@types/detox.d.ts @@ -1,4 +1,4 @@ -// tslint:disable:no-namespace no-method-signature +/* eslint-disable @typescript-eslint/no-namespace */ declare namespace Detox { interface Detox { diff --git a/ts/@types/native-base-types.d.ts b/ts/@types/native-base-types.d.ts index 04343a34cad..03e425e3172 100644 --- a/ts/@types/native-base-types.d.ts +++ b/ts/@types/native-base-types.d.ts @@ -15,17 +15,17 @@ declare module "native-base-shoutem-theme" { } export type MapPropsToStyleNames =

( - styleNames: string[], + styleNames: Array, props: P ) => ReadonlyArray; /** * The connectStyle function does not use forwardRef. * To get a ref to the wrapped component you have to use _root. - * + * * RT = _root Type */ - export function connectStyle( + export function connectStyle( componentStyleName: string, componentStyle = {}, mapPropsToStyleNames: MapPropsToStyleNames, @@ -34,7 +34,7 @@ declare module "native-base-shoutem-theme" { } declare module "native-base/src/utils/mapPropsToStyleNames" { - export default function

( + export default function

( styleNames: ReadonlyArray, props: P ): ReadonlyArray; @@ -43,7 +43,7 @@ declare module "native-base/src/utils/mapPropsToStyleNames" { declare module "native-base/src/theme/components" { type Variables = any; type Theme = any; - export default function(variables: Variables): Theme; + export default function (variables: Variables): Theme; } declare module "native-base/src/theme/variables/material" { diff --git a/ts/@types/react-native-barcode-builder.d.ts b/ts/@types/react-native-barcode-builder.d.ts index 4da017654fa..07881fc8def 100644 --- a/ts/@types/react-native-barcode-builder.d.ts +++ b/ts/@types/react-native-barcode-builder.d.ts @@ -1,26 +1,23 @@ declare module "react-native-barcode-builder" { - import { PureComponent } from "react"; - import { oneOf } from "fp-ts/lib/Foldable2v"; - import { api } from "jsbarcode/jsbarcode"; + import { PureComponent } from "react"; + import { oneOf } from "fp-ts/lib/Foldable2v"; + import { api } from "jsbarcode/jsbarcode"; - // For not included barcode format, if required, - // review rules on value to encode as barcode - type barcodeTypes = "CODE39" | - "CODE128" | - "CODE128A" | - "CODE128B" ; - export interface BarcodeProps { - value: string; - width?: number; - height?: number; - background?: string; - format: barcodeTypes; - text?: string; - lineColor?: string; - onError?: () => void; - } + // For not included barcode format, if required, + // review rules on value to encode as barcode + type barcodeTypes = "CODE39" | "CODE128" | "CODE128A" | "CODE128B"; + export interface BarcodeProps { + value: string; + width?: number; + height?: number; + background?: string; + format: barcodeTypes; + text?: string; + lineColor?: string; + onError?: () => void; + } - export default class Barcode extends React.PureComponent{ - constructor(props); - } + export default class Barcode extends React.PureComponent { + constructor(props); + } } diff --git a/ts/@types/react-native-pull.d.ts b/ts/@types/react-native-pull.d.ts index 7bf9ead4de5..29e938b469b 100644 --- a/ts/@types/react-native-pull.d.ts +++ b/ts/@types/react-native-pull.d.ts @@ -9,6 +9,7 @@ * * */ +// eslint-disable-next-line max-classes-per-file declare module "react-native-pull" { import * as React from "react"; import { diff --git a/ts/@types/react-native-screen-brightness.d.ts b/ts/@types/react-native-screen-brightness.d.ts index 33dedc4e5f9..750e9b80f1e 100644 --- a/ts/@types/react-native-screen-brightness.d.ts +++ b/ts/@types/react-native-screen-brightness.d.ts @@ -1,9 +1,9 @@ -declare module 'react-native-screen-brightness'{ - const ScreenBrightness: { - getAppBrightness(): Promise; - setAppBrightness(val: number): Promise; - getBrightness(): Promise; - setBrightness(val: number): Promise; - } - export default ScreenBrightness; -} \ No newline at end of file +declare module "react-native-screen-brightness" { + const ScreenBrightness: { + getAppBrightness(): Promise; + setAppBrightness(val: number): Promise; + getBrightness(): Promise; + setBrightness(val: number): Promise; + }; + export default ScreenBrightness; +} diff --git a/ts/@types/react-native-touch-id.d.ts b/ts/@types/react-native-touch-id.d.ts index c36463446b6..79a818e5def 100644 --- a/ts/@types/react-native-touch-id.d.ts +++ b/ts/@types/react-native-touch-id.d.ts @@ -1,112 +1,111 @@ -declare module 'react-native-touch-id' { +declare module "react-native-touch-id" { + /** + * The supported biometry type + */ + export type BiometryType = "FaceID" | "TouchID"; + + /** + * Base config to pass to `TouchID.isSupported` and `TouchID.authenticate` + */ + interface IsSupportedConfig { /** - * The supported biometry type + * Return unified error messages */ - export type BiometryType = 'FaceID' | 'TouchID'; - + unifiedErrors?: boolean; + } + + /** + * Authentication config + */ + export interface AuthenticateConfig extends IsSupportedConfig { + /** + * **Android only** - Title of confirmation dialog + */ + title?: string; /** - * Base config to pass to `TouchID.isSupported` and `TouchID.authenticate` + * **Android only** - Color of fingerprint image */ - interface IsSupportedConfig { - /** - * Return unified error messages - */ - unifiedErrors?: boolean; - } - + imageColor?: string; /** - * Authentication config + * **Android only** - Color of fingerprint image after failed attempt */ - export interface AuthenticateConfig extends IsSupportedConfig { - /** - * **Android only** - Title of confirmation dialog - */ - title?: string; - /** - * **Android only** - Color of fingerprint image - */ - imageColor?: string; - /** - * **Android only** - Color of fingerprint image after failed attempt - */ - imageErrorColor?: string; - /** - * **Android only** - Text shown next to the fingerprint image - */ - sensorDescription?: string; - /** - * **Android only** - Text shown next to the fingerprint image after failed attempt - */ - sensorErrorDescription?: string; - /** - * **Android only** - Cancel button text - */ - cancelText?: string; - /** - * **iOS only** - By default specified 'Show Password' label. If set to empty string label is invisible. - */ - fallbackLabel?: string; - /** - * **iOS only** - By default set to false. If set to true, will allow use of keypad passcode. - */ - passcodeFallback?: boolean; - } + imageErrorColor?: string; /** - * `isSupported` error code + * **Android only** - Text shown next to the fingerprint image */ - type IsSupportedErrorCode = - | 'NOT_SUPPORTED' - | 'NOT_AVAILABLE' - | 'NOT_PRESENT' - | 'NOT_ENROLLED'; - + sensorDescription?: string; /** - * `authenticate` error code + * **Android only** - Text shown next to the fingerprint image after failed attempt */ - type AuthenticateErrorCode = - | IsSupportedErrorCode - | 'AUTHENTICATION_FAILED' - | 'USER_CANCELED' - | 'SYSTEM_CANCELED' - | 'TIMEOUT' - | 'LOCKOUT' - | 'LOCKOUT_PERMANENT' - | 'PROCESSING_ERROR' - | 'USER_FALLBACK' - | 'UNKNOWN_ERROR'; - + sensorErrorDescription?: string; /** - * Error returned from `authenticate` + * **Android only** - Cancel button text */ - export interface AuthenticationError { - name: 'TouchIDError'; - message: string; - code: AuthenticateErrorCode; - details: string; - } + cancelText?: string; /** - * Error returned from `isSupported` + * **iOS only** - By default specified 'Show Password' label. If set to empty string label is invisible. */ - export interface IsSupportedError { - name: 'TouchIDError'; - message: string; - code: IsSupportedErrorCode; - details: string; - } - - const TouchID: { - /** - * - * @param reason String that provides a clear reason for requesting authentication. - * @param config Configuration object for more detailed dialog setup - */ - authenticate(reason?: string, config?: AuthenticateConfig); - /** - * - * @param config - Returns a `Promise` that rejects if TouchID is not supported. On iOS resolves with a `biometryType` `String` of `FaceID` or `TouchID` - */ - isSupported(config?: IsSupportedConfig): Promise; - }; - export default TouchID; + fallbackLabel?: string; + /** + * **iOS only** - By default set to false. If set to true, will allow use of keypad passcode. + */ + passcodeFallback?: boolean; + } + /** + * `isSupported` error code + */ + type IsSupportedErrorCode = + | "NOT_SUPPORTED" + | "NOT_AVAILABLE" + | "NOT_PRESENT" + | "NOT_ENROLLED"; + + /** + * `authenticate` error code + */ + type AuthenticateErrorCode = + | IsSupportedErrorCode + | "AUTHENTICATION_FAILED" + | "USER_CANCELED" + | "SYSTEM_CANCELED" + | "TIMEOUT" + | "LOCKOUT" + | "LOCKOUT_PERMANENT" + | "PROCESSING_ERROR" + | "USER_FALLBACK" + | "UNKNOWN_ERROR"; + + /** + * Error returned from `authenticate` + */ + export interface AuthenticationError { + name: "TouchIDError"; + message: string; + code: AuthenticateErrorCode; + details: string; } - \ No newline at end of file + /** + * Error returned from `isSupported` + */ + export interface IsSupportedError { + name: "TouchIDError"; + message: string; + code: IsSupportedErrorCode; + details: string; + } + + const TouchID: { + /** + * + * @param reason String that provides a clear reason for requesting authentication. + * @param config Configuration object for more detailed dialog setup + */ + authenticate(reason?: string, config?: AuthenticateConfig); + /** + * + * @param config - Returns a `Promise` that rejects if TouchID is not supported. On iOS resolves with a `biometryType` `String` of `FaceID` or `TouchID` + */ + isSupported(config?: IsSupportedConfig): Promise; + }; + export default TouchID; +} diff --git a/ts/@types/remark-custom-blocks.d.ts b/ts/@types/remark-custom-blocks.d.ts index 798016534bf..8b4412281da 100644 --- a/ts/@types/remark-custom-blocks.d.ts +++ b/ts/@types/remark-custom-blocks.d.ts @@ -1,3 +1,3 @@ declare module "remark-custom-blocks" { - export default function(): any; + export default function (): any; } diff --git a/ts/@types/remark-html.d.ts b/ts/@types/remark-html.d.ts index 36f6f17d713..76f8111f4cb 100644 --- a/ts/@types/remark-html.d.ts +++ b/ts/@types/remark-html.d.ts @@ -1,3 +1,3 @@ declare module "remark-html" { - export default function(): any; + export default function (): any; } diff --git a/ts/@types/remark.d.ts b/ts/@types/remark.d.ts index 2b8c2163c56..96d712224f8 100644 --- a/ts/@types/remark.d.ts +++ b/ts/@types/remark.d.ts @@ -1,3 +1,3 @@ declare module "remark" { - export default function(): any; + export default function (): any; } diff --git a/ts/@types/xss.d.ts b/ts/@types/xss.d.ts index 2810ac83b4c..d283e4c45e1 100644 --- a/ts/@types/xss.d.ts +++ b/ts/@types/xss.d.ts @@ -1,4 +1,5 @@ declare module "xss" { + import { FilterXSS } from "xss"; export type FilterXSSOptions = any; /** @@ -9,7 +10,7 @@ declare module "xss" { * @return {String} */ export function filterXSS(html: string, options?: FilterXSSOptions): string { - var xss = new FilterXSS(options); + const xss = new FilterXSS(options); return xss.process(html); } } diff --git a/ts/RootContainer.tsx b/ts/RootContainer.tsx index 70c8fd8955d..6da924bf299 100644 --- a/ts/RootContainer.tsx +++ b/ts/RootContainer.tsx @@ -76,7 +76,7 @@ class RootContainer extends React.PureComponent { if (Platform.OS === "android") { Linking.getInitialURL() .then(this.navigateToUrlHandler) - .catch(console.error); // tslint:disable-line:no-console + .catch(console.error); // eslint-disable-line no-console } else { Linking.addEventListener("url", this.handleOpenUrlEvent); } @@ -156,7 +156,4 @@ const mapDispatchToProps = { navigateBack }; -export default connect( - mapStateToProps, - mapDispatchToProps -)(RootContainer); +export default connect(mapStateToProps, mapDispatchToProps)(RootContainer); diff --git a/ts/__e2e__/app.e2e.ts b/ts/__e2e__/app.e2e.ts index c9488dc2758..1a1c1907f52 100644 --- a/ts/__e2e__/app.e2e.ts +++ b/ts/__e2e__/app.e2e.ts @@ -1,4 +1,4 @@ -// tslint:disable:no-commented-code +/* eslint-disable */ // FIXME: putting these declarations in detox.d.ts makes them available in all // test modules clashing with Jest's expect diff --git a/ts/__mocks__/react-native-keychain.ts b/ts/__mocks__/react-native-keychain.ts index c9d39b2bece..70fe6f425a9 100644 --- a/ts/__mocks__/react-native-keychain.ts +++ b/ts/__mocks__/react-native-keychain.ts @@ -16,19 +16,19 @@ type Options = { const keychainDB: KeychainDB = {}; +// eslint-disable-next-line functional/immutable-data module.exports = { ACCESSIBLE: jest.fn(), - getGenericPassword: jest.fn( - (options: Options) => - keychainDB[options.service] - ? Promise.resolve(keychainDB[options.service]) - : Promise.resolve(false) + getGenericPassword: jest.fn((options: Options) => + keychainDB[options.service] + ? Promise.resolve(keychainDB[options.service]) + : Promise.resolve(false) ), setGenericPassword: jest.fn( (username: string, password: string, options: Options) => { - // tslint:disable-next-line no-object-mutation + // eslint-disable-next-line keychainDB[options.service] = { username, password, @@ -39,7 +39,7 @@ module.exports = { ), resetGenericPassword: jest.fn((options: Options) => { - // tslint:disable-next-line no-object-mutation + // eslint-disable-next-line delete keychainDB[options.service]; return Promise.resolve(true); }) diff --git a/ts/api/backend.ts b/ts/api/backend.ts index da9cd8f17d3..283bc0e5962 100644 --- a/ts/api/backend.ts +++ b/ts/api/backend.ts @@ -1,4 +1,6 @@ import * as t from "io-ts"; + +import { DeferredPromise } from "italia-ts-commons/lib/promises"; import * as r from "italia-ts-commons/lib/requests"; import { ApiHeaderJson, @@ -13,7 +15,9 @@ import { RequestHeaders, ResponseDecoder } from "italia-ts-commons/lib/requests"; +import { Tuple2 } from "italia-ts-commons/lib/tuples"; import { Omit } from "italia-ts-commons/lib/types"; +import { Millisecond } from "italia-ts-commons/lib/units"; import { InitializedProfile } from "../../definitions/backend/InitializedProfile"; import { ProblemJson } from "../../definitions/backend/ProblemJson"; import { @@ -49,10 +53,6 @@ import { upsertUserMetadataDefaultDecoder, UpsertUserMetadataT } from "../../definitions/backend/requestTypes"; - -import { DeferredPromise } from "italia-ts-commons/lib/promises"; -import { Tuple2 } from "italia-ts-commons/lib/tuples"; -import { Millisecond } from "italia-ts-commons/lib/units"; import { SessionToken } from "../types/SessionToken"; import { constantPollingFetch, defaultRetryingFetch } from "../utils/fetch"; @@ -117,18 +117,16 @@ export type LogoutT = IPostApiRequestType< function ParamAuthorizationBearerHeaderProducer< P extends { readonly Bearer: string } >(): RequestHeaderProducer { - return (p: P): RequestHeaders<"Authorization"> => { - return { + return (p: P): RequestHeaders<"Authorization"> => ({ Authorization: `Bearer ${p.Bearer}` - }; - }; + }); } // // Create client // -// tslint:disable-next-line: no-big-function +// eslint-disable-next-line export function BackendClient( baseUrl: string, token: SessionToken, @@ -208,8 +206,7 @@ export function BackendClient( // Custom decoder until we fix the problem in the io-utils generator // https://www.pivotaltracker.com/story/show/169915207 - const startEmailValidationCustomDecoder = () => { - return r.composeResponseDecoders( + const startEmailValidationCustomDecoder = () => r.composeResponseDecoders( r.composeResponseDecoders( r.composeResponseDecoders( r.composeResponseDecoders( @@ -217,31 +214,30 @@ export function BackendClient( r.constantResponseDecoder(202, undefined), r.ioResponseDecoder< 400, - (typeof ProblemJson)["_A"], - (typeof ProblemJson)["_O"] + typeof ProblemJson["_A"], + typeof ProblemJson["_O"] >(400, ProblemJson) ), r.constantResponseDecoder(401, undefined) ), r.ioResponseDecoder< 404, - (typeof ProblemJson)["_A"], - (typeof ProblemJson)["_O"] + typeof ProblemJson["_A"], + typeof ProblemJson["_O"] >(404, ProblemJson) ), r.ioResponseDecoder< 429, - (typeof ProblemJson)["_A"], - (typeof ProblemJson)["_O"] + typeof ProblemJson["_A"], + typeof ProblemJson["_O"] >(429, ProblemJson) ), r.ioResponseDecoder< 500, - (typeof ProblemJson)["_A"], - (typeof ProblemJson)["_O"] + typeof ProblemJson["_A"], + typeof ProblemJson["_O"] >(500, ProblemJson) ); - }; const postStartEmailValidationProcessT: StartEmailValidationProcessT = { method: "post", diff --git a/ts/api/backendPublic.ts b/ts/api/backendPublic.ts index b042c213d1c..c998d93f5b3 100644 --- a/ts/api/backendPublic.ts +++ b/ts/api/backendPublic.ts @@ -9,7 +9,7 @@ import { ServerInfo } from "../../definitions/backend/ServerInfo"; import { defaultRetryingFetch } from "../utils/fetch"; type GetServerInfoT = IGetApiRequestType< - {}, + Record, never, never, BasicResponseType @@ -29,7 +29,7 @@ export const BackendStatus = t.exact(BackendStatusR, "ServerInfo"); export type BackendStatus = t.TypeOf; type GetStatusT = IGetApiRequestType< - {}, + Record, never, never, BasicResponseType diff --git a/ts/api/content.ts b/ts/api/content.ts index 95cfaaef3fb..12c17f8bcce 100644 --- a/ts/api/content.ts +++ b/ts/api/content.ts @@ -46,9 +46,7 @@ type GetMunicipalityT = IGetApiRequestType< const getMunicipalityT: GetMunicipalityT = { method: "get", url: params => - `/municipalities/${params.codiceCatastale[0]}/${ - params.codiceCatastale[1] - }/${params.codiceCatastale}.json`, + `/municipalities/${params.codiceCatastale[0]}/${params.codiceCatastale[1]}/${params.codiceCatastale}.json`, query: _ => ({}), headers: _ => ({}), response_decoder: basicResponseDecoder(MunicipalityMedadata) diff --git a/ts/api/pagopa.ts b/ts/api/pagopa.ts index 355d0e42efc..a640fc0ac78 100644 --- a/ts/api/pagopa.ts +++ b/ts/api/pagopa.ts @@ -3,6 +3,9 @@ * to call the different API available */ import { flip } from "fp-ts/lib/function"; + +import * as t from "io-ts"; +import * as r from "italia-ts-commons/lib/requests"; import { AddResponseType, ApiHeaderJson, @@ -18,21 +21,6 @@ import { TypeofApiParams } from "italia-ts-commons/lib/requests"; import { Omit } from "italia-ts-commons/lib/types"; -import { - NullableWallet, - PagoPAErrorResponse, - PaymentManagerToken, - PspListResponse, - PspResponse -} from "../types/pagopa"; -import { SessionResponse } from "../types/pagopa"; -import { TransactionListResponse } from "../types/pagopa"; -import { TransactionResponse } from "../types/pagopa"; -import { WalletListResponse } from "../types/pagopa"; -import { WalletResponse } from "../types/pagopa"; - -import * as t from "io-ts"; -import * as r from "italia-ts-commons/lib/requests"; import { addWalletCreditCardUsingPOSTDecoder, AddWalletCreditCardUsingPOSTT, @@ -60,6 +48,18 @@ import { updateWalletUsingPUTDecoder, UpdateWalletUsingPUTT } from "../../definitions/pagopa/requestTypes"; +import { + NullableWallet, + PagoPAErrorResponse, + PaymentManagerToken, + PspListResponse, + PspResponse, + SessionResponse, + TransactionListResponse, + TransactionResponse, + WalletListResponse, + WalletResponse +} from "../types/pagopa"; import { getLocalePrimaryWithFallback } from "../utils/locale"; import { fixWalletPspTagsValues } from "../utils/wallet"; @@ -95,7 +95,7 @@ export type GetTransactionsUsingGETT = r.IGetApiRequestType< { readonly Bearer: string; readonly start: number }, "Authorization", never, - // tslint:disable-next-line: max-union-size + // eslint-disable-next-line | r.IResponseType<200, TransactionListResponse> | r.IResponseType<401, undefined> | r.IResponseType<403, undefined> @@ -110,18 +110,14 @@ type GetTransactionsUsingGETTExtra = MapResponseType< const ParamAuthorizationBearerHeader =

( p: P -): RequestHeaders<"Authorization"> => { - return { +): RequestHeaders<"Authorization"> => ({ Authorization: `Bearer ${p.Bearer}` - }; -}; + }); const ParamAuthorizationBearerHeaderProducer = < P extends { readonly Bearer: string } ->(): RequestHeaderProducer => { - return (p: P): RequestHeaders<"Authorization"> => +>(): RequestHeaderProducer => (p: P): RequestHeaders<"Authorization"> => ParamAuthorizationBearerHeader(p); -}; const tokenHeaderProducer = ParamAuthorizationBearerHeaderProducer(); const transactionsSliceLength = 10; @@ -170,7 +166,7 @@ const getPatchedWalletsUsingGETDecoder = ( r.composeResponseDecoders( r.composeResponseDecoders( r.composeResponseDecoders( - r.ioResponseDecoder<200, (typeof type)["_A"], (typeof type)["_O"]>( + r.ioResponseDecoder<200, typeof type["_A"], typeof type["_O"]>( 200, type, payload => { @@ -409,7 +405,10 @@ export function PaymentManagerClient( ) )({ id }), checkPayment: (id: TypeofApiParams["id"]) => - createFetchRequestForApi(checkPayment, altOptions)({ + createFetchRequestForApi( + checkPayment, + altOptions + )({ id }), getPspList: ( diff --git a/ts/boot/configureInstabug.ts b/ts/boot/configureInstabug.ts index 06e6ecaf113..e4a785f5ff7 100644 --- a/ts/boot/configureInstabug.ts +++ b/ts/boot/configureInstabug.ts @@ -39,7 +39,7 @@ export enum TypeLogs { } type InstabugLoggerType = { - [key in keyof typeof TypeLogs]: (value: string) => void + [key in keyof typeof TypeLogs]: (value: string) => void; }; const InstabugLogger: InstabugLoggerType = { INFO: Instabug.logInfo, diff --git a/ts/boot/configureStoreAndPersistor.ts b/ts/boot/configureStoreAndPersistor.ts index 36a7af46455..ee96a02c625 100644 --- a/ts/boot/configureStoreAndPersistor.ts +++ b/ts/boot/configureStoreAndPersistor.ts @@ -62,21 +62,17 @@ const migrations: MigrationManifest = { // Version 2 // Adds messagesIdsByServiceId - "2": (state: PersistedState) => { - return addMessagesIdsByServiceId(state as PersistedGlobalState); - }, + "2": (state: PersistedState) => addMessagesIdsByServiceId(state as PersistedGlobalState), // Version 3 // we changed the entities of organizations "3": (state: PersistedState) => { const entitiesState = (state as any).entities; const orgNameByFiscalCode = entitiesState.organizations; - const allOrganizations = Object.keys(orgNameByFiscalCode).map(key => { - return { + const allOrganizations = Object.keys(orgNameByFiscalCode).map(key => ({ fiscalCode: key, name: orgNameByFiscalCode[key] - }; - }); + })); return { ...state, @@ -92,8 +88,7 @@ const migrations: MigrationManifest = { // Version 4 // we added a state to monitor what pagoPA environment is selected - "4": (state: PersistedState) => { - return (state as PersistedGlobalState).persistedPreferences + "4": (state: PersistedState) => (state as PersistedGlobalState).persistedPreferences .isPagoPATestEnabled === undefined ? { ...state, @@ -104,8 +99,7 @@ const migrations: MigrationManifest = { } : { ...state - }; - }, + }, // Version 5 // we changed the way ToS acceptance is managed @@ -138,8 +132,7 @@ const migrations: MigrationManifest = { // Version 7 // we empty the services list to get both services list and services metadata being reloaded and persisted - "7": (state: PersistedState) => { - return { + "7": (state: PersistedState) => ({ ...state, entities: { ...(state as PersistedGlobalState).entities, @@ -148,14 +141,12 @@ const migrations: MigrationManifest = { byId: {} } } - }; - }, + }), // Version 8 // we load services scope in an specific view. So now it is uselss to hold (old) services metadata // they will be stored only when a service details screen is displayed - "8": (state: PersistedState) => { - return { + "8": (state: PersistedState) => ({ ...state, content: { ...(state as PersistedGlobalState).content, @@ -164,66 +155,55 @@ const migrations: MigrationManifest = { byId: {} } } - }; - }, + }), // Version 9 // we fix a bug on the version 8 of the migration implying a no proper creation of the content segment of store // (the servicesByScope state was not properly initialized) - "9": (state: PersistedState) => { - return { + "9": (state: PersistedState) => ({ ...state, content: { ...(state as PersistedGlobalState).content, servicesByScope: pot.none } - }; - }, + }), // Version 10 // since entities.messages are not persisted anymore, empty the related store section - "10": (state: PersistedState) => { - return { + "10": (state: PersistedState) => ({ ...state, entities: { ...(state as PersistedGlobalState).entities, messages: {} } - }; - }, + }), // Version 11 // add the default state for isCustomEmailChannelEnabled - "11": (state: PersistedState) => { - return { + "11": (state: PersistedState) => ({ ...state, persistedPreferences: { ...(state as PersistedGlobalState).persistedPreferences, isCustomEmailChannelEnabled: pot.none } - }; - }, + }), // Version 12 // change default state of isDebugModeEnabled: false - "12": (state: PersistedState) => { - return { + "12": (state: PersistedState) => ({ ...state, debug: { isDebugModeEnabled: false } - }; - }, + }), // Version 13 // add content.idpTextData // set default value - "13": (state: PersistedState) => { - return { + "13": (state: PersistedState) => ({ ...state, content: { ...(state as PersistedGlobalState).content, idpTextData: pot.none } - }; - }, + }), // Version 14 // remove content.idpTextData // add context.contextualHelp @@ -313,6 +293,7 @@ function configureStoreAndPersistor(): { store: Store; persistor: Persistor } { */ const composeEnhancers = + // eslint-disable-next-line no-underscore-dangle (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; const middlewares = applyMiddleware( sagaMiddleware, @@ -329,14 +310,16 @@ function configureStoreAndPersistor(): { store: Store; persistor: Persistor } { ? composeEnhancers(middlewares, RTron.createEnhancer()) : composeEnhancers(middlewares); - const store: Store = createStore( - persistedReducer, - enhancer - ); + const store: Store = createStore< + PersistedGlobalState, + Action, + Record, + Record + >(persistedReducer, enhancer); const persistor = persistStore(store); if (isDebuggingInChrome) { - // tslint:disable-next-line:no-object-mutation + // eslint-disable-next-line (window as any).store = store; } diff --git a/ts/components/AdviceComponent.tsx b/ts/components/AdviceComponent.tsx index 3cdcbcf50c4..a5278e2f9e8 100644 --- a/ts/components/AdviceComponent.tsx +++ b/ts/components/AdviceComponent.tsx @@ -28,8 +28,7 @@ const iconSize = 18; * This component displays an info icon on top-left and a text message * @constructor */ -const AdviceComponent: React.FunctionComponent = (props: Props) => { - return ( +const AdviceComponent: React.FunctionComponent = (props: Props) => ( = (props: Props) => { {props.text} ); -}; export default React.memo(AdviceComponent); diff --git a/ts/components/CalendarsListContainer.tsx b/ts/components/CalendarsListContainer.tsx index b49bfba9c7d..d8651084549 100644 --- a/ts/components/CalendarsListContainer.tsx +++ b/ts/components/CalendarsListContainer.tsx @@ -1,19 +1,18 @@ +import * as pot from "italia-ts-commons/lib/pot"; import { Button, Text, View } from "native-base"; import * as React from "react"; + +import { ListRenderItemInfo, SectionList } from "react-native"; import RNCalendarEvents, { Calendar } from "react-native-calendar-events"; import { connect } from "react-redux"; - -import * as pot from "italia-ts-commons/lib/pot"; -import { EdgeBorderComponent } from "../components/screens/EdgeBorderComponent"; import ListItemComponent from "../components/screens/ListItemComponent"; - -import { ListRenderItemInfo, SectionList } from "react-native"; import I18n from "../i18n"; import { preferredCalendarSaveSuccess } from "../store/actions/persistedPreferences"; import { Dispatch } from "../store/actions/types"; import { GlobalState } from "../store/reducers/types"; import customVariables from "../theme/variables"; import { convertLocalCalendarName } from "../utils/calendar"; +import { EdgeBorderComponent } from "./screens/EdgeBorderComponent"; import SectionHeaderComponent from "./screens/SectionHeaderComponent"; type CalendarByAccount = Readonly<{ diff --git a/ts/components/ChooserListContainer.tsx b/ts/components/ChooserListContainer.tsx index 209c3384d67..46b457f752a 100644 --- a/ts/components/ChooserListContainer.tsx +++ b/ts/components/ChooserListContainer.tsx @@ -309,7 +309,7 @@ class ChooserListContainer extends React.PureComponent, State> { } } -export default () => { +export default >() => { const hocComponent = (props: Props) => { const { selectedItemIds, diff --git a/ts/components/ChooserListSearch.tsx b/ts/components/ChooserListSearch.tsx index 3cac07bb342..b967726bbd4 100644 --- a/ts/components/ChooserListSearch.tsx +++ b/ts/components/ChooserListSearch.tsx @@ -72,9 +72,8 @@ class ChooserListSearch extends React.PureComponent, State> { return Promise.resolve(listState); } return new Promise(resolve => { - const result = listState.filter( - _ => - matchingTextPredicate ? matchingTextPredicate(_, searchText) : false + const result = listState.filter(_ => + matchingTextPredicate ? matchingTextPredicate(_, searchText) : false ); resolve(result); }); diff --git a/ts/components/ConnectionBar.tsx b/ts/components/ConnectionBar.tsx index 13f66bd8b6f..852e7a1c0f7 100644 --- a/ts/components/ConnectionBar.tsx +++ b/ts/components/ConnectionBar.tsx @@ -19,9 +19,7 @@ const styles = StyleSheet.create({ zIndex: Platform.OS === "ios" ? 1 : undefined }, inner: { - backgroundColor: color(customVariables.brandDarkestGray) - .fade(0.5) - .string(), + backgroundColor: color(customVariables.brandDarkestGray).fade(0.5).string(), height: 30, position: "absolute", flexDirection: "row", diff --git a/ts/components/ContextualHelp.tsx b/ts/components/ContextualHelp.tsx index 449ab653354..17d35395d5c 100644 --- a/ts/components/ContextualHelp.tsx +++ b/ts/components/ContextualHelp.tsx @@ -10,10 +10,10 @@ import * as React from "react"; import { BackHandler, StyleSheet } from "react-native"; import IconFont from "../components/ui/IconFont"; -import ButtonDefaultOpacity from "./ButtonDefaultOpacity"; -import AppHeader from "./ui/AppHeader"; import themeVariables from "../theme/variables"; +import ButtonDefaultOpacity from "./ButtonDefaultOpacity"; +import AppHeader from "./ui/AppHeader"; type Props = Readonly<{ title: string; diff --git a/ts/components/ContextualHelpModal.tsx b/ts/components/ContextualHelpModal.tsx index d39c0efb2ce..e3dcfc92519 100644 --- a/ts/components/ContextualHelpModal.tsx +++ b/ts/components/ContextualHelpModal.tsx @@ -65,22 +65,18 @@ const ContextualHelpModal: React.FunctionComponent = (props: Props) => { undefined ); - React.useEffect( - () => { - // if the contextual data is empty or is in error -> try to reload - if ( - !pot.isLoading(props.potContextualData) && - pot.isNone(props.potContextualData) && - pot.isError(props.potContextualData) - ) { - props.loadContextualHelpData(); - } - }, - [ - pot.isNone(props.potContextualData) || - pot.isError(props.potContextualData) - ] - ); + React.useEffect(() => { + // if the contextual data is empty or is in error -> try to reload + if ( + !pot.isLoading(props.potContextualData) && + pot.isNone(props.potContextualData) && + pot.isError(props.potContextualData) + ) { + props.loadContextualHelpData(); + } + }, [ + pot.isNone(props.potContextualData) || pot.isError(props.potContextualData) + ]); // after the modal is fully visible, render the content - // in case of complex markdown this can take some time and we don't @@ -90,7 +86,7 @@ const ContextualHelpModal: React.FunctionComponent = (props: Props) => { // on close, we set a handler to cleanup the content after all // interactions (animations) are complete const onClose = () => { - InteractionManager.runAfterInteractions(() => setContent(null)); + void InteractionManager.runAfterInteractions(() => setContent(null)); props.close(); }; @@ -154,13 +150,12 @@ const ContextualHelpModal: React.FunctionComponent = (props: Props) => { {customizedContent} - {props.faqCategories && - isContentLoaded && ( - - )} + {props.faqCategories && isContentLoaded && ( + + )} {isContentLoaded && ( diff --git a/ts/components/DetailedlistItemComponent.tsx b/ts/components/DetailedlistItemComponent.tsx index 31ed7138e58..868666b580c 100644 --- a/ts/components/DetailedlistItemComponent.tsx +++ b/ts/components/DetailedlistItemComponent.tsx @@ -87,13 +87,11 @@ const ICON_WIDTH = 24; export default class DetailedlistItemComponent extends React.PureComponent< Props > { - private getIconName = () => { - return this.props.isSelectionModeEnabled + private getIconName = () => this.props.isSelectionModeEnabled ? this.props.isItemSelected ? "io-checkbox-on" : "io-checkbox-off" : "io-right"; - }; public render() { return ( diff --git a/ts/components/FAQComponent.tsx b/ts/components/FAQComponent.tsx index 47af5f23094..617b15d3967 100644 --- a/ts/components/FAQComponent.tsx +++ b/ts/components/FAQComponent.tsx @@ -11,8 +11,7 @@ type Props = Readonly<{ onLinkClicked?: (url: string) => void; }>; -const FAQComponent: React.FunctionComponent = (props: Props) => { - return ( +const FAQComponent: React.FunctionComponent = (props: Props) => ( <> {getFAQsFromCategories(props.faqCategories).map( (faqType: FAQType, i: number) => ( @@ -26,6 +25,5 @@ const FAQComponent: React.FunctionComponent = (props: Props) => { )} ); -}; export default FAQComponent; diff --git a/ts/components/FiscalCodeLandscapeOverlay.tsx b/ts/components/FiscalCodeLandscapeOverlay.tsx index 1594b9172ed..ddc33d4a529 100644 --- a/ts/components/FiscalCodeLandscapeOverlay.tsx +++ b/ts/components/FiscalCodeLandscapeOverlay.tsx @@ -72,7 +72,7 @@ export default class FiscalCodeLandscapeOverlay extends React.PureComponent< // if there is an active timeout, clear it! if (this.scrollTimeout !== undefined) { clearTimeout(this.scrollTimeout); - // tslint:disable-next-line: no-object-mutation + // eslint-disable-next-line this.scrollTimeout = undefined; } } @@ -80,7 +80,7 @@ export default class FiscalCodeLandscapeOverlay extends React.PureComponent< private scrollToEnd = () => { if (this.props.showBackSide && this.ScrollVewRef.current) { // dalay the scroll to end command to wait until the ingress animation is completed - // tslint:disable-next-line: no-object-mutation + // eslint-disable-next-line this.scrollTimeout = setTimeout(() => { if (this.ScrollVewRef.current) { this.ScrollVewRef.current.scrollToEnd({ animated: true }); diff --git a/ts/components/FlagSecure.tsx b/ts/components/FlagSecure.tsx index d000f2035ac..2e80d7152be 100644 --- a/ts/components/FlagSecure.tsx +++ b/ts/components/FlagSecure.tsx @@ -15,16 +15,13 @@ type Props = ReturnType; * @constructor */ const FlagSecureComponent: React.FunctionComponent = props => { - useEffect( - () => { - if (props.isAllowedSnapshotCurrentScreen) { - FlagSecure.deactivate(); - } else { - FlagSecure.activate(); - } - }, - [props.isAllowedSnapshotCurrentScreen] - ); + useEffect(() => { + if (props.isAllowedSnapshotCurrentScreen) { + FlagSecure.deactivate(); + } else { + FlagSecure.activate(); + } + }, [props.isAllowedSnapshotCurrentScreen]); return null; }; diff --git a/ts/components/IdpsGrid.tsx b/ts/components/IdpsGrid.tsx index c67324f6fb5..2911fad6f75 100644 --- a/ts/components/IdpsGrid.tsx +++ b/ts/components/IdpsGrid.tsx @@ -75,8 +75,7 @@ const renderItem = (props: Props) => ( ); }; -const IdpsGrid: React.FunctionComponent = (props: Props) => { - return ( +const IdpsGrid: React.FunctionComponent = (props: Props) => ( = (props: Props) => { renderItem={renderItem(props)} /> ); -}; export default IdpsGrid; diff --git a/ts/components/LabelledItem.tsx b/ts/components/LabelledItem.tsx index 62c50219db3..80c83c0e07d 100644 --- a/ts/components/LabelledItem.tsx +++ b/ts/components/LabelledItem.tsx @@ -53,7 +53,8 @@ type Props = CommonProp & | Readonly<{ type: "text"; inputProps: TextInputProps; - }>); + }> + ); export class LabelledItem extends React.Component { constructor(props: Props) { diff --git a/ts/components/NavBarLabel.tsx b/ts/components/NavBarLabel.tsx index d220b4c3932..a0046a5fb64 100644 --- a/ts/components/NavBarLabel.tsx +++ b/ts/components/NavBarLabel.tsx @@ -38,13 +38,13 @@ const routeOrder = new Map([ ["PROFILE_NAVIGATOR", 4] ]); -const getLabel = (routeName: string, locale: Locales): string => { +const getLabel = (routeName: string, locale: Locales): string => // "routeName as Routes" is assumed to be safe as explained @https://github.com/pagopa/io-app/pull/193#discussion_r192347234 // adding fallback anyway -- better safe than sorry - return fromNullable(ROUTE_LABEL[routeName as Routes]).fold(fallbackLabel, l => + fromNullable(ROUTE_LABEL[routeName as Routes]).fold(fallbackLabel, l => I18n.t(l, { locale }) - ); -}; + ) +; const styles = StyleSheet.create({ labelStyle: { diff --git a/ts/components/Pinpad/KeyPad.tsx b/ts/components/Pinpad/KeyPad.tsx index 0a3002f6ffe..92a0f5a8608 100644 --- a/ts/components/Pinpad/KeyPad.tsx +++ b/ts/components/Pinpad/KeyPad.tsx @@ -75,8 +75,8 @@ const renderPinCol = ( style === "digit" ? styles.roundButton : style === "label" - ? [styles.roundButton, styles.transparent] - : undefined; + ? [styles.roundButton, styles.transparent] + : undefined; return ( @@ -89,8 +89,7 @@ const renderPinCol = ( unNamed={buttonType === "light"} > {label.fold( - l => { - return ( + l => ( {l} - ); - }, - ic => { - return ( + ), + ic => ( - ); - } + ) )} @@ -130,20 +126,19 @@ const renderPinRow = ( isDisabled: boolean ) => ( - {digits.map( - (el, i) => - el ? ( - renderPinCol( - el.e1, - el.e2, - el.e1.isLeft() ? "digit" : "label", - `pinpad-digit-${el.e2}`, - buttonType, - isDisabled - ) - ) : ( - + {digits.map((el, i) => + el ? ( + renderPinCol( + el.e1, + el.e2, + el.e1.isLeft() ? "digit" : "label", + `pinpad-digit-${el.e2}`, + buttonType, + isDisabled ) + ) : ( + + ) )} ); diff --git a/ts/components/Pinpad/index.tsx b/ts/components/Pinpad/index.tsx index ba4b30e730b..86758a4a55b 100644 --- a/ts/components/Pinpad/index.tsx +++ b/ts/components/Pinpad/index.tsx @@ -268,7 +268,7 @@ class Pinpad extends React.PureComponent { }); // re-enable after delayOnFailureMillis milliseconds - // tslint:disable-next-line: no-object-mutation + // eslint-disable-next-line this.onDelayOnFailureTimeoutId = setTimeout(() => { this.setState({ isDisabled: false @@ -283,7 +283,7 @@ class Pinpad extends React.PureComponent { // Fire the callback asynchronously, otherwise this component // will be unmounted before the render of the last bullet placeholder. - // tslint:disable-next-line no-object-mutation + // eslint-disable-next-line this.onFulfillTimeoutId = setTimeout(() => this.props.onFulfill(inputValue as PinString, isValid) ); diff --git a/ts/components/RemindEmailValidationOverlay.tsx b/ts/components/RemindEmailValidationOverlay.tsx index ceac7f61513..a6ea821b2ed 100644 --- a/ts/components/RemindEmailValidationOverlay.tsx +++ b/ts/components/RemindEmailValidationOverlay.tsx @@ -86,6 +86,7 @@ const profilePolling = 5000 as Millisecond; // 5 seconds const EMPTY_EMAIL = ""; const MARKDOWN_BODY_STYLE = "body { text-align: center;}"; const VALIDATION_ICON_WIDTH = 84; +const emailCtaKey = "email.validate.cta"; class RemindEmailValidationOverlay extends React.PureComponent { private idTimeout?: number; @@ -94,7 +95,7 @@ class RemindEmailValidationOverlay extends React.PureComponent { constructor(props: Props) { super(props); this.state = { - ctaSendEmailValidationText: I18n.t("email.validate.cta"), + ctaSendEmailValidationText: I18n.t(emailCtaKey), isLoading: false, isContentLoadCompleted: false, isCtaSentEmailValidationDisabled: false, @@ -111,7 +112,7 @@ class RemindEmailValidationOverlay extends React.PureComponent { public componentDidMount() { BackHandler.addEventListener("hardwareBackPress", this.handleHardwareBack); // Periodically check if the user validate his own email address - // tslint:disable-next-line: no-object-mutation + // eslint-disable-next-line this.idPolling = setInterval(this.props.reloadProfile, profilePolling); this.props.reloadProfile(); // since we are here, set the user doesn't acknowledge about the email validation @@ -162,7 +163,7 @@ class RemindEmailValidationOverlay extends React.PureComponent { // and we got an error if (pot.isError(this.props.emailValidationRequest)) { this.setState({ - ctaSendEmailValidationText: I18n.t("email.validate.cta"), + ctaSendEmailValidationText: I18n.t(emailCtaKey), isLoading: false, isCtaSentEmailValidationDisabled: false }); @@ -173,12 +174,12 @@ class RemindEmailValidationOverlay extends React.PureComponent { // schedule a timeout to make the cta button disabled and showing inside // the string that email has been sent. // after timeout we restore the default state - // tslint:disable-next-line: no-object-mutation + // eslint-disable-next-line this.idTimeout = setTimeout(() => { - // tslint:disable-next-line: no-object-mutation + // eslint-disable-next-line this.idTimeout = undefined; this.setState({ - ctaSendEmailValidationText: I18n.t("email.validate.cta"), + ctaSendEmailValidationText: I18n.t(emailCtaKey), isCtaSentEmailValidationDisabled: false }); }, emailSentTimeout); diff --git a/ts/components/RemindUpdatePagoPaVersionOverlay.tsx b/ts/components/RemindUpdatePagoPaVersionOverlay.tsx index 79d07141e2a..f899a996180 100644 --- a/ts/components/RemindUpdatePagoPaVersionOverlay.tsx +++ b/ts/components/RemindUpdatePagoPaVersionOverlay.tsx @@ -30,8 +30,11 @@ const styles = StyleSheet.create({ const timeoutErrorMsg: Millisecond = 5000 as Millisecond; -class RemindUpdatePagoPaVersionOverlay extends React.PureComponent<{}, State> { - constructor(props: {}) { +class RemindUpdatePagoPaVersionOverlay extends React.PureComponent< + Record, + State +> { + constructor(props: Record) { super(props); this.state = { hasError: false @@ -58,7 +61,7 @@ class RemindUpdatePagoPaVersionOverlay extends React.PureComponent<{}, State> { hasError: true }); // After 5 seconds restore state - // tslint:disable-next-line: no-object-mutation + // eslint-disable-next-line this.idTimeout = setTimeout(() => { this.setState({ hasError: false diff --git a/ts/components/ScreenHeader.tsx b/ts/components/ScreenHeader.tsx index 79968181997..d604d1ca0ef 100644 --- a/ts/components/ScreenHeader.tsx +++ b/ts/components/ScreenHeader.tsx @@ -51,12 +51,10 @@ class ScreenHeader extends React.Component { return fromNullable(iconFont).fold(undefined, ic => { const { dark } = this.props; const imageColor = fromNullable(ic.color).getOrElse( - fromNullable(dark).fold( - customVariables.headerIconLight, - isDark => - isDark - ? customVariables.headerIconDark - : customVariables.headerIconLight + fromNullable(dark).fold(customVariables.headerIconLight, isDark => + isDark + ? customVariables.headerIconDark + : customVariables.headerIconLight ) ); return ( diff --git a/ts/components/SelectLogoutOption.tsx b/ts/components/SelectLogoutOption.tsx index bb8c0166c3d..bff9ad011e6 100644 --- a/ts/components/SelectLogoutOption.tsx +++ b/ts/components/SelectLogoutOption.tsx @@ -101,17 +101,12 @@ class SelectLogoutOption extends React.PureComponent { } } -const mapStateToProps = (state: GlobalState) => { - return { +const mapStateToProps = (state: GlobalState) => ({ isLogoutInProgress: isLogoutRequested(state) - }; -}; + }); const mapDispatchToProps = (dispatch: Dispatch) => ({ logout: (logoutOption: LogoutOption) => dispatch(logoutRequest(logoutOption)) }); -export default connect( - mapStateToProps, - mapDispatchToProps -)(SelectLogoutOption); +export default connect(mapStateToProps, mapDispatchToProps)(SelectLogoutOption); diff --git a/ts/components/TosWebviewComponent.tsx b/ts/components/TosWebviewComponent.tsx index c8bbdb8b947..051595924c4 100644 --- a/ts/components/TosWebviewComponent.tsx +++ b/ts/components/TosWebviewComponent.tsx @@ -15,8 +15,7 @@ type Props = { onExit: () => void; }; -const TosWebviewComponent: React.FunctionComponent = (props: Props) => { - return ( +const TosWebviewComponent: React.FunctionComponent = (props: Props) => ( <> = (props: Props) => { )} ); -}; export default React.memo(TosWebviewComponent); diff --git a/ts/components/TouchableDefaultOpacity.tsx b/ts/components/TouchableDefaultOpacity.tsx index 6a701d68e7f..014a490479f 100644 --- a/ts/components/TouchableDefaultOpacity.tsx +++ b/ts/components/TouchableDefaultOpacity.tsx @@ -9,8 +9,7 @@ const defaultActiveOpacity = 1.0; */ const TouchableDefaultOpacity = ( props: TouchableOpacityProps & React.Props -) => { - return ( +) => ( ); -}; export default TouchableDefaultOpacity; diff --git a/ts/components/animations/AnimatedRing.tsx b/ts/components/animations/AnimatedRing.tsx index 4efe1992dec..1200c76a090 100644 --- a/ts/components/animations/AnimatedRing.tsx +++ b/ts/components/animations/AnimatedRing.tsx @@ -29,7 +29,7 @@ export default class AnimatedRing extends React.Component { public componentDidMount() { // Here an animation is created: a ring expands its area in a time interval and repeat it infinitely. // The animation starts with a delay passed in the props - // tslint:disable-next-line: no-object-mutation + // eslint-disable-next-line this.idTimeout = setTimeout(() => { Animated.loop( Animated.timing(this.animatedValue, { diff --git a/ts/components/cie/CieReadingCardAnimation.tsx b/ts/components/cie/CieReadingCardAnimation.tsx index 493940ce4d6..3ffa2ff5b6a 100644 --- a/ts/components/cie/CieReadingCardAnimation.tsx +++ b/ts/components/cie/CieReadingCardAnimation.tsx @@ -72,7 +72,7 @@ export default class CieReadingCardAnimation extends React.PureComponent< this.state = { progressBarValue: 0 }; - // tslint:disable-next-line: no-object-mutation + // eslint-disable-next-line this.progressAnimatedValue = new Animated.Value(0); this.createAnimation(); } @@ -94,7 +94,7 @@ export default class CieReadingCardAnimation extends React.PureComponent< easing: Easing.linear, duration: 10000 }); - // tslint:disable-next-line: no-object-mutation + // eslint-disable-next-line this.progressAnimation = Animated.sequence([firstAnim, secondAnim]); this.addAnimationListener(); } diff --git a/ts/components/cie/CieRequestAuthenticationOverlay.tsx b/ts/components/cie/CieRequestAuthenticationOverlay.tsx index b95dbb77fbb..77bd1c8fb77 100644 --- a/ts/components/cie/CieRequestAuthenticationOverlay.tsx +++ b/ts/components/cie/CieRequestAuthenticationOverlay.tsx @@ -103,8 +103,7 @@ export default class CieRequestAuthenticationOverlay extends React.PureComponent return true; }; - private renderError = () => { - return ( + private renderError = () => ( ); - }; // Updating the webView key its content is refreshed private handleOnRetry = () => { diff --git a/ts/components/core/__test__/fontsAndroid.test.ts b/ts/components/core/__test__/fontsAndroid.test.ts index b1557548ba7..9ce00d70452 100644 --- a/ts/components/core/__test__/fontsAndroid.test.ts +++ b/ts/components/core/__test__/fontsAndroid.test.ts @@ -3,6 +3,7 @@ import { fontWeightsMocks, italics } from "../__mock__/fontMocks"; import { makeFontStyleObject } from "../fonts"; jest.mock("react-native", () => ({ + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Platform: { OS: "android", select: obj => obj.android } })); diff --git a/ts/components/core/__test__/fontsiOS.test.ts b/ts/components/core/__test__/fontsiOS.test.ts index 74368ff83a8..c15e19351a9 100644 --- a/ts/components/core/__test__/fontsiOS.test.ts +++ b/ts/components/core/__test__/fontsiOS.test.ts @@ -3,6 +3,7 @@ import { fontWeightsMocks, italics } from "../__mock__/fontMocks"; import { FontStyle, fontWeights, makeFontStyleObject } from "../fonts"; jest.mock("react-native", () => ({ + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Platform: { OS: "ios", select: obj => obj.ios } })); diff --git a/ts/components/core/typography/BaseTypography.tsx b/ts/components/core/typography/BaseTypography.tsx index 7e9fcab2c58..c05e1abd6a5 100644 --- a/ts/components/core/typography/BaseTypography.tsx +++ b/ts/components/core/typography/BaseTypography.tsx @@ -4,7 +4,7 @@ import { StyleProp, Text, TextStyle } from "react-native"; import { IOFontFamily, IOFontWeight, makeFontStyleObject } from "../fonts"; import { IOColors, IOColorType } from "../variables/IOColors"; -/*** +/** * The specific properties needed to calculate the font style using {@link makeFontStyleObject} (these information * cannot be included in the default StyleProp */ diff --git a/ts/components/core/typography/Body.tsx b/ts/components/core/typography/Body.tsx index ce2961c0dd2..993c22831c0 100644 --- a/ts/components/core/typography/Body.tsx +++ b/ts/components/core/typography/Body.tsx @@ -14,18 +14,16 @@ type OwnProps = ExternalTypographyProps< const fontName: IOFontFamily = "TitilliumWeb"; const fontSize = 16; -/*** +/** * Typography component to render `Body` text with font size {@link fontSize} and fontFamily {@link fontName}. * default values(if not defined) are weight: `Regular`, color: `bluegreyDark` * @param props` * @constructor */ -export const Body: React.FunctionComponent = props => { - return typographyFactory({ +export const Body: React.FunctionComponent = props => typographyFactory({ ...props, defaultWeight: "Regular", defaultColor: "bluegreyDark", font: fontName, fontStyle: { fontSize } }); -}; diff --git a/ts/components/core/typography/H1.tsx b/ts/components/core/typography/H1.tsx index 60fd7d77920..b5ff2776d2a 100644 --- a/ts/components/core/typography/H1.tsx +++ b/ts/components/core/typography/H1.tsx @@ -14,18 +14,16 @@ type OwnProps = ExternalTypographyProps< const fontName: IOFontFamily = "TitilliumWeb"; const fontSize = 28; -/*** +/** * Typography component to render H1 text with font size {@link fontSize} and fontFamily {@link fontName}. * default values(if not defined) are weight: `Bold`, color: `bluegreyDark` * @param props * @constructor */ -export const H1: React.FunctionComponent = props => { - return typographyFactory({ +export const H1: React.FunctionComponent = props => typographyFactory({ ...props, defaultWeight: "Bold", defaultColor: "bluegreyDark", font: fontName, fontStyle: { fontSize } }); -}; diff --git a/ts/components/core/typography/H2.tsx b/ts/components/core/typography/H2.tsx index 440b5c465c4..d3020f0ec5d 100644 --- a/ts/components/core/typography/H2.tsx +++ b/ts/components/core/typography/H2.tsx @@ -14,18 +14,16 @@ type OwnProps = ExternalTypographyProps< const fontName: IOFontFamily = "TitilliumWeb"; const fontSize = 20; -/*** +/** * Typography component to render `H2` text with font size {@link fontSize} and fontFamily {@link fontName}. * default values(if not defined) are weight: `Bold`, color: `bluegreyDark` * @param props * @constructor */ -export const H2: React.FunctionComponent = props => { - return typographyFactory({ +export const H2: React.FunctionComponent = props => typographyFactory({ ...props, defaultWeight: "Bold", defaultColor: "bluegreyDark", font: fontName, fontStyle: { fontSize } }); -}; diff --git a/ts/components/core/typography/H3.tsx b/ts/components/core/typography/H3.tsx index 3baa5e34144..09b7af57bef 100644 --- a/ts/components/core/typography/H3.tsx +++ b/ts/components/core/typography/H3.tsx @@ -38,7 +38,7 @@ type OwnProps = ExternalTypographyProps; const fontName: IOFontFamily = "TitilliumWeb"; const fontSize = 18; -/*** +/** * A custom function to calculate the values if no weight or color is provided. * The choose of the default color depends on the weight, for this reason cannot be used * the default calculateWeightColor with fallback if undefined. @@ -49,30 +49,28 @@ const calculateWeightColor = ( weight?: AllowedWeight, color?: AllowedColors ): RequiredTypographyProps => { - const newWeight = weight !== undefined ? weight : "SemiBold"; + const newWeight = weight ?? "SemiBold"; const newColor = color !== undefined ? color : newWeight === "SemiBold" - ? "bluegreyDark" - : "white"; + ? "bluegreyDark" + : "white"; return { weight: newWeight, color: newColor }; }; -/*** +/** * Typography component to render `H3` text with font size {@link fontSize} and fontFamily {@link fontName}. * default values(if not defined) are weight: `SemiBold`, color: `bluegreyDark` * @param props * @constructor */ -export const H3: React.FunctionComponent = props => { - return typographyFactory({ +export const H3: React.FunctionComponent = props => typographyFactory({ ...props, weightColorFactory: calculateWeightColor, font: fontName, fontStyle: { fontSize } }); -}; diff --git a/ts/components/core/typography/H4.tsx b/ts/components/core/typography/H4.tsx index 569dd16675c..3acc4717231 100644 --- a/ts/components/core/typography/H4.tsx +++ b/ts/components/core/typography/H4.tsx @@ -54,7 +54,7 @@ type OwnProps = ExternalTypographyProps; const fontName: IOFontFamily = "TitilliumWeb"; const fontSize = 16; -/*** +/** * A custom function to calculate the values if no weight or color is provided. * The choose of the default color depends on the weight, for this reason cannot be used * the default calculateWeightColor with fallback if undefined. @@ -65,32 +65,30 @@ const calculateWeightColor = ( weight?: AllowedWeight, color?: AllowedColors ): RequiredTypographyProps => { - const newWeight = weight !== undefined ? weight : "Bold"; + const newWeight = weight ?? "Bold"; const newColor = color !== undefined ? color : newWeight === "Bold" - ? "bluegreyDark" - : newWeight === "SemiBold" - ? "white" - : "bluegreyDark"; + ? "bluegreyDark" + : newWeight === "SemiBold" + ? "white" + : "bluegreyDark"; return { weight: newWeight, color: newColor }; }; -/*** +/** * Typography component to render `H4` text with font size {@link fontSize} and fontFamily {@link fontName}. * default values(if not defined) are weight: `Bold`, color: `bluegreyDark` * @param props * @constructor */ -export const H4: React.FunctionComponent = props => { - return typographyFactory({ +export const H4: React.FunctionComponent = props => typographyFactory({ ...props, weightColorFactory: calculateWeightColor, font: fontName, fontStyle: { fontSize } }); -}; diff --git a/ts/components/core/typography/H5.tsx b/ts/components/core/typography/H5.tsx index e20eb8a4849..d3bd088b745 100644 --- a/ts/components/core/typography/H5.tsx +++ b/ts/components/core/typography/H5.tsx @@ -42,18 +42,16 @@ type OwnProps = ExternalTypographyProps; const fontName: IOFontFamily = "TitilliumWeb"; const fontSize = 14; -/*** +/** * Typography component to render `H5` text with font size {@link fontSize} and fontFamily {@link fontName}. * default values(if not defined) are weight: `SemiBold`, color: `bluegreyDark` * @param props * @constructor */ -export const H5: React.FunctionComponent = props => { - return typographyFactory({ +export const H5: React.FunctionComponent = props => typographyFactory({ ...props, defaultWeight: "SemiBold", defaultColor: "bluegreyDark", font: fontName, fontStyle: { fontSize } }); -}; diff --git a/ts/components/core/typography/Label.tsx b/ts/components/core/typography/Label.tsx index e9b94b3d95b..c8c65f9e14a 100644 --- a/ts/components/core/typography/Label.tsx +++ b/ts/components/core/typography/Label.tsx @@ -14,18 +14,16 @@ type OwnProps = ExternalTypographyProps< const fontName: IOFontFamily = "TitilliumWeb"; const fontSize = 16; -/*** +/** * Typography component to render `Label` text with font size {@link fontSize} and fontFamily {@link fontName}. * default values(if not defined) are weight: `Bold`, color: `blue` * @param props` * @constructor */ -export const Label: React.FunctionComponent = props => { - return typographyFactory({ +export const Label: React.FunctionComponent = props => typographyFactory({ ...props, defaultWeight: "Bold", defaultColor: "blue", font: fontName, fontStyle: { fontSize } }); -}; diff --git a/ts/components/core/typography/LabelSmall.tsx b/ts/components/core/typography/LabelSmall.tsx index 4aed7644dd4..0e9d72c5f8d 100644 --- a/ts/components/core/typography/LabelSmall.tsx +++ b/ts/components/core/typography/LabelSmall.tsx @@ -18,18 +18,16 @@ type OwnProps = ExternalTypographyProps< const fontName: IOFontFamily = "TitilliumWeb"; const fontSize = 14; -/*** +/** * Typography component to render `LabelSmall` text with font size {@link fontSize} and fontFamily {@link fontName}. * default values(if not defined) are weight: `Bold`, color: `blue` * @param props` * @constructor */ -export const LabelSmall: React.FunctionComponent = props => { - return typographyFactory({ +export const LabelSmall: React.FunctionComponent = props => typographyFactory({ ...props, defaultWeight: "Bold", defaultColor: "blue", font: fontName, fontStyle: { fontSize } }); -}; diff --git a/ts/components/core/typography/Link.tsx b/ts/components/core/typography/Link.tsx index d53b141834d..40c09566241 100644 --- a/ts/components/core/typography/Link.tsx +++ b/ts/components/core/typography/Link.tsx @@ -14,14 +14,13 @@ type OwnProps = ExternalTypographyProps< const fontName: IOFontFamily = "TitilliumWeb"; const fontSize = 16; -/*** +/** * Typography component to render `Link` text with font size {@link fontSize} and fontFamily {@link fontName}. * default values(if not defined) are weight: `SemiBold`, color: `blue` * @param props` * @constructor */ -export const Link: React.FunctionComponent = props => { - return typographyFactory({ +export const Link: React.FunctionComponent = props => typographyFactory({ ...props, defaultWeight: "SemiBold", defaultColor: "blue", @@ -31,4 +30,3 @@ export const Link: React.FunctionComponent = props => { textDecorationLine: "underline" } }); -}; diff --git a/ts/components/core/typography/Monospace.tsx b/ts/components/core/typography/Monospace.tsx index 12f533c8c45..ab0808a73d2 100644 --- a/ts/components/core/typography/Monospace.tsx +++ b/ts/components/core/typography/Monospace.tsx @@ -14,18 +14,16 @@ type OwnProps = ExternalTypographyProps< const fontName: IOFontFamily = "RobotoMono"; const fontSize = 16; -/*** +/** * Typography component to render `Monospace` text with font size {@link fontSize} and fontFamily {@link fontName}. * default values(if not defined) are weight: `Regular`, color: `bluegrey` * @param props` * @constructor */ -export const Monospace: React.FunctionComponent = props => { - return typographyFactory({ +export const Monospace: React.FunctionComponent = props => typographyFactory({ ...props, defaultWeight: "Regular", defaultColor: "bluegrey", font: fontName, fontStyle: { fontSize } }); -}; diff --git a/ts/components/core/typography/common.tsx b/ts/components/core/typography/common.tsx index d49d7c79fed..6b10f8572b9 100644 --- a/ts/components/core/typography/common.tsx +++ b/ts/components/core/typography/common.tsx @@ -4,7 +4,7 @@ import { RequiredAll } from "../../../types/utils"; import { IOFontWeight } from "../fonts"; import { IOColorType } from "../variables/IOColors"; -/*** +/** * A default function used to calculate the weight and color with some fallback values if not specified. * @param defaultWeight the default weight value to use if weight is not defined * @param defaultColor the default color value to use if color is not defined diff --git a/ts/components/helpers/withConditionalView.tsx b/ts/components/helpers/withConditionalView.tsx index bba03e52a00..b6f8bc82209 100644 --- a/ts/components/helpers/withConditionalView.tsx +++ b/ts/components/helpers/withConditionalView.tsx @@ -16,7 +16,7 @@ export function withConditionalView( * the contition component to ensure the nagivigation can address the proper * navigation paramaters */ - type nullN = {}; + type nullN = Record; type NP = P extends NavigationInjectedProps ? N : nullN; type NC = C extends NavigationInjectedProps ? N : nullN; type NN = NavigationInjectedProps; @@ -24,9 +24,9 @@ export function withConditionalView( class ConditionalView extends React.PureComponent<(P | C) & T & NN> { public render() { return check(this.props as T) ? ( - + ) : ( - + ); } } diff --git a/ts/components/helpers/withErrorModal.tsx b/ts/components/helpers/withErrorModal.tsx index ac005f63b6a..29a4fad6ea2 100644 --- a/ts/components/helpers/withErrorModal.tsx +++ b/ts/components/helpers/withErrorModal.tsx @@ -89,8 +89,7 @@ export function withErrorModal< ); - private renderButtons = () => { - return ( + private renderButtons = () => ( ); - }; } return WithErrorModal; diff --git a/ts/components/helpers/withItemsSelection.tsx b/ts/components/helpers/withItemsSelection.tsx index 31187f70b2f..b8c019ca819 100644 --- a/ts/components/helpers/withItemsSelection.tsx +++ b/ts/components/helpers/withItemsSelection.tsx @@ -35,7 +35,7 @@ export function withItemsSelection

( const { selectedItemIds } = this.state; return ( ( // A function to add/remove an id from the selectedItemIds Set. private toggleItemSelection = (id: string) => { - this.setState(({ selectedItemIds }) => { - return selectedItemIds + this.setState(({ selectedItemIds }) => + selectedItemIds .map(_ => { const newSelectedItemIds = new Set(_); - newSelectedItemIds.has(id) - ? newSelectedItemIds.delete(id) - : newSelectedItemIds.add(id); + if (newSelectedItemIds.has(id)) { + newSelectedItemIds.delete(id); + } else { + newSelectedItemIds.add(id); + } return { selectedItemIds: some(newSelectedItemIds) }; }) .getOrElse({ - selectedItemIds: some(new Set([id])) - }); - }); + selectedItemIds: some( + new Set([id]) + ) + }) + ); }; private setSelectedItemIds = (newSelectedItemIds: Option>) => { diff --git a/ts/components/infoScreen/imageRendering.tsx b/ts/components/infoScreen/imageRendering.tsx index 4b347927472..e3e12096b15 100644 --- a/ts/components/infoScreen/imageRendering.tsx +++ b/ts/components/infoScreen/imageRendering.tsx @@ -1,11 +1,14 @@ import * as React from "react"; -import { Dimensions, Image, ImageSourcePropType } from "react-native"; +import { + Dimensions, + Image, + ImageSourcePropType, + StyleSheet +} from "react-native"; import { heightPercentageToDP } from "react-native-responsive-screen"; import customVariables from "../../theme/variables"; import IconFont from "../ui/IconFont"; -import { StyleSheet } from "react-native"; - const infoImageSize = 102; const screenHeight = Dimensions.get("screen").height; const maxHeightFullSize = 650; diff --git a/ts/components/messages/CalendarEventButton.tsx b/ts/components/messages/CalendarEventButton.tsx index 87e5f4c53a0..c19f0a79cd0 100644 --- a/ts/components/messages/CalendarEventButton.tsx +++ b/ts/components/messages/CalendarEventButton.tsx @@ -96,7 +96,10 @@ class CalendarEventButton extends React.PureComponent { calendarEvent.eventId ).run(); this.setState({ - isEventInDeviceCalendar: mayBeInCalendar.fold(_ => false, s => s) + isEventInDeviceCalendar: mayBeInCalendar.fold( + _ => false, + s => s + ) }); }; @@ -240,7 +243,7 @@ class CalendarEventButton extends React.PureComponent { } // Check the authorization status - checkAndRequestPermission() + void checkAndRequestPermission() .then(calendarPermission => { if (calendarPermission.authorized) { if (this.state.isEventInDeviceCalendar) { @@ -268,9 +271,10 @@ class CalendarEventButton extends React.PureComponent { { cancelable: false } ); } else if (preferredCalendar !== undefined) { - this.addCalendarEventToDeviceCalendar(message, due_date)( - preferredCalendar - ); + this.addCalendarEventToDeviceCalendar( + message, + due_date + )(preferredCalendar); } else { // The event need to be added // Show a modal to let the user select a calendar diff --git a/ts/components/messages/EmptyListComponent.tsx b/ts/components/messages/EmptyListComponent.tsx index 1b7ee86eb6a..879ad45f573 100644 --- a/ts/components/messages/EmptyListComponent.tsx +++ b/ts/components/messages/EmptyListComponent.tsx @@ -23,8 +23,7 @@ type Props = Readonly<{ subtitle?: string; }>; -export const EmptyListComponent = (props: Props) => { - return ( +export const EmptyListComponent = (props: Props) => ( @@ -32,4 +31,3 @@ export const EmptyListComponent = (props: Props) => { {props.subtitle && {props.subtitle}} ); -}; diff --git a/ts/components/messages/ErrorLoadingComponent.tsx b/ts/components/messages/ErrorLoadingComponent.tsx index 9ea36808b13..bde0bd5bfe3 100644 --- a/ts/components/messages/ErrorLoadingComponent.tsx +++ b/ts/components/messages/ErrorLoadingComponent.tsx @@ -14,8 +14,7 @@ const styles = StyleSheet.create({ } }); -export const ErrorLoadingComponent = () => { - return ( +export const ErrorLoadingComponent = () => ( { {I18n.t("messages.loadingErrorTitle")} ); -}; diff --git a/ts/components/messages/MedicalPrescriptionAttachments.tsx b/ts/components/messages/MedicalPrescriptionAttachments.tsx index b9e7f916a1e..ec8e682d735 100644 --- a/ts/components/messages/MedicalPrescriptionAttachments.tsx +++ b/ts/components/messages/MedicalPrescriptionAttachments.tsx @@ -63,12 +63,10 @@ export default class MedicalPrescriptionAttachments extends React.PureComponent< const barCodeContents = await new Promise((res, _) => { const attchs = this.attachmentsToRender; const content = attchs.reduce( - (acc: BarCodeContents, curr: MessageAttachment) => { - return { + (acc: BarCodeContents, curr: MessageAttachment) => ({ ...acc, [curr.name]: Buffer.from(curr.content, "base64").toString("ascii") - }; - }, + }), {} ); res(content); diff --git a/ts/components/messages/MedicalPrescriptionDueDateBar.tsx b/ts/components/messages/MedicalPrescriptionDueDateBar.tsx index 0d24eee2a19..bc28e7f9fec 100644 --- a/ts/components/messages/MedicalPrescriptionDueDateBar.tsx +++ b/ts/components/messages/MedicalPrescriptionDueDateBar.tsx @@ -134,8 +134,8 @@ class MedicalPrescriptionDueDateBar extends React.PureComponent { const textColor = this.isPrescriptionExpiring ? customVariables.calendarExpirableColor : this.isPrescriptionExpired - ? customVariables.brandDarkGray - : customVariables.colorWhite; + ? customVariables.brandDarkGray + : customVariables.colorWhite; return ( { */ public render() { const { dueDate } = this; - return dueDate.fold(null, _ => { - return !this.isPrescriptionExpiring && !this.isPrescriptionExpired ? ( + return dueDate.fold(null, _ => !this.isPrescriptionExpiring && !this.isPrescriptionExpired ? ( {this.textContent} @@ -174,8 +173,7 @@ class MedicalPrescriptionDueDateBar extends React.PureComponent { {this.textContent} - ); - }); + )); } } diff --git a/ts/components/messages/MedicalPrescriptionIdentifiersComponent.tsx b/ts/components/messages/MedicalPrescriptionIdentifiersComponent.tsx index 714d1292cac..d23f311820a 100644 --- a/ts/components/messages/MedicalPrescriptionIdentifiersComponent.tsx +++ b/ts/components/messages/MedicalPrescriptionIdentifiersComponent.tsx @@ -32,8 +32,7 @@ const styles = StyleSheet.create({ export default class MedicalPrescriptionIdentifiersComponent extends React.PureComponent< Props > { - private renderItem = (label: string, value: string) => { - return ( + private renderItem = (label: string, value: string) => ( {label} @@ -44,7 +43,6 @@ export default class MedicalPrescriptionIdentifiersComponent extends React.PureC ); - }; public render() { const { prescriptionData } = this.props; diff --git a/ts/components/messages/MessageAgenda.tsx b/ts/components/messages/MessageAgenda.tsx index 91bd0ff6e2a..7f99753a69b 100644 --- a/ts/components/messages/MessageAgenda.tsx +++ b/ts/components/messages/MessageAgenda.tsx @@ -147,7 +147,7 @@ export type MessageAgendaSection = SectionListData< MessageAgendaItem | FakeItem >; -// tslint:disable-next-line: readonly-array +// eslint-disable-next-line export type Sections = MessageAgendaSection[]; export type ItemLayout = { @@ -183,9 +183,7 @@ type State = { isFirstLoading: boolean; }; -export const isFakeItem = (item: any): item is FakeItem => { - return item.fake; -}; +export const isFakeItem = (item: any): item is FakeItem => item.fake; // Min number of items to activate continuos scroll const minItemsToScroll = 4; @@ -203,15 +201,16 @@ const keyExtractor = (_: MessageAgendaItem | FakeItem, index: number) => * Here we calculate the ItemLayout for each cell. */ const generateItemLayouts = (sections: Sections) => { - // tslint:disable-next-line: no-let + // eslint-disable-next-line let offset = LIST_HEADER_HEIGHT; - // tslint:disable-next-line: no-let + // eslint-disable-next-line let index = 0; - // tslint:disable-next-line: readonly-array + // eslint-disable-next-line const itemLayouts: ItemLayout[] = []; sections.forEach(section => { // Push the info about the SECTION_HEADER cell. + // eslint-disable-next-line functional/immutable-data itemLayouts.push({ length: SECTION_HEADER_HEIGHT, offset, @@ -230,6 +229,7 @@ const generateItemLayouts = (sections: Sections) => { const cellHeight = isLastItem ? itemHeight : itemHeight + ITEM_SEPARATOR_HEIGHT; + // eslint-disable-next-line functional/immutable-data itemLayouts.push({ length: cellHeight, offset, @@ -243,6 +243,7 @@ const generateItemLayouts = (sections: Sections) => { // Push the info about the SECTION_FOOTER cell. // NOTE: VirtualizedSectionList component creates a cell instance for // the SECTION_FOOTER even when not rendered. + // eslint-disable-next-line functional/immutable-data itemLayouts.push({ length: 0, offset, @@ -285,7 +286,7 @@ class MessageAgenda extends React.PureComponent { } } - // tslint:disable-next-line: cognitive-complexity + // eslint-disable-next-line public componentDidUpdate(prevProps: Props) { // Change status loading to show progress if ( @@ -302,7 +303,7 @@ class MessageAgenda extends React.PureComponent { this.setState({ isFirstLoading: false }); } else { // We leave half a second longer to show the progress even for faster requests - // tslint:disable-next-line: no-object-mutation + // eslint-disable-next-line this.idTimeoutProgress = setTimeout(() => { this.setState({ isLoadingProgress: false @@ -425,9 +426,7 @@ class MessageAgenda extends React.PureComponent { const payment = message.content.payment_data !== undefined && service !== undefined ? paymentsByRptId[ - `${service.organization_fiscal_code}${ - message.content.payment_data.notice_number - }` + `${service.organization_fiscal_code}${message.content.payment_data.notice_number}` ] : undefined; @@ -449,9 +448,8 @@ class MessageAgenda extends React.PureComponent { ); }; - private getItemLayout = (_: Sections | null, index: number) => { - return this.state.itemLayouts[index]; - }; + private getItemLayout = (_: Sections | null, index: number) => + this.state.itemLayouts[index]; // On scroll download more data private onScrollHandler = (e: NativeSyntheticEvent) => { @@ -541,27 +539,24 @@ class MessageAgenda extends React.PureComponent { : ListEmptyComponent } /> - {isLoadingProgress && - isContinuosScrollEnabled && ( - - - - )} + {isLoadingProgress && isContinuosScrollEnabled && ( + + + + )} ); } - public noOtherDeadlines = () => { - return ( - - {I18n.t("reminders.noOtherDeadlines")} - - ); - }; + public noOtherDeadlines = () => ( + + {I18n.t("reminders.noOtherDeadlines")} + + ); public scrollToLocation = (params: SectionListScrollParams) => { if ( diff --git a/ts/components/messages/MessageDetailCTABar.tsx b/ts/components/messages/MessageDetailCTABar.tsx index f0e579ede46..7a4748d9654 100644 --- a/ts/components/messages/MessageDetailCTABar.tsx +++ b/ts/components/messages/MessageDetailCTABar.tsx @@ -49,16 +49,14 @@ class MessageDetailCTABar extends React.PureComponent { } // Render a button to add/remove an event related to the message in the calendar - private renderCalendarEventButton = () => { + private renderCalendarEventButton = () => // The add/remove reminder button is hidden: // - if the message hasn't a due date // - if the message has a payment and it has been paid or is expired - return this.dueDate + this.dueDate .chain(fromPredicate(() => !this.paid && !this.isPaymentExpired)) - .fold(null, _ => { - return ; - }); - }; + .fold(null, _ => ) + ; // Render a button to display details of the payment related to the message private renderPaymentButton() { diff --git a/ts/components/messages/MessageDetailComponent.tsx b/ts/components/messages/MessageDetailComponent.tsx index d51d1d3cc11..4287767c4d7 100644 --- a/ts/components/messages/MessageDetailComponent.tsx +++ b/ts/components/messages/MessageDetailComponent.tsx @@ -118,17 +118,14 @@ export default class MessageDetailComponent extends React.PureComponent< return this.service.fold(undefined, service => { if (message.content.payment_data !== undefined) { return paymentsByRptId[ - `${service.organization_fiscal_code}${ - message.content.payment_data.notice_number - }` + `${service.organization_fiscal_code}${message.content.payment_data.notice_number}` ]; } return undefined; }); } - private getTitle = () => { - return this.maybeMedicalData.fold( + private getTitle = () => this.maybeMedicalData.fold(

{this.props.message.content.subject}

, _ => ( @@ -137,7 +134,6 @@ export default class MessageDetailComponent extends React.PureComponent< ) ); - }; public render() { const { @@ -154,13 +150,12 @@ export default class MessageDetailComponent extends React.PureComponent< {/** Header */} - {service !== undefined && - service.isSome() && ( - - {service && } - - - )} + {service !== undefined && service.isSome() && ( + + {service && } + + + )} {/* Subject */} {this.getTitle()} @@ -192,19 +187,18 @@ export default class MessageDetailComponent extends React.PureComponent< - {this.attachments.isSome() && - this.state.isContentLoadCompleted && ( - - s.organization_name) - .toUndefined()} - /> - - - )} + {this.attachments.isSome() && this.state.isContentLoadCompleted && ( + + s.organization_name) + .toUndefined()} + /> + + + )} {this.state.isContentLoadCompleted && ( diff --git a/ts/components/messages/MessageDetailData.tsx b/ts/components/messages/MessageDetailData.tsx index cfda7bd3550..4a74899d328 100644 --- a/ts/components/messages/MessageDetailData.tsx +++ b/ts/components/messages/MessageDetailData.tsx @@ -100,19 +100,18 @@ class MessageDetailData extends React.PureComponent { )} - {this.data.service_name.isSome() && - this.data.service_detail.isSome() && ( - - {`${I18n.t("messageDetails.service")} `} - - {this.data.service_detail.value.service_name} - + {this.data.service_name.isSome() && this.data.service_detail.isSome() && ( + + {`${I18n.t("messageDetails.service")} `} + + {this.data.service_detail.value.service_name} - )} + + )} {this.hasEmailOrPhone && ( diff --git a/ts/components/messages/MessageDueDateBar.tsx b/ts/components/messages/MessageDueDateBar.tsx index 8bf647f47a4..02bb395b84a 100644 --- a/ts/components/messages/MessageDueDateBar.tsx +++ b/ts/components/messages/MessageDueDateBar.tsx @@ -156,16 +156,16 @@ class MessageDueDateBar extends React.PureComponent { const iconBackgoundColor = this.paid ? customVariables.lighterGray : this.isPaymentExpiring || this.isPaymentExpired - ? customVariables.colorWhite - : customVariables.brandDarkGray; + ? customVariables.colorWhite + : customVariables.brandDarkGray; const textColor = this.paid ? customVariables.colorWhite : this.isPaymentExpiring - ? customVariables.calendarExpirableColor - : this.isPaymentExpired - ? customVariables.brandDarkGray - : customVariables.colorWhite; + ? customVariables.calendarExpirableColor + : this.isPaymentExpired + ? customVariables.brandDarkGray + : customVariables.colorWhite; return ( ({ onGoToWallet: () => dispatch(navigateToWalletHome()) }); -export default connect( - undefined, - mapDispatchToProps -)(MessageDueDateBar); +export default connect(undefined, mapDispatchToProps)(MessageDueDateBar); diff --git a/ts/components/messages/MessageList.tsx b/ts/components/messages/MessageList.tsx index 20ed80bcaa1..2006f27313f 100644 --- a/ts/components/messages/MessageList.tsx +++ b/ts/components/messages/MessageList.tsx @@ -119,9 +119,9 @@ const getItemHeight = (messageState: MessageState): number => { }; const generateItemLayouts = (messageStates: ReadonlyArray) => { - // tslint:disable-next-line: no-let + // eslint-disable-next-line let offset = 0; - // tslint:disable-next-line: readonly-array + // eslint-disable-next-line const itemLayouts: ItemLayout[] = []; messageStates.forEach((messageState, index) => { @@ -132,6 +132,7 @@ const generateItemLayouts = (messageStates: ReadonlyArray) => { ? itemHeight : itemHeight + ITEM_SEPARATOR_HEIGHT; + // eslint-disable-next-line functional/immutable-data itemLayouts.push({ length: itemHeightWithSeparator, offset, @@ -252,9 +253,7 @@ class MessageList extends React.Component { const payment = message.content.payment_data !== undefined && service !== undefined ? paymentsByRptId[ - `${service.organization_fiscal_code}${ - message.content.payment_data.notice_number - }` + `${service.organization_fiscal_code}${message.content.payment_data.notice_number}` ] : undefined; @@ -277,9 +276,7 @@ class MessageList extends React.Component { private getItemLayout = ( _: ReadonlyArray | null, index: number - ) => { - return this.state.itemLayouts[index]; - }; + ) => this.state.itemLayouts[index]; private onLongPress = (id: string) => { Vibration.vibrate(VIBRATION_LONG_PRESS_DURATION); @@ -333,13 +330,12 @@ class MessageList extends React.Component { see https://stackoverflow.com/questions/50307314/react-native-flatlist-refreshing-not-showing-when-its-true-during-first-load see https://github.com/facebook/react-native/issues/15892 */} - {refreshing && - this.state.isFirstLoad && ( - - )} + {refreshing && this.state.isFirstLoad && ( + + )} { }; // Render a button to add/remove an event related to the message in the calendar - private renderCalendarEventButton = () => { + private renderCalendarEventButton = () => // The add/remove reminder button is shown if: // - if the message has a due date // - if the message has a payment and it is not paid nor expired - return this.dueDate + this.dueDate .filter(() => !this.paid && !this.isPaymentExpired) .fold(undefined, _ => ( { disabled={this.props.disabled} message={this.props.message} /> - )); - }; + )) + ; // Render a button to display details of the payment related to the message private renderPaymentButton() { diff --git a/ts/components/messages/MessageListItem.tsx b/ts/components/messages/MessageListItem.tsx index 303d07ce13b..82436509c88 100644 --- a/ts/components/messages/MessageListItem.tsx +++ b/ts/components/messages/MessageListItem.tsx @@ -99,18 +99,17 @@ class MessageListItem extends React.PureComponent { ...uiService })} > - {!hasPrescriptionData(message) && - messageNeedsCTABar(message) && ( - - - - - )} + {!hasPrescriptionData(message) && messageNeedsCTABar(message) && ( + + + + + )} ); } diff --git a/ts/components/messages/MessageNestedCTABar.tsx b/ts/components/messages/MessageNestedCTABar.tsx index 390493a0e09..c3804c84b9b 100644 --- a/ts/components/messages/MessageNestedCTABar.tsx +++ b/ts/components/messages/MessageNestedCTABar.tsx @@ -19,15 +19,14 @@ export const MessageNestedCTABar: React.FunctionComponent = ( handleCtaAction(cta, props.dispatch); }; const { ctas } = props; - const cta2 = ctas.cta_2 && - isCtaActionValid(ctas.cta_2) && ( - - ); + const cta2 = ctas.cta_2 && isCtaActionValid(ctas.cta_2) && ( + + ); const cta1 = isCtaActionValid(ctas.cta_1) && ( => { - return fromNullable(sections) +export const getLastDeadlineId = (sections: Sections): Option => + fromNullable(sections) .chain(s => fpIndex(0, s)) .chain(d => fpIndex(0, [...d.data])) .fold(none, item => { @@ -92,7 +93,6 @@ export const getLastDeadlineId = (sections: Sections): Option => { } return none; }); -}; /** * Get the next deadline id @@ -133,7 +133,7 @@ const generateSections = ( pot.map( potMessagesState, _ => - // tslint:disable-next-line:readonly-array + // eslint-disable-next-line _.reduce((accumulator, messageState) => { const { message, isArchived, isRead } = messageState; if ( @@ -165,7 +165,7 @@ const generateSections = ( // add the message to the last section .reduce<{ lastTitle: Option; - // tslint:disable-next-line:readonly-array + // eslint-disable-next-line sections: MessageAgendaSection[]; }>( (accumulator, messageAgendaItem) => { @@ -242,9 +242,9 @@ const filterSectionsWithTimeLimit = ( const selectFutureData = (sections: Sections): Sections => { const startOfTodayTime = startOfToday().getTime(); - const initialIndex = sections.findIndex(section => { - return new Date(section.title).getTime() >= startOfTodayTime; - }); + const initialIndex = sections.findIndex( + section => new Date(section.title).getTime() >= startOfTodayTime + ); return initialIndex < 0 ? [] : sections.slice(initialIndex); }; @@ -340,8 +340,8 @@ const selectInitialSectionsToRender = ( const selectMoreSectionsToRenderAsync = async ( sections: Sections, maybeLastLoadedStartOfMonthTime: Option -): Promise => { - return new Promise(resolve => { +): Promise => + new Promise(resolve => { const moreSectionsToRender: Sections = []; moreSectionsToRender.push( @@ -358,7 +358,6 @@ const selectMoreSectionsToRenderAsync = async ( resolve(moreSectionsToRender); }); -}; /** * A component to show the messages with a due_date. @@ -378,7 +377,7 @@ class MessagesDeadlines extends React.PureComponent { this.scrollToLocation.value ); // Reset the value to none. - // tslint:disable-next-line: no-object-mutation + // eslint-disable-next-line this.scrollToLocation = none; } }; @@ -435,7 +434,7 @@ class MessagesDeadlines extends React.PureComponent { const itemIndex = moreSectionsToRender[moreSectionsToRender.length - 1].data .length - 1; - // tslint:disable-next-line: no-object-mutation + // eslint-disable-next-line this.scrollToLocation = some({ sectionIndex, itemIndex, @@ -444,7 +443,7 @@ class MessagesDeadlines extends React.PureComponent { animated: true }); } else { - // tslint:disable-next-line: no-object-mutation + // eslint-disable-next-line this.scrollToLocation = some({ sectionIndex: moreSectionsToRender.length, itemIndex: -1, @@ -571,7 +570,7 @@ class MessagesDeadlines extends React.PureComponent { private generateMessagesIdsFromMessageAgendaSection( sections: Sections ): Set { - // tslint:disable-next-line: readonly-array + // eslint-disable-next-line const messagesIds: string[] = []; sections.forEach(messageAgendaSection => messageAgendaSection.data.forEach(item => { diff --git a/ts/components/messages/MessagesSearch.tsx b/ts/components/messages/MessagesSearch.tsx index a36cf0d0f99..39e2e6a4c0a 100644 --- a/ts/components/messages/MessagesSearch.tsx +++ b/ts/components/messages/MessagesSearch.tsx @@ -42,8 +42,7 @@ const generateMessagesStateMatchingSearchTextArrayAsync = ( potMessagesState: pot.Pot, string>, servicesById: ServicesByIdState, searchText: string -): Promise> => { - return new Promise(resolve => { +): Promise> => new Promise(resolve => { const result = pot.getOrElse( pot.map(potMessagesState, _ => _.filter(messageState => @@ -74,7 +73,6 @@ const generateMessagesStateMatchingSearchTextArrayAsync = ( resolve(result); }); -}; /** * A component to render a list of messages that match a searchText. diff --git a/ts/components/messages/PaymentButton.tsx b/ts/components/messages/PaymentButton.tsx index 49a01490db7..69e41dedfbc 100644 --- a/ts/components/messages/PaymentButton.tsx +++ b/ts/components/messages/PaymentButton.tsx @@ -177,7 +177,4 @@ const mapDispatchToProps = (dispatch: Dispatch, ownProps: OwnProps) => ({ navigateToWalletHomeScreen: () => dispatch(navigateToWalletHome()) }); -export default connect( - mapStateToProps, - mapDispatchToProps -)(PaymentButton); +export default connect(mapStateToProps, mapDispatchToProps)(PaymentButton); diff --git a/ts/components/messages/__tests__/MessageDeadlines.test.ts b/ts/components/messages/__tests__/MessageDeadlines.test.ts index eaf172d9f0e..dde7711eb6d 100644 --- a/ts/components/messages/__tests__/MessageDeadlines.test.ts +++ b/ts/components/messages/__tests__/MessageDeadlines.test.ts @@ -29,7 +29,7 @@ const generateSections = ( pot.map( potMessagesState, _ => - // tslint:disable-next-line:readonly-array + // eslint-disable-next-line _.reduce((accumulator, messageState) => { const { message, isArchived, isRead } = messageState; if ( @@ -62,7 +62,7 @@ const generateSections = ( // add the message to the last section .reduce<{ lastTitle: Option; - // tslint:disable-next-line:readonly-array + // eslint-disable-next-line sections: MessageAgendaSection[]; }>( (accumulator, messageAgendaItem) => { @@ -88,6 +88,7 @@ const generateSections = ( // We need to add the message to the last section. // We are sure that pop will return at least one element because // of the previous `if` step. + // eslint-disable-next-line functional/immutable-data const prevSection = accumulator.sections.pop() as MessageAgendaSection; const newSection = { title, @@ -239,7 +240,7 @@ describe("last id check", () => { } }); - it("should return none", () => { + it("getLastDeadlineId should return none", () => { const lastDeadlineId = getLastDeadlineId([]); expect(lastDeadlineId.isNone()).toBeTruthy(); }); diff --git a/ts/components/screens/AnimatedScreenContent.tsx b/ts/components/screens/AnimatedScreenContent.tsx index c5f315ae951..3ae7ac990a0 100644 --- a/ts/components/screens/AnimatedScreenContent.tsx +++ b/ts/components/screens/AnimatedScreenContent.tsx @@ -124,15 +124,14 @@ export default class AnimatedScreenContent extends React.Component< return ( - {Platform.OS === "ios" && - this.props.dark && ( - - )} + {Platform.OS === "ios" && this.props.dark && ( + + )} { // set accessibility focus when component is mounted // it should be used paired with avoidNavigationEvents === true (navigation context not available) public componentDidMount() { - AccessibilityInfo.isScreenReaderEnabled() + void AccessibilityInfo.isScreenReaderEnabled() .then(isScreenReaderActive => { this.setState({ isScreenReaderActive }); if ( @@ -125,8 +125,8 @@ class BaseHeaderComponent extends React.PureComponent { }, noReferenceTimeout); } - private renderBodyLabel = (label?: string, ref?: Ref) => { - return maybeNotNullyString(label).fold(undefined, l => { + private renderBodyLabel = (label?: string, ref?: Ref) => + maybeNotNullyString(label).fold(undefined, l => { const isWhite = this.props.primary || this.props.dark; return ( { ); }); - }; public render() { const { @@ -198,37 +197,36 @@ class BaseHeaderComponent extends React.PureComponent { return ( {isSearchAvailable && } - {!isSearchEnabled && - showInstabugChat !== false && } - {onShowHelp && - !isSearchEnabled && ( - - - - )} + {!isSearchEnabled && showInstabugChat !== false && ( + + )} + {onShowHelp && !isSearchEnabled && ( + + + + )} - {customRightIcon && - !isSearchEnabled && ( - - - - )} + {customRightIcon && !isSearchEnabled && ( + + + + )} {fromNullable(this.props.accessibilityEvents).fold( true, ({ avoidNavigationEventsUsage }) => !avoidNavigationEventsUsage @@ -262,8 +260,8 @@ class BaseHeaderComponent extends React.PureComponent { const iconColor = isPagoPATestEnabled ? variables.brandHighlight : primary || dark - ? variables.colorWhite - : variables.brandPrimary; + ? variables.colorWhite + : variables.brandPrimary; return ( !isSearchEnabled && diff --git a/ts/components/screens/BaseScreenComponent.tsx b/ts/components/screens/BaseScreenComponent.tsx index 0ab89463f0a..9d82484ea34 100644 --- a/ts/components/screens/BaseScreenComponent.tsx +++ b/ts/components/screens/BaseScreenComponent.tsx @@ -201,20 +201,20 @@ class BaseScreenComponent extends React.PureComponent { const ch = contextualHelp ? { body: contextualHelp.body, title: contextualHelp.title } : contextualHelpMarkdown - ? { - body: () => ( - { - this.setState({ markdownContentLoaded: some(true) }); - }} - > - {I18n.t(contextualHelpMarkdown.body)} - - ), - title: I18n.t(contextualHelpMarkdown.title) - } - : undefined; + ? { + body: () => ( + { + this.setState({ markdownContentLoaded: some(true) }); + }} + > + {I18n.t(contextualHelpMarkdown.body)} + + ), + title: I18n.t(contextualHelpMarkdown.title) + } + : undefined; return ( diff --git a/ts/components/screens/EdgeBorderComponent.tsx b/ts/components/screens/EdgeBorderComponent.tsx index 52fc7eaa05a..ff11dd7ebda 100644 --- a/ts/components/screens/EdgeBorderComponent.tsx +++ b/ts/components/screens/EdgeBorderComponent.tsx @@ -12,7 +12,7 @@ const styles = StyleSheet.create({ } }); -export class EdgeBorderComponent extends React.PureComponent<{}> { +export class EdgeBorderComponent extends React.PureComponent { public render() { return ( diff --git a/ts/components/screens/IdpCustomContextualHelpContent.tsx b/ts/components/screens/IdpCustomContextualHelpContent.tsx index ed9e030c59a..805e0c61e17 100644 --- a/ts/components/screens/IdpCustomContextualHelpContent.tsx +++ b/ts/components/screens/IdpCustomContextualHelpContent.tsx @@ -11,12 +11,10 @@ type Props = Readonly<{ idpTextData: Idp; }>; -const IdpCustomContextualHelpContent = (idpTextData: Idp) => { - return { +const IdpCustomContextualHelpContent = (idpTextData: Idp) => ({ title: I18n.t("authentication.idp_login.contextualHelpTitle2"), body: () => - }; -}; + }); const IdpCustomContextualHelpBody: React.FunctionComponent = props => { const { idpTextData } = props; diff --git a/ts/components/screens/ListItemComponent.tsx b/ts/components/screens/ListItemComponent.tsx index ade2b3b7bf3..0678ef997e7 100644 --- a/ts/components/screens/ListItemComponent.tsx +++ b/ts/components/screens/ListItemComponent.tsx @@ -169,17 +169,16 @@ export default class ListItemComponent extends React.Component { )} - {this.props.iconName !== undefined && - this.props.hideIcon !== true && ( - - - - )} + {this.props.iconName !== undefined && this.props.hideIcon !== true && ( + + + + )} ); } diff --git a/ts/components/screens/MarkdownScreenComponent.tsx b/ts/components/screens/MarkdownScreenComponent.tsx index 673eeecf4bb..4c0546d6cd2 100644 --- a/ts/components/screens/MarkdownScreenComponent.tsx +++ b/ts/components/screens/MarkdownScreenComponent.tsx @@ -39,7 +39,7 @@ export class MarkdownScreenComponent extends React.PureComponent { } public componentDidMount() { - InteractionManager.runAfterInteractions(() => + void InteractionManager.runAfterInteractions(() => this.setState({ content: {this.props.markdown} }) diff --git a/ts/components/screens/ScreenContent.tsx b/ts/components/screens/ScreenContent.tsx index a1d0764dfac..1e4bb4046c7 100644 --- a/ts/components/screens/ScreenContent.tsx +++ b/ts/components/screens/ScreenContent.tsx @@ -22,6 +22,7 @@ class ScreenContent extends React.PureComponent { private content = React.createRef(); private scrollTop = () => { if (this.content.current) { + // eslint-disable-next-line no-underscore-dangle this.content.current._root.scrollToPosition(0, 0, false); } }; diff --git a/ts/components/search/SearchButton.tsx b/ts/components/search/SearchButton.tsx index 1e8d1d32873..d37911d446c 100644 --- a/ts/components/search/SearchButton.tsx +++ b/ts/components/search/SearchButton.tsx @@ -133,7 +133,4 @@ const mapDispatchToProps = (dispatch: Dispatch, props: OwnProps) => ({ } }); -export default connect( - null, - mapDispatchToProps -)(SearchButton); +export default connect(null, mapDispatchToProps)(SearchButton); diff --git a/ts/components/services/NewServiceListItem.tsx b/ts/components/services/NewServiceListItem.tsx index 8894534b493..9c886e43355 100644 --- a/ts/components/services/NewServiceListItem.tsx +++ b/ts/components/services/NewServiceListItem.tsx @@ -77,15 +77,13 @@ export default class NewServiceListItem extends React.PureComponent< private getServiceKey = ( potService: pot.Pot - ): string => { - return pot.getOrElse( + ): string => pot.getOrElse( pot.map( potService, service => `${service.service_id}-${service.version || 0}` ), `service-switch` ); - }; private isInboxChannelEnabled() { const potService = this.props.item; @@ -128,8 +126,8 @@ export default class NewServiceListItem extends React.PureComponent< const serviceName = pot.isLoading(potService) ? I18n.t("global.remoteStates.loading") : pot.isError(potService) || pot.isNone(potService) - ? I18n.t("global.remoteStates.notAvailable") - : potService.value.service_name; + ? I18n.t("global.remoteStates.notAvailable") + : potService.value.service_name; return ( { private getServiceKey = ( potService: pot.Pot, index: number - ): string => { - return pot.getOrElse( + ): string => pot.getOrElse( pot.map( potService, service => `${service.service_id}-${service.version}` ), `service-pot-${index}` ); - }; private renderServiceSectionHeader = (info: { section: ServicesSectionState; @@ -126,12 +124,10 @@ class ServiceList extends React.Component { private isRead = ( potService: pot.Pot, readServices: ReadStateByServicesId - ): boolean => { - return pot.getOrElse( + ): boolean => pot.getOrElse( pot.map(potService, s => s && readServices[s.service_id] !== undefined), false ); - }; public render() { const { diff --git a/ts/components/services/ServicesSearch.tsx b/ts/components/services/ServicesSearch.tsx index 139ea32e238..2d54f5b037f 100644 --- a/ts/components/services/ServicesSearch.tsx +++ b/ts/components/services/ServicesSearch.tsx @@ -40,8 +40,7 @@ type State = { const generateSectionsServicesStateMatchingSearchTextArrayAsync = ( servicesState: ReadonlyArray, searchText: string -): Promise> => { - return new Promise(resolve => { +): Promise> => new Promise(resolve => { const result = servicesState .map(section => filterSectionListDataMatchingSearchText(section, searchText) @@ -50,7 +49,6 @@ const generateSectionsServicesStateMatchingSearchTextArrayAsync = ( resolve(result); }); -}; function filterSectionListDataMatchingSearchText( sectionListData: SectionListData>, diff --git a/ts/components/services/ServicesSectionsList.tsx b/ts/components/services/ServicesSectionsList.tsx index 14d78ce5d07..d01ab03f7aa 100644 --- a/ts/components/services/ServicesSectionsList.tsx +++ b/ts/components/services/ServicesSectionsList.tsx @@ -126,8 +126,7 @@ class ServicesSectionsList extends React.PureComponent { ); } - private renderEditButton = () => { - return ( + private renderEditButton = () => ( this.props.isLocal && this.props.selectedOrganizationsFiscalCodes && this.props.selectedOrganizationsFiscalCodes.size > 0 && ( @@ -151,7 +150,6 @@ class ServicesSectionsList extends React.PureComponent { ) ); - }; private renderList = () => { // empty component is different from local and others (national and all) diff --git a/ts/components/services/ServicesTab.tsx b/ts/components/services/ServicesTab.tsx index 53360c37cd4..464fb17f33d 100644 --- a/ts/components/services/ServicesTab.tsx +++ b/ts/components/services/ServicesTab.tsx @@ -43,7 +43,7 @@ type OwnProps = Readonly<{ updateToast?: () => void; sections: ReadonlyArray; isRefreshing: boolean; - onRefresh: (hideToast?: boolean) => void; // tslint:disable-line bool-param-default + onRefresh: (hideToast?: boolean) => void; // eslint-disable-line onServiceSelect: (service: ServicePublic) => void; handleOnLongPressItem: () => void; isLongPressEnabled: boolean; @@ -146,8 +146,7 @@ class ServicesTab extends React.PureComponent { } }; - private renderLocalQuickSectionDeletion = (section: ServicesSectionState) => { - return ( + private renderLocalQuickSectionDeletion = (section: ServicesSectionState) => ( this.onPressItem(section)}> { ); - }; private renderSwitchAllOrganizationServices = ( section: ServicesSectionState @@ -202,8 +200,7 @@ class ServicesTab extends React.PureComponent { ); }; - private onTabScroll = () => { - return { + private onTabScroll = () => ({ onScroll: Animated.event([ { nativeEvent: { @@ -212,8 +209,7 @@ class ServicesTab extends React.PureComponent { } ]), scrollEventThrottle: 8 - }; - }; + }); public render() { // the right icon in the organization section could be @@ -223,8 +219,8 @@ class ServicesTab extends React.PureComponent { const renderRightIcon = this.props.isLongPressEnabled ? this.renderSwitchAllOrganizationServices : this.props.isLocal - ? this.renderLocalQuickSectionDeletion - : undefined; + ? this.renderLocalQuickSectionDeletion + : undefined; return ( { const mapStateToProps = (state: GlobalState) => { const localServicesSections = localServicesSectionsSelector(state); const selectableOrganizations = localServicesSections.map( - (section: ServicesSectionState) => { - return { + (section: ServicesSectionState) => ({ name: section.organizationName, fiscalCode: section.organizationFiscalCode - }; - } + }) ); const potUserMetadata = userMetadataSelector(state); const userMetadata = pot.getOrElse(potUserMetadata, undefined); diff --git a/ts/components/ui/Accordion.tsx b/ts/components/ui/Accordion.tsx index 4fb10d4a2c9..5cb4c1d04bc 100644 --- a/ts/components/ui/Accordion.tsx +++ b/ts/components/ui/Accordion.tsx @@ -39,8 +39,7 @@ const styles = StyleSheet.create({ const Accordion: React.FunctionComponent = (props: Props) => { const [expanded, setExpanded] = React.useState(false); - const renderHeader = (title: string) => { - return ( + const renderHeader = (title: string) => ( = (props: Props) => { {!expanded && } ); - }; const renderContent = (content: string) => ( diff --git a/ts/components/ui/AppHeader.tsx b/ts/components/ui/AppHeader.tsx index 4af922d5272..af817f05da7 100644 --- a/ts/components/ui/AppHeader.tsx +++ b/ts/components/ui/AppHeader.tsx @@ -9,8 +9,7 @@ import ConnectionBar from "../ConnectionBar"; type Props = NativeBase.Header & ViewProps; -const AppHeader = (props: React.PropsWithChildren) => { - return ( +const AppHeader = (props: React.PropsWithChildren) => (
) => { ); -}; export default AppHeader; diff --git a/ts/components/ui/BlockButtons.tsx b/ts/components/ui/BlockButtons.tsx index e0b4a70722e..d65741432e3 100644 --- a/ts/components/ui/BlockButtons.tsx +++ b/ts/components/ui/BlockButtons.tsx @@ -129,8 +129,7 @@ export default class BlockButtons extends React.Component { private renderButton = ( props: BlockButtonProps, style: ComponentProps["style"] - ) => { - return ( + ) => ( {props.iconName && ( { /> )} { - return { fontSize: fs }; - })} + style={fromNullable(props.buttonFontSize).fold(undefined, fs => ({ fontSize: fs }))} > {props.title} ); - }; public render() { return ( diff --git a/ts/components/ui/FooterWithButtons.tsx b/ts/components/ui/FooterWithButtons.tsx index b2ac5f4ceda..b99297742d0 100644 --- a/ts/components/ui/FooterWithButtons.tsx +++ b/ts/components/ui/FooterWithButtons.tsx @@ -1,9 +1,9 @@ import { View } from "native-base"; import * as React from "react"; -import variables from "../../theme/variables"; -import BlockButtons, { BlockButtonsProps } from "./BlockButtons"; import { StyleSheet } from "react-native"; +import variables from "../../theme/variables"; +import BlockButtons, { BlockButtonsProps } from "./BlockButtons"; // TODO: Refactor with an unique component like `FooterTopShadow` after bonus vacanze const styles = StyleSheet.create({ diff --git a/ts/components/ui/LightModal.tsx b/ts/components/ui/LightModal.tsx index bae6357cff9..9f8b403fc4e 100644 --- a/ts/components/ui/LightModal.tsx +++ b/ts/components/ui/LightModal.tsx @@ -39,7 +39,7 @@ export const LightModalContext = React.createContext< setOnHiddenModal: () => undefined }); -type Props = {}; +type Props = Record; type State = LightModalContextInterface; diff --git a/ts/components/ui/Markdown/handlers/link.ts b/ts/components/ui/Markdown/handlers/link.ts index 8760061cf5b..9584b52ee36 100644 --- a/ts/components/ui/Markdown/handlers/link.ts +++ b/ts/components/ui/Markdown/handlers/link.ts @@ -31,9 +31,7 @@ export function handleLinkMessage(dispatch: Dispatch, href: string) { } // remove protocol from a link ex: http://www.site.com -> www.site.com -export const removeProtocol = (link: string): string => { - return link.replace(new RegExp(/https?:\/\//gi), ""); -}; +export const removeProtocol = (link: string): string => link.replace(new RegExp(/https?:\/\//gi), ""); // try to open the given url. If it fails an error toast will shown export function openLink(url: string, customError?: string) { diff --git a/ts/components/ui/Markdown/index.tsx b/ts/components/ui/Markdown/index.tsx index 7b2917c47e8..497fbf8e5de 100644 --- a/ts/components/ui/Markdown/index.tsx +++ b/ts/components/ui/Markdown/index.tsx @@ -120,11 +120,9 @@ div.custom-block.io-demo-block .custom-block-body::after { `; -const generateInlineCss = (cssStyle: string) => { - return ``; -}; const generateCustomFontList = `