@imerss/inat-components 2.0.1 → 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.
Files changed (66) hide show
  1. package/README.md +23 -4
  2. package/dist/index.d.ts +87 -75
  3. package/dist/index.js +261 -173
  4. package/dist/standalone.min.js +1 -1
  5. package/package.json +10 -12
  6. package/PUBLISH.md +0 -13
  7. package/declaration.d.ts +0 -2
  8. package/public/favicon.ico +0 -0
  9. package/public/index.html +0 -20
  10. package/public/logo192.png +0 -0
  11. package/public/logo512.png +0 -0
  12. package/public/manifest.json +0 -25
  13. package/public/robots.txt +0 -3
  14. package/public/standalone.html +0 -55
  15. package/rollup.config.js +0 -47
  16. package/src/__shared/api/common-taxa.ts +0 -57
  17. package/src/__shared/api/favourites.ts +0 -57
  18. package/src/__shared/api/index.ts +0 -4
  19. package/src/__shared/api/recent-observations.ts +0 -44
  20. package/src/__shared/api/summary.ts +0 -86
  21. package/src/__shared/constants.ts +0 -6
  22. package/src/__shared/index.ts +0 -4
  23. package/src/__shared/typings.ts +0 -83
  24. package/src/__shared/utils/configUtils.ts +0 -25
  25. package/src/__shared/utils/dateUtils.ts +0 -14
  26. package/src/__shared/utils/index.ts +0 -3
  27. package/src/__shared/utils/numberUtils.ts +0 -1
  28. package/src/components/common-taxa/__tests__/common-taxa.test.tsx +0 -14
  29. package/src/components/common-taxa/common-taxa.tsx +0 -73
  30. package/src/components/error/__tests__/error.test.tsx +0 -9
  31. package/src/components/error/error.module.scss +0 -7
  32. package/src/components/error/error.tsx +0 -15
  33. package/src/components/favourites/__tests__/favourites.test.tsx +0 -13
  34. package/src/components/favourites/favourites.tsx +0 -73
  35. package/src/components/hooks/hooks.tsx +0 -34
  36. package/src/components/loader/__tests__/loader.test.tsx +0 -10
  37. package/src/components/loader/loader.tsx +0 -26
  38. package/src/components/no-results/__tests__/no-results.test.tsx +0 -9
  39. package/src/components/no-results/no-results.tsx +0 -9
  40. package/src/components/observation/__tests__/observation.test.tsx +0 -14
  41. package/src/components/observation/observation.module.scss +0 -20
  42. package/src/components/observation/observation.tsx +0 -30
  43. package/src/components/recent-observations/__tests__/recent-observations.test.tsx +0 -9
  44. package/src/components/recent-observations/recent-observations.tsx +0 -84
  45. package/src/components/seasonality-graph/__tests__/seasonality-graph.test.tsx +0 -9
  46. package/src/components/seasonality-graph/seasonality-graph.module.scss +0 -7
  47. package/src/components/seasonality-graph/seasonality-graph.tsx +0 -46
  48. package/src/components/shared/css/general.module.scss +0 -73
  49. package/src/components/summary/ObserverList.tsx +0 -24
  50. package/src/components/summary/__tests__/summary.test.tsx +0 -18
  51. package/src/components/summary/summary.module.scss +0 -88
  52. package/src/components/summary/summary.tsx +0 -91
  53. package/src/components/tabs/__tests__/tabs.test.tsx +0 -16
  54. package/src/components/tabs/tabs.module.scss +0 -28
  55. package/src/components/tabs/tabs.tsx +0 -65
  56. package/src/components/taxon-panel/__tests__/taxon-panel.test.tsx +0 -10
  57. package/src/components/taxon-panel/taxon-panel.module.scss +0 -7
  58. package/src/components/taxon-panel/taxon-panel.tsx +0 -110
  59. package/src/components/year-dropdown/__tests__/year-dropdown.test.tsx +0 -14
  60. package/src/components/year-dropdown/year-dropdown.module.scss +0 -3
  61. package/src/components/year-dropdown/year-dropdown.tsx +0 -37
  62. package/src/hooks/useLoadSourceData.ts +0 -81
  63. package/src/index.ts +0 -15
  64. package/src/types/index.d.ts +0 -17
  65. package/src/types/standalone.d.ts +0 -6
  66. package/tsconfig.json +0 -6
package/dist/index.js CHANGED
@@ -54,12 +54,12 @@ function __awaiter(thisArg, _arguments, P, generator) {
54
54
  }
55
55
 
56
56
  function __generator(thisArg, body) {
57
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
58
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
57
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
58
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
59
59
  function verb(n) { return function (v) { return step([n, v]); }; }
60
60
  function step(op) {
61
61
  if (f) throw new TypeError("Generator is already executing.");
62
- while (_) try {
62
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
63
63
  if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
64
64
  if (y = 0, t) op = [op[0] & 2, t.value];
65
65
  switch (op[0]) {
@@ -79,14 +79,43 @@ function __generator(thisArg, body) {
79
79
  } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
80
80
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
81
81
  }
82
- }
82
+ }
83
+
84
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
85
+ var e = new Error(message);
86
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
87
+ };
88
+
89
+ var filterParamNames = [
90
+ ["taxonId", "taxon_id"],
91
+ ["placeId", "place_id"],
92
+ ["projectId", "project_id"]
93
+ ];
94
+ /**
95
+ * Render a filter as query parameters, to be appended to a URL which already has a query.
96
+ * @param filter - The taxon, place and project of the observations
97
+ * @return The parameters, each beginning with "&", of those members of the filter which are supplied
98
+ */
99
+ var filterParams = function (filter) {
100
+ return filterParamNames
101
+ .filter(function (_a) {
102
+ var member = _a[0];
103
+ return filter[member] !== undefined && filter[member] !== null && filter[member] !== "";
104
+ })
105
+ // The commas of a list are left as they are, as iNaturalist's own pages write them
106
+ .map(function (_a) {
107
+ var member = _a[0], param = _a[1];
108
+ return "&".concat(param, "=").concat(encodeURIComponent(String(filter[member])).replace(/%2C/gi, ","));
109
+ })
110
+ .join("");
111
+ };
83
112
 
84
113
  var BASE_API_URL = 'https://api.inaturalist.org';
85
114
  var NUM_RESULTS = 100;
86
115
  var DEFAULT_NUM_YEARS = 10;
87
116
  var BASE_URL = "https://www.inaturalist.org"; // /people/name_here
88
- var ERROR_LOG_FILENAME = "inat-components-error.log";
89
117
  var DEFAULT_ITEM_WIDTH = 150;
118
+ var DEFAULT_NUM_TOP_OBSERVERS = 10;
90
119
 
91
120
  var constants = /*#__PURE__*/Object.freeze({
92
121
  __proto__: null,
@@ -94,18 +123,18 @@ var constants = /*#__PURE__*/Object.freeze({
94
123
  NUM_RESULTS: NUM_RESULTS,
95
124
  DEFAULT_NUM_YEARS: DEFAULT_NUM_YEARS,
96
125
  BASE_URL: BASE_URL,
97
- ERROR_LOG_FILENAME: ERROR_LOG_FILENAME,
98
- DEFAULT_ITEM_WIDTH: DEFAULT_ITEM_WIDTH
126
+ DEFAULT_ITEM_WIDTH: DEFAULT_ITEM_WIDTH,
127
+ DEFAULT_NUM_TOP_OBSERVERS: DEFAULT_NUM_TOP_OBSERVERS
99
128
  });
100
129
 
101
130
  var getCommonTaxa = function (_a) {
102
- var year = _a.year, taxonId = _a.taxonId, placeId = _a.placeId, numResults = _a.numResults;
131
+ var year = _a.year, taxonId = _a.taxonId, placeId = _a.placeId, projectId = _a.projectId, numResults = _a.numResults;
103
132
  return __awaiter(void 0, void 0, void 0, function () {
104
133
  var url, response, resp, sortedTaxa;
105
134
  return __generator(this, function (_b) {
106
135
  switch (_b.label) {
107
136
  case 0:
108
- url = "".concat(BASE_API_URL, "/v1/observations/species_counts?verifiable=true&spam=false&place_id=").concat(placeId, "&taxon_id=").concat(taxonId, "&locale=en-US&per_page=").concat(numResults);
137
+ url = "".concat(BASE_API_URL, "/v1/observations/species_counts?verifiable=true&spam=false").concat(filterParams({ taxonId: taxonId, placeId: placeId, projectId: projectId }), "&locale=en-US&per_page=").concat(numResults);
109
138
  if (year !== "all") {
110
139
  url += "&d1=".concat(year, "-01-01&d2=").concat(year, "-12-31");
111
140
  }
@@ -148,13 +177,13 @@ var getCommonTaxa = function (_a) {
148
177
  };
149
178
 
150
179
  var getFavourites = function (_a) {
151
- var year = _a.year, taxonId = _a.taxonId, placeId = _a.placeId, numResults = _a.numResults;
180
+ var year = _a.year, taxonId = _a.taxonId, placeId = _a.placeId, projectId = _a.projectId, numResults = _a.numResults;
152
181
  return __awaiter(void 0, void 0, void 0, function () {
153
182
  var url, response, resp, sortedTaxa;
154
183
  return __generator(this, function (_b) {
155
184
  switch (_b.label) {
156
185
  case 0:
157
- url = "".concat(BASE_API_URL, "/v1/observations?verifiable=true&order_by=votes&order=desc&page=1&spam=false&place_id=").concat(placeId, "&taxon_id=").concat(taxonId, "&locale=en-US&per_page=").concat(numResults);
186
+ url = "".concat(BASE_API_URL, "/v1/observations?verifiable=true&order_by=votes&order=desc&page=1&spam=false").concat(filterParams({ taxonId: taxonId, placeId: placeId, projectId: projectId }), "&locale=en-US&per_page=").concat(numResults);
158
187
  if (year !== "all") {
159
188
  url += "&d1=".concat(year, "-01-01&d2=").concat(year, "-12-31");
160
189
  }
@@ -175,15 +204,19 @@ var getFavourites = function (_a) {
175
204
  });
176
205
  return [2 /*return*/, {
177
206
  totalResults: resp.total_results,
178
- results: sortedTaxa.map(function (row) { return ({
179
- id: row.id,
180
- imageUrl: row.observation_photos[0].photo.url || "",
181
- obsDate: row.observed_on_string,
182
- obsUrl: row.uri,
183
- taxonName: row.taxon.name || "",
184
- taxonCommonName: row.taxon.preferred_common_name,
185
- numFaves: row.faves.length
186
- }); })
207
+ results: sortedTaxa.map(function (row) {
208
+ var _a;
209
+ return ({
210
+ id: row.id,
211
+ imageUrl: row.observation_photos[0].photo.url || "",
212
+ obsDate: row.observed_on_string,
213
+ obsUrl: row.uri,
214
+ observerUsername: ((_a = row.user) === null || _a === void 0 ? void 0 : _a.login) || "",
215
+ taxonName: row.taxon.name || "",
216
+ taxonCommonName: row.taxon.preferred_common_name,
217
+ numFaves: row.faves.length
218
+ });
219
+ })
187
220
  }];
188
221
  }
189
222
  });
@@ -191,13 +224,13 @@ var getFavourites = function (_a) {
191
224
  };
192
225
 
193
226
  var getRecentObservations = function (_a) {
194
- var taxonId = _a.taxonId, placeId = _a.placeId, numResults = _a.numResults;
227
+ var taxonId = _a.taxonId, placeId = _a.placeId, projectId = _a.projectId, numResults = _a.numResults;
195
228
  return __awaiter(void 0, void 0, void 0, function () {
196
229
  var url, response, obs;
197
230
  return __generator(this, function (_b) {
198
231
  switch (_b.label) {
199
232
  case 0:
200
- url = "".concat(BASE_API_URL, "/v1/observations?photos=true&per_page=").concat(numResults, "&taxon_id=").concat(taxonId, "&place_id=").concat(placeId, "&order=desc&order_by=observed_on");
233
+ url = "".concat(BASE_API_URL, "/v1/observations?photos=true&per_page=").concat(numResults).concat(filterParams({ taxonId: taxonId, placeId: placeId, projectId: projectId }), "&order=desc&order_by=observed_on");
201
234
  return [4 /*yield*/, fetch$1(url)];
202
235
  case 1:
203
236
  response = _b.sent();
@@ -225,20 +258,22 @@ var getRecentObservations = function (_a) {
225
258
  };
226
259
 
227
260
  var getSummary = function (_a) {
228
- var taxonId = _a.taxonId, placeId = _a.placeId, year = _a.year;
261
+ var taxonId = _a.taxonId, placeId = _a.placeId, projectId = _a.projectId, year = _a.year, _b = _a.numTopObservers, numTopObservers = _b === void 0 ? DEFAULT_NUM_TOP_OBSERVERS : _b;
229
262
  return __awaiter(void 0, void 0, void 0, function () {
230
- var observers, observations, seasonalityData;
231
- return __generator(this, function (_b) {
232
- switch (_b.label) {
233
- case 0: return [4 /*yield*/, getObserverSummary(taxonId, placeId, year)];
263
+ var filter, observers, observations, seasonalityData;
264
+ return __generator(this, function (_c) {
265
+ switch (_c.label) {
266
+ case 0:
267
+ filter = { taxonId: taxonId, placeId: placeId, projectId: projectId };
268
+ return [4 /*yield*/, getObserverSummary(filter, year, numTopObservers)];
234
269
  case 1:
235
- observers = _b.sent();
236
- return [4 /*yield*/, getObservationSummary(taxonId, placeId, year)];
270
+ observers = _c.sent();
271
+ return [4 /*yield*/, getObservationSummary(filter, year)];
237
272
  case 2:
238
- observations = _b.sent();
239
- return [4 /*yield*/, getSeasonalityData(taxonId, placeId, year)];
273
+ observations = _c.sent();
274
+ return [4 /*yield*/, getSeasonalityData(filter, year)];
240
275
  case 3:
241
- seasonalityData = _b.sent();
276
+ seasonalityData = _c.sent();
242
277
  return [2 /*return*/, {
243
278
  observers: observers,
244
279
  observations: observations,
@@ -248,39 +283,42 @@ var getSummary = function (_a) {
248
283
  });
249
284
  });
250
285
  };
251
- var getObserverSummary = function (taxonId, placeId, year) { return __awaiter(void 0, void 0, void 0, function () {
252
- var url, response, data;
253
- return __generator(this, function (_a) {
254
- switch (_a.label) {
255
- case 0:
256
- url = "".concat(BASE_API_URL, "/v1/observations/observers?verifiable=true&order_by=votes&order=desc&page=1&spam=false&place_id=").concat(placeId, "&taxon_id=").concat(taxonId, "&locale=en-US&per_page=10");
257
- if (year !== "all") {
258
- url += "&d1=".concat(year, "-01-01&d2=").concat(year, "-12-31");
259
- }
260
- return [4 /*yield*/, fetch$1(url)];
261
- case 1:
262
- response = _a.sent();
263
- return [4 /*yield*/, response.json()];
264
- case 2:
265
- data = _a.sent();
266
- return [2 /*return*/, {
267
- totalCount: data.total_results,
268
- top: data.results.map(function (result) { return ({
269
- id: result.user.id,
270
- userName: result.user.login,
271
- numObservations: result.observation_count,
272
- iconUrl: result.user.icon_url
273
- }); })
274
- }];
275
- }
286
+ var getObserverSummary = function (filter, year, numTopObservers) {
287
+ if (numTopObservers === void 0) { numTopObservers = DEFAULT_NUM_TOP_OBSERVERS; }
288
+ return __awaiter(void 0, void 0, void 0, function () {
289
+ var url, response, data;
290
+ return __generator(this, function (_a) {
291
+ switch (_a.label) {
292
+ case 0:
293
+ url = "".concat(BASE_API_URL, "/v1/observations/observers?verifiable=true&order_by=votes&order=desc&page=1&spam=false").concat(filterParams(filter), "&locale=en-US&per_page=").concat(numTopObservers);
294
+ if (year !== "all") {
295
+ url += "&d1=".concat(year, "-01-01&d2=").concat(year, "-12-31");
296
+ }
297
+ return [4 /*yield*/, fetch$1(url)];
298
+ case 1:
299
+ response = _a.sent();
300
+ return [4 /*yield*/, response.json()];
301
+ case 2:
302
+ data = _a.sent();
303
+ return [2 /*return*/, {
304
+ totalCount: data.total_results,
305
+ top: data.results.map(function (result) { return ({
306
+ id: result.user.id,
307
+ userName: result.user.login,
308
+ numObservations: result.observation_count,
309
+ iconUrl: result.user.icon_url
310
+ }); })
311
+ }];
312
+ }
313
+ });
276
314
  });
277
- }); };
278
- var getObservationSummary = function (taxonId, placeId, year) { return __awaiter(void 0, void 0, void 0, function () {
315
+ };
316
+ var getObservationSummary = function (filter, year) { return __awaiter(void 0, void 0, void 0, function () {
279
317
  var url, response, data;
280
318
  return __generator(this, function (_a) {
281
319
  switch (_a.label) {
282
320
  case 0:
283
- url = "".concat(BASE_API_URL, "/v1/observations?photos=true&per_page=1&taxon_id=").concat(taxonId, "&place_id=").concat(placeId, "&order=desc&order_by=observed_on");
321
+ url = "".concat(BASE_API_URL, "/v1/observations?photos=true&per_page=1").concat(filterParams(filter), "&order=desc&order_by=observed_on");
284
322
  if (year !== "all") {
285
323
  url += "&d1=".concat(year, "-01-01&d2=").concat(year, "-12-31");
286
324
  }
@@ -296,12 +334,12 @@ var getObservationSummary = function (taxonId, placeId, year) { return __awaiter
296
334
  }
297
335
  });
298
336
  }); };
299
- var getSeasonalityData = function (taxonId, placeId, year) { return __awaiter(void 0, void 0, void 0, function () {
337
+ var getSeasonalityData = function (filter, year) { return __awaiter(void 0, void 0, void 0, function () {
300
338
  var url, response, resp;
301
339
  return __generator(this, function (_a) {
302
340
  switch (_a.label) {
303
341
  case 0:
304
- url = "".concat(BASE_API_URL, "/v1/observations/histogram?verifiable=true&taxon_id=").concat(taxonId, "&place_id=").concat(placeId, "&locale=en-US&date_field=observed&interval=month_of_year");
342
+ url = "".concat(BASE_API_URL, "/v1/observations/histogram?verifiable=true").concat(filterParams(filter), "&locale=en-US&date_field=observed&interval=month_of_year");
305
343
  if (year !== "all") {
306
344
  url += "&d1=".concat(year, "-01-01&d2=").concat(year, "-12-31");
307
345
  }
@@ -332,25 +370,28 @@ var DataSourceEnum;
332
370
  })(DataSourceEnum || (DataSourceEnum = {}));
333
371
 
334
372
  /*
335
- * Note that right now the source filenames aren't configurable.
373
+ * Note that right now the source filenames aren't configurable. A file is named by the `str` of each of the taxon,
374
+ * place and project which are supplied, in that order - so that the names of files for a taxon and a place are as they
375
+ * were before projects could be supplied.
336
376
  */
337
- var getSourceFile = function (api, taxon, place, year) {
338
- if (!taxon || !place) {
377
+ var getSourceFile = function (api, taxon, place, year, project) {
378
+ if (!project && (!taxon || !place)) {
339
379
  return '';
340
380
  }
341
381
  var yearStr = year === "all" ? "allyears" : year;
382
+ var stem = [taxon, place, project].filter(function (item) { return item; }).map(function (item) { return item.str; }).join("-");
342
383
  var filename = "";
343
384
  if (api === Feature.recentObservations) {
344
- filename = "".concat(taxon.str, "-").concat(place.str, "-recent.json");
385
+ filename = "".concat(stem, "-recent.json");
345
386
  }
346
387
  else if (api === Feature.commonTaxa) {
347
- filename = "".concat(taxon.str, "-").concat(place.str, "-").concat(yearStr, "-commonTaxa.json");
388
+ filename = "".concat(stem, "-").concat(yearStr, "-commonTaxa.json");
348
389
  }
349
390
  else if (api === Feature.favourites) {
350
- filename = "".concat(taxon.str, "-").concat(place.str, "-").concat(yearStr, "-favourites.json");
391
+ filename = "".concat(stem, "-").concat(yearStr, "-favourites.json");
351
392
  }
352
393
  else if (api === Feature.stats) {
353
- filename = "".concat(taxon.str, "-").concat(place.str, "-").concat(yearStr, "-stats.json");
394
+ filename = "".concat(stem, "-").concat(yearStr, "-stats.json");
354
395
  }
355
396
  return filename;
356
397
  };
@@ -398,204 +439,242 @@ function styleInject(css, ref) {
398
439
  }
399
440
  }
400
441
 
401
- var css_248z$4 = ".observation-module_obs__-5hGT {\n cursor: pointer;\n border-radius: 8px;\n background-color: #f9f9f9;\n text-align: center;\n transition: all 0.15s ease-in-out;\n}\n.observation-module_obs__-5hGT:hover {\n background-color: #e1e1e1;\n}\n\n.observation-module_obs__-5hGT h3 {\n margin: 0;\n}\n\n.observation-module_image__BBTP8 {\n max-width: 100%;\n max-height: 100%;\n}";
402
- var styles$4 = {"obs":"observation-module_obs__-5hGT","image":"observation-module_image__BBTP8"};
403
- styleInject(css_248z$4);
442
+ var css_248z$5 = ".observation-module_obs__5i2W5 {\n cursor: pointer;\n border-radius: 8px;\n /* Rounds the corners of the photo with those of the card */\n overflow: hidden;\n background-color: #f9f9f9;\n text-align: center;\n transition: all 0.15s ease-in-out;\n}\n.observation-module_obs__5i2W5:hover {\n background-color: #e1e1e1;\n}\n\n.observation-module_obs__5i2W5 h3 {\n margin: 0;\n}\n\n.observation-module_image__R07tV {\n width: 100%;\n aspect-ratio: 1;\n overflow: hidden;\n}\n";
443
+ var styles$5 = {"obs":"observation-module_obs__5i2W5","image":"observation-module_image__R07tV"};
444
+ styleInject(css_248z$5);
404
445
 
446
+ /**
447
+ * The columns of a grid of observations. Each is at least `itemWidth` wide, but no wider than allows two across a narrow
448
+ * screen, and a row of fewer results than fill it leaves the rest empty, rather than stretching them across it.
449
+ * @param itemWidth - The least width of a column, in pixels
450
+ * @return The value of the grid's `grid-template-columns`
451
+ */
452
+ var gridColumns = function (itemWidth) {
453
+ return "repeat(auto-fill, minmax(min(".concat(itemWidth, "px, calc(50% - 4px)), 1fr))");
454
+ };
405
455
  var Observation = function (_a) {
406
- var imageUrl = _a.imageUrl, linkUrl = _a.linkUrl, itemWidth = _a.itemWidth, children = _a.children;
456
+ var imageUrl = _a.imageUrl, linkUrl = _a.linkUrl, children = _a.children;
407
457
  var gotoObservation = useCallback(function () {
408
458
  window.open(linkUrl);
409
459
  }, [linkUrl]);
410
- return (jsxs("article", __assign({ className: styles$4.obs, onClick: gotoObservation }, { children: [jsx("div", { style: {
411
- width: itemWidth,
412
- height: itemWidth,
413
- overflow: "hidden",
414
- borderRadius: 5,
460
+ return (jsxs("article", __assign({ className: styles$5.obs, onClick: gotoObservation }, { children: [jsx("div", { className: styles$5.image, style: {
415
461
  background: "url(".concat(imageUrl, ") 50% 50% no-repeat"),
416
- margin: "0 auto",
417
462
  backgroundSize: "cover"
418
463
  } }), children] })));
419
464
  };
420
465
 
421
- var css_248z$3 = ".general-module_page__ziNB9 {\n padding: 80px 10px 10px;\n margin: 0 auto;\n max-width: 1100px;\n}\n.general-module_page__ziNB9 h1 {\n border-bottom: 1px solid #efefef;\n padding-bottom: 2px;\n margin-bottom: 25px;\n}\n\n.general-module_panel__WjWzy {\n position: relative;\n}\n\n.general-module_grid__VwNiL {\n display: grid;\n width: 100%;\n grid-gap: 8px;\n text-align: center;\n}\n\n.general-module_obsLabel__9R-PO {\n padding: 10px 20px;\n}\n.general-module_obsLabel__9R-PO a {\n text-decoration: none;\n color: #336699;\n}\n.general-module_obsLabel__9R-PO a:hover {\n text-decoration: underline;\n}\n\n.general-module_loader__gBvfF {\n position: absolute;\n top: 50px;\n left: 0;\n right: 0;\n z-index: 1;\n margin: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.general-module_loaderBg__URuj7 {\n position: absolute;\n background-color: #cccccc;\n padding: 20px;\n width: 100px;\n border-radius: 10px;\n height: 100%;\n opacity: 0.8;\n}\n\n.general-module_count__Gnr8W {\n background-color: #efefef;\n color: #666666;\n padding: 2px 8px;\n margin-top: 6px;\n display: inline-block;\n border-radius: 3px;\n font-weight: bold;\n font-size: 18px;\n}\n\n.general-module_tabDesc__zOFiV {\n font-size: 14px;\n margin-bottom: 20px;\n}";
422
- var styles$3 = {"page":"general-module_page__ziNB9","panel":"general-module_panel__WjWzy","grid":"general-module_grid__VwNiL","obsLabel":"general-module_obsLabel__9R-PO","loader":"general-module_loader__gBvfF","loaderBg":"general-module_loaderBg__URuj7","count":"general-module_count__Gnr8W","tabDesc":"general-module_tabDesc__zOFiV"};
423
- styleInject(css_248z$3);
466
+ var css_248z$4 = ".general-module_page__ijzIy {\n padding: 80px 10px 10px;\n margin: 0 auto;\n max-width: 1100px;\n}\n.general-module_page__ijzIy h1 {\n border-bottom: 1px solid #efefef;\n padding-bottom: 2px;\n margin-bottom: 25px;\n}\n\n.general-module_panel__rdHWU {\n position: relative;\n}\n\n.general-module_grid__wJM1E {\n display: grid;\n width: 100%;\n grid-gap: 8px;\n text-align: center;\n}\n\n.general-module_obsLabel__Gudlw {\n padding: 10px 20px;\n}\n.general-module_obsLabel__Gudlw a {\n text-decoration: none;\n color: #336699;\n}\n.general-module_obsLabel__Gudlw a:hover {\n text-decoration: underline;\n}\n\n.general-module_loader__p0Lxn {\n position: absolute;\n top: 50px;\n left: 0;\n right: 0;\n z-index: 1;\n margin: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.general-module_loaderBg__AnbjC {\n position: absolute;\n background-color: #cccccc;\n padding: 20px;\n width: 100px;\n border-radius: 10px;\n height: 100%;\n opacity: 0.8;\n}\n\n.general-module_count__50oeR {\n background-color: #efefef;\n color: #666666;\n padding: 2px 8px;\n margin-top: 6px;\n display: inline-block;\n border-radius: 3px;\n font-weight: bold;\n font-size: 18px;\n}\n\n.general-module_tabDesc__RhIql {\n font-size: 14px;\n margin-bottom: 20px;\n}\n";
467
+ var styles$4 = {"page":"general-module_page__ijzIy","panel":"general-module_panel__rdHWU","grid":"general-module_grid__wJM1E","obsLabel":"general-module_obsLabel__Gudlw","loader":"general-module_loader__p0Lxn","loaderBg":"general-module_loaderBg__AnbjC","count":"general-module_count__50oeR","tabDesc":"general-module_tabDesc__RhIql"};
468
+ styleInject(css_248z$4);
424
469
 
425
470
  var Loader = function (_a) {
426
471
  var loading = _a.loading;
427
- var loaderClasses = styles$3.loader;
428
- // if (loading) {
429
- // loaderClasses += ` ${styles.loading}`;
430
- // }
431
472
  if (!loading) {
432
473
  return null;
433
474
  }
434
- return (jsxs("div", __assign({ className: loaderClasses }, { children: [jsx("div", { className: styles$3.loaderBg }), jsx(LoadingSpinner, { color: "#000000" })] })));
475
+ return (jsxs("div", __assign({ className: styles$4.loader }, { children: [jsx("div", { className: styles$4.loaderBg }), jsx(LoadingSpinner, { color: "#000000" })] })));
435
476
  };
436
477
 
437
478
  var NoResults = function () {
438
479
  return (jsx("p", { children: "No results found." }));
439
480
  };
440
481
 
482
+ var css_248z$3 = ".error-module_error__trW7H {\n color: #993333;\n}\n";
483
+ var styles$3 = {"error":"error-module_error__trW7H"};
484
+ styleInject(css_248z$3);
485
+
486
+ /**
487
+ * Shown in place of a tab's results when they could not be loaded. A site may supply its own, as `components.error`.
488
+ */
489
+ var LoadError = function () { return (jsx("p", __assign({ className: styles$3.error }, { children: "The observations could not be loaded from iNaturalist. Please try again later." }))); };
490
+
441
491
  /**
442
492
  * This hook handles loading the iNat data from whatever source has been specified (DataSource):
443
- * nothing needs to be done.
444
- * - "autoLoad": the user is developing locally and wants to just ping iNat directly for the source
445
- * - "url": the user has generated the data sources at a URL somewhere via @imerss/inat-component-utils
493
+ * - "autoLoad": the data is requested from iNaturalist's API directly, by the `action` supplied
494
+ * - "url": the data is read from files generated at a URL somewhere via @imerss/inat-components-utils
495
+ * It returns `error` as `true` once a request has failed, or returned something other than the data.
446
496
  */
447
497
  var useLoadSourceData = function (_a) {
448
- var taxonId = _a.taxonId, placeId = _a.placeId, numResults = _a.numResults, source = _a.source, dataUrl = _a.dataUrl, year = _a.year, action = _a.action, _b = _a.isSummaryData, isSummaryData = _b === void 0 ? false : _b;
498
+ var taxonId = _a.taxonId, placeId = _a.placeId, projectId = _a.projectId, numResults = _a.numResults, source = _a.source, dataUrl = _a.dataUrl, year = _a.year, action = _a.action, _b = _a.isSummaryData, isSummaryData = _b === void 0 ? false : _b;
449
499
  var _c = useState(false), loading = _c[0], setLoading = _c[1];
450
500
  var _d = useState([]), results = _d[0], setResults = _d[1];
501
+ var _e = useState(false), error = _e[0], setError = _e[1];
502
+ // Runs a load, recording its results, or else that it failed
503
+ var load = function (fetchResults) { return __awaiter(void 0, void 0, void 0, function () {
504
+ var _a, e_1;
505
+ return __generator(this, function (_b) {
506
+ switch (_b.label) {
507
+ case 0:
508
+ setLoading(true);
509
+ setError(false);
510
+ _b.label = 1;
511
+ case 1:
512
+ _b.trys.push([1, 3, , 4]);
513
+ _a = setResults;
514
+ return [4 /*yield*/, fetchResults()];
515
+ case 2:
516
+ _a.apply(void 0, [_b.sent()]);
517
+ return [3 /*break*/, 4];
518
+ case 3:
519
+ e_1 = _b.sent();
520
+ console.error("Failed to load iNaturalist data", e_1);
521
+ setResults([]);
522
+ setError(true);
523
+ return [3 /*break*/, 4];
524
+ case 4:
525
+ setLoading(false);
526
+ return [2 /*return*/];
527
+ }
528
+ });
529
+ }); };
451
530
  useEffect(function () {
452
531
  if (source === DataSourceEnum.autoLoad) {
453
- if (!taxonId) {
454
- console.error("Please supply a `taxonId` prop for the `autoLoad` source prop option.");
532
+ // A project brings its own taxa and places, so that it may be supplied in place of both
533
+ if (!projectId && !taxonId) {
534
+ console.error("Please supply a `taxonId` or `projectId` prop for the `autoLoad` source prop option.");
455
535
  return;
456
536
  }
457
- if (!placeId) {
458
- console.error("Please supply a `placeId` prop for the `autoLoad` source prop option.");
537
+ if (!projectId && !placeId) {
538
+ console.error("Please supply a `placeId` or `projectId` prop for the `autoLoad` source prop option.");
459
539
  return;
460
540
  }
461
- (function () { return __awaiter(void 0, void 0, void 0, function () {
541
+ // note that `year` isn't used for recentObservations, but we pass it anyway to get more reusability out
542
+ // of this hook
543
+ load(function () { return __awaiter(void 0, void 0, void 0, function () {
462
544
  var obs;
463
545
  return __generator(this, function (_a) {
464
546
  switch (_a.label) {
465
- case 0:
466
- setLoading(true);
467
- return [4 /*yield*/, action({ taxonId: taxonId, placeId: placeId, numResults: numResults, year: year })];
547
+ case 0: return [4 /*yield*/, action({ taxonId: taxonId, placeId: placeId, projectId: projectId, numResults: numResults, year: year })];
468
548
  case 1:
469
549
  obs = _a.sent();
470
- setResults(obs.results);
471
- setLoading(false);
472
- return [2 /*return*/];
550
+ return [2 /*return*/, obs.results];
473
551
  }
474
552
  });
475
- }); })();
553
+ }); });
476
554
  }
477
555
  if (source === DataSourceEnum.url) {
478
556
  if (!dataUrl) {
479
557
  console.error("Please supply a `dataUrl` prop for the `url` source prop option.");
480
558
  return;
481
559
  }
482
- (function () { return __awaiter(void 0, void 0, void 0, function () {
560
+ load(function () { return __awaiter(void 0, void 0, void 0, function () {
483
561
  var obs, json;
484
562
  return __generator(this, function (_a) {
485
563
  switch (_a.label) {
486
- case 0:
487
- setLoading(true);
488
- return [4 /*yield*/, fetch(dataUrl)];
564
+ case 0: return [4 /*yield*/, fetch(dataUrl)];
489
565
  case 1:
490
566
  obs = _a.sent();
567
+ if (!obs.ok) {
568
+ throw new Error("".concat(dataUrl, " returned ").concat(obs.status));
569
+ }
491
570
  return [4 /*yield*/, obs.json()];
492
571
  case 2:
493
572
  json = _a.sent();
494
573
  // hack workaround. Better solution would have been to standardize the JSON structure at the top-level
495
- if (isSummaryData) {
496
- setResults(json);
497
- }
498
- else {
499
- setResults(json.results);
500
- }
501
- setLoading(false);
502
- return [2 /*return*/];
574
+ return [2 /*return*/, isSummaryData ? json : json.results];
503
575
  }
504
576
  });
505
- }); })();
577
+ }); });
506
578
  }
507
- }, [source, dataUrl, taxonId, placeId, year, numResults, isSummaryData]);
579
+ }, [source, dataUrl, taxonId, placeId, projectId, year, numResults, isSummaryData]);
508
580
  return {
509
581
  loading: loading,
510
- results: results
582
+ results: results,
583
+ error: error
511
584
  };
512
585
  };
513
586
 
514
587
  var RecentObservationLabel = function (obs) {
515
588
  var _a, _b, _c;
516
- return (jsxs("div", __assign({ className: styles$3.obsLabel }, { children: [jsx("h3", __assign({ className: (_a = obs.classes) === null || _a === void 0 ? void 0 : _a.observationLabelTitle }, { children: obs.taxonCommonName || obs.taxonName })), jsx("div", __assign({ className: (_b = obs.classes) === null || _b === void 0 ? void 0 : _b.observationLabelDate }, { children: formatDate(obs.obsDate) })), jsx("div", __assign({ className: (_c = obs.classes) === null || _c === void 0 ? void 0 : _c.observationLabelName }, { children: jsx("a", __assign({ href: "".concat(BASE_URL, "/people/").concat(obs.observerUsername), target: "_blank", rel: "noreferrer", onClick: function (e) { return e.stopPropagation(); } }, { children: obs.observerUsername })) }))] })));
589
+ return (jsxs("div", __assign({ className: styles$4.obsLabel }, { children: [jsx("h3", __assign({ className: (_a = obs.classes) === null || _a === void 0 ? void 0 : _a.observationLabelTitle }, { children: obs.taxonCommonName || obs.taxonName })), jsx("div", __assign({ className: (_b = obs.classes) === null || _b === void 0 ? void 0 : _b.observationLabelDate }, { children: formatDate(obs.obsDate) })), jsx("div", __assign({ className: (_c = obs.classes) === null || _c === void 0 ? void 0 : _c.observationLabelName }, { children: jsx("a", __assign({ href: "".concat(BASE_URL, "/people/").concat(obs.observerUsername), target: "_blank", rel: "noreferrer", onClick: function (e) { return e.stopPropagation(); } }, { children: obs.observerUsername })) }))] })));
517
590
  };
518
591
  var RecentObservations = function (_a) {
519
- var taxonId = _a.taxonId, placeId = _a.placeId, dataUrl = _a.dataUrl, components = _a.components, className = _a.className, generalClasses = _a.generalClasses, tabDesc = _a.tabDesc, _b = _a.source, source = _b === void 0 ? DataSourceEnum.autoLoad : _b, _c = _a.numResults, numResults = _c === void 0 ? NUM_RESULTS : _c, _d = _a.itemWidth, itemWidth = _d === void 0 ? DEFAULT_ITEM_WIDTH : _d;
592
+ var taxonId = _a.taxonId, placeId = _a.placeId, projectId = _a.projectId, dataUrl = _a.dataUrl, components = _a.components, className = _a.className, generalClasses = _a.generalClasses, tabDesc = _a.tabDesc, _b = _a.source, source = _b === void 0 ? DataSourceEnum.autoLoad : _b, _c = _a.numResults, numResults = _c === void 0 ? NUM_RESULTS : _c, _d = _a.itemWidth, itemWidth = _d === void 0 ? DEFAULT_ITEM_WIDTH : _d;
520
593
  var _e = useLoadSourceData({
521
594
  taxonId: taxonId,
522
595
  placeId: placeId,
596
+ projectId: projectId,
523
597
  numResults: numResults,
524
598
  dataUrl: dataUrl,
525
599
  source: source,
526
600
  action: getRecentObservations
527
- }), loading = _e.loading, observations = _e.results;
601
+ }), loading = _e.loading, observations = _e.results, error = _e.error;
528
602
  var Load = (components === null || components === void 0 ? void 0 : components.loader) ? components.loader : Loader;
603
+ var ErrorMessage = (components === null || components === void 0 ? void 0 : components.error) ? components.error : LoadError;
529
604
  var Label = (components === null || components === void 0 ? void 0 : components.label) ? components.label : RecentObservationLabel;
530
- var componentClasses = styles$3.panel;
605
+ var componentClasses = styles$4.panel;
531
606
  if (className) {
532
607
  componentClasses += " ".concat(className);
533
608
  }
534
- var descClasses = styles$3.tabDesc;
609
+ var descClasses = styles$4.tabDesc;
535
610
  if (generalClasses === null || generalClasses === void 0 ? void 0 : generalClasses.tabDesc) {
536
611
  descClasses += " ".concat(generalClasses.tabDesc);
537
612
  }
538
- return (jsxs("div", __assign({ className: componentClasses }, { children: [tabDesc && jsx("p", __assign({ className: descClasses }, { children: tabDesc })), jsx(Load, { loading: loading }), jsxs("div", __assign({ className: styles$3.grid, style: { gridTemplateColumns: "repeat(auto-fit, minmax(".concat(itemWidth, "px, 1fr))") } }, { children: [!loading && observations.length === 0 && jsx(NoResults, {}), observations.map(function (obs) { return (jsx(Observation, __assign({ imageUrl: obs.imageUrl.replace(/square/, "medium"), itemWidth: itemWidth, linkUrl: obs.obsUrl }, { children: jsx(Label, __assign({}, obs, { classes: generalClasses })) }), obs.id)); })] }))] })));
613
+ return (jsxs("div", __assign({ className: componentClasses }, { children: [tabDesc && jsx("p", __assign({ className: descClasses }, { children: tabDesc })), jsx(Load, { loading: loading }), jsxs("div", __assign({ className: styles$4.grid, style: { gridTemplateColumns: gridColumns(itemWidth) } }, { children: [error && jsx(ErrorMessage, {}), !loading && !error && observations.length === 0 && jsx(NoResults, {}), observations.map(function (obs) { return (jsx(Observation, __assign({ imageUrl: obs.imageUrl.replace(/square/, "medium"), linkUrl: obs.obsUrl }, { children: jsx(Label, __assign({}, obs, { classes: generalClasses })) }), obs.id)); })] }))] })));
539
614
  };
540
615
 
541
616
  var CommonTaxaLabel = function (data) {
542
617
  var _a, _b;
543
- return (jsxs("div", __assign({ className: styles$3.obsLabel }, { children: [jsx("h3", __assign({ className: (_a = data.classes) === null || _a === void 0 ? void 0 : _a.observationLabelTitle }, { children: data.taxonCommonName || data.taxonName })), jsx("label", __assign({ className: "".concat(((_b = data.classes) === null || _b === void 0 ? void 0 : _b.observationCount) || '', " ").concat(styles$3.count) }, { children: numberWithCommas(data.obsCount) }))] })));
618
+ return (jsxs("div", __assign({ className: styles$4.obsLabel }, { children: [jsx("h3", __assign({ className: (_a = data.classes) === null || _a === void 0 ? void 0 : _a.observationLabelTitle }, { children: data.taxonCommonName || data.taxonName })), jsx("label", __assign({ className: "".concat(((_b = data.classes) === null || _b === void 0 ? void 0 : _b.observationCount) || '', " ").concat(styles$4.count) }, { children: numberWithCommas(data.obsCount) }))] })));
544
619
  };
545
620
  var CommonTaxa = function (_a) {
546
- var year = _a.year, source = _a.source, taxonId = _a.taxonId, placeId = _a.placeId, _b = _a.numResults, numResults = _b === void 0 ? NUM_RESULTS : _b, _c = _a.itemWidth, itemWidth = _c === void 0 ? DEFAULT_ITEM_WIDTH : _c, dataUrl = _a.dataUrl, components = _a.components, generalClasses = _a.generalClasses, className = _a.className, tabDesc = _a.tabDesc;
621
+ var year = _a.year, source = _a.source, taxonId = _a.taxonId, placeId = _a.placeId, projectId = _a.projectId, _b = _a.numResults, numResults = _b === void 0 ? NUM_RESULTS : _b, _c = _a.itemWidth, itemWidth = _c === void 0 ? DEFAULT_ITEM_WIDTH : _c, dataUrl = _a.dataUrl, components = _a.components, generalClasses = _a.generalClasses, className = _a.className, tabDesc = _a.tabDesc;
547
622
  var _d = useLoadSourceData({
548
623
  taxonId: taxonId,
549
624
  placeId: placeId,
625
+ projectId: projectId,
550
626
  numResults: numResults,
551
627
  dataUrl: dataUrl,
552
628
  source: source,
553
629
  year: year,
554
630
  action: getCommonTaxa
555
- }), loading = _d.loading, taxa = _d.results;
631
+ }), loading = _d.loading, taxa = _d.results, error = _d.error;
556
632
  var Load = (components === null || components === void 0 ? void 0 : components.loader) ? components.loader : Loader;
633
+ var ErrorMessage = (components === null || components === void 0 ? void 0 : components.error) ? components.error : LoadError;
557
634
  var Label = (components === null || components === void 0 ? void 0 : components.label) ? components.label : CommonTaxaLabel;
558
- var elClasses = styles$3.panel;
635
+ var elClasses = styles$4.panel;
559
636
  if (className) {
560
637
  elClasses += " ".concat(className);
561
638
  }
562
- var descClasses = styles$3.tabDesc;
639
+ var descClasses = styles$4.tabDesc;
563
640
  if (generalClasses === null || generalClasses === void 0 ? void 0 : generalClasses.tabDesc) {
564
641
  descClasses += " ".concat(generalClasses.tabDesc);
565
642
  }
566
- return (jsxs("div", __assign({ className: elClasses }, { children: [tabDesc && jsx("p", __assign({ className: descClasses }, { children: tabDesc })), jsx(Load, { loading: loading }), !loading && taxa.length === 0 && jsx(NoResults, {}), jsx("div", __assign({ className: styles$3.grid, style: { gridTemplateColumns: "repeat(auto-fit, minmax(".concat(itemWidth, "px, 1fr))") } }, { children: taxa.map(function (data) { return (jsx(Observation, __assign({ imageUrl: data.imageUrl.replace(/square/, "medium"), itemWidth: itemWidth, linkUrl: "".concat(BASE_URL, "/").concat(data.id) }, { children: jsx(Label, __assign({}, data, { classes: generalClasses })) }), data.id)); }) }))] })));
643
+ return (jsxs("div", __assign({ className: elClasses }, { children: [tabDesc && jsx("p", __assign({ className: descClasses }, { children: tabDesc })), jsx(Load, { loading: loading }), error && jsx(ErrorMessage, {}), !loading && !error && taxa.length === 0 && jsx(NoResults, {}), jsx("div", __assign({ className: styles$4.grid, style: { gridTemplateColumns: gridColumns(itemWidth) } }, { children: taxa.map(function (data) { return (jsx(Observation, __assign({ imageUrl: data.imageUrl.replace(/square/, "medium"), linkUrl: "".concat(BASE_URL, "/taxa/").concat(data.id) }, { children: jsx(Label, __assign({}, data, { classes: generalClasses })) }), data.id)); }) }))] })));
567
644
  };
568
645
 
569
646
  var FavouritesLabel = function (data) {
570
647
  var _a, _b, _c, _d;
571
- return (jsxs("div", __assign({ className: styles$3.obsLabel }, { children: [jsx("h3", __assign({ className: (_a = data.classes) === null || _a === void 0 ? void 0 : _a.observationLabelTitle }, { children: data.taxonCommonName || data.taxonName })), jsx("div", __assign({ className: (_b = data.classes) === null || _b === void 0 ? void 0 : _b.observationLabelTitle }, { children: data.observerUsername })), jsx("div", __assign({ className: (_c = data.classes) === null || _c === void 0 ? void 0 : _c.observationLabelDate }, { children: formatDate(data.obsDate) })), jsx("label", __assign({ className: "".concat(((_d = data.classes) === null || _d === void 0 ? void 0 : _d.observationCount) || '', " ").concat(styles$3.count) }, { children: data.numFaves }))] })));
648
+ return (jsxs("div", __assign({ className: styles$4.obsLabel }, { children: [jsx("h3", __assign({ className: (_a = data.classes) === null || _a === void 0 ? void 0 : _a.observationLabelTitle }, { children: data.taxonCommonName || data.taxonName })), jsx("div", __assign({ className: (_b = data.classes) === null || _b === void 0 ? void 0 : _b.observationLabelName }, { children: data.observerUsername })), jsx("div", __assign({ className: (_c = data.classes) === null || _c === void 0 ? void 0 : _c.observationLabelDate }, { children: formatDate(data.obsDate) })), jsx("label", __assign({ className: "".concat(((_d = data.classes) === null || _d === void 0 ? void 0 : _d.observationCount) || '', " ").concat(styles$4.count) }, { children: data.numFaves }))] })));
572
649
  };
573
650
  var Favourites = function (_a) {
574
- var year = _a.year, source = _a.source, taxonId = _a.taxonId, placeId = _a.placeId, dataUrl = _a.dataUrl, components = _a.components, className = _a.className, tabDesc = _a.tabDesc, generalClasses = _a.generalClasses, _b = _a.itemWidth, itemWidth = _b === void 0 ? DEFAULT_ITEM_WIDTH : _b, _c = _a.numResults, numResults = _c === void 0 ? NUM_RESULTS : _c;
651
+ var year = _a.year, source = _a.source, taxonId = _a.taxonId, placeId = _a.placeId, projectId = _a.projectId, dataUrl = _a.dataUrl, components = _a.components, className = _a.className, tabDesc = _a.tabDesc, generalClasses = _a.generalClasses, _b = _a.itemWidth, itemWidth = _b === void 0 ? DEFAULT_ITEM_WIDTH : _b, _c = _a.numResults, numResults = _c === void 0 ? NUM_RESULTS : _c;
575
652
  var _d = useLoadSourceData({
576
653
  year: year,
577
654
  taxonId: taxonId,
578
655
  placeId: placeId,
656
+ projectId: projectId,
579
657
  numResults: numResults,
580
658
  dataUrl: dataUrl,
581
659
  source: source,
582
660
  action: getFavourites
583
- }), loading = _d.loading, observations = _d.results;
661
+ }), loading = _d.loading, observations = _d.results, error = _d.error;
584
662
  var Load = (components === null || components === void 0 ? void 0 : components.loader) ? components.loader : Loader;
663
+ var ErrorMessage = (components === null || components === void 0 ? void 0 : components.error) ? components.error : LoadError;
585
664
  var Label = (components === null || components === void 0 ? void 0 : components.label) ? components.label : FavouritesLabel;
586
- var elClasses = styles$3.panel;
665
+ var elClasses = styles$4.panel;
587
666
  if (className) {
588
667
  elClasses += " ".concat(className);
589
668
  }
590
- var descClasses = styles$3.tabDesc;
669
+ var descClasses = styles$4.tabDesc;
591
670
  if (generalClasses === null || generalClasses === void 0 ? void 0 : generalClasses.tabDesc) {
592
671
  descClasses += " ".concat(generalClasses.tabDesc);
593
672
  }
594
- return (jsxs("div", __assign({ className: elClasses }, { children: [tabDesc && jsx("p", __assign({ className: descClasses }, { children: tabDesc })), jsx(Load, { loading: loading }), !loading && observations.length === 0 && jsx(NoResults, {}), jsx("div", __assign({ className: styles$3.grid, style: { gridTemplateColumns: "repeat(auto-fit, minmax(".concat(itemWidth, "px, 1fr))") } }, { children: observations.map(function (obs) { return (jsx(Observation, __assign({ imageUrl: obs.imageUrl.replace(/square/, "medium"), itemWidth: itemWidth, linkUrl: obs.obsUrl }, { children: jsx(Label, __assign({}, obs, { classes: generalClasses })) }), obs.id)); }) }))] })));
673
+ return (jsxs("div", __assign({ className: elClasses }, { children: [tabDesc && jsx("p", __assign({ className: descClasses }, { children: tabDesc })), jsx(Load, { loading: loading }), error && jsx(ErrorMessage, {}), !loading && !error && observations.length === 0 && jsx(NoResults, {}), jsx("div", __assign({ className: styles$4.grid, style: { gridTemplateColumns: gridColumns(itemWidth) } }, { children: observations.map(function (obs) { return (jsx(Observation, __assign({ imageUrl: obs.imageUrl.replace(/square/, "medium"), linkUrl: obs.obsUrl }, { children: jsx(Label, __assign({}, obs, { classes: generalClasses })) }), obs.id)); }) }))] })));
595
674
  };
596
675
 
597
- var css_248z$2 = ".summary-module_summaryPage__NMmsj {\n position: relative;\n}\n.summary-module_summaryPage__NMmsj section {\n display: flex;\n}\n\n.summary-module_top__TKW0j {\n list-style-type: none;\n margin: 0;\n padding: 0;\n}\n.summary-module_top__TKW0j .summary-module_avatar__16ZeD, .summary-module_top__TKW0j .summary-module_noAvatar__OsMWn {\n margin-right: 10px;\n border-radius: 20px;\n width: 40px;\n height: 40px;\n}\n.summary-module_top__TKW0j .summary-module_noAvatar__OsMWn {\n display: inline-block;\n background-color: #efefef;\n}\n.summary-module_top__TKW0j h3 {\n flex: 1;\n color: black;\n}\n.summary-module_top__TKW0j label {\n flex: 0;\n background-color: #efefef;\n color: #666666;\n padding: 2px 8px;\n margin-top: 6px;\n border-radius: 3px;\n font-weight: bold;\n font-size: 16px;\n}\n.summary-module_top__TKW0j li {\n border-radius: 3px;\n}\n.summary-module_top__TKW0j li a {\n display: flex;\n align-items: center;\n text-decoration: none;\n}\n.summary-module_top__TKW0j li:hover {\n background-color: #efefef;\n}\n\n.summary-module_countSummary__Xc2Kd {\n list-style-type: none;\n line-height: 28px;\n font-size: 16px;\n padding: 0;\n margin: 0 0 30px;\n}\n\n.summary-module_seasonalityBlock__BL8L- {\n flex: 3;\n}\n\n.summary-module_observersBlock__0wnbm {\n flex: 1;\n margin-left: 40px;\n margin-bottom: -40px;\n}\n\n@media screen and (max-width: 800px) {\n .summary-module_summaryPage__NMmsj section {\n display: block;\n }\n .summary-module_seasonalityBlock__BL8L- {\n height: 250px;\n margin-bottom: 80px;\n }\n .summary-module_observersBlock__0wnbm {\n margin-left: 0;\n }\n}";
598
- var styles$2 = {"summaryPage":"summary-module_summaryPage__NMmsj","top":"summary-module_top__TKW0j","avatar":"summary-module_avatar__16ZeD","noAvatar":"summary-module_noAvatar__OsMWn","countSummary":"summary-module_countSummary__Xc2Kd","seasonalityBlock":"summary-module_seasonalityBlock__BL8L-","observersBlock":"summary-module_observersBlock__0wnbm"};
676
+ var css_248z$2 = ".summary-module_summaryPage__zFqlS {\n position: relative;\n}\n.summary-module_summaryPage__zFqlS section {\n display: flex;\n}\n\n.summary-module_top__IGZ10 {\n list-style-type: none;\n margin: 0;\n padding: 0;\n}\n.summary-module_top__IGZ10 .summary-module_avatar__tmqK8, .summary-module_top__IGZ10 .summary-module_noAvatar__3Z4-0 {\n margin-right: 10px;\n border-radius: 20px;\n width: 40px;\n height: 40px;\n}\n\n.summary-module_top__IGZ10 .summary-module_noAvatar__3Z4-0 {\n display: inline-block;\n background-color: #efefef;\n}\n\n.summary-module_top__IGZ10 h3 {\n flex: 1;\n color: black;\n}\n\n.summary-module_top__IGZ10 label {\n flex: 0;\n background-color: #efefef;\n color: #666666;\n padding: 2px 8px;\n margin-top: 6px;\n border-radius: 3px;\n font-weight: bold;\n font-size: 16px;\n}\n\n.summary-module_top__IGZ10 li {\n border-radius: 3px;\n}\n.summary-module_top__IGZ10 li a {\n display: flex;\n align-items: center;\n text-decoration: none;\n}\n\n.summary-module_top__IGZ10 li:hover {\n background-color: #efefef;\n}\n\n.summary-module_countSummary__XQyps {\n list-style-type: none;\n line-height: 28px;\n font-size: 16px;\n padding: 0;\n margin: 0 0 30px;\n}\n\n/* The chart fills the height left to it in its block, which must have a height of its own. Its month labels are\n rotated, and drawn beyond the chart's height, which leaves room for them beneath it */\n.summary-module_seasonalityBlock__zUmrb {\n flex: 3;\n display: flex;\n flex-direction: column;\n height: 500px;\n box-sizing: border-box;\n}\n\n.summary-module_chart__B8Ysr {\n flex: 1 1 0;\n min-height: 0;\n margin-bottom: 80px;\n}\n\n.summary-module_observersBlock__pQW1h {\n flex: 1;\n margin-left: 40px;\n margin-bottom: -40px;\n}\n\n@media screen and (max-width: 800px) {\n .summary-module_summaryPage__zFqlS section {\n display: block;\n }\n .summary-module_seasonalityBlock__zUmrb {\n height: 330px;\n }\n .summary-module_observersBlock__pQW1h {\n margin-left: 0;\n }\n}\n";
677
+ var styles$2 = {"summaryPage":"summary-module_summaryPage__zFqlS","top":"summary-module_top__IGZ10","avatar":"summary-module_avatar__tmqK8","noAvatar":"summary-module_noAvatar__3Z4-0","countSummary":"summary-module_countSummary__XQyps","seasonalityBlock":"summary-module_seasonalityBlock__zUmrb","chart":"summary-module_chart__B8Ysr","observersBlock":"summary-module_observersBlock__pQW1h"};
599
678
  styleInject(css_248z$2);
600
679
 
601
680
  var ObserverList = function (_a) {
@@ -637,28 +716,34 @@ var SeasonalityGraph = function (_a) {
637
716
 
638
717
  var Summary = function (_a) {
639
718
  var _b, _c, _d;
640
- var source = _a.source, dataUrl = _a.dataUrl, taxonId = _a.taxonId, placeId = _a.placeId, year = _a.year, generalClasses = _a.generalClasses, className = _a.className, tabDesc = _a.tabDesc, observersListClass = _a.observersListClass, statsCountSummaryClass = _a.statsCountSummaryClass;
641
- var _e = useLoadSourceData({
719
+ var source = _a.source, dataUrl = _a.dataUrl, taxonId = _a.taxonId, placeId = _a.placeId, projectId = _a.projectId, year = _a.year, generalClasses = _a.generalClasses, className = _a.className, tabDesc = _a.tabDesc, observersListClass = _a.observersListClass, statsCountSummaryClass = _a.statsCountSummaryClass, _e = _a.numTopObservers, numTopObservers = _e === void 0 ? DEFAULT_NUM_TOP_OBSERVERS : _e, components = _a.components;
720
+ var _f = useLoadSourceData({
642
721
  year: year,
643
722
  taxonId: taxonId,
644
723
  placeId: placeId,
724
+ projectId: projectId,
645
725
  dataUrl: dataUrl,
646
726
  source: source,
727
+ // The hook passes this on to the action as `numResults`
728
+ numResults: numTopObservers,
647
729
  isSummaryData: true,
648
730
  // shim to standardize the response from the `action` method with a top-level `results` property. This
649
731
  // just lets the useLoadSourceData hook work for all tab components
650
- action: function (data) { return __awaiter(void 0, void 0, void 0, function () {
732
+ action: function (_a) { return __awaiter(void 0, void 0, void 0, function () {
651
733
  var results;
652
- return __generator(this, function (_a) {
653
- switch (_a.label) {
654
- case 0: return [4 /*yield*/, getSummary(data)];
734
+ var numResults = _a.numResults, data = __rest(_a, ["numResults"]);
735
+ return __generator(this, function (_b) {
736
+ switch (_b.label) {
737
+ case 0: return [4 /*yield*/, getSummary(__assign(__assign({}, data), { numTopObservers: numResults }))];
655
738
  case 1:
656
- results = _a.sent();
739
+ results = _b.sent();
657
740
  return [2 /*return*/, { results: results }];
658
741
  }
659
742
  });
660
743
  }); }
661
- }), loading = _e.loading, summaryData = _e.results;
744
+ }), loading = _f.loading, summaryData = _f.results, error = _f.error;
745
+ var Load = (components === null || components === void 0 ? void 0 : components.loader) ? components.loader : Loader;
746
+ var ErrorMessage = (components === null || components === void 0 ? void 0 : components.error) ? components.error : LoadError;
662
747
  var countSummaryClasses = styles$2.countSummary;
663
748
  if (statsCountSummaryClass) {
664
749
  countSummaryClasses += " ".concat(statsCountSummaryClass);
@@ -671,11 +756,11 @@ var Summary = function (_a) {
671
756
  if (className) {
672
757
  classList += " ".concat(className);
673
758
  }
674
- return (jsxs("div", __assign({ className: classList }, { children: [tabDesc && jsx("p", __assign({ className: descClasses }, { children: tabDesc })), jsx(Loader, { loading: loading }), jsxs("ul", __assign({ className: countSummaryClasses }, { children: [jsxs("li", { children: ["Total number of observers: ", jsx("b", { children: ((_b = summaryData.observers) === null || _b === void 0 ? void 0 : _b.totalCount) ? numberWithCommas(summaryData.observers.totalCount) : "" })] }), jsxs("li", { children: ["Total number of observations: ", jsx("b", { children: ((_c = summaryData.observations) === null || _c === void 0 ? void 0 : _c.totalCount) ? numberWithCommas(summaryData.observations.totalCount) : "" })] })] })), jsxs("section", { children: [jsxs("div", __assign({ className: styles$2.seasonalityBlock }, { children: [jsx("h1", { children: "Seasonality" }), summaryData.seasonalityData && jsx(SeasonalityGraph, { data: summaryData.seasonalityData.monthOfYear })] })), jsxs("div", __assign({ className: styles$2.observersBlock }, { children: [jsx("h1", { children: "Top observers" }), ((_d = summaryData.observers) === null || _d === void 0 ? void 0 : _d.top) && (jsx(ObserverList, { observers: summaryData.observers.top, className: observersListClass, generalClasses: generalClasses }))] }))] })] })));
759
+ return (jsxs("div", __assign({ className: classList }, { children: [tabDesc && jsx("p", __assign({ className: descClasses }, { children: tabDesc })), jsx(Load, { loading: loading }), error && jsx(ErrorMessage, {}), jsxs("ul", __assign({ className: countSummaryClasses }, { children: [jsxs("li", { children: ["Total number of observers: ", jsx("b", { children: ((_b = summaryData.observers) === null || _b === void 0 ? void 0 : _b.totalCount) ? numberWithCommas(summaryData.observers.totalCount) : "" })] }), jsxs("li", { children: ["Total number of observations: ", jsx("b", { children: ((_c = summaryData.observations) === null || _c === void 0 ? void 0 : _c.totalCount) ? numberWithCommas(summaryData.observations.totalCount) : "" })] })] })), jsxs("section", { children: [jsxs("div", __assign({ className: styles$2.seasonalityBlock }, { children: [jsx("h1", { children: "Seasonality" }), jsx("div", __assign({ className: styles$2.chart }, { children: summaryData.seasonalityData && jsx(SeasonalityGraph, { data: summaryData.seasonalityData.monthOfYear }) }))] })), jsxs("div", __assign({ className: styles$2.observersBlock }, { children: [jsx("h1", { children: "Top observers" }), ((_d = summaryData.observers) === null || _d === void 0 ? void 0 : _d.top) && (jsx(ObserverList, { observers: summaryData.observers.top, className: observersListClass, generalClasses: generalClasses }))] }))] })] })));
675
760
  };
676
761
 
677
- var css_248z$1 = ".year-dropdown-module_dropdown__iD9sj {\n font-size: 18px;\n}";
678
- var styles$1 = {"dropdown":"year-dropdown-module_dropdown__iD9sj"};
762
+ var css_248z$1 = ".year-dropdown-module_dropdown__hKFwD {\n font-size: 18px;\n}\n";
763
+ var styles$1 = {"dropdown":"year-dropdown-module_dropdown__hKFwD"};
679
764
  styleInject(css_248z$1);
680
765
 
681
766
  var Years = function (_a) {
@@ -696,8 +781,8 @@ var Years = function (_a) {
696
781
  return (jsxs("select", __assign({ className: classes, onChange: function (e) { return onChange(e.target.value); }, defaultValue: value }, { children: [jsx("option", __assign({ value: "all" }, { children: "All years" })), years.map(function (year) { return jsx("option", __assign({ value: year }, { children: year }), year); })] })));
697
782
  };
698
783
 
699
- var css_248z = ".tabs-module_tabs__UMeM9 {\n display: flex;\n flex-direction: row;\n list-style: none;\n font-size: 18px;\n padding: 0;\n margin-bottom: 30px;\n}\n.tabs-module_tabs__UMeM9 li {\n margin: 0 20px;\n padding: 4px 20px;\n cursor: pointer;\n color: #999999;\n transition: all 0.2s ease-in-out;\n}\n.tabs-module_tabs__UMeM9 li.tabs-module_selected__SVr0E, .tabs-module_tabs__UMeM9 li:hover {\n border-bottom: 5px solid #0099cc;\n color: black;\n}\n\n@media screen and (max-width: 600px) {\n .tabs-module_tabs__UMeM9 li {\n margin: 0 5px;\n padding: 4px 6px;\n }\n}";
700
- var styles = {"tabs":"tabs-module_tabs__UMeM9","selected":"tabs-module_selected__SVr0E"};
784
+ var css_248z = ".tabs-module_tabs__vVmY7 {\n display: flex;\n flex-direction: row;\n list-style: none;\n font-size: 18px;\n padding: 0;\n margin-bottom: 30px;\n}\n.tabs-module_tabs__vVmY7 li {\n margin: 0 20px;\n padding: 4px 20px;\n cursor: pointer;\n color: #999999;\n /* Every tab bears the border which marks the selected one, so that selecting or hovering over a tab moves nothing */\n border-bottom: 5px solid transparent;\n transition: all 0.2s ease-in-out;\n}\n.tabs-module_tabs__vVmY7 li.tabs-module_selected__-yd68, .tabs-module_tabs__vVmY7 li:hover {\n border-bottom-color: #0099cc;\n color: black;\n}\n\n@media screen and (max-width: 600px) {\n .tabs-module_tabs__vVmY7 li {\n margin: 0 5px;\n padding: 4px 6px;\n }\n}\n";
785
+ var styles = {"tabs":"tabs-module_tabs__vVmY7","selected":"tabs-module_selected__-yd68"};
701
786
  styleInject(css_248z);
702
787
 
703
788
  var _a;
@@ -707,20 +792,22 @@ var defaultTitles = (_a = {},
707
792
  _a[Feature.favourites] = "Most favourited",
708
793
  _a[Feature.stats] = "General stats",
709
794
  _a);
710
- var useFeatureTitles = function (features) {
711
- var _a = useState(defaultTitles), titles = _a[0], setTitles = _a[1];
712
- useEffect(function () {
713
- var _a;
714
- var _b, _c, _d, _e;
715
- setTitles((_a = {},
716
- _a[Feature.recentObservations] = ((_b = features.recentObservations) === null || _b === void 0 ? void 0 : _b.title) || defaultTitles[Feature.recentObservations],
717
- _a[Feature.commonTaxa] = ((_c = features.commonTaxa) === null || _c === void 0 ? void 0 : _c.title) || defaultTitles[Feature.commonTaxa],
718
- _a[Feature.favourites] = ((_d = features.favourites) === null || _d === void 0 ? void 0 : _d.title) || defaultTitles[Feature.favourites],
719
- _a[Feature.stats] = ((_e = features.stats) === null || _e === void 0 ? void 0 : _e.title) || defaultTitles[Feature.stats],
720
- _a));
721
- }, [features]);
722
- return titles;
723
- };
795
+ /**
796
+ * The title of each feature - its own `title`, or the default.
797
+ * @param features - The features, as TaxonPanel's array of them, or as an object keyed by feature
798
+ * @return The titles, keyed by feature
799
+ */
800
+ var useFeatureTitles = function (features) { return useMemo(function () {
801
+ var _a;
802
+ var _b, _c, _d, _e;
803
+ var byFeature = Array.isArray(features) ? convertFeaturesToObj(features) : features;
804
+ return _a = {},
805
+ _a[Feature.recentObservations] = ((_b = byFeature.recentObservations) === null || _b === void 0 ? void 0 : _b.title) || defaultTitles[Feature.recentObservations],
806
+ _a[Feature.commonTaxa] = ((_c = byFeature.commonTaxa) === null || _c === void 0 ? void 0 : _c.title) || defaultTitles[Feature.commonTaxa],
807
+ _a[Feature.favourites] = ((_d = byFeature.favourites) === null || _d === void 0 ? void 0 : _d.title) || defaultTitles[Feature.favourites],
808
+ _a[Feature.stats] = ((_e = byFeature.stats) === null || _e === void 0 ? void 0 : _e.title) || defaultTitles[Feature.stats],
809
+ _a;
810
+ }, [features]); };
724
811
  var convertFeaturesToObj = function (features) {
725
812
  var featuresObj = {};
726
813
  features.forEach(function (row) {
@@ -758,7 +845,7 @@ var Tabs = function (_a) {
758
845
 
759
846
  var TaxonPanel = function (_a) {
760
847
  var _b;
761
- var taxon = _a.taxon, place = _a.place, features = _a.features, dataSource = _a.dataSource, dataSourceBaseUrl = _a.dataSourceBaseUrl, itemWidth = _a.itemWidth, generalClasses = _a.generalClasses;
848
+ var taxon = _a.taxon, place = _a.place, project = _a.project, features = _a.features, dataSource = _a.dataSource, dataSourceBaseUrl = _a.dataSourceBaseUrl, itemWidth = _a.itemWidth, generalClasses = _a.generalClasses;
762
849
  var _c = useState(features[0].feature), tab = _c[0], setTab = _c[1];
763
850
  var _d = useState("all"), year = _d[0], setYear = _d[1];
764
851
  var featuresObj = useMemo(function () {
@@ -775,11 +862,12 @@ var TaxonPanel = function (_a) {
775
862
  className: (_b = featuresObj[feature]) === null || _b === void 0 ? void 0 : _b.className
776
863
  };
777
864
  if (dataSource === DataSourceEnum.url) {
778
- props.dataUrl = dataSourceBaseUrl + '/' + getSourceFile(feature, taxon, place, year);
865
+ props.dataUrl = dataSourceBaseUrl + '/' + getSourceFile(feature, taxon, place, year, project);
779
866
  }
780
867
  else {
781
- props.placeId = place.id;
782
- props.taxonId = taxon.id;
868
+ props.placeId = place === null || place === void 0 ? void 0 : place.id;
869
+ props.taxonId = taxon === null || taxon === void 0 ? void 0 : taxon.id;
870
+ props.projectId = project === null || project === void 0 ? void 0 : project.id;
783
871
  }
784
872
  if (feature !== Feature.stats) {
785
873
  props.numResults = (_c = featuresObj[feature]) === null || _c === void 0 ? void 0 : _c.numResults;
@@ -790,7 +878,7 @@ var TaxonPanel = function (_a) {
790
878
  return props;
791
879
  };
792
880
  var getCurrentTab = function () {
793
- var _a, _b;
881
+ var _a, _b, _c;
794
882
  switch (tab) {
795
883
  case Feature.recentObservations:
796
884
  return jsx(RecentObservations, __assign({}, getProps(Feature.recentObservations)));
@@ -799,12 +887,12 @@ var TaxonPanel = function (_a) {
799
887
  case Feature.favourites:
800
888
  return jsx(Favourites, __assign({}, getProps(Feature.favourites)));
801
889
  case Feature.stats:
802
- return (jsx(Summary, __assign({}, getProps(Feature.stats), { observersListClass: (_a = featuresObj[Feature.stats]) === null || _a === void 0 ? void 0 : _a.observersListClass, statsCountSummaryClass: (_b = featuresObj[Feature.stats]) === null || _b === void 0 ? void 0 : _b.statsCountSummaryClass })));
890
+ return (jsx(Summary, __assign({}, getProps(Feature.stats), { observersListClass: (_a = featuresObj[Feature.stats]) === null || _a === void 0 ? void 0 : _a.observersListClass, statsCountSummaryClass: (_b = featuresObj[Feature.stats]) === null || _b === void 0 ? void 0 : _b.statsCountSummaryClass, numTopObservers: (_c = featuresObj[Feature.stats]) === null || _c === void 0 ? void 0 : _c.numTopObservers })));
803
891
  }
804
892
  };
805
893
  var tabsClass = (generalClasses === null || generalClasses === void 0 ? void 0 : generalClasses.tabsElement) || '';
806
894
  var yearDropdownClass = (generalClasses === null || generalClasses === void 0 ? void 0 : generalClasses.yearsDropdown) || '';
807
- return (jsxs("div", __assign({ className: styles$3.page }, { children: [features.length > 1 && jsx(Tabs, { selectedTab: tab, onChangeTab: setTab, features: features, className: tabsClass }), jsxs("div", { children: [tab !== Feature.recentObservations && (jsx("div", __assign({ style: { float: "right" }, className: yearDropdownClass }, { children: jsx(Years, { value: year, numYears: ((_b = featuresObj[tab]) === null || _b === void 0 ? void 0 : _b.numYears) || DEFAULT_NUM_YEARS, onChange: setYear }) }))), jsx("h1", __assign({ className: generalClasses === null || generalClasses === void 0 ? void 0 : generalClasses.pageHeadings }, { children: titles[tab] }))] }), getCurrentTab()] })));
895
+ return (jsxs("div", __assign({ className: styles$4.page }, { children: [features.length > 1 && jsx(Tabs, { selectedTab: tab, onChangeTab: setTab, features: features, className: tabsClass }), jsxs("div", { children: [tab !== Feature.recentObservations && (jsx("div", __assign({ style: { float: "right" }, className: yearDropdownClass }, { children: jsx(Years, { value: year, numYears: ((_b = featuresObj[tab]) === null || _b === void 0 ? void 0 : _b.numYears) || DEFAULT_NUM_YEARS, onChange: setYear }) }))), jsx("h1", __assign({ className: generalClasses === null || generalClasses === void 0 ? void 0 : generalClasses.pageHeadings }, { children: titles[tab] }))] }), getCurrentTab()] })));
808
896
  };
809
897
 
810
- export { constants as C, CommonTaxa, CommonTaxaLabel, DataSourceEnum, Favourites, FavouritesLabel, Feature, Observation, RecentObservationLabel, RecentObservations, SeasonalityGraph, Summary, TaxonPanel as default, formatDate, getCommonTaxa, getCurrentYear, getFavourites, getObservationSummary, getObserverSummary, getRecentObservations, getSeasonalityData, getSourceFile, getSummary, numberWithCommas };
898
+ export { constants as C, CommonTaxa, CommonTaxaLabel, DataSourceEnum, Favourites, FavouritesLabel, Feature, Observation, RecentObservationLabel, RecentObservations, SeasonalityGraph, Summary, TaxonPanel as default, filterParams, formatDate, getCommonTaxa, getCurrentYear, getFavourites, getObservationSummary, getObserverSummary, getRecentObservations, getSeasonalityData, getSourceFile, getSummary, gridColumns, numberWithCommas };