diff --git a/components/Observations/ObsCard.js b/components/Observations/ObsCard.js new file mode 100644 index 000000000..5ffb0053e --- /dev/null +++ b/components/Observations/ObsCard.js @@ -0,0 +1,45 @@ +// @flow strict-local + +import React from "react"; +import { Pressable, Text, View, Image } from "react-native"; +import type { Node } from "react"; + +import { viewStyles, textStyles } from "../../styles/observations/obsCard"; + +type Props = { + item: { + uuid: string, + userPhoto: string, + commonName: string, + location: string, + timeObservedAt: string, + identifications: number, + comments: number, + qualityGrade: string + } +} + +const ObsCard = ( { item }: Props ): Node => { + const handlePress = ( ) => console.log( "obs card was pressed" ); + + return ( + + + + {item.commonName} + {item.location} + {item.timeObservedAt} + + + {item.identifications} + {item.comments} + {item.qualityGrade} + + + ); +}; + +export default ObsCard; diff --git a/components/Observations/ObservationsList.js b/components/Observations/ObservationsList.js new file mode 100644 index 000000000..fb808a7e1 --- /dev/null +++ b/components/Observations/ObservationsList.js @@ -0,0 +1,27 @@ +// @flow strict-local + +import React from "react"; +import { FlatList } from "react-native"; +import type { Node } from "react"; + +import ObsCard from "./ObsCard"; +import viewStyles from "../../styles/observations/observationsList"; +import useFetchObservations from "../hooks/fetchObservations"; + +const ObservationsList = ( ): Node => { + const observations = useFetchObservations( ); + + const extractKey = item => item.uuid; + const renderItem = ( { item } ) => ; + + return ( + + ); +}; + +export default ObservationsList; diff --git a/components/hooks/fetchObservations.js b/components/hooks/fetchObservations.js new file mode 100644 index 000000000..f6024d300 --- /dev/null +++ b/components/hooks/fetchObservations.js @@ -0,0 +1,40 @@ +// @flow strict-local + +import { useState, useEffect } from "react"; +import inatjs from "inaturalistjs"; + +const useFetchObservations = ( ): any => { + const [observations, setObservations] = useState( [] ); + + useEffect( ( ) => { + const fetchObservations = async ( ) => { + try { + const testUser = "albulltest"; + const params = { user_login: testUser }; + const response = await inatjs.observations.search( params ); + const userObservations = response.results; + + const onlyNecessaryObsDetails = userObservations.map( ( obs => { + return { + uuid: obs.uuid, + userPhoto: obs.taxon.default_photo.square_url, + commonName: obs.taxon.preferred_common_name || obs.taxon.name, + location: obs.place_guess || obs.location, + timeObservedAt: obs.time_observed_at, + identifications: obs.identifications_count, + comments: obs.comments.length, + qualityGrade: obs.quality_grade + }; + } ) ); + setObservations( onlyNecessaryObsDetails ); + } catch ( e ) { + console.log( e, JSON.stringify( e ), "couldn't fetch observations" ); + } + }; + fetchObservations( ); + }, [] ); + + return observations; +}; + +export default useFetchObservations; diff --git a/index.js b/index.js index eca558087..be4cb1b9b 100644 --- a/index.js +++ b/index.js @@ -3,7 +3,7 @@ */ import {AppRegistry} from "react-native"; -import App from "./App"; +import ObsList from "./components/Observations/ObservationsList"; import {name as appName} from "./app.json"; -AppRegistry.registerComponent( appName, () => App ); +AppRegistry.registerComponent( appName, () => ObsList ); diff --git a/ios/iNaturalistReactNative.xcodeproj/project.pbxproj b/ios/iNaturalistReactNative.xcodeproj/project.pbxproj index dfe7801be..a2e140fcc 100644 --- a/ios/iNaturalistReactNative.xcodeproj/project.pbxproj +++ b/ios/iNaturalistReactNative.xcodeproj/project.pbxproj @@ -114,7 +114,6 @@ AA97B3DCA18D747D9E7F0358 /* Pods-iNaturalistReactNative-iNaturalistReactNativeTests.debug.xcconfig */, ACD831F90866E862C17F1AD1 /* Pods-iNaturalistReactNative-iNaturalistReactNativeTests.release.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -263,7 +262,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "set -e\n\nexport NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n"; + shellScript = "export NODE_BINARY=/Users/amanda/.nvm/versions/node/v12.13.0/bin/node\n../node_modules/react-native/scripts/react-native-xcode.sh\n"; }; 010B3221A1D8DF0722FE9DE2 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; @@ -485,6 +484,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = N5J7L4P93Z; ENABLE_BITCODE = NO; INFOPLIST_FILE = iNaturalistReactNative/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -511,6 +511,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = N5J7L4P93Z; INFOPLIST_FILE = iNaturalistReactNative/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/package-lock.json b/package-lock.json index 7e2c1856e..2eacc63cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "inaturalistreactnative", "version": "0.0.1", "dependencies": { + "inaturalistjs": "github:inaturalist/inaturalistjs", "react": "17.0.2", "react-native": "0.65.1" }, @@ -25,6 +26,7 @@ "eslint-plugin-react": "^7.25.1", "eslint-plugin-react-hooks": "^4.2.0", "eslint-plugin-react-native": "^3.11.0", + "flow-bin": "^0.149.0", "jest": "^26.6.3", "metro-react-native-babel-preset": "^0.66.0", "react-native-codegen": "^0.0.7", @@ -4376,8 +4378,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "node_modules/atob": { "version": "2.1.2", @@ -5128,7 +5129,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -5305,6 +5305,28 @@ "node": ">=4" } }, + "node_modules/cross-fetch": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.5.tgz", + "integrity": "sha512-xqYAhQb4NhCJSRym03dwxpP1bYXpK3y7UN83Bo2WFi3x1Zmzn0SL/6xGoPr+gpt4WmNrgCCX3HPysvOwFOW36w==", + "dependencies": { + "node-fetch": "2.6.1", + "whatwg-fetch": "2.0.4" + } + }, + "node_modules/cross-fetch/node_modules/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/cross-fetch/node_modules/whatwg-fetch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -5450,7 +5472,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -6843,6 +6864,18 @@ "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", "dev": true }, + "node_modules/flow-bin": { + "version": "0.149.0", + "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.149.0.tgz", + "integrity": "sha512-32hM6iKSInPCUuooS23SJ4c5Up0Tt9ozrXEE6urEpTDJU0z/vQblnCBRt3QZaEEDzSKOu2QZAU6K7fbShOOHaQ==", + "dev": true, + "bin": { + "flow": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/flow-parser": { "version": "0.121.0", "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.121.0.tgz", @@ -6864,7 +6897,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -7399,6 +7431,15 @@ "node": ">=0.8.19" } }, + "node_modules/inaturalistjs": { + "version": "1.13.2", + "resolved": "git+ssh://git@github.com/inaturalist/inaturalistjs.git#b60365d9b49c68f77e684b0d79c49933a88117cb", + "license": "MIT", + "dependencies": { + "cross-fetch": "^2.2.3", + "form-data": "^3.0.0" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -17139,8 +17180,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "atob": { "version": "2.1.2", @@ -17716,7 +17756,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -17870,6 +17909,27 @@ } } }, + "cross-fetch": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.5.tgz", + "integrity": "sha512-xqYAhQb4NhCJSRym03dwxpP1bYXpK3y7UN83Bo2WFi3x1Zmzn0SL/6xGoPr+gpt4WmNrgCCX3HPysvOwFOW36w==", + "requires": { + "node-fetch": "2.6.1", + "whatwg-fetch": "2.0.4" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "whatwg-fetch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" + } + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -17984,8 +18044,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "denodeify": { "version": "1.2.1", @@ -19032,6 +19091,12 @@ "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", "dev": true }, + "flow-bin": { + "version": "0.149.0", + "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.149.0.tgz", + "integrity": "sha512-32hM6iKSInPCUuooS23SJ4c5Up0Tt9ozrXEE6urEpTDJU0z/vQblnCBRt3QZaEEDzSKOu2QZAU6K7fbShOOHaQ==", + "dev": true + }, "flow-parser": { "version": "0.121.0", "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.121.0.tgz", @@ -19047,7 +19112,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -19435,6 +19499,14 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "inaturalistjs": { + "version": "git+ssh://git@github.com/inaturalist/inaturalistjs.git#b60365d9b49c68f77e684b0d79c49933a88117cb", + "from": "inaturalistjs@github:inaturalist/inaturalistjs", + "requires": { + "cross-fetch": "^2.2.3", + "form-data": "^3.0.0" + } + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", diff --git a/package.json b/package.json index 999d1c6fc..45ee7bafc 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "lint": "eslint ." }, "dependencies": { + "inaturalistjs": "github:inaturalist/inaturalistjs", "react": "17.0.2", "react-native": "0.65.1" }, @@ -27,6 +28,7 @@ "eslint-plugin-react": "^7.25.1", "eslint-plugin-react-hooks": "^4.2.0", "eslint-plugin-react-native": "^3.11.0", + "flow-bin": "^0.149.0", "jest": "^26.6.3", "metro-react-native-babel-preset": "^0.66.0", "react-native-codegen": "^0.0.7", diff --git a/styles/global.js b/styles/global.js new file mode 100644 index 000000000..a255aac70 --- /dev/null +++ b/styles/global.js @@ -0,0 +1,6 @@ +// @flow strict-local + +export const colors = { + white: "#ffffff", + black: "#000000" +}; diff --git a/styles/observations/obsCard.js b/styles/observations/obsCard.js new file mode 100644 index 000000000..3ae9463ac --- /dev/null +++ b/styles/observations/obsCard.js @@ -0,0 +1,33 @@ +// @flow strict-local + +import { StyleSheet } from "react-native"; + +import type { ViewStyleProp, TextStyleProp } from "react-native/Libraries/StyleSheet/StyleSheet"; +import { colors } from "../global"; + +const viewStyles: { [string]: ViewStyleProp } = StyleSheet.create( { + imageBackground: { + width: 75, + height: 75, + borderRadius: 10, + backgroundColor: colors.black, + marginHorizontal: 20 + }, + obsDetailsColumn: { + width: 200 + }, + row: { + flexDirection: "row", + flexWrap: "nowrap", + marginVertical: 10 + } +} ); + +const textStyles: { [string]: TextStyleProp } = StyleSheet.create( { + text: { } +} ); + +export { + viewStyles, + textStyles +}; diff --git a/styles/observations/observationsList.js b/styles/observations/observationsList.js new file mode 100644 index 000000000..0310de2af --- /dev/null +++ b/styles/observations/observationsList.js @@ -0,0 +1,15 @@ +// @flow strict-local + +import { StyleSheet } from "react-native"; +import { colors } from "../global"; + +import type { ViewStyleProp } from "react-native/Libraries/StyleSheet/StyleSheet"; + +const viewStyles: { [string]: ViewStyleProp } = StyleSheet.create( { + background: { + backgroundColor: colors.white, + flex: 1 + } +} ); + +export default viewStyles;