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;