@imerss/inat-components 2.0.0 → 3.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/README.md +24 -13
- package/dist/index.d.ts +87 -75
- package/dist/index.js +261 -173
- package/dist/standalone.min.js +1 -1
- package/package.json +10 -12
- package/PUBLISH.md +0 -13
- package/declaration.d.ts +0 -2
- package/public/favicon.ico +0 -0
- package/public/index.html +0 -20
- package/public/logo192.png +0 -0
- package/public/logo512.png +0 -0
- package/public/manifest.json +0 -25
- package/public/robots.txt +0 -3
- package/public/standalone.html +0 -55
- package/rollup.config.js +0 -47
- package/src/__shared/api/common-taxa.ts +0 -57
- package/src/__shared/api/favourites.ts +0 -57
- package/src/__shared/api/index.ts +0 -4
- package/src/__shared/api/recent-observations.ts +0 -44
- package/src/__shared/api/summary.ts +0 -86
- package/src/__shared/constants.ts +0 -6
- package/src/__shared/index.ts +0 -4
- package/src/__shared/typings.ts +0 -83
- package/src/__shared/utils/configUtils.ts +0 -25
- package/src/__shared/utils/dateUtils.ts +0 -14
- package/src/__shared/utils/index.ts +0 -3
- package/src/__shared/utils/numberUtils.ts +0 -1
- package/src/components/common-taxa/__tests__/common-taxa.test.tsx +0 -14
- package/src/components/common-taxa/common-taxa.tsx +0 -73
- package/src/components/error/__tests__/error.test.tsx +0 -9
- package/src/components/error/error.module.scss +0 -7
- package/src/components/error/error.tsx +0 -15
- package/src/components/favourites/__tests__/favourites.test.tsx +0 -13
- package/src/components/favourites/favourites.tsx +0 -73
- package/src/components/hooks/hooks.tsx +0 -34
- package/src/components/loader/__tests__/loader.test.tsx +0 -10
- package/src/components/loader/loader.tsx +0 -26
- package/src/components/no-results/__tests__/no-results.test.tsx +0 -9
- package/src/components/no-results/no-results.tsx +0 -9
- package/src/components/observation/__tests__/observation.test.tsx +0 -14
- package/src/components/observation/observation.module.scss +0 -20
- package/src/components/observation/observation.tsx +0 -30
- package/src/components/recent-observations/__tests__/recent-observations.test.tsx +0 -9
- package/src/components/recent-observations/recent-observations.tsx +0 -84
- package/src/components/seasonality-graph/__tests__/seasonality-graph.test.tsx +0 -9
- package/src/components/seasonality-graph/seasonality-graph.module.scss +0 -7
- package/src/components/seasonality-graph/seasonality-graph.tsx +0 -46
- package/src/components/shared/css/general.module.scss +0 -73
- package/src/components/summary/ObserverList.tsx +0 -24
- package/src/components/summary/__tests__/summary.test.tsx +0 -18
- package/src/components/summary/summary.module.scss +0 -88
- package/src/components/summary/summary.tsx +0 -91
- package/src/components/tabs/__tests__/tabs.test.tsx +0 -16
- package/src/components/tabs/tabs.module.scss +0 -28
- package/src/components/tabs/tabs.tsx +0 -65
- package/src/components/taxon-panel/__tests__/taxon-panel.test.tsx +0 -10
- package/src/components/taxon-panel/taxon-panel.module.scss +0 -7
- package/src/components/taxon-panel/taxon-panel.tsx +0 -110
- package/src/components/year-dropdown/__tests__/year-dropdown.test.tsx +0 -14
- package/src/components/year-dropdown/year-dropdown.module.scss +0 -3
- package/src/components/year-dropdown/year-dropdown.tsx +0 -37
- package/src/hooks/useLoadSourceData.ts +0 -81
- package/src/index.ts +0 -15
- package/src/types/index.d.ts +0 -17
- package/src/types/standalone.d.ts +0 -6
- package/tsconfig.json +0 -6
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
.summaryPage {
|
|
2
|
-
position: relative;
|
|
3
|
-
|
|
4
|
-
section {
|
|
5
|
-
display: flex;
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
.top {
|
|
10
|
-
list-style-type: none;
|
|
11
|
-
margin: 0;
|
|
12
|
-
padding: 0;
|
|
13
|
-
|
|
14
|
-
.avatar, .noAvatar {
|
|
15
|
-
margin-right: 10px;
|
|
16
|
-
border-radius: 20px;
|
|
17
|
-
width: 40px;
|
|
18
|
-
height: 40px;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.noAvatar {
|
|
22
|
-
display: inline-block;
|
|
23
|
-
background-color: #efefef;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
h3 {
|
|
27
|
-
flex: 1;
|
|
28
|
-
color: black;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
label {
|
|
32
|
-
flex: 0;
|
|
33
|
-
background-color: #efefef;
|
|
34
|
-
color: #666666;
|
|
35
|
-
padding: 2px 8px;
|
|
36
|
-
margin-top: 6px;
|
|
37
|
-
border-radius: 3px;
|
|
38
|
-
font-weight: bold;
|
|
39
|
-
font-size: 16px;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
li {
|
|
43
|
-
border-radius: 3px;
|
|
44
|
-
|
|
45
|
-
a {
|
|
46
|
-
display: flex;
|
|
47
|
-
align-items: center;
|
|
48
|
-
text-decoration: none;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
&:hover {
|
|
52
|
-
background-color: #efefef;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.countSummary {
|
|
58
|
-
list-style-type: none;
|
|
59
|
-
line-height: 28px;
|
|
60
|
-
font-size: 16px;
|
|
61
|
-
padding: 0;
|
|
62
|
-
margin: 0 0 30px;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
.seasonalityBlock {
|
|
66
|
-
flex: 3;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.observersBlock {
|
|
70
|
-
flex: 1;
|
|
71
|
-
margin-left: 40px;
|
|
72
|
-
margin-bottom: -40px;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
@media screen and (max-width: 800px) {
|
|
76
|
-
.summaryPage section {
|
|
77
|
-
display: block;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.seasonalityBlock {
|
|
81
|
-
height: 250px;
|
|
82
|
-
margin-bottom: 80px;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.observersBlock {
|
|
86
|
-
margin-left: 0;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { numberWithCommas, DataSource, getSummary, GeneralClasses } from "../../__shared";
|
|
3
|
-
import { ObserverList } from './ObserverList';
|
|
4
|
-
import Loader from "../loader/loader";
|
|
5
|
-
import { SeasonalityGraph } from "../seasonality-graph/seasonality-graph";
|
|
6
|
-
import styles from "./summary.module.scss";
|
|
7
|
-
import { useLoadSourceData } from "../../hooks/useLoadSourceData";
|
|
8
|
-
|
|
9
|
-
export type SummaryProps = {
|
|
10
|
-
taxonId: number;
|
|
11
|
-
placeId: number;
|
|
12
|
-
year: number;
|
|
13
|
-
source: DataSource;
|
|
14
|
-
dataUrl?: string;
|
|
15
|
-
generalClasses?: GeneralClasses;
|
|
16
|
-
className?: string;
|
|
17
|
-
tabDesc?: string;
|
|
18
|
-
observersListClass?: string;
|
|
19
|
-
statsCountSummaryClass?: string;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export const Summary = ({
|
|
23
|
-
source,
|
|
24
|
-
dataUrl,
|
|
25
|
-
taxonId,
|
|
26
|
-
placeId,
|
|
27
|
-
year,
|
|
28
|
-
generalClasses,
|
|
29
|
-
className,
|
|
30
|
-
tabDesc,
|
|
31
|
-
observersListClass,
|
|
32
|
-
statsCountSummaryClass
|
|
33
|
-
}: SummaryProps) => {
|
|
34
|
-
const { loading, results: summaryData } = useLoadSourceData({
|
|
35
|
-
year,
|
|
36
|
-
taxonId,
|
|
37
|
-
placeId,
|
|
38
|
-
dataUrl,
|
|
39
|
-
source,
|
|
40
|
-
isSummaryData: true,
|
|
41
|
-
|
|
42
|
-
// shim to standardize the response from the `action` method with a top-level `results` property. This
|
|
43
|
-
// just lets the useLoadSourceData hook work for all tab components
|
|
44
|
-
action: async (data) => {
|
|
45
|
-
const results = await getSummary(data);
|
|
46
|
-
|
|
47
|
-
return { results };
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
let countSummaryClasses = styles.countSummary;
|
|
52
|
-
if (statsCountSummaryClass) {
|
|
53
|
-
countSummaryClasses += ` ${statsCountSummaryClass}`;
|
|
54
|
-
}
|
|
55
|
-
let descClasses = styles.tabDesc;
|
|
56
|
-
if (generalClasses?.tabDesc) {
|
|
57
|
-
descClasses += ` ${generalClasses.tabDesc}`;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let classList = styles.summaryPage;
|
|
61
|
-
if (className) {
|
|
62
|
-
classList += ` ${className}`;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
<div className={classList}>
|
|
67
|
-
{tabDesc && <p className={descClasses}>{tabDesc}</p>}
|
|
68
|
-
<Loader loading={loading} />
|
|
69
|
-
<ul className={countSummaryClasses}>
|
|
70
|
-
<li>Total number of observers: <b>{summaryData.observers?.totalCount ? numberWithCommas(summaryData.observers.totalCount): ""}</b></li>
|
|
71
|
-
<li>Total number of observations: <b>{summaryData.observations?.totalCount ? numberWithCommas(summaryData.observations.totalCount): ""}</b></li>
|
|
72
|
-
</ul>
|
|
73
|
-
<section>
|
|
74
|
-
<div className={styles.seasonalityBlock}>
|
|
75
|
-
<h1>Seasonality</h1>
|
|
76
|
-
{summaryData.seasonalityData && <SeasonalityGraph data={summaryData.seasonalityData.monthOfYear} />}
|
|
77
|
-
</div>
|
|
78
|
-
<div className={styles.observersBlock}>
|
|
79
|
-
<h1>Top observers</h1>
|
|
80
|
-
{summaryData.observers?.top && (
|
|
81
|
-
<ObserverList
|
|
82
|
-
observers={summaryData.observers.top}
|
|
83
|
-
className={observersListClass}
|
|
84
|
-
generalClasses={generalClasses}
|
|
85
|
-
/>
|
|
86
|
-
)}
|
|
87
|
-
</div>
|
|
88
|
-
</section>
|
|
89
|
-
</div>
|
|
90
|
-
);
|
|
91
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import {render} from '@testing-library/react';
|
|
2
|
-
import Tabs from '../tabs';
|
|
3
|
-
import {Tab} from "../../../index";
|
|
4
|
-
|
|
5
|
-
const defaultProps = {
|
|
6
|
-
selectedTab: Tab.recent,
|
|
7
|
-
onChangeTab: () => null,
|
|
8
|
-
features: {}
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
describe('Tabs', () => {
|
|
12
|
-
it('should render successfully', () => {
|
|
13
|
-
const {baseElement} = render(<Tabs {...defaultProps} />);
|
|
14
|
-
expect(baseElement).toBeTruthy();
|
|
15
|
-
});
|
|
16
|
-
});
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
.tabs {
|
|
2
|
-
display: flex;
|
|
3
|
-
flex-direction: row;
|
|
4
|
-
list-style: none;
|
|
5
|
-
font-size: 18px;
|
|
6
|
-
padding: 0;
|
|
7
|
-
margin-bottom: 30px;
|
|
8
|
-
|
|
9
|
-
li {
|
|
10
|
-
margin: 0 20px;
|
|
11
|
-
padding: 4px 20px;
|
|
12
|
-
cursor: pointer;
|
|
13
|
-
color: #999999;
|
|
14
|
-
transition: all 0.2s ease-in-out;
|
|
15
|
-
|
|
16
|
-
&.selected, &:hover {
|
|
17
|
-
border-bottom: 5px solid #0099cc;
|
|
18
|
-
color: black;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
@media screen and (max-width: 600px) {
|
|
24
|
-
.tabs li {
|
|
25
|
-
margin: 0 5px;
|
|
26
|
-
padding: 4px 6px;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Feature, TaxonPanelFeatures } from "../../__shared";
|
|
3
|
-
import styles from "./tabs.module.scss";
|
|
4
|
-
import { useFeatureTitles } from "../hooks/hooks";
|
|
5
|
-
|
|
6
|
-
export type TabsProps = {
|
|
7
|
-
selectedTab: Feature;
|
|
8
|
-
onChangeTab: (tab: Feature) => void;
|
|
9
|
-
features: TaxonPanelFeatures;
|
|
10
|
-
className?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const Tabs = ({ selectedTab, onChangeTab, features, className }: TabsProps) => {
|
|
14
|
-
const titles = useFeatureTitles(features);
|
|
15
|
-
|
|
16
|
-
let classes = styles.tabs;
|
|
17
|
-
if (className) {
|
|
18
|
-
classes += ` ${className}`;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const items = features.map((item) => {
|
|
22
|
-
if (item.feature == Feature.recentObservations) {
|
|
23
|
-
return (
|
|
24
|
-
<li key={Feature.recentObservations}
|
|
25
|
-
onClick={() => onChangeTab(Feature.recentObservations)}
|
|
26
|
-
className={selectedTab === Feature.recentObservations ? styles.selected : ""}>
|
|
27
|
-
{titles[Feature.recentObservations]}
|
|
28
|
-
</li>
|
|
29
|
-
);
|
|
30
|
-
} else if (item.feature == Feature.commonTaxa) {
|
|
31
|
-
return (
|
|
32
|
-
<li key={Feature.commonTaxa}
|
|
33
|
-
onClick={() => onChangeTab(Feature.commonTaxa)}
|
|
34
|
-
className={selectedTab === Feature.commonTaxa ? styles.selected : ""}>
|
|
35
|
-
{titles[Feature.commonTaxa]}
|
|
36
|
-
</li>
|
|
37
|
-
);
|
|
38
|
-
} else if (item.feature == Feature.favourites) {
|
|
39
|
-
return (
|
|
40
|
-
<li key={Feature.favourites}
|
|
41
|
-
onClick={() => onChangeTab(Feature.favourites)}
|
|
42
|
-
className={selectedTab === Feature.favourites ? styles.selected : ""}>
|
|
43
|
-
{titles[Feature.favourites]}
|
|
44
|
-
</li>
|
|
45
|
-
);
|
|
46
|
-
} else if (item.feature == Feature.stats) {
|
|
47
|
-
return (
|
|
48
|
-
<li key={Feature.stats} onClick={() => onChangeTab(Feature.stats)} className={selectedTab === Feature.stats ? styles.selected : ""}>
|
|
49
|
-
{titles[Feature.stats]}
|
|
50
|
-
</li>
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// possibly a user has included something wacky
|
|
55
|
-
return undefined;
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
return (
|
|
59
|
-
<ul className={classes}>
|
|
60
|
-
{items}
|
|
61
|
-
</ul>
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export default Tabs;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import {render} from '@testing-library/react';
|
|
2
|
-
|
|
3
|
-
import TaxonPanel from '../taxon-panel';
|
|
4
|
-
|
|
5
|
-
describe('TaxonPanel', () => {
|
|
6
|
-
it('should render successfully', () => {
|
|
7
|
-
const {baseElement} = render(<TaxonPanel />);
|
|
8
|
-
expect(baseElement).toBeTruthy();
|
|
9
|
-
});
|
|
10
|
-
});
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import React, { useMemo, useState } from "react";
|
|
2
|
-
import { C, getSourceFile, DataSource, DataSourceEnum, Feature, GeneralClasses, TaxonPanelFeatures } from "../../__shared";
|
|
3
|
-
import { RecentObservations } from '../recent-observations/recent-observations';
|
|
4
|
-
import { CommonTaxa } from '../common-taxa/common-taxa';
|
|
5
|
-
import { Favourites } from "../favourites/favourites"
|
|
6
|
-
import { Summary } from "../summary/summary";
|
|
7
|
-
import Years from "../year-dropdown/year-dropdown";
|
|
8
|
-
import Tabs from "../tabs/tabs";
|
|
9
|
-
import { convertFeaturesToObj, useFeatureTitles } from "../hooks/hooks";
|
|
10
|
-
import styles from "../shared/css/general.module.scss";
|
|
11
|
-
|
|
12
|
-
export type TaxonPanelProps = {
|
|
13
|
-
taxon: {
|
|
14
|
-
id: number;
|
|
15
|
-
str: string;
|
|
16
|
-
};
|
|
17
|
-
place: {
|
|
18
|
-
id: number;
|
|
19
|
-
str: string;
|
|
20
|
-
}
|
|
21
|
-
dataSourceBaseUrl: string;
|
|
22
|
-
dataSource: DataSource;
|
|
23
|
-
features: TaxonPanelFeatures;
|
|
24
|
-
generalClasses: GeneralClasses;
|
|
25
|
-
itemWidth?: number;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const TaxonPanel = ({ taxon, place, features, dataSource, dataSourceBaseUrl, itemWidth, generalClasses }: TaxonPanelProps) => {
|
|
29
|
-
const [tab, setTab] = useState(features[0].feature);
|
|
30
|
-
const [year, setYear] = useState<string>("all");
|
|
31
|
-
const featuresObj = useMemo(() => {
|
|
32
|
-
return convertFeaturesToObj(features);
|
|
33
|
-
}, [features]);
|
|
34
|
-
const titles = useFeatureTitles(featuresObj);
|
|
35
|
-
|
|
36
|
-
const getProps = (feature: Feature): any => {
|
|
37
|
-
const props: any = {
|
|
38
|
-
source: dataSource,
|
|
39
|
-
itemWidth,
|
|
40
|
-
tabDesc: featuresObj[feature]?.desc,
|
|
41
|
-
generalClasses,
|
|
42
|
-
className: featuresObj[feature]?.className
|
|
43
|
-
};
|
|
44
|
-
if (dataSource === DataSourceEnum.url) {
|
|
45
|
-
props.dataUrl = dataSourceBaseUrl + '/' + getSourceFile(feature, taxon, place, year);
|
|
46
|
-
} else {
|
|
47
|
-
props.placeId = place.id;
|
|
48
|
-
props.taxonId = taxon.id;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (feature !== Feature.stats) {
|
|
52
|
-
props.numResults = featuresObj[feature]?.numResults;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (feature !== Feature.recentObservations) {
|
|
56
|
-
props.year = year;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return props;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const getCurrentTab = () => {
|
|
63
|
-
switch (tab) {
|
|
64
|
-
case Feature.recentObservations:
|
|
65
|
-
return <RecentObservations {...getProps(Feature.recentObservations)} />;
|
|
66
|
-
case Feature.commonTaxa:
|
|
67
|
-
return <CommonTaxa {...getProps(Feature.commonTaxa)} />;
|
|
68
|
-
case Feature.favourites:
|
|
69
|
-
return <Favourites {...getProps(Feature.favourites)} />;
|
|
70
|
-
|
|
71
|
-
case Feature.stats:
|
|
72
|
-
return (
|
|
73
|
-
<Summary
|
|
74
|
-
{...getProps(Feature.stats)}
|
|
75
|
-
observersListClass={featuresObj[Feature.stats]?.observersListClass}
|
|
76
|
-
statsCountSummaryClass={featuresObj[Feature.stats]?.statsCountSummaryClass}
|
|
77
|
-
/>
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const tabsClass = generalClasses?.tabsElement || '';
|
|
83
|
-
const yearDropdownClass = generalClasses?.yearsDropdown || '';
|
|
84
|
-
|
|
85
|
-
return (
|
|
86
|
-
<div className={styles.page}>
|
|
87
|
-
{features.length > 1 && <Tabs
|
|
88
|
-
selectedTab={tab}
|
|
89
|
-
onChangeTab={setTab}
|
|
90
|
-
features={features}
|
|
91
|
-
className={tabsClass}
|
|
92
|
-
/>}
|
|
93
|
-
<div>
|
|
94
|
-
{tab !== Feature.recentObservations && (
|
|
95
|
-
<div style={{ float: "right" }} className={yearDropdownClass}>
|
|
96
|
-
<Years
|
|
97
|
-
value={year}
|
|
98
|
-
numYears={featuresObj[tab]?.numYears || C.DEFAULT_NUM_YEARS}
|
|
99
|
-
onChange={setYear}
|
|
100
|
-
/>
|
|
101
|
-
</div>
|
|
102
|
-
)}
|
|
103
|
-
<h1 className={generalClasses?.pageHeadings}>{titles[tab]}</h1>
|
|
104
|
-
</div>
|
|
105
|
-
{getCurrentTab()}
|
|
106
|
-
</div>
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export default TaxonPanel;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {render} from '@testing-library/react';
|
|
2
|
-
import YearDropdown from '../year-dropdown';
|
|
3
|
-
|
|
4
|
-
const defaultProps = {
|
|
5
|
-
value: "1",
|
|
6
|
-
onChange: () => null
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
describe('YearDropdown', () => {
|
|
10
|
-
it('should render successfully', () => {
|
|
11
|
-
const {baseElement} = render(<YearDropdown {...defaultProps} />);
|
|
12
|
-
expect(baseElement).toBeTruthy();
|
|
13
|
-
});
|
|
14
|
-
});
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
|
2
|
-
import { getCurrentYear } from "../../__shared";
|
|
3
|
-
import styles from "./year-dropdown.module.scss";
|
|
4
|
-
|
|
5
|
-
interface YearsProps {
|
|
6
|
-
value: string;
|
|
7
|
-
onChange: (year: string) => void;
|
|
8
|
-
numYears: number;
|
|
9
|
-
className?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const Years = ({ value, onChange, numYears, className }: YearsProps) => {
|
|
13
|
-
const [years, setYears] = useState([]);
|
|
14
|
-
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
const currentYear = getCurrentYear();
|
|
17
|
-
const years: any = [];
|
|
18
|
-
for (let i = currentYear; i>currentYear-numYears; i--) {
|
|
19
|
-
years.push(i);
|
|
20
|
-
}
|
|
21
|
-
setYears(years);
|
|
22
|
-
}, [numYears]);
|
|
23
|
-
|
|
24
|
-
let classes = styles.dropdown;
|
|
25
|
-
if (className) {
|
|
26
|
-
classes += ` ${className}`;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<select className={classes} onChange={(e) => onChange(e.target.value)} defaultValue={value}>
|
|
31
|
-
<option value="all">All years</option>
|
|
32
|
-
{years.map((year) => <option value={year} key={year}>{year}</option>)}
|
|
33
|
-
</select>
|
|
34
|
-
)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export default Years;
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
import { DataSource, DataSourceEnum } from "../__shared";
|
|
3
|
-
|
|
4
|
-
type UseLoadSourceData = {
|
|
5
|
-
action: any;
|
|
6
|
-
taxonId?: number;
|
|
7
|
-
placeId?: number;
|
|
8
|
-
numResults?: number;
|
|
9
|
-
source?: DataSource;
|
|
10
|
-
dataUrl?: string;
|
|
11
|
-
year?: number | string,
|
|
12
|
-
isSummaryData?: boolean;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* This hook handles loading the iNat data from whatever source has been specified (DataSource):
|
|
17
|
-
* nothing needs to be done.
|
|
18
|
-
* - "autoLoad": the user is developing locally and wants to just ping iNat directly for the source
|
|
19
|
-
* - "url": the user has generated the data sources at a URL somewhere via @imerss/inat-component-utils
|
|
20
|
-
*/
|
|
21
|
-
export const useLoadSourceData = ({
|
|
22
|
-
taxonId,
|
|
23
|
-
placeId,
|
|
24
|
-
numResults,
|
|
25
|
-
source,
|
|
26
|
-
dataUrl,
|
|
27
|
-
year,
|
|
28
|
-
action,
|
|
29
|
-
isSummaryData = false
|
|
30
|
-
}: UseLoadSourceData) => {
|
|
31
|
-
const [loading, setLoading] = useState(false);
|
|
32
|
-
const [results, setResults] = useState<any>([]);
|
|
33
|
-
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
if (source === DataSourceEnum.autoLoad) {
|
|
36
|
-
if (!taxonId) {
|
|
37
|
-
console.error("Please supply a `taxonId` prop for the `autoLoad` source prop option.");
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
if (!placeId) {
|
|
41
|
-
console.error("Please supply a `placeId` prop for the `autoLoad` source prop option.");
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
(async () => {
|
|
46
|
-
setLoading(true);
|
|
47
|
-
|
|
48
|
-
// note that `year` isn't used for recentObservations, but we pass it anyway to get more reusability out
|
|
49
|
-
// of this hook
|
|
50
|
-
const obs = await action({ taxonId, placeId, numResults, year });
|
|
51
|
-
setResults(obs.results);
|
|
52
|
-
setLoading(false);
|
|
53
|
-
})();
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (source === DataSourceEnum.url) {
|
|
57
|
-
if (!dataUrl) {
|
|
58
|
-
console.error("Please supply a `dataUrl` prop for the `url` source prop option.");
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
(async () => {
|
|
63
|
-
setLoading(true);
|
|
64
|
-
const obs = await fetch(dataUrl);
|
|
65
|
-
const json = await obs.json();
|
|
66
|
-
|
|
67
|
-
// hack workaround. Better solution would have been to standardize the JSON structure at the top-level
|
|
68
|
-
if (isSummaryData) {
|
|
69
|
-
setResults(json);
|
|
70
|
-
} else {
|
|
71
|
-
setResults(json.results);
|
|
72
|
-
}
|
|
73
|
-
setLoading(false);
|
|
74
|
-
})();
|
|
75
|
-
}
|
|
76
|
-
}, [source, dataUrl, taxonId, placeId, year, numResults, isSummaryData]);
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
loading, results
|
|
80
|
-
};
|
|
81
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import TaxonPanel from "./components/taxon-panel/taxon-panel";
|
|
2
|
-
|
|
3
|
-
// front-end components
|
|
4
|
-
export * from "./components/observation/observation";
|
|
5
|
-
export * from "./components/common-taxa/common-taxa";
|
|
6
|
-
export * from "./components/recent-observations/recent-observations";
|
|
7
|
-
export * from "./components/favourites/favourites";
|
|
8
|
-
export * from "./components/taxon-panel/taxon-panel";
|
|
9
|
-
export * from "./components/seasonality-graph/seasonality-graph";
|
|
10
|
-
export * from "./components/summary/summary";
|
|
11
|
-
|
|
12
|
-
// all typings
|
|
13
|
-
export * from "./__shared";
|
|
14
|
-
|
|
15
|
-
export default TaxonPanel;
|
package/src/types/index.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { TaxonPanelProps } from "../components/taxon-panel/taxon-panel";
|
|
2
|
-
|
|
3
|
-
export {};
|
|
4
|
-
declare global {
|
|
5
|
-
interface Window {
|
|
6
|
-
inatComponents: {
|
|
7
|
-
initTaxonPanel: (domId: string, taxonPanelProps: TaxonPanelProps) => void;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
window.initStandalone = window.initStandalone || {};
|
|
13
|
-
|
|
14
|
-
export enum DataSource {
|
|
15
|
-
autoLoad = "autoLoad",
|
|
16
|
-
url = "url"
|
|
17
|
-
}
|