Update Eslint to support TypeScript (#1419)

* Add typescript parser and fix Flow errors in JS files

* Uninstall packages from react-native/eslint-config

* Fix all flow errors (or ignore them for unknowns
This commit is contained in:
Amanda Bullington
2024-04-18 21:35:26 -07:00
committed by GitHub
parent 6b3eacfc19
commit 21b9cc6a97
122 changed files with 693 additions and 475 deletions

View File

@@ -1,6 +1,6 @@
module.exports = {
root: true,
parser: "@babel/eslint-parser",
parser: "@typescript-eslint/parser",
parserOptions: {
requireConfigFile: false,
babelOptions: {
@@ -13,14 +13,16 @@ module.exports = {
// "@react-native",
"plugin:i18next/recommended",
"plugin:@tanstack/eslint-plugin-query/recommended",
"plugin:react-native-a11y/ios"
"plugin:react-native-a11y/ios",
"plugin:@typescript-eslint/recommended"
],
plugins: [
"module-resolver",
"react-hooks",
"react-native",
"simple-import-sort",
"@tanstack/query"
"@tanstack/query",
"@typescript-eslint"
],
rules: {
"arrow-parens": [2, "as-needed"],
@@ -123,13 +125,19 @@ module.exports = {
"react-native-a11y/has-valid-accessibility-descriptors": 1,
"react-native-a11y/has-valid-accessibility-ignores-invert-colors": 1,
"react-native-a11y/has-valid-accessibility-live-region": 1,
"react-native-a11y/has-valid-important-for-accessibility": 1
"react-native-a11y/has-valid-important-for-accessibility": 1,
// TODO: we should actually type these at some point ~amanda 041824
"@typescript-eslint/ban-types": 0,
"@typescript-eslint/no-unused-vars": 0,
"@typescript-eslint/no-var-requires": 0
},
// need this so jest doesn't show as undefined in jest.setup.js
env: {
jest: true
},
ignorePatterns: ["/coverage/*", "/vendor/*"],
ignorePatterns: ["/coverage/*", "/vendor/*", "**/flow-typed"],
settings: {
"import/resolver": {
"babel-module": { allowExistingDirectories: true },

View File

@@ -1,4 +1,9 @@
import type {Config} from 'jest';
import type { Config } from "jest";
const ignorePatterns = "node_modules/(?!(jest-)?@react-native|react-native|"
+ "react-clone-referenced-element|@react-native-community|expo(nent)?|"
+ "@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|"
+ "unimodules|sentry-expo|native-base||(?!react-native-redash))|jest-runner";
const config: Config = {
moduleNameMapper: {
@@ -16,14 +21,12 @@ const config: Config = {
"<rootDir>/tests/realm.setup.js",
"<rootDir>/tests/initI18next.setup.js"
],
transformIgnorePatterns: [
"node_modules/(?!(jest-)?@react-native|react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base||(?!react-native-redash))|jest-runner"
],
verbose: true,
transformIgnorePatterns: [ignorePatterns],
verbose: true
// uncomment reporters below to see which tests are running the slowest in jest
// reporters: [
// ["jest-slow-test-reporter", {"numTests": 8, "warnOnSlowerThan": 300, "color": true}]
// ],
};
export default config;
export default config;

2
nativewind-env.d.ts vendored
View File

@@ -1 +1 @@
/// <reference types="nativewind/types" />
/// <reference types="nativewind/types" />

175
package-lock.json generated
View File

@@ -104,8 +104,6 @@
"zustand": "^4.5.2"
},
"devDependencies": {
"@babel/core": "^7.24.4",
"@babel/eslint-parser": "^7.24.1",
"@babel/preset-react": "^7.24.1",
"@babel/preset-typescript": "^7.24.1",
"@babel/runtime": "^7.24.4",
@@ -117,6 +115,7 @@
"@react-native/typescript-config": "0.73.1",
"@tanstack/eslint-plugin-query": "^5.28.11",
"@testing-library/jest-native": "^5.4.3",
"@testing-library/react": "^15.0.2",
"@testing-library/react-native": "^12.4.5",
"@types/jest": "^29.5.12",
"@types/react": "^18.2.74",
@@ -136,9 +135,6 @@
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-module-resolver": "^1.5.0",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-native": "^4.1.0",
"eslint-plugin-react-native-a11y": "^3.3.0",
"eslint-plugin-simple-import-sort": "^12.0.0",
"eslint-plugin-testing-library": "^6.2.0",
@@ -5957,6 +5953,127 @@
"react": "^18.0.0"
}
},
"node_modules/@testing-library/dom": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.0.0.tgz",
"integrity": "sha512-PmJPnogldqoVFf+EwbHvbBJ98MmqASV8kLrBYgsDNxQcFMeIS7JFL48sfyXvuMtgmWO/wMhh25odr+8VhDmn4g==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
"@types/aria-query": "^5.0.1",
"aria-query": "5.3.0",
"chalk": "^4.1.0",
"dom-accessibility-api": "^0.5.9",
"lz-string": "^1.5.0",
"pretty-format": "^27.0.2"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@testing-library/dom/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@testing-library/dom/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/@testing-library/dom/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/@testing-library/dom/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/@testing-library/dom/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/@testing-library/dom/node_modules/pretty-format": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
"react-is": "^17.0.1"
},
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"node_modules/@testing-library/dom/node_modules/pretty-format/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@testing-library/dom/node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true
},
"node_modules/@testing-library/dom/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@testing-library/jest-native": {
"version": "5.4.3",
"resolved": "https://registry.npmjs.org/@testing-library/jest-native/-/jest-native-5.4.3.tgz",
@@ -6045,6 +6162,24 @@
"node": ">=8"
}
},
"node_modules/@testing-library/react": {
"version": "15.0.2",
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-15.0.2.tgz",
"integrity": "sha512-5mzIpuytB1ctpyywvyaY2TAAUQVCZIGqwiqFQf6u9lvj/SJQepGUzNV18Xpk+NLCaCE2j7CWrZE0tEf9xLZYiQ==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.12.5",
"@testing-library/dom": "^10.0.0",
"@types/react-dom": "^18.0.0"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
},
"node_modules/@testing-library/react-native": {
"version": "12.4.5",
"resolved": "https://registry.npmjs.org/@testing-library/react-native/-/react-native-12.4.5.tgz",
@@ -6099,6 +6234,12 @@
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"devOptional": true
},
"node_modules/@types/aria-query": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
"dev": true
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -6224,6 +6365,15 @@
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-dom": {
"version": "18.2.25",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.25.tgz",
"integrity": "sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==",
"dev": true,
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/react-native": {
"version": "0.71.6",
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.71.6.tgz",
@@ -9432,6 +9582,12 @@
"node": ">=6.0.0"
}
},
"node_modules/dom-accessibility-api": {
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true
},
"node_modules/dom-serializer": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
@@ -14755,6 +14911,15 @@
"node": ">=10"
}
},
"node_modules/lz-string": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"dev": true,
"bin": {
"lz-string": "bin/bin.js"
}
},
"node_modules/make-dir": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",

View File

@@ -132,8 +132,6 @@
"zustand": "^4.5.2"
},
"devDependencies": {
"@babel/core": "^7.24.4",
"@babel/eslint-parser": "^7.24.1",
"@babel/preset-react": "^7.24.1",
"@babel/preset-typescript": "^7.24.1",
"@babel/runtime": "^7.24.4",
@@ -145,6 +143,7 @@
"@react-native/typescript-config": "0.73.1",
"@tanstack/eslint-plugin-query": "^5.28.11",
"@testing-library/jest-native": "^5.4.3",
"@testing-library/react": "^15.0.2",
"@testing-library/react-native": "^12.4.5",
"@types/jest": "^29.5.12",
"@types/react": "^18.2.74",
@@ -164,9 +163,6 @@
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-module-resolver": "^1.5.0",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-native": "^4.1.0",
"eslint-plugin-react-native-a11y": "^3.3.0",
"eslint-plugin-simple-import-sort": "^12.0.0",
"eslint-plugin-testing-library": "^6.2.0",

View File

@@ -17,7 +17,7 @@ const PARAMS = {
placement: "mobile"
};
const searchAnnouncements = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const searchAnnouncements = async ( params: Object = {}, opts: Object = {} ): Promise<?Object> => {
try {
const { results } = await inatjs.announcements.search(
{ ...PARAMS, ...params },

View File

@@ -1,43 +0,0 @@
// @flow
import inatjs from "inaturalistjs";
import handleError from "./error";
const PARAMS = {
fields: "application.official,application.name,created_at"
};
const fetchAuthorizedApplications = async (
params: Object = {},
opts: Object = {}
): Promise<any> => {
try {
const { results } = await inatjs.authorized_applications.search(
{ ...PARAMS, ...params },
opts
);
return results;
} catch ( e ) {
return handleError( e );
}
};
const revokeAuthorizedApplications = async (
params: Object = {},
opts: Object = {}
): Promise<any> => {
try {
return await inatjs.authorized_applications.delete(
params,
opts
);
} catch ( e ) {
return handleError( e );
}
};
export {
fetchAuthorizedApplications,
revokeAuthorizedApplications
};

View File

@@ -12,7 +12,7 @@ const PARAMS = {
const createComment = async (
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const { results } = await inatjs.comments.create( { ...PARAMS, ...params }, opts );
return results;
@@ -24,7 +24,7 @@ const createComment = async (
const updateComment = async (
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const { results } = await inatjs.comments.update( { ...PARAMS, ...params }, opts );
return results;
@@ -36,7 +36,7 @@ const updateComment = async (
const deleteComments = async (
id: number,
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const { results } = await inatjs.comments.delete( { id }, opts );
return results;

View File

@@ -14,7 +14,7 @@ const PARAMS = {
const scoreImage = async (
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
return inatjs.computervision.score_image( { ...PARAMS, ...params }, opts );
} catch ( e ) {

View File

@@ -11,7 +11,7 @@ const PARAMS = {
const createFlag = async (
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const { results } = await inatjs.flags.create( { ...PARAMS, ...params }, opts );
return results;

View File

@@ -12,7 +12,7 @@ const PARAMS = {
const createIdentification = async (
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const { results } = await inatjs.identifications.create( { ...PARAMS, ...params }, opts );
return results;
@@ -24,7 +24,7 @@ const createIdentification = async (
const updateIdentification = async (
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const { results } = await inatjs.identifications.update( { ...PARAMS, ...params }, opts );
return results;

View File

@@ -1,5 +1,6 @@
import { getUserAgent } from "api/userAgent";
import { create } from "apisauce";
// eslint-disable-next-line import/no-cycle
import { getAnonymousJWT, getJWT } from "components/LoginSignUp/AuthenticationService";
import Config from "react-native-config";
import { transportFunctionType } from "react-native-logs";
@@ -35,11 +36,14 @@ const iNatLogstashTransport: transportFunctionType = async props => {
level: props.level.text,
message,
context: props.extension,
timestamp: new Date().toISOString(),
timestamp: new Date().toISOString()
// TODO: I couldn't really find a good way to get the error type and backtrace
// within the react-native-logs transporter paradigm. There could be some string handling to get it
// but that seems excessive to me because it would need to be adapted to every logger.error call because
// sometimes the error is used in a template string and sometimes it's an object. Maybe at one point we
// within the react-native-logs transporter paradigm.
// There could be some string handling to get it
// but that seems excessive to me because it would
// need to be adapted to every logger.error call because
// sometimes the error is used in a template string and
// sometimes it's an object. Maybe at one point we
// need to build a solution outside of the transporter paradigm.
// error_type: some_error_type,
// backtrace: some_backtrace

View File

@@ -16,7 +16,7 @@ const PARAMS = {
fields: MESSAGE_FIELDS
};
const searchMessages = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const searchMessages = async ( params: Object = {}, opts: Object = {} ): Promise<?Object> => {
try {
const { results } = await inatjs.messages.search( { ...PARAMS, ...params }, opts );
return results;

View File

@@ -7,7 +7,7 @@ import handleError from "./error";
const deleteRemoteObservationSound = async (
params: Object = {},
opts: Object = {}
) : Promise<?any> => {
) : Promise<?Object> => {
try {
return await inatjs.observation_sounds.delete( params, opts );
} catch ( e ) {

View File

@@ -17,7 +17,7 @@ function mapToLocalSchema( observation ) {
return observation;
}
const searchObservations = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const searchObservations = async ( params: Object = {}, opts: Object = {} ): Promise<Object> => {
try {
const response = await inatjs.observations.search( params, opts );
response.results = response.results.map( mapToLocalSchema );
@@ -76,7 +76,7 @@ const markAsReviewed = async ( params: Object = {}, opts: Object = {} ): Promise
const markObservationUpdatesViewed = async (
params: Object = {},
opts: Object = {}
): Promise<?any> => {
): Promise<?Object> => {
try {
return await inatjs.observations.viewedUpdates( params, opts );
} catch ( e ) {
@@ -87,7 +87,7 @@ const markObservationUpdatesViewed = async (
const createObservation = async (
params: Object = {},
opts: Object = {}
): Promise<?any> => {
): Promise<?Object> => {
try {
return await inatjs.observations.create( params, opts );
} catch ( e ) {
@@ -98,7 +98,7 @@ const createObservation = async (
const updateObservation = async (
params: Object = {},
opts: Object = {}
): Promise<?any> => {
): Promise<?Object> => {
try {
return await inatjs.observations.update( params, opts );
} catch ( e ) {
@@ -114,7 +114,7 @@ const createOrUpdateEvidence = async (
apiEndpoint: Function,
params: Object = {},
opts: Object = {}
): Promise<?any> => {
): Promise<?Object> => {
try {
return await apiEndpoint( params, opts );
} catch ( e ) {
@@ -125,7 +125,7 @@ const createOrUpdateEvidence = async (
const fetchObservationUpdates = async (
params: Object = {},
opts: Object = {}
): Promise<?any> => {
): Promise<?Object> => {
try {
const { results } = await inatjs.observations.updates( params, opts );
return results;
@@ -136,7 +136,7 @@ const fetchObservationUpdates = async (
const fetchUnviewedObservationUpdatesCount = async (
opts: Object
): Promise<Number> => {
): Promise<number> => {
try {
const { total_results: updatesCount } = await inatjs.observations.updates( {
observations_by: "owner",
@@ -152,7 +152,7 @@ const fetchUnviewedObservationUpdatesCount = async (
const deleteRemoteObservation = async (
params: Object = {},
opts: Object = {}
) : Promise<?any> => {
) : Promise<?Object> => {
try {
return await inatjs.observations.delete( params, opts );
} catch ( e ) {
@@ -160,7 +160,7 @@ const deleteRemoteObservation = async (
}
};
const fetchObservers = async ( params: Object = {} ) : Promise<?any> => {
const fetchObservers = async ( params: Object = {} ) : Promise<?Object> => {
try {
return await inatjs.observations.observers( params );
} catch ( e ) {
@@ -168,7 +168,7 @@ const fetchObservers = async ( params: Object = {} ) : Promise<?any> => {
}
};
const fetchIdentifiers = async ( params: Object = {} ) : Promise<?any> => {
const fetchIdentifiers = async ( params: Object = {} ) : Promise<?Object> => {
try {
return await inatjs.observations.identifiers( params );
} catch ( e ) {
@@ -176,7 +176,7 @@ const fetchIdentifiers = async ( params: Object = {} ) : Promise<?any> => {
}
};
const fetchSpeciesCounts = async ( params: Object = {} ) : Promise<?any> => {
const fetchSpeciesCounts = async ( params: Object = {} ) : Promise<?Object> => {
try {
return await inatjs.observations.speciesCounts( params );
} catch ( e ) {
@@ -187,7 +187,7 @@ const fetchSpeciesCounts = async ( params: Object = {} ) : Promise<?any> => {
const checkForDeletedObservations = async (
params: Object = {},
opts: Object = {}
) : Promise<?any> => {
) : Promise<?Object> => {
try {
return await inatjs.observations.deleted( params, opts );
} catch ( e ) {

View File

@@ -8,7 +8,11 @@ const PARAMS = {
fields: "display_name"
};
const fetchPlace = async ( id: number, params: Object = {}, opts: Object = {} ): Promise<any> => {
const fetchPlace = async (
id: number,
params: Object = {},
opts: Object = {}
): Promise<?Object> => {
try {
const { results } = await inatjs.places.fetch( id, { ...PARAMS, ...params, ...opts } );
return results[0];

View File

@@ -32,7 +32,7 @@ const fetchProjects = async (
id: number,
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const { results } = await inatjs.projects.fetch( id, { ...DETAIL_PARAMS, ...params }, opts );
return results[0];
@@ -44,7 +44,7 @@ const fetchProjects = async (
const fetchProjectMembers = async (
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const response = await inatjs.projects.members( params, opts );
return response.total_results;
@@ -56,7 +56,7 @@ const fetchProjectMembers = async (
const fetchProjectPosts = async (
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const response = await inatjs.projects.posts( params, opts );
return response.total_results;
@@ -65,7 +65,7 @@ const fetchProjectPosts = async (
}
};
const searchProjects = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const searchProjects = async ( params: Object = {}, opts: Object = {} ): Promise<?Object> => {
try {
const { results } = await inatjs.projects.search( { ...PARAMS, ...params }, opts );
return results;
@@ -74,7 +74,7 @@ const searchProjects = async ( params: Object = {}, opts: Object = {} ): Promise
}
};
const joinProject = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const joinProject = async ( params: Object = {}, opts: Object = {} ): Promise<?Object> => {
try {
return await inatjs.projects.join( { ...PARAMS, ...params }, opts );
} catch ( e ) {
@@ -82,7 +82,7 @@ const joinProject = async ( params: Object = {}, opts: Object = {} ): Promise<an
}
};
const leaveProject = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const leaveProject = async ( params: Object = {}, opts: Object = {} ): Promise<?Object> => {
try {
return await inatjs.projects.leave( { ...PARAMS, ...params }, opts );
} catch ( e ) {
@@ -90,7 +90,7 @@ const leaveProject = async ( params: Object = {}, opts: Object = {} ): Promise<a
}
};
const fetchMembership = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const fetchMembership = async ( params: Object = {}, opts: Object = {} ): Promise<?Object> => {
try {
const response = await inatjs.projects.membership( { ...PARAMS, ...params }, opts );
return response.total_results;

View File

@@ -1,26 +0,0 @@
// @flow
import inatjs from "inaturalistjs";
import handleError from "./error";
const PARAMS = {
fields: "provider_name,created_at"
};
const fetchProviderAuthorizations = async (
params: Object = {},
opts: Object = {}
): Promise<any> => {
try {
const { results } = await inatjs.provider_authorizations.search(
{ ...PARAMS, ...params },
opts
);
return results;
} catch ( e ) {
return handleError( e );
}
};
export default fetchProviderAuthorizations;

View File

@@ -7,7 +7,7 @@ import handleError from "./error";
const setQualityMetric = async (
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const response = await inatjs.observations.setQualityMetric( params, opts );
return response.results;
@@ -19,7 +19,7 @@ const setQualityMetric = async (
const deleteQualityMetric = async (
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const { results } = await inatjs.observations.deleteQualityMetric( params, opts );
return results;
@@ -31,7 +31,7 @@ const deleteQualityMetric = async (
const fetchQualityMetrics = async (
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const response = await inatjs.observations.qualityMetrics( params, opts );
return response.results;

View File

@@ -8,7 +8,7 @@ const PARAMS = {
fields: "all"
};
const fetchRelationships = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const fetchRelationships = async ( params: Object = {}, opts: Object = {} ): Promise<?Object> => {
try {
const response = await inatjs.relationships.search( { ...PARAMS, ...params }, opts );
return response;
@@ -17,7 +17,7 @@ const fetchRelationships = async ( params: Object = {}, opts: Object = {} ): Pro
}
};
const createRelationships = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const createRelationships = async ( params: Object = {}, opts: Object = {} ): Promise<?Object> => {
try {
const response = await inatjs.relationships.create( { ...PARAMS, ...params }, opts );
return response;
@@ -26,7 +26,7 @@ const createRelationships = async ( params: Object = {}, opts: Object = {} ): Pr
}
};
const updateRelationships = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const updateRelationships = async ( params: Object = {}, opts: Object = {} ): Promise<?Object> => {
try {
const response = await inatjs.relationships.update( { ...PARAMS, ...params }, opts );
return response;
@@ -35,7 +35,7 @@ const updateRelationships = async ( params: Object = {}, opts: Object = {} ): Pr
}
};
const deleteRelationships = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const deleteRelationships = async ( params: Object = {}, opts: Object = {} ): Promise<?Object> => {
try {
const response = await inatjs.relationships.delete( params, opts );
return response;

View File

@@ -16,7 +16,7 @@ const PARAMS = {
fields: "all"
};
const fetchSearchResults = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const fetchSearchResults = async ( params: Object = {}, opts: Object = {} ): Promise<?Object> => {
try {
const response = await inatjs.search( { ...PARAMS, ...params }, opts );
if ( !response ) { return null; }

View File

@@ -68,7 +68,7 @@ function mapToLocalSchema( taxon ) {
return taxon;
}
async function fetchTaxon( id: any, params: Object = {}, opts: Object = {} ): Promise<any> {
async function fetchTaxon( id: number, params: Object = {}, opts: Object = {} ): Promise<?Object> {
try {
const fetchParams = { ...PARAMS, ...params };
const response = await inatjs.taxa.fetch( id, fetchParams, opts );
@@ -81,7 +81,7 @@ async function fetchTaxon( id: any, params: Object = {}, opts: Object = {} ): Pr
}
}
async function searchTaxa( params: Object = {}, opts: Object = {} ): Promise<any> {
async function searchTaxa( params: Object = {}, opts: Object = {} ): Promise<?Object> {
try {
const { results } = await inatjs.taxa.search( { ...PARAMS, ...params }, opts );
return results;

View File

@@ -41,7 +41,7 @@ const REMOTE_USER_PARAMS = {
fields: REMOTE_USER_FIELDS
};
const fetchUserMe = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const fetchUserMe = async ( params: Object = {}, opts: Object = {} ): Promise<?Object> => {
try {
const response = await inatjs.users.me( { ...REMOTE_USER_PARAMS, ...params, ...opts } );
return response?.results[0];
@@ -50,7 +50,7 @@ const fetchUserMe = async ( params: Object = {}, opts: Object = {} ): Promise<an
}
};
const fetchMemberProjects = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const fetchMemberProjects = async ( params: Object = {}, opts: Object = {} ): Promise<?Object> => {
try {
const { results } = await inatjs.users.projects( {
...MEMBER_PROJECT_PARAMS,
@@ -67,7 +67,7 @@ const fetchRemoteUser = async (
id: number,
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
if ( !id ) return null;
try {
const { results } = await inatjs.users.fetch( id, {
@@ -85,7 +85,7 @@ const fetchRemoteUsers = async (
ids: Array<number>,
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const responses = await Promise.all( ids.map(
userId => inatjs.users.fetch( userId, {
@@ -104,7 +104,7 @@ const blockUser = async (
id: number,
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const response = await inatjs.users.block( { id }, {
...params,
@@ -120,7 +120,7 @@ const muteUser = async (
id: number,
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const response = await inatjs.users.mute( { id }, {
...params,
@@ -136,7 +136,7 @@ const unblockUser = async (
id: number,
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const response = await inatjs.users.unblock( { id }, {
...params,
@@ -152,7 +152,7 @@ const unmuteUser = async (
id: number,
params: Object = {},
opts: Object = {}
): Promise<any> => {
): Promise<?Object> => {
try {
const response = await inatjs.users.unmute( { id }, {
...params,
@@ -164,7 +164,7 @@ const unmuteUser = async (
}
};
const updateUsers = async ( params: Object = {}, opts: Object = {} ): Promise<any> => {
const updateUsers = async ( params: Object = {}, opts: Object = {} ): Promise<?Object> => {
try {
return await inatjs.users.update( params, opts );
} catch ( e ) {

View File

@@ -14,7 +14,7 @@ import useStore from "stores/useStore";
type Props = {
closeModal: ( ) => void,
navAndCloseModal: ( string, ?{ camera: string } ) => void
navAndCloseModal: Function
}
const AddObsModal = ( { closeModal, navAndCloseModal }: Props ): React.Node => {

View File

@@ -34,7 +34,8 @@ Realm.setLogLevel( "warn" );
LogBox.ignoreLogs( ["new NativeEventEmitter"] );
type Props = {
children?: any,
// $FlowIgnore
children?: unknown,
};
// this children prop is here for the sake of testing with jest

View File

@@ -38,8 +38,8 @@ const isTablet = DeviceInfo.isTablet();
// };
type Props = {
camera: any,
device: any,
camera: Object,
device: Object,
flipCamera: Function,
handleCheckmarkPress: Function,
isLandscapeMode: boolean

View File

@@ -20,7 +20,8 @@ import { useDeviceOrientation } from "sharedHooks";
import * as InatVision from "vision-camera-plugin-inatvision";
type Props = {
animatedProps: any,
// $FlowIgnore
animatedProps: unknown,
cameraRef: Object,
confidenceThreshold?: number,
device: Object,

View File

@@ -30,7 +30,7 @@ type Props = {
onCaptureError?: Function,
onCameraError?: Function,
frameProcessor?: Function,
animatedProps: any,
animatedProps: unknown,
onZoomStart?: Function,
onZoomChange?: Function,
resizeMode?: string

View File

@@ -7,7 +7,8 @@ import { Animated } from "react-native";
type Props = {
tappedCoordinates: Object,
singleTapToFocusAnimation: any
// $FlowIgnore
singleTapToFocusAnimation: unknown
}
const FocusSquare = ( { tappedCoordinates, singleTapToFocusAnimation }: Props ): Node => {

View File

@@ -42,8 +42,8 @@ export const MAX_PHOTOS_ALLOWED = 20;
type Props = {
addEvidence: ?boolean,
camera: any,
device: any,
camera: Object,
device: Object,
flipCamera: Function,
handleCheckmarkPress: Function,
isLandscapeMode: boolean

View File

@@ -1,7 +1,8 @@
import { Alert } from "react-native";
import { log } from "../../../../react-native-logs.config";
const logger = log.extend("CameraView");
const logger = log.extend( "CameraView" );
type Error = {
message: string;
@@ -11,38 +12,38 @@ type Event = {
log: string;
}
const handleClassifierError = (error: Error) => {
const handleClassifierError = ( error: Error ) => {
// When we hit this error, there is an error with the classifier.
logger.info(`handleClassifierError: ${error.message}`);
Alert.alert("error", error.message);
logger.info( `handleClassifierError: ${error.message}` );
Alert.alert( "error", error.message );
};
const handleDeviceNotSupported = (error: Error) => {
const handleDeviceNotSupported = ( error: Error ) => {
// When we hit this error, something with the current device is not supported.
logger.info(`handleDeviceNotSupported: ${error.message}`);
Alert.alert("error", error.message);
logger.info( `handleDeviceNotSupported: ${error.message}` );
Alert.alert( "error", error.message );
};
const handleCaptureError = (error: Error) => {
const handleCaptureError = ( error: Error ) => {
// When we hit this error, taking a photo did not work correctly
logger.info(`handleCaptureError: ${error.message}`);
Alert.alert("error", error.message);
logger.info( `handleCaptureError: ${error.message}` );
Alert.alert( "error", error.message );
};
const handleCameraError = (error: Error) => {
const handleCameraError = ( error: Error ) => {
// This error is thrown when it does not fit in any of the above categories.
logger.info(`handleCameraError: ${error.message}`);
Alert.alert("error", error.message);
logger.info( `handleCameraError: ${error.message}` );
Alert.alert( "error", error.message );
};
const handleLog = (event: Event) => {
logger.info(event.log);
const handleLog = ( event: Event ) => {
logger.info( event.log );
};
export {
handleCameraError,
handleCaptureError,
handleClassifierError,
handleDeviceNotSupported,
handleCaptureError,
handleCameraError,
handleLog,
handleLog
};

View File

@@ -55,7 +55,7 @@ const { useRealm } = RealmContext;
interface Props {
closeModal: Function,
updateTaxon: Function,
};
}
const FilterModal = ( {
closeModal,
@@ -649,7 +649,7 @@ const FilterModal = ( {
accessibilityRole="button"
onPress={async ( ) => {
const exploreLocation = await setExploreLocation( );
dispatch( { type: EXPLORE_ACTION.RESET, exploreLocation } )
dispatch( { type: EXPLORE_ACTION.RESET, exploreLocation } );
}}
>
{t( "Reset-verb" )}

View File

@@ -17,8 +17,12 @@ interface Props {
}
const NumberBadge = ( { number, light }: Props ): Node => {
const backgroundColor = light ? "bg-white" : "bg-inatGreen";
const textColor = light ? "text-darkGray" : "text-white";
const backgroundColor = light
? "bg-white"
: "bg-inatGreen";
const textColor = light
? "text-darkGray"
: "text-white";
return (
<View
className={classNames(

View File

@@ -1,5 +1,5 @@
import { useNavigation } from "@react-navigation/native";
import { DisplayTaxonName, Body4 } from "components/SharedComponents";
import { Body4, DisplayTaxonName } from "components/SharedComponents";
import ObsImagePreview from "components/SharedComponents/ObservationsFlashList/ObsImagePreview";
import SpeciesSeenCheckmark from "components/SharedComponents/SpeciesSeenCheckmark";
import { Pressable, View } from "components/styledComponents";

View File

@@ -32,7 +32,7 @@ const FullPageWebView = ( ) => {
} );
return unsubscribe;
}
return ( ) => { };
return ( ) => undefined;
}, [navigation, params.blurEvent] );
useFocusEffect(

View File

@@ -28,9 +28,10 @@ type Props = {
hidePlaceResults: boolean,
keysToUpdate: Object,
loading: boolean,
locationName: ?string,
locationName: string,
mapType: string,
mapViewRef: any,
// $FlowIgnore
mapViewRef: unknown,
region: Object,
selectPlaceResult: Function,
setMapReady: Function,
@@ -52,7 +53,7 @@ const LocationPicker = ( {
mapType,
region,
selectPlaceResult,
setMapReady = ( ) => { },
setMapReady = ( ) => undefined,
showCrosshairs,
updateLocationName,
updateRegion,

View File

@@ -28,7 +28,7 @@ const estimatedAccuracy = longitudeDelta => longitudeDelta * 1000 * (
const initialState = {
accuracy: 0,
accuracyTest: "pass",
locationName: null,
locationName: "",
mapType: "standard",
region: {
latitude: 0.0,
@@ -185,7 +185,7 @@ const LocationPickerContainer = ( { route }: Props ): Node => {
const placeName = await fetchPlaceName( newRegion.latitude, newRegion.longitude );
dispatch( {
type: "UPDATE_REGION",
locationName: placeName || null,
locationName: placeName || "",
region: newRegion,
accuracy: newAccuracy
} );

View File

@@ -17,14 +17,14 @@ import colors from "styles/tailwindColors";
const DROP_SHADOW = getShadowForColor( colors.darkGray );
type Props = {
locationName: ?string,
locationName: string,
updateLocationName: Function,
selectPlaceResult: Function,
hidePlaceResults: boolean
};
const LocationSearch = ( {
locationName, updateLocationName, selectPlaceResult, hidePlaceResults
locationName = "", updateLocationName, selectPlaceResult, hidePlaceResults
}: Props ): Node => {
const queryClient = useQueryClient( );
const locationInput = useRef( );

View File

@@ -34,7 +34,7 @@ const axiosInstance = axios.create( {
* Creates base API client for all requests
* @param additionalHeaders any additional headers that will be passed to the API
*/
const createAPI = ( additionalHeaders: any ) => create( {
const createAPI = additionalHeaders => create( {
axiosInstance,
headers: { "User-Agent": getUserAgent(), ...additionalHeaders }
} );
@@ -149,7 +149,8 @@ const getAnonymousJWT = (): string => {
* logged-in, use anonymous JWT
* @returns {Promise<string|*>}
*/
const getJWT = async ( allowAnonymousJWT: boolean = false ): Promise<?string> => {
// $FlowIgnore
const getJWT = async ( allowAnonymousJWT = false ): Promise<?string> => {
let jwtToken = await RNSInfo.getItem( "jwtToken", {} );
let jwtGeneratedAt = await RNSInfo.getItem( "jwtGeneratedAt", {} );
if ( jwtGeneratedAt ) {
@@ -228,8 +229,10 @@ const getJWT = async ( allowAnonymousJWT: boolean = false ): Promise<?string> =>
* @returns {Promise<string|*>} access token, null if not logged in
*/
const getAPIToken = async (
useJWT: boolean = false,
allowAnonymousJWT: boolean = false
// $FlowIgnore
useJWT = false,
// $FlowIgnore
allowAnonymousJWT = false
): Promise<?string> => {
const loggedIn = await isLoggedIn();
if ( !loggedIn ) {
@@ -402,7 +405,7 @@ const authenticateUser = async (
*
* @returns null if successful, otherwise an error string
*/
const registerUser = async ( user: Object ): any => {
const registerUser = async ( user: Object ): ?Object => {
const locales = RNLocalize.getLocales();
const formData = {
user: {
@@ -441,7 +444,7 @@ const isCurrentUser = async ( username: string ): Promise<boolean> => {
*/
const resetPassword = async (
email: string
): any => {
): ?Object => {
const formData = {
user: {
email

View File

@@ -12,8 +12,10 @@ import {
} from "react-native";
type Props = {
backgroundSource: any,
children: any,
// $FlowIgnore
backgroundSource: unknown,
// $FlowIgnore
children: unknown,
keyboardVerticalOffset?: number,
scrollEnabled?: boolean
}
@@ -38,7 +40,7 @@ const LoginSignupWrapper = ( {
// Make the StatusBar translucent in Android but reset it when we leave
// because this alters the layout.
useEffect( ( ) => {
if ( Platform.OS !== "android" ) return ( ) => { };
if ( Platform.OS !== "android" ) return ( ) => undefined;
// Hide on first render
StatusBar.setTranslucent( true );
// StatusBar.setTranslucent( true );
@@ -50,7 +52,7 @@ const LoginSignupWrapper = ( {
}, [navigation] );
useEffect( ( ) => {
if ( Platform.OS !== "android" ) return ( ) => { };
if ( Platform.OS !== "android" ) return ( ) => undefined;
const unsubscribe = navigation.addListener( "blur", ( ) => {
StatusBar.setTranslucent( false );
} );

View File

@@ -12,7 +12,7 @@ import colors from "styles/tailwindColors";
type Props = {
attribution?: string,
licenseCode?: string,
optionalClasses?: any
optionalClasses?: string
};
const AttributionButton = ( {

View File

@@ -19,7 +19,8 @@ import CustomImageZoom from "./CustomImageZoom";
type Props = {
autoPlaySound?: boolean, // automatically start playing a sound when it is visible
editable?: boolean,
horizontalScroll: any,
// $FlowIgnore
horizontalScroll: unknown,
onDeletePhoto?: Function,
onDeleteSound?: Function,
photos: Array<{
@@ -40,8 +41,8 @@ const MainMediaDisplay = ( {
autoPlaySound,
editable,
horizontalScroll,
onDeletePhoto = ( ) => { },
onDeleteSound = ( ) => { },
onDeletePhoto = ( ) => undefined,
onDeleteSound = ( ) => undefined,
photos,
sounds = [],
selectedMediaIndex,

View File

@@ -44,7 +44,7 @@ const MediaViewer = ( {
autoPlaySound,
editable,
header,
onClose = ( ) => { },
onClose = ( ) => undefined,
onDeletePhoto,
onDeleteSound,
photos = [],

View File

@@ -31,7 +31,7 @@ const MediaViewerModal = ( {
autoPlaySound,
editable,
header,
onClose = ( ) => { },
onClose = ( ) => undefined,
onDeletePhoto,
onDeleteSound,
photos = [],

View File

@@ -16,7 +16,7 @@ import React from "react";
import ActivityHeaderContainer from "./ActivityHeaderContainer";
type Props = {
currentUserId?: Number,
currentUserId?: number,
isFirstDisplay: boolean,
isOnline: boolean,
item: Object,

View File

@@ -19,14 +19,14 @@ import colors from "styles/tailwindColors";
type Props = {
observation: Object,
currentUser?: Object,
afterToggleFave: ( wasFaved: boolean ) => void,
afterToggleFave: Function,
top?: boolean
}
const FaveButton = ( {
observation,
currentUser,
afterToggleFave = ( ) => { },
afterToggleFave = ( ) => undefined,
top = false
}: Props ): Node => {
const { t } = useTranslation( );

View File

@@ -36,7 +36,7 @@ const ObsMedia = ( {
tablet
}: Props ): Node => {
const { width } = Dimensions.get( "window" );
const [index, setIndex] = useState<number>( 0 );
const [index, setIndex] = useState( 0 );
const [mediaViewerVisible, setMediaViewerVisible] = useState( false );
const paginationColor = colors.white;

View File

@@ -24,7 +24,7 @@ type Props = {
handleDragAndDrop: Function,
isFetchingLocation: boolean,
locationPermissionNeeded: boolean,
locationTextClassNames: any,
locationTextClassNames: Array<string>,
onLocationPermissionBlocked: Function,
onLocationPermissionDenied: Function,
onLocationPermissionGranted: Function,

View File

@@ -74,7 +74,7 @@ const EvidenceSectionContainer = ( {
return function cleanup( ) {
mountedRef.current = false;
};
}, [] );
}, [mountedRef] );
useEffect( ( ) => {
if ( difference( obsPhotoUris, photoEvidenceUris ).length > 0 ) {
@@ -179,7 +179,9 @@ const EvidenceSectionContainer = ( {
setPassesEvidenceTest
] );
const locationTextClassNames = ( !latitude || !longitude ) && ["color-warningRed"];
const locationTextClassNames = ( !latitude || !longitude )
? ["color-warningRed"]
: [];
const handleDragAndDrop = ( { data } ) => {
// Turn from Realm object to simple JS objects (so we can update the position)

View File

@@ -9,7 +9,7 @@ import useTranslation from "sharedHooks/useTranslation";
type Props = {
handleClose: Function,
selectedValue?: any,
selectedValue?: boolean,
updateGeoprivacyStatus: Function
}

View File

@@ -9,7 +9,7 @@ import useTranslation from "sharedHooks/useTranslation";
type Props = {
handleClose: Function,
selectedValue: any,
selectedValue: boolean,
updateCaptiveStatus: Function
}

View File

@@ -53,7 +53,7 @@ const PhotoSharing = ( ): Node => {
resetStore( );
// Create a new observation with multiple shared photos (one or more)
let photoUris:any[];
let photoUris;
// data is returned as a string for a single photo on Android
// and an object with an array of data strings on iOS, i.e.

View File

@@ -1,12 +1,14 @@
import { View } from "components/styledComponents";
import React from "react";
import { useTheme } from "react-native-paper";
import { Confetti } from "./Confetti";
import IndeterminateProgressBar from "./IndeterminateProgressBar";
const count: number = 30;
const duration: number = 7000;
export default function ActivityAnimation() {
const count = 30;
const duration = 7000;
const ActivityAnimation = ( ) => {
const theme = useTheme();
return (
<View className="flex-1">
@@ -18,4 +20,6 @@ export default function ActivityAnimation() {
<Confetti key="confetti" count={count} duration={duration} />
</View>
);
}
};
export default ActivityAnimation;

View File

@@ -1,17 +1,20 @@
import { PropsWithChildren, memo, useEffect, useState } from 'react'
import { StyleSheet, useWindowDimensions } from 'react-native'
/* eslint-disable no-use-before-define */
import classNames from "classnames";
import { INatIcon } from "components/SharedComponents";
import { View } from "components/styledComponents";
import React, {
memo, PropsWithChildren, useEffect, useState
} from "react";
import { StyleSheet, useWindowDimensions } from "react-native";
import { useTheme } from "react-native-paper";
import Animated, {
Easing,
interpolate,
runOnJS,
useAnimatedStyle,
useSharedValue,
withTiming,
} from 'react-native-reanimated'
import { INatIcon } from "components/SharedComponents";
import { View } from "components/styledComponents";
import classNames from "classnames";
import { useTheme } from "react-native-paper";
withTiming
} from "react-native-reanimated";
type ConfettiProps = PropsWithChildren<{
count: number
@@ -26,74 +29,77 @@ type AnimatedElementProps = PropsWithChildren<{
}>
const AnimatedElement = memo(
({ index, count, children, duration, animation }: AnimatedElementProps) => {
const { start, end, rotation, startTime, endTime, scale } = getAnimationConfigForElement(
( {
index, count, children, duration, animation
}: AnimatedElementProps ) => {
const {
start, end, rotation, startTime, endTime, scale
} = getAnimationConfigForElement(
duration,
index,
count
)
const { width, height } = useWindowDimensions()
const style = useAnimatedStyle(() => {
return {
opacity: 0.8,
position: 'absolute',
transform: [
{
translateX: interpolate(
animation.value,
[startTime, endTime],
[start.x * width, end.x * width]
),
},
{
translateY: interpolate(
animation.value,
[startTime, endTime],
[start.y * height, (end.y * height) / 2]
),
},
{
rotate: `${interpolate(animation.value, [startTime, endTime], [0, rotation])}rad`,
},
{
scale,
},
],
}
})
return <Animated.View style={style}>{children}</Animated.View>
);
const { width, height } = useWindowDimensions();
const style = useAnimatedStyle( () => ( {
opacity: 0.8,
position: "absolute",
transform: [
{
translateX: interpolate(
animation.value,
[startTime, endTime],
[start.x * width, end.x * width]
)
},
{
translateY: interpolate(
animation.value,
[startTime, endTime],
[start.y * height, ( end.y * height ) / 2]
)
},
{
rotate: `${interpolate( animation.value, [startTime, endTime], [0, rotation] )}rad`
},
{
scale
}
]
} ) );
return <Animated.View style={style}>{children}</Animated.View>;
}
)
);
export function Confetti({ count, duration = 5000, children }: ConfettiProps) {
const Confetti = ( { count, duration = 5000 }: ConfettiProps ) => {
const theme = useTheme();
const animation = useSharedValue(0)
const [autoDestroy, setAutoDestroy] = useState(false)
const animation = useSharedValue( 0 );
const [autoDestroy, setAutoDestroy] = useState( false );
useEffect(() => {
useEffect( () => {
animation.value = withTiming(
1,
{
duration,
easing: Easing.linear,
easing: Easing.linear
},
(finished) => {
if (finished) {
runOnJS(setAutoDestroy)(true)
finished => {
if ( finished ) {
runOnJS( setAutoDestroy )( true );
}
}
)
}, [])
);
}, [
animation,
duration
] );
const fadeOutBeforeDestroy = useSharedValue(300 / duration)
const stylez = useAnimatedStyle(() => {
return {
opacity: interpolate(animation.value, [1 - fadeOutBeforeDestroy.value, 1], [1, 0]),
}
})
const fadeOutBeforeDestroy = useSharedValue( 300 / duration );
const stylez = useAnimatedStyle( () => ( {
opacity: interpolate( animation.value, [1 - fadeOutBeforeDestroy.value, 1], [1, 0] )
} ) );
if (autoDestroy) {
return null
if ( autoDestroy ) {
return null;
}
const iconicTaxonIcons = [
@@ -115,7 +121,7 @@ export function Confetti({ count, duration = 5000, children }: ConfettiProps) {
return (
<Animated.View pointerEvents="none" style={[StyleSheet.absoluteFillObject, stylez]}>
{[...Array(count).keys()].map((i) => {
{[...Array( count ).keys()].map( i => {
// With the index loop through the iconicTaxonIcons multiple times
const randomIconicTaxon = iconicTaxonIcons[i % iconicTaxonIcons.length];
return (
@@ -141,55 +147,62 @@ export function Confetti({ count, duration = 5000, children }: ConfettiProps) {
/>
</View>
</AnimatedElement>
)
})}
);
} )}
</Animated.View>
)
}
);
};
// Helpers
function clamp(value: number, lowerBound: number, upperBound: number) {
'worklet'
return Math.min(Math.max(lowerBound, value), upperBound)
function clamp( value: number, lowerBound: number, upperBound: number ) {
"worklet";
return Math.min( Math.max( lowerBound, value ), upperBound );
}
function getRandomStartEndCoordinates() {
'worklet'
"worklet";
// First, generate a start x between 0 and 1
// then subtract that from 1 to get the end x
// In this way, we now that the end x will always
// be on the opposite side of the screen from the start x
// We want a range between [0, 1] because we will
// multiply this with the screen width/height.
const x = randomNumberInRange(0, 1)
const y = randomNumberInRange(1, 1.3)
const x = randomNumberInRange( 0, 1 );
const y = randomNumberInRange( 1, 1.3 );
// y -> -x
return { start: { x, y: 0 }, end: { x: randomNumberInRange(0, 1.5) - x, y } }
return { start: { x, y: 0 }, end: { x: randomNumberInRange( 0, 1.5 ) - x, y } };
}
function randomNumberInRange(min: number, max: number) {
'worklet'
return Math.random() * (max - min) + min
function randomNumberInRange( min: number, max: number ) {
"worklet";
return Math.random() * ( max - min ) + min;
}
function getAnimationConfigForElement(duration: number, index: number, count: number) {
'worklet'
function getAnimationConfigForElement( duration: number, index: number, count: number ) {
"worklet";
// In a nutshell, to constrain the duration
// of each element and also to ensure that it is evenly
// distributing the elements across the duration [0, 1]
const minDuration = duration / 4
const maxDuration = clamp(2000, minDuration, duration * 0.7)
const minDurationFraction = minDuration / duration
const maxDurationFraction = maxDuration / duration
const minDuration = duration / 4;
const maxDuration = clamp( 2000, minDuration, duration * 0.7 );
const minDurationFraction = minDuration / duration;
const maxDurationFraction = maxDuration / duration;
// Distribute the start times evenly across the duration, based on index and count
const startTime = (index / count) * (1 - maxDurationFraction) // between [0, 1 - maxDurationFraction]
const animationDuration = randomNumberInRange(minDurationFraction, maxDurationFraction)
// between [0, 1 - maxDurationFraction]
const startTime = ( index / count ) * ( 1 - maxDurationFraction );
const animationDuration = randomNumberInRange( minDurationFraction, maxDurationFraction );
return {
...getRandomStartEndCoordinates(),
startTime, // from [0, .5]
endTime: clamp(startTime + animationDuration, 0, 1), // from [startTime, 1]:
rotation: randomNumberInRange(0, 1) * Math.PI, // max 2PI (360deg)
scale: randomNumberInRange(0.7, 2),
}
endTime: clamp( startTime + animationDuration, 0, 1 ), // from [startTime, 1]:
rotation: randomNumberInRange( 0, 1 ) * Math.PI, // max 2PI (360deg)
scale: randomNumberInRange( 0.7, 2 )
};
}
export default Confetti;

View File

@@ -1,4 +1,3 @@
import { View } from "components/styledComponents";
import React, { useEffect, useMemo } from "react";
import { Dimensions } from "react-native";
import Animated, {

View File

@@ -14,11 +14,11 @@ type ButtonProps = {
className?: string,
disabled?: boolean,
forceDark?: boolean,
icon?: any,
icon?: string,
level?: string,
loading?: boolean,
onPress: any,
style?: any,
onPress: Function,
style?: string | Array<string>,
testID?: string,
text: string,
dropdown?: boolean

View File

@@ -5,9 +5,9 @@ import { useTheme } from "react-native-paper";
import colors from "styles/tailwindColors";
type Props = {
icon: any,
icon: string,
disabled?: boolean,
handlePress: any,
handlePress: Function,
accessibilityLabel: string,
accessibilityHint?: string
}

View File

@@ -11,7 +11,8 @@ import { useTheme } from "react-native-paper";
type Props = {
accessibilityHint?: string,
accessibilityLabel: string,
children?: any,
// $FlowIgnore
children?: unknown,
color?: string,
disabled?: boolean,
height?: number,

View File

@@ -20,7 +20,8 @@ type Props = {
accessibilityHint?: string,
accessibilityLabel: string,
backgroundColor?: string,
children?: any,
// $FlowIgnore
children?: unknown,
color?: string,
disabled?: boolean,
height?: number,

View File

@@ -28,7 +28,8 @@ type Props = {
longitude: number,
obscured?: boolean,
positionalAccuracy?: number,
mapViewRef: any,
// $FlowIgnore
mapViewRef: unknown,
region?: Object,
closeModal: Function,
tileMapParams: Object,

View File

@@ -9,8 +9,8 @@ import { useEffect, useState } from "react";
// However, for the most part, it is preferable to remove the component from the DOM
type Props = {
noInitialRender?: bool,
show?: bool,
noInitialRender?: boolean,
show?: boolean,
children: React.Node
}

View File

@@ -11,7 +11,8 @@ import { useIconicTaxa, useTranslation } from "sharedHooks";
import colors from "styles/tailwindColors";
type Props = {
before: any,
// $FlowIgnore
before: unknown,
onTaxonChosen: Function,
taxon: {
id: number,

View File

@@ -16,7 +16,10 @@ import { useTranslation } from "react-i18next";
import User from "realmModels/User";
type Props = {
user: any,
user: {
id: number,
icon_url?: string
},
isOnline: boolean
};

View File

@@ -10,7 +10,8 @@ import colors from "styles/tailwindColors";
type Props = {
accessibilityHint?: string,
accessibilityLabel?: string,
children: any,
// $FlowIgnore
children: unknown,
large?: boolean,
setVisible: Function,
visible: boolean,

View File

@@ -87,7 +87,8 @@ export function metersToLatitudeDelta( meters: number, latitude: number ): numbe
}
type Props = {
children?: any,
// $FlowIgnore
children?: unknown,
className?: string,
currentLocationButtonClassName?: string,
currentLocationZoomLevel?: number,
@@ -144,8 +145,8 @@ const Map = ( {
obscured,
obsLatitude,
obsLongitude,
onMapReady = ( ) => { },
onPanDrag = ( ) => { },
onMapReady = ( ) => undefined,
onPanDrag = ( ) => undefined,
onPermissionBlocked: onPermissionBlockedProp,
onPermissionDenied: onPermissionDeniedProp,
onPermissionGranted: onPermissionGrantedProp,
@@ -331,9 +332,12 @@ const Map = ( {
] );
const params = useMemo( ( ) => {
const newTileParams: any = { ...tileMapParams };
const newTileParams = { ...tileMapParams };
// $FlowIgnore
delete newTileParams.order;
// $FlowIgnore
delete newTileParams.order_by;
// $FlowIgnore
delete newTileParams.per_page;
return newTileParams;
}, [tileMapParams] );

View File

@@ -7,7 +7,8 @@ import RNModal from "react-native-modal";
type Props = {
showModal: boolean,
closeModal: Function,
modal: any,
// $FlowIgnore
modal: unknown,
backdropOpacity?: number,
fullScreen?: boolean,
onModalHide?: Function,

View File

@@ -8,7 +8,8 @@ type Props = {
icon: string,
size?: number,
classNameMargin?: string,
children: any
// $FlowIgnore
children: unknown
}
const ContentWithIcon = ( {

View File

@@ -10,7 +10,8 @@ import useStore from "stores/useStore";
type Props = {
observation: Object,
testID?: string,
children: any
// $FlowIgnore
children: unknown
}
const MyObservationsPressable = ( { observation, testID, children }: Props ): Node => {

View File

@@ -17,7 +17,7 @@ type Props = {
style?: Object,
uploadSingleObservation?: Function,
uploadState: {
uploadProgress: Number
uploadProgress: number
},
explore: boolean
};

View File

@@ -140,7 +140,7 @@ const PermissionGateContainer = ( {
&& result !== null
) {
setModalShown( true );
return () => {};
return () => undefined;
}
if ( !withoutNavigation ) {
const unsubscribe = navigation.addListener( "focus", async () => {
@@ -149,7 +149,7 @@ const PermissionGateContainer = ( {
} );
return unsubscribe;
}
return () => {};
return () => undefined;
}, [
checkPermission,
children,

View File

@@ -17,7 +17,8 @@ type Props = {
containerClass?: string,
handleTextChange: Function,
hasShadow?: boolean,
input?: any,
// $FlowIgnore
input?: unknown,
placeholder?: string,
testID?: string,
value: string,

View File

@@ -26,7 +26,7 @@ type Props = {
handleClose?: Function,
hideCloseButton?: boolean,
headerText?: string,
snapPoints?: any,
snapPoints?: Array<string>,
insideModal?: boolean
}

View File

@@ -7,7 +7,7 @@ import type { Node } from "react";
import React from "react";
type Props = {
props: any
props: Object
}
const BottomSheetStandardBackdrop = ( { props }: Props ): Node => (

View File

@@ -15,7 +15,7 @@ type Props = {
confirm: Function,
headerText: string,
pickerValues: Object,
selectedValue: any,
selectedValue: boolean,
};
const PickerSheet = ( {

View File

@@ -15,7 +15,7 @@ type Props = {
confirm: Function,
headerText: string,
radioValues: Object,
selectedValue?: any
selectedValue?: string
}
const RadioButtonSheet = ( {

View File

@@ -12,7 +12,7 @@ type Tab = {
id: string,
text: string,
testID?: string,
onPress: ( any ) => void
onPress: Function
}
type Props = {

View File

@@ -9,7 +9,7 @@ import React from "react";
import { Text } from "react-native";
// This is the same as List1 Typography in Figma
const Body1 = ( props: any ): Node => (
const Body1 = ( props: Object ): Node => (
<Text
className={classnames(
"text-base trailing-tight text-darkGray",

View File

@@ -8,7 +8,7 @@ import type { Node } from "react";
import React from "react";
import { Text } from "react-native";
const Body2 = ( props: any ): Node => (
const Body2 = ( props: Object ): Node => (
<Text
className={classnames(
"text-md trailing-tight text-darkGray",

View File

@@ -8,7 +8,7 @@ import type { Node } from "react";
import React from "react";
import { Text } from "react-native";
const Body3 = ( props: any ): Node => (
const Body3 = ( props: Object ): Node => (
<Text
className={classnames(
"text-xs trailing-tight text-darkGray",

View File

@@ -8,7 +8,7 @@ import type { Node } from "react";
import React from "react";
import { Text } from "react-native";
const Body4 = ( props: any ): Node => (
const Body4 = ( props: Object ): Node => (
<Text
className={classnames(
"text-2xs text-darkGray",

View File

@@ -8,7 +8,7 @@ import type { Node } from "react";
import React from "react";
import { Text } from "react-native";
const Heading1 = ( props: any ): Node => (
const Heading1 = ( props: Object ): Node => (
<Text
className={classnames(
"text-3xl tracking-tight text-darkGray",

View File

@@ -8,7 +8,7 @@ import type { Node } from "react";
import React from "react";
import { Text } from "react-native";
const Heading2 = ( props: any ): Node => (
const Heading2 = ( props: Object ): Node => (
<Text
className={classnames(
"text-2xl text-darkGray",

View File

@@ -8,7 +8,7 @@ import type { Node } from "react";
import React from "react";
import { Text } from "react-native";
const Heading3 = ( props: any ): Node => (
const Heading3 = ( props: Object ): Node => (
<Text
className={classnames(
"text-lg text-darkGray",

View File

@@ -8,7 +8,7 @@ import type { Node } from "react";
import React from "react";
import { Text } from "react-native";
const Heading4 = ( props: any ): Node => (
const Heading4 = ( props: Object ): Node => (
<Text
className={classnames(
"text-md tracking-widest text-darkGray",

View File

@@ -8,7 +8,7 @@ import type { Node } from "react";
import React from "react";
import { Text } from "react-native";
const Heading5 = ( props: any ): Node => (
const Heading5 = ( props: Object ): Node => (
<Text
className={classnames(
"text-3xs tracking-wide text-darkGray",

View File

@@ -8,7 +8,7 @@ import type { Node } from "react";
import React from "react";
import { Text } from "react-native";
const List2 = ( props: any ): Node => (
const List2 = ( props: Object ): Node => (
<Text
className={classnames(
"text-sm trailing-tight text-darkGray",

View File

@@ -4,7 +4,7 @@ import { View } from "components/styledComponents";
import type { Node } from "react";
import React from "react";
const P = ( props: any ): Node => (
const P = ( props: Object ): Node => (
// eslint-disable-next-line react/jsx-props-no-spreading
<View className="mb-3" {...props}>{ props.children }</View>
);

View File

@@ -8,7 +8,7 @@ import type { Node } from "react";
import React from "react";
import { Text } from "react-native";
const Subheading1 = ( props: any ): Node => (
const Subheading1 = ( props: Object ): Node => (
<Text
className={classnames(
"text-xl trailing-tight text-darkGray",

View File

@@ -8,7 +8,7 @@ import type { Node } from "react";
import React from "react";
import { Text } from "react-native";
const UnderlinedLink = ( props: any ): Node => (
const UnderlinedLink = ( props: Object ): Node => (
<Text
className={classnames(
"text-md text-darkGray underline",

View File

@@ -21,7 +21,8 @@ type Props = {
progress: number,
uploadObservation: Function,
layout: string,
children: any,
// $FlowIgnore
children: unknown,
uuid: string
}
const AnimatedView = Reanimated.createAnimatedComponent( View );

View File

@@ -78,7 +78,7 @@ function hyperlinkMentions( text ) {
}
type Props = {
text:String,
text:string,
htmlStyle?:Object,
}

View File

@@ -27,7 +27,7 @@ import SuggestionsEmpty from "./SuggestionsEmpty";
type Props = {
commonAncestor: ?string,
debugData: any,
debugData: Object,
hasVisionSuggestion: boolean,
loading: boolean,
onPressPhoto: Function,

View File

@@ -1,21 +1,21 @@
// @flow
import { useNavigation, useRoute } from "@react-navigation/native";
import {
View
} from "components/styledComponents";
import {
ActivityIndicator,
Body1,
Button
} from "components/SharedComponents";
import {
View
} from "components/styledComponents";
import type { Node } from "react";
import React, { useCallback } from "react";
import React from "react";
import { useTranslation } from "sharedHooks";
interface Props {
loading: boolean
};
}
const SuggestionsEmpty = ( {
loading
@@ -25,7 +25,7 @@ const SuggestionsEmpty = ( {
const { params } = useRoute( );
const { lastScreen } = params;
const textClass = "mt-10 px-10 text-center"
const textClass = "mt-10 px-10 text-center";
const renderEmpty = ( ) => {
if ( loading ) {
@@ -42,20 +42,20 @@ const SuggestionsEmpty = ( {
</Body1>
{lastScreen === "CameraWithDevice" && (
<>
<Body1 className={textClass}>
{t( "You-can-upload-this-observation-to-our-community" )}
</Body1>
<Button
className="mx-5 mt-10"
text={t( "CONTINUE" )}
onPress={( ) => navigation.navigate( "ObsEdit" )}
level="focus"
/>
<Body1 className={textClass}>
{t( "You-can-upload-this-observation-to-our-community" )}
</Body1>
<Button
className="mx-5 mt-10"
text={t( "CONTINUE" )}
onPress={( ) => navigation.navigate( "ObsEdit" )}
level="focus"
/>
</>
)}
</>
);
}
};
return renderEmpty( );
};

View File

@@ -38,7 +38,11 @@ const resizeImage = async (
};
type FlattenUploadArgs = {
image: any,
image: {
uri: string,
name: string,
type: string
},
lat?: number,
lng?: number
}

View File

@@ -15,7 +15,7 @@ import React from "react";
import { useTranslation } from "sharedHooks";
type Props = {
optionalClasses?: any,
optionalClasses?: string,
taxon?: {
rank: string,
rank_level: number,

View File

@@ -232,12 +232,14 @@ yargs
.command(
"write-translation-loader",
"Write loadTranslations.js",
// eslint-disable-next-line @typescript-eslint/no-empty-function
( ) => {},
( ) => writeLoadTranslations( )
)
.command(
"build",
"Prepare existing localizations for use in the app",
// eslint-disable-next-line @typescript-eslint/no-empty-function
( ) => {},
async argv => {
await validate( );
@@ -251,7 +253,7 @@ yargs
.command(
"validate",
"Validate source strings",
( ) => { },
( ) => undefined,
_argv => {
validate( );
}
@@ -259,7 +261,7 @@ yargs
.command(
"normalize",
"Normalize source strings",
( ) => { },
( ) => undefined,
_argv => {
normalize( );
}
@@ -267,7 +269,7 @@ yargs
.command(
"unused",
"List unused translation keys",
( ) => { },
( ) => undefined,
_argv => {
unused( );
}
@@ -275,7 +277,7 @@ yargs
.command(
"untranslatable",
"List translation keys in source code but not in strings.ftl",
( ) => { },
( ) => undefined,
_argv => {
untranslatable( );
}

View File

@@ -7,8 +7,8 @@ import colors from "styles/tailwindColors";
type Props = {
testID: string,
icon: any,
onPress: any,
icon: string,
onPress: Function,
userIconUri?: string,
accessibilityLabel: string,
accessibilityRole?: string,

View File

@@ -11,7 +11,7 @@ type Props = {
unread: boolean,
icon: string,
testID: string,
onPress: any,
onPress: Function,
active:boolean,
accessibilityLabel: string,
accessibilityRole?: string,

View File

@@ -13,8 +13,8 @@ import useStore from "stores/useStore";
type Props = {
testID: string,
icon: any,
onPress: any,
icon: string,
onPress: Function,
active:boolean,
accessibilityLabel: string,
accessibilityRole?: string,

View File

@@ -32,9 +32,9 @@ const drawerScrollViewStyle = {
};
type Props = {
state: any,
navigation: any,
descriptors: any
state: Object,
navigation: Object,
descriptors: Object
}
const CustomDrawerContent = ( { ...props }: Props ): Node => {
@@ -63,7 +63,7 @@ const CustomDrawerContent = ( { ...props }: Props ): Node => {
} ), [] );
const drawerItems = useMemo( ( ) => {
const items: any = {
const items = {
// search: {
// label: t( "SEARCH" ),
// navigation: "search",
@@ -115,6 +115,7 @@ const CustomDrawerContent = ( { ...props }: Props ): Node => {
}
};
if ( isDebug ) {
// $FlowIgnore
items.debug = {
label: "DEBUG",
navigation: "Debug",
@@ -133,6 +134,7 @@ const CustomDrawerContent = ( { ...props }: Props ): Node => {
<INatIconButton
icon={drawerItems[item].icon}
size={20}
// $FlowIgnore
color={drawerItems[item].color}
accessibilityLabel={drawerItems[item].label}
/>
@@ -188,6 +190,7 @@ const CustomDrawerContent = ( { ...props }: Props ): Node => {
), [currentUser, navigation, t] );
const renderDrawerItem = useCallback( item => {
// $FlowIgnore
if ( drawerItems[item].loggedInOnly && !currentUser ) {
return null;
}
@@ -197,6 +200,7 @@ const CustomDrawerContent = ( { ...props }: Props ): Node => {
testID={drawerItems[item].testID}
label={drawerItems[item].label}
onPress={( ) => {
// $FlowIgnore
navigation.navigate( drawerItems[item].navigation, drawerItems[item].params );
}}
labelStyle={labelStyle}

Some files were not shown because too many files have changed in this diff Show More