@imerss/inat-components 1.1.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PUBLISH.md +13 -0
- package/README.md +20 -0
- package/dist/index.d.ts +86 -83
- package/dist/index.js +280 -395
- package/dist/standalone.min.js +3 -0
- package/package.json +17 -5
- package/public/standalone.html +55 -0
- package/rollup.config.js +15 -4
- package/src/__shared/api/common-taxa.ts +3 -3
- package/src/__shared/api/favourites.ts +3 -3
- package/src/__shared/api/recent-observations.ts +3 -3
- package/src/__shared/api/summary.ts +1 -0
- package/src/__shared/constants.ts +3 -2
- package/src/__shared/index.ts +1 -1
- package/src/__shared/typings.ts +49 -57
- package/src/__shared/utils/configUtils.ts +7 -7
- package/src/__shared/utils/dateUtils.ts +1 -1
- package/src/components/common-taxa/common-taxa.tsx +22 -57
- package/src/components/error/error.tsx +1 -1
- package/src/components/favourites/favourites.tsx +23 -58
- package/src/components/hooks/hooks.tsx +20 -10
- package/src/components/loader/loader.tsx +1 -1
- package/src/components/observation/observation.tsx +1 -1
- package/src/components/recent-observations/recent-observations.tsx +24 -58
- package/src/components/summary/ObserverList.tsx +3 -3
- package/src/components/summary/summary.tsx +53 -54
- package/src/components/tabs/tabs.tsx +41 -26
- package/src/components/taxon-panel/taxon-panel.tsx +75 -96
- package/src/components/year-dropdown/year-dropdown.tsx +11 -7
- package/src/hooks/useLoadSourceData.ts +81 -0
- package/src/index.ts +1 -1
- package/src/types/index.d.ts +17 -0
- package/src/types/standalone.d.ts +6 -0
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imerss/inat-components",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
|
+
"license": "MIT",
|
|
6
7
|
"scripts": {
|
|
7
|
-
"build": "rollup -c",
|
|
8
|
+
"build": "rollup -c --environment BUILD:production && cd ../inat-components-standalone && npm run build && npm run copyToInatComponentsPackage",
|
|
9
|
+
"clean": "shx rm -rf dist src/__shared",
|
|
8
10
|
"watch": "rollup -cw"
|
|
9
11
|
},
|
|
10
12
|
"dependencies": {
|
|
@@ -14,23 +16,33 @@
|
|
|
14
16
|
"sleep-promise": "^9.1.0"
|
|
15
17
|
},
|
|
16
18
|
"peerDependencies": {
|
|
17
|
-
"react": ">=
|
|
18
|
-
"react-dom": ">=
|
|
19
|
+
"react": ">=18.0.0",
|
|
20
|
+
"react-dom": ">=18.0.0"
|
|
19
21
|
},
|
|
20
22
|
"devDependencies": {
|
|
21
23
|
"@modular-css/rollup": "^28.2.2",
|
|
22
24
|
"@rollup/plugin-typescript": "^8.3.3",
|
|
25
|
+
"@rollup/plugin-commonjs": "^24.1.0",
|
|
26
|
+
"@rollup/plugin-json": "^6.0.0",
|
|
27
|
+
"@rollup/plugin-node-resolve": "^15.0.2",
|
|
28
|
+
"@rollup/plugin-replace": "^5.0.2",
|
|
23
29
|
"@testing-library/react": "^13.3.0",
|
|
24
30
|
"@types/cli-progress": "^3.11.0",
|
|
31
|
+
"@types/isomorphic-fetch": "0.0.36",
|
|
25
32
|
"@types/jest": "^28.1.4",
|
|
33
|
+
"@types/react": "^18.0.38",
|
|
34
|
+
"@types/react-dom": "^18.0.5",
|
|
26
35
|
"jest": "^28.1.2",
|
|
27
36
|
"node-sass": "^7.0.1",
|
|
28
37
|
"postcss": "^8.4.14",
|
|
29
38
|
"react-charts": "3.0.0-beta.38",
|
|
30
|
-
"rollup": "^2.
|
|
39
|
+
"rollup": "^2.79.1",
|
|
31
40
|
"rollup-plugin-dts": "^4.2.2",
|
|
32
41
|
"rollup-plugin-postcss": "^4.0.2",
|
|
42
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
43
|
+
"rollup-plugin-visualizer": "^5.9.0",
|
|
33
44
|
"tslib": "^2.4.0",
|
|
45
|
+
"shx": "0.3.4",
|
|
34
46
|
"typescript": "^4.7.4"
|
|
35
47
|
},
|
|
36
48
|
"publishConfig": {
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<body>
|
|
3
|
+
|
|
4
|
+
<h1>Standalone example</h1>
|
|
5
|
+
|
|
6
|
+
<div id="inat-components-el"></div>
|
|
7
|
+
|
|
8
|
+
<script>
|
|
9
|
+
inatComponents.initTaxonPanel("inat-components-el", {
|
|
10
|
+
taxon: {
|
|
11
|
+
id: 47157,
|
|
12
|
+
str: "leps"
|
|
13
|
+
},
|
|
14
|
+
place: {
|
|
15
|
+
id: 7085,
|
|
16
|
+
str: "bc"
|
|
17
|
+
},
|
|
18
|
+
dataSource: "url",
|
|
19
|
+
dataSourceBaseUrl: "https://sisyphean.ca/inat",
|
|
20
|
+
itemWidth: 180,
|
|
21
|
+
features: {
|
|
22
|
+
recentObservations: {
|
|
23
|
+
numResults: 100,
|
|
24
|
+
desc: "This page lists the most recent butterfly and moth observations made in BC. Click on any of them to go to the inaturalist site for more information.",
|
|
25
|
+
},
|
|
26
|
+
commonTaxa: {
|
|
27
|
+
numResults: 100,
|
|
28
|
+
numYears: 10,
|
|
29
|
+
desc: "This page lists the most commonly reported species in BC. You can use the dropdown at the top right to filter the results to a particular year."
|
|
30
|
+
},
|
|
31
|
+
favourites: {
|
|
32
|
+
numResults: 100,
|
|
33
|
+
numYears: 10,
|
|
34
|
+
desc: "Any time iNaturalist users encounter an observation they like, they can choose to \"favourite\" it. This page lists the most favourited moth and butterfly observations made in BC."
|
|
35
|
+
},
|
|
36
|
+
stats: {
|
|
37
|
+
numTopObservers: 10,
|
|
38
|
+
observersListClass: "inat-observers-list",
|
|
39
|
+
statsCountSummaryClass: "inat-stats-count-summary",
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
generalClasses: {
|
|
43
|
+
tabsElement: "inat-tabs",
|
|
44
|
+
yearsDropdown: "inat-years-dropdown",
|
|
45
|
+
pageHeadings: "inat-page-headings",
|
|
46
|
+
observationLabelTitle: "inat-observation-label-title",
|
|
47
|
+
observationLabelDate: "inat-observation-label-data",
|
|
48
|
+
observationLabelName: "inat-observation-label-name",
|
|
49
|
+
tabDesc: "inat-tab-desc"
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
</body>
|
|
55
|
+
</html>
|
package/rollup.config.js
CHANGED
|
@@ -3,6 +3,7 @@ import postcss from "rollup-plugin-postcss";
|
|
|
3
3
|
import dts from "rollup-plugin-dts";
|
|
4
4
|
|
|
5
5
|
export default [
|
|
6
|
+
|
|
6
7
|
// front-end components + generate() node utils method, exposed as "@imerss/inat-components"
|
|
7
8
|
{
|
|
8
9
|
input: "src/index.ts",
|
|
@@ -10,8 +11,18 @@ export default [
|
|
|
10
11
|
dir: "dist",
|
|
11
12
|
format: "es"
|
|
12
13
|
},
|
|
14
|
+
|
|
15
|
+
// these let's rollup know that these are external scripts + can be excluded from the final bundle without
|
|
16
|
+
// any warnings. TODO: check these are peer deps.
|
|
13
17
|
external: [
|
|
14
|
-
"react"
|
|
18
|
+
"react",
|
|
19
|
+
"fs",
|
|
20
|
+
"react-charts",
|
|
21
|
+
"date-fns",
|
|
22
|
+
"react-spinners",
|
|
23
|
+
"react-spinners/MoonLoader.js",
|
|
24
|
+
"isomorphic-unfetch",
|
|
25
|
+
"react/jsx-runtime"
|
|
15
26
|
],
|
|
16
27
|
plugins: [
|
|
17
28
|
postcss({
|
|
@@ -19,10 +30,10 @@ export default [
|
|
|
19
30
|
plugins: []
|
|
20
31
|
}),
|
|
21
32
|
typescript()
|
|
22
|
-
]
|
|
33
|
+
],
|
|
23
34
|
},
|
|
24
35
|
|
|
25
|
-
//
|
|
36
|
+
// rolls up all typings for export
|
|
26
37
|
{
|
|
27
38
|
input: "src/index.ts",
|
|
28
39
|
output: {
|
|
@@ -33,4 +44,4 @@ export default [
|
|
|
33
44
|
dts()
|
|
34
45
|
]
|
|
35
46
|
}
|
|
36
|
-
];
|
|
47
|
+
];
|
|
@@ -5,7 +5,7 @@ export type CommonTaxaCallProps = {
|
|
|
5
5
|
year: string | number;
|
|
6
6
|
taxonId: string | number;
|
|
7
7
|
placeId: string | number;
|
|
8
|
-
|
|
8
|
+
numResults: number;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
export type CommonTaxData = {
|
|
@@ -21,8 +21,8 @@ export type CommonTaxaRespData = {
|
|
|
21
21
|
results: [CommonTaxData]
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export const getCommonTaxa = async ({ year, taxonId, placeId,
|
|
25
|
-
let url = `${C.BASE_API_URL}/v1/observations/species_counts?verifiable=true&spam=false&place_id=${placeId}&taxon_id=${taxonId}&locale=en-US&per_page=${
|
|
24
|
+
export const getCommonTaxa = async ({ year, taxonId, placeId, numResults }: CommonTaxaCallProps): Promise<CommonTaxaRespData> => {
|
|
25
|
+
let url = `${C.BASE_API_URL}/v1/observations/species_counts?verifiable=true&spam=false&place_id=${placeId}&taxon_id=${taxonId}&locale=en-US&per_page=${numResults}`;
|
|
26
26
|
if (year !== "all") {
|
|
27
27
|
url += `&d1=${year}-01-01&d2=${year}-12-31`;
|
|
28
28
|
}
|
|
@@ -5,7 +5,7 @@ export type FavouritesCallProps = {
|
|
|
5
5
|
year: string | number;
|
|
6
6
|
taxonId: string | number;
|
|
7
7
|
placeId: string | number;
|
|
8
|
-
|
|
8
|
+
numResults: number;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
export type FavouritesData = {
|
|
@@ -24,8 +24,8 @@ export type FavouritesRespData = {
|
|
|
24
24
|
results: [FavouritesData]
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export const getFavourites = async ({ year, taxonId, placeId,
|
|
28
|
-
let url = `${C.BASE_API_URL}/v1/observations?verifiable=true&order_by=votes&order=desc&page=1&spam=false&place_id=${placeId}&taxon_id=${taxonId}&locale=en-US&per_page=${
|
|
27
|
+
export const getFavourites = async ({ year, taxonId, placeId, numResults }: FavouritesCallProps): Promise<FavouritesRespData> => {
|
|
28
|
+
let url = `${C.BASE_API_URL}/v1/observations?verifiable=true&order_by=votes&order=desc&page=1&spam=false&place_id=${placeId}&taxon_id=${taxonId}&locale=en-US&per_page=${numResults}`;
|
|
29
29
|
if (year !== "all") {
|
|
30
30
|
url += `&d1=${year}-01-01&d2=${year}-12-31`;
|
|
31
31
|
}
|
|
@@ -4,7 +4,7 @@ import * as C from "../constants";
|
|
|
4
4
|
export type RecentObservationsCallProps = {
|
|
5
5
|
taxonId: string | number;
|
|
6
6
|
placeId: string | number;
|
|
7
|
-
|
|
7
|
+
numResults: number;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
export type RecentObservationData = {
|
|
@@ -22,8 +22,8 @@ export type RecentObservationsRespData = {
|
|
|
22
22
|
results: [RecentObservationData]
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export const getRecentObservations = async ({ taxonId, placeId,
|
|
26
|
-
const url = `${C.BASE_API_URL}/v1/observations?photos=true&per_page=${
|
|
25
|
+
export const getRecentObservations = async ({ taxonId, placeId, numResults }: RecentObservationsCallProps): Promise<RecentObservationsRespData> => {
|
|
26
|
+
const url = `${C.BASE_API_URL}/v1/observations?photos=true&per_page=${numResults}&taxon_id=${taxonId}&place_id=${placeId}&order=desc&order_by=observed_on`;
|
|
27
27
|
const response = await fetch(url);
|
|
28
28
|
const obs = await response.json();
|
|
29
29
|
|
|
@@ -32,6 +32,7 @@ export type SummaryData = {
|
|
|
32
32
|
|
|
33
33
|
export const getObserverSummary = async (taxonId: number, placeId: number, year: string | number): Promise<SummaryData> => {
|
|
34
34
|
let url = `${C.BASE_API_URL}/v1/observations/observers?verifiable=true&order_by=votes&order=desc&page=1&spam=false&place_id=${placeId}&taxon_id=${taxonId}&locale=en-US&per_page=10`;
|
|
35
|
+
|
|
35
36
|
if (year !== "all") {
|
|
36
37
|
url += `&d1=${year}-01-01&d2=${year}-12-31`;
|
|
37
38
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export const BASE_API_URL = 'https://api.inaturalist.org';
|
|
2
|
-
export const
|
|
2
|
+
export const NUM_RESULTS = 100;
|
|
3
|
+
export const DEFAULT_NUM_YEARS = 10;
|
|
3
4
|
export const BASE_URL = "https://www.inaturalist.org"; // /people/name_here
|
|
4
5
|
export const ERROR_LOG_FILENAME = "inat-components-error.log";
|
|
5
|
-
export const DEFAULT_ITEM_WIDTH = 150;
|
|
6
|
+
export const DEFAULT_ITEM_WIDTH = 150;
|
package/src/__shared/index.ts
CHANGED
package/src/__shared/typings.ts
CHANGED
|
@@ -1,30 +1,3 @@
|
|
|
1
|
-
export type ConfigFile = {
|
|
2
|
-
taxa: TaxaConfig[];
|
|
3
|
-
places: PlaceConfig[];
|
|
4
|
-
features: {
|
|
5
|
-
[Feature.commonTaxa]?: {
|
|
6
|
-
numResults?: number;
|
|
7
|
-
};
|
|
8
|
-
[Feature.favourites]?: {
|
|
9
|
-
numResults?: number;
|
|
10
|
-
numYears?: number;
|
|
11
|
-
};
|
|
12
|
-
[Feature.recentObservations]?: {
|
|
13
|
-
numResults?: number;
|
|
14
|
-
numYears?: number;
|
|
15
|
-
};
|
|
16
|
-
[Feature.stats]?: {
|
|
17
|
-
numTopObservers?: number;
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export enum DataSource {
|
|
23
|
-
autoLoad = "autoLoad",
|
|
24
|
-
dataProp = "dataProp",
|
|
25
|
-
url = "url"
|
|
26
|
-
}
|
|
27
|
-
|
|
28
1
|
export enum Feature {
|
|
29
2
|
commonTaxa = "commonTaxa",
|
|
30
3
|
favourites = "favourites",
|
|
@@ -32,33 +5,35 @@ export enum Feature {
|
|
|
32
5
|
stats = "stats"
|
|
33
6
|
}
|
|
34
7
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
8
|
+
export enum DataSourceEnum {
|
|
9
|
+
autoLoad = "autoLoad",
|
|
10
|
+
url = "url"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type DataSource = `${DataSourceEnum}`;
|
|
14
|
+
|
|
15
|
+
// used for places + taxons
|
|
16
|
+
export type ItemConfig = {
|
|
17
|
+
id: number;
|
|
18
|
+
str: string;
|
|
41
19
|
}
|
|
42
20
|
|
|
43
|
-
export type
|
|
44
|
-
|
|
21
|
+
export type GeneralClasses = {
|
|
22
|
+
tabsElement?: string;
|
|
45
23
|
yearsDropdown?: string;
|
|
46
24
|
pageHeadings?: string;
|
|
25
|
+
tabDesc?: string;
|
|
47
26
|
observationLabelTitle?: string;
|
|
48
27
|
observationLabelDate?: string;
|
|
49
28
|
observationLabelName?: string;
|
|
50
|
-
|
|
51
|
-
statsCountSummary?: string;
|
|
52
|
-
tabDesc?: string;
|
|
29
|
+
observationCount?: string;
|
|
53
30
|
}
|
|
54
31
|
|
|
55
32
|
export type BaseComponentProps = {
|
|
56
33
|
taxonId?: number;
|
|
57
34
|
placeId?: number;
|
|
58
|
-
|
|
59
|
-
perPage?: number;
|
|
35
|
+
numResults?: number;
|
|
60
36
|
source?: DataSource;
|
|
61
|
-
data?: any;
|
|
62
37
|
dataUrl?: string;
|
|
63
38
|
className?: string;
|
|
64
39
|
itemWidth?: number;
|
|
@@ -67,25 +42,42 @@ export type BaseComponentProps = {
|
|
|
67
42
|
error?: any;
|
|
68
43
|
loader?: any;
|
|
69
44
|
};
|
|
70
|
-
|
|
45
|
+
generalClasses?: GeneralClasses;
|
|
71
46
|
tabDesc?: string;
|
|
72
47
|
};
|
|
73
48
|
|
|
74
|
-
export type
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
49
|
+
export type RecentObservationsConfig = {
|
|
50
|
+
feature: Feature.recentObservations,
|
|
51
|
+
title?: string;
|
|
52
|
+
numResults?: number;
|
|
53
|
+
desc?: string;
|
|
54
|
+
className?: string;
|
|
78
55
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
56
|
+
export type CommonTaxaConfig = {
|
|
57
|
+
feature: Feature.commonTaxa,
|
|
58
|
+
title?: string;
|
|
59
|
+
numResults?: number;
|
|
60
|
+
numYears?: number;
|
|
61
|
+
desc?: string;
|
|
62
|
+
className?: string;
|
|
84
63
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
64
|
+
export type FavouritesConfig = {
|
|
65
|
+
feature: Feature.favourites;
|
|
66
|
+
title?: string;
|
|
67
|
+
numResults?: number;
|
|
68
|
+
numYears?: number;
|
|
69
|
+
desc?: string;
|
|
70
|
+
className?: string;
|
|
91
71
|
}
|
|
72
|
+
export type StatsConfig = {
|
|
73
|
+
feature: Feature.stats;
|
|
74
|
+
title?: string;
|
|
75
|
+
numTopObservers?: number;
|
|
76
|
+
numYears?: number;
|
|
77
|
+
desc?: string;
|
|
78
|
+
className?: string;
|
|
79
|
+
observersListClass?: string;
|
|
80
|
+
statsCountSummaryClass?: string;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type TaxonPanelFeatures = (RecentObservationsConfig|CommonTaxaConfig|FavouritesConfig|StatsConfig)[];
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {Feature,
|
|
1
|
+
import { Feature, ItemConfig } from "../typings";
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
4
|
* Note that right now the source filenames aren't configurable.
|
|
5
5
|
*/
|
|
6
|
-
export const getSourceFile = (api: Feature,
|
|
7
|
-
if (!
|
|
6
|
+
export const getSourceFile = (api: Feature, taxon: ItemConfig, place: ItemConfig, year?: string | number): string => {
|
|
7
|
+
if (!taxon || !place) {
|
|
8
8
|
return '';
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -12,13 +12,13 @@ export const getSourceFile = (api: Feature, taxonInfo?: TaxaConfig, placeInfo?:
|
|
|
12
12
|
|
|
13
13
|
let filename = "";
|
|
14
14
|
if (api === Feature.recentObservations) {
|
|
15
|
-
filename = `${
|
|
15
|
+
filename = `${taxon.str}-${place.str}-recent.json`;
|
|
16
16
|
} else if (api === Feature.commonTaxa) {
|
|
17
|
-
filename = `${
|
|
17
|
+
filename = `${taxon.str}-${place.str}-${yearStr}-commonTaxa.json`;
|
|
18
18
|
} else if (api === Feature.favourites) {
|
|
19
|
-
filename = `${
|
|
19
|
+
filename = `${taxon.str}-${place.str}-${yearStr}-favourites.json`;
|
|
20
20
|
} else if (api === Feature.stats) {
|
|
21
|
-
filename = `${
|
|
21
|
+
filename = `${taxon.str}-${place.str}-${yearStr}-stats.json`;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
return filename;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import {numberWithCommas, C, CommonTaxData, getCommonTaxa, BaseComponentProps,
|
|
3
|
-
import {Observation} from "../observation/observation";
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { numberWithCommas, C, CommonTaxData, getCommonTaxa, BaseComponentProps, GeneralClasses } from "../../__shared";
|
|
3
|
+
import { Observation } from "../observation/observation";
|
|
4
4
|
import Loader from "../loader/loader";
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
5
|
+
import { NoResults } from "../no-results/no-results";
|
|
6
|
+
import { useLoadSourceData } from "../../hooks/useLoadSourceData";
|
|
7
7
|
import styles from "../shared/css/general.module.scss";
|
|
8
8
|
|
|
9
9
|
export type CommonTaxaProps = BaseComponentProps & {
|
|
10
|
-
year:
|
|
10
|
+
year: number;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export const CommonTaxaLabel = (data: CommonTaxData & { classes:
|
|
13
|
+
export const CommonTaxaLabel = (data: CommonTaxData & { classes: GeneralClasses }) => (
|
|
14
14
|
<div className={styles.obsLabel}>
|
|
15
15
|
<h3 className={data.classes?.observationLabelTitle}>{data.taxonCommonName || data.taxonName}</h3>
|
|
16
|
-
<label className={styles.count}>{numberWithCommas(data.obsCount)}</label>
|
|
16
|
+
<label className={`${data.classes?.observationCount || ''} ${styles.count}`}>{numberWithCommas(data.obsCount)}</label>
|
|
17
17
|
</div>
|
|
18
18
|
);
|
|
19
19
|
|
|
@@ -22,69 +22,34 @@ export const CommonTaxa = ({
|
|
|
22
22
|
source,
|
|
23
23
|
taxonId,
|
|
24
24
|
placeId,
|
|
25
|
-
|
|
25
|
+
numResults = C.NUM_RESULTS,
|
|
26
26
|
itemWidth = C.DEFAULT_ITEM_WIDTH,
|
|
27
|
-
data,
|
|
28
27
|
dataUrl,
|
|
29
28
|
components,
|
|
30
|
-
|
|
29
|
+
generalClasses,
|
|
31
30
|
className,
|
|
32
31
|
tabDesc
|
|
33
32
|
}: CommonTaxaProps) => {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
if (!placeId) {
|
|
46
|
-
console.error("Please supply a `placeId` prop for the `autoLoad` source prop option.");
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
(async () => {
|
|
51
|
-
setLoading(true);
|
|
52
|
-
const resp = await getCommonTaxa({taxonId, placeId, year, perPage});
|
|
53
|
-
setTaxa(resp.results);
|
|
54
|
-
setLoading(false);
|
|
55
|
-
})();
|
|
56
|
-
}, [source, year, placeId, taxonId, perPage]);
|
|
57
|
-
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
if (source !== DataSource.url) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (!dataUrl) {
|
|
64
|
-
console.error("Please supply a `dataUrl` prop for the `url` source prop option.");
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
(async () => {
|
|
69
|
-
setLoading(true);
|
|
70
|
-
const obs = await fetch(dataUrl);
|
|
71
|
-
const json = await obs.json();
|
|
72
|
-
setTaxa(json.results);
|
|
73
|
-
setLoading(false);
|
|
74
|
-
})();
|
|
75
|
-
}, [source, dataUrl]);
|
|
33
|
+
const { loading, results: taxa } = useLoadSourceData({
|
|
34
|
+
taxonId,
|
|
35
|
+
placeId,
|
|
36
|
+
numResults,
|
|
37
|
+
dataUrl,
|
|
38
|
+
source,
|
|
39
|
+
year,
|
|
40
|
+
action: getCommonTaxa
|
|
41
|
+
});
|
|
76
42
|
|
|
77
43
|
const Load = components?.loader ? components.loader as any : Loader;
|
|
78
44
|
const Label = components?.label ? components.label as any : CommonTaxaLabel;
|
|
79
|
-
const ErrorMsg = components?.error ? components.error as any : Error;
|
|
80
45
|
|
|
81
46
|
let elClasses = styles.panel;
|
|
82
47
|
if (className) {
|
|
83
48
|
elClasses += ` ${className}`;
|
|
84
49
|
}
|
|
85
50
|
let descClasses = styles.tabDesc;
|
|
86
|
-
if (
|
|
87
|
-
descClasses += ` ${
|
|
51
|
+
if (generalClasses?.tabDesc) {
|
|
52
|
+
descClasses += ` ${generalClasses.tabDesc}`;
|
|
88
53
|
}
|
|
89
54
|
|
|
90
55
|
return (
|
|
@@ -99,7 +64,7 @@ export const CommonTaxa = ({
|
|
|
99
64
|
imageUrl={data.imageUrl.replace(/square/, "medium")}
|
|
100
65
|
itemWidth={itemWidth}
|
|
101
66
|
linkUrl={`${C.BASE_URL}/${data.id}`}>
|
|
102
|
-
<Label {...data} classes={
|
|
67
|
+
<Label {...data} classes={generalClasses} />
|
|
103
68
|
</Observation>
|
|
104
69
|
))}
|
|
105
70
|
</div>
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import {formatDate, C, getFavourites, FavouritesData, BaseComponentProps,
|
|
3
|
-
import {Observation} from "../observation/observation";
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { formatDate, C, getFavourites, FavouritesData, BaseComponentProps, GeneralClasses } from "../../__shared";
|
|
3
|
+
import { Observation } from "../observation/observation";
|
|
4
4
|
import Loader from "../loader/loader";
|
|
5
|
-
import {NoResults} from "../no-results/no-results";
|
|
5
|
+
import { NoResults } from "../no-results/no-results";
|
|
6
|
+
import { useLoadSourceData } from "../../hooks/useLoadSourceData";
|
|
6
7
|
import generalStyles from "../shared/css/general.module.scss";
|
|
7
|
-
import styles from "../shared/css/general.module.scss";
|
|
8
8
|
|
|
9
9
|
export type FavouritesProps = BaseComponentProps & {
|
|
10
|
-
year:
|
|
10
|
+
year: number | string;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export const FavouritesLabel = (data: FavouritesData & { classes:
|
|
13
|
+
export const FavouritesLabel = (data: FavouritesData & { classes: GeneralClasses }) => (
|
|
14
14
|
<div className={generalStyles.obsLabel}>
|
|
15
15
|
<h3 className={data.classes?.observationLabelTitle}>{data.taxonCommonName || data.taxonName}</h3>
|
|
16
16
|
<div className={data.classes?.observationLabelTitle}>{data.observerUsername}</div>
|
|
17
17
|
<div className={data.classes?.observationLabelDate}>{formatDate(data.obsDate)}</div>
|
|
18
|
-
<label className={generalStyles.count}>{data.numFaves}</label>
|
|
18
|
+
<label className={`${data.classes?.observationCount || ''} ${generalStyles.count}`}>{data.numFaves}</label>
|
|
19
19
|
</div>
|
|
20
20
|
);
|
|
21
21
|
|
|
@@ -24,58 +24,23 @@ export const Favourites = ({
|
|
|
24
24
|
source,
|
|
25
25
|
taxonId,
|
|
26
26
|
placeId,
|
|
27
|
-
data,
|
|
28
27
|
dataUrl,
|
|
29
28
|
components,
|
|
30
29
|
className,
|
|
31
30
|
tabDesc,
|
|
32
|
-
|
|
31
|
+
generalClasses,
|
|
33
32
|
itemWidth = C.DEFAULT_ITEM_WIDTH,
|
|
34
|
-
|
|
33
|
+
numResults = C.NUM_RESULTS
|
|
35
34
|
}: FavouritesProps) => {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
if (!placeId) {
|
|
48
|
-
console.error("Please supply a `placeId` prop for the `autoLoad` source prop option.");
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
(async () => {
|
|
53
|
-
setLoading(true);
|
|
54
|
-
const resp = await getFavourites({taxonId, placeId, year, perPage});
|
|
55
|
-
setObservations(resp.results);
|
|
56
|
-
setLoading(false);
|
|
57
|
-
})();
|
|
58
|
-
}, [source, year, placeId, taxonId, perPage]);
|
|
59
|
-
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
if (source !== DataSource.url) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (!dataUrl) {
|
|
66
|
-
console.error("Please supply a `dataUrl` prop for the `url` source prop option.");
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
(async () => {
|
|
71
|
-
setLoading(true);
|
|
72
|
-
const obs = await fetch(dataUrl);
|
|
73
|
-
const json = await obs.json();
|
|
74
|
-
setObservations(json.results);
|
|
75
|
-
setLoading(false);
|
|
76
|
-
})();
|
|
77
|
-
}, [source, dataUrl]);
|
|
78
|
-
|
|
35
|
+
const { loading, results: observations } = useLoadSourceData({
|
|
36
|
+
year,
|
|
37
|
+
taxonId,
|
|
38
|
+
placeId,
|
|
39
|
+
numResults,
|
|
40
|
+
dataUrl,
|
|
41
|
+
source,
|
|
42
|
+
action: getFavourites
|
|
43
|
+
});
|
|
79
44
|
const Load = components?.loader ? components.loader as any : Loader;
|
|
80
45
|
const Label = components?.label ? components.label as any : FavouritesLabel;
|
|
81
46
|
|
|
@@ -83,9 +48,9 @@ export const Favourites = ({
|
|
|
83
48
|
if (className) {
|
|
84
49
|
elClasses += ` ${className}`;
|
|
85
50
|
}
|
|
86
|
-
let descClasses =
|
|
87
|
-
if (
|
|
88
|
-
descClasses += ` ${
|
|
51
|
+
let descClasses = generalStyles.tabDesc;
|
|
52
|
+
if (generalClasses?.tabDesc) {
|
|
53
|
+
descClasses += ` ${generalClasses.tabDesc}`;
|
|
89
54
|
}
|
|
90
55
|
return (
|
|
91
56
|
<div className={elClasses}>
|
|
@@ -99,7 +64,7 @@ export const Favourites = ({
|
|
|
99
64
|
imageUrl={obs.imageUrl.replace(/square/, "medium")}
|
|
100
65
|
itemWidth={itemWidth}
|
|
101
66
|
linkUrl={obs.obsUrl}>
|
|
102
|
-
<Label {...obs} classes={
|
|
67
|
+
<Label {...obs} classes={generalClasses} />
|
|
103
68
|
</Observation>
|
|
104
69
|
))}
|
|
105
70
|
</div>
|