Skip to content

Commit 2889cac

Browse files
authored
Merge pull request #76 from UW-Macrostrat/explore-style
Explore style
2 parents 374c974 + fc7381e commit 2889cac

File tree

7 files changed

+408
-281
lines changed

7 files changed

+408
-281
lines changed

.env.example

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ VITE_MACROSTRAT_API_DOMAIN='https://macrostrat.org'
66

77
VITE_ROCKD_API_URL='https://dev.rockd.org/api/v2/'
88

9-
# For matomo analytics
10-
VITE_MATOMO_API_URL='<our-matomo-api-url>'
11-
VITE_MATOMO_API_TOKEN='<your-matomo-api-token>'
12-
139
# Needed for map ingestion system
1410
# SECRET_KEY='Replace with api signing key'
1511

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"@macrostrat/mapbox-react": "^2.5.0",
5454
"@macrostrat/mapbox-utils": "^1.4.0",
5555
"@macrostrat/style-system": "^0.2.0",
56-
"@macrostrat/ui-components": "^4.1.2",
56+
"@macrostrat/ui-components": "^4.4.4",
5757
"@supabase/postgrest-js": "^1.11.0",
5858
"@universal-middleware/express": "^0.0.2",
5959
"@vitejs/plugin-react": "^4.0.4",

pages/explore/+Page.client.ts

Lines changed: 5 additions & 274 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { useMapRef } from "@macrostrat/mapbox-react";
2-
import { Spinner, Icon, Divider, Button } from "@blueprintjs/core";
2+
import { Spinner, Icon, Button } from "@blueprintjs/core";
33
import { SETTINGS } from "~/settings";
44
import {buildInspectorStyle } from "@macrostrat/map-interface";
55
import { buildMacrostratStyle } from "@macrostrat/map-styles";
66
import { mergeStyles } from "@macrostrat/mapbox-utils";
77
import { useDarkMode, DarkModeButton } from "@macrostrat/ui-components";
88
import mapboxgl from "mapbox-gl";
9-
import { useCallback, useEffect, useState, useMemo } from "react";
9+
import { useCallback, useEffect, useState } from "react";
1010
import h from "./main.module.sass";
1111
import { useRockdAPI, Image, pageCarousel, createCheckins } from "~/components";
1212
import "@macrostrat/style-system";
@@ -18,6 +18,9 @@ import {
1818
} from "@macrostrat/map-interface";
1919
import { mapboxAccessToken } from "~/settings";
2020

21+
import { AutoComplete } from "./autocomplete";
22+
import { deletePins } from "./utils";
23+
import { FeatureDetails } from "./featuredcheckins";
2124

2225
export function Page() {
2326
return h(
@@ -410,278 +413,6 @@ function createFilteredCheckins(filteredData, setInspectPosition) {
410413
return createCheckins(filteredData?.filteredData, mapRef, setInspectPosition);
411414
}
412415

413-
function AutoComplete({setFilteredData, autocompleteOpen, setAutocompleteOpen}) {
414-
const mapRef = useMapRef();
415-
const map = mapRef.current;
416-
const [input, setInput] = useState('');
417-
const [close, setClose] = useState(false);
418-
const [page, setPage] = useState(1);
419-
420-
// test
421-
const [peopleIds, setPeople] = useState([]);
422-
const [structures, setStructures] = useState([]);
423-
const [lithologyAttributes, setLithologyAttributes] = useState([]);
424-
const [stratNameOrphans, setStratNameOrphans] = useState([]);
425-
const [lithologyIds, setLithologies] = useState([]);
426-
// const [taxaIds, setTaxa] = useState([]); // fails
427-
// const [intervalIds, setIntervals] = useState([]); // fails
428-
// const [stratNameConcepts, setStratNameConcepts] = useState([]); // fails
429-
// const [minerals, setMinerals] = useState([]); // fails
430-
// const [lithologyTypes, setLithologyTypes] = useState([]); // doesn't exist
431-
// const [lithologyClasses, setLithologyClasses] = useState([]); // doesn't exist
432-
433-
const lithParam = "lith_id=" + lithologyIds.map(item => item.id).join(',');
434-
const peopleParam = "person_id=" + peopleIds.map(item => item.id).join(',');
435-
const stratNameOrphanParam = "strat_name_orphan_id=" + stratNameOrphans.map(item => item.id).join(',');
436-
const lithologyAttributeParam = "lith_att_id=" + lithologyAttributes.map(item => item.id).join(',');
437-
const structureParam = "structure_id=" + structures.map(item => item.id).join(',');
438-
// const taxaParam = "taxon_id=" + taxaIds.map(item => item.id).join(','); // fails
439-
// const intervalParam = "int_id=" + intervalIds.map(item => item.id).join(','); // fails
440-
// const stratNameConceptParam = "strat_name_concept_id=" + stratNameConcepts.map(item => item.id).join(','); // fails
441-
// const mineralParam = "mineral_id=" + minerals.map(item => item.id).join(','); // fails
442-
// const lithologyTypeParam = "=" + lithologyTypes.map(item => item.id).join(','); // doesn't exist
443-
// const lithologyClassParam = "=" + lithologyClasses.map(item => item.id).join(','); // doesn't exist
444-
445-
// develop query
446-
const finalParams = useMemo(() => {
447-
const params = [
448-
lithParam,
449-
peopleParam,
450-
lithologyAttributeParam,
451-
stratNameOrphanParam,
452-
structureParam
453-
].filter(param => /\d/.test(param));
454-
455-
return params.join('&');
456-
}, [lithologyIds, peopleIds, lithologyAttributes, stratNameOrphans, structures]);
457-
458-
const queryString = useMemo(() => {
459-
return finalParams ? `/protected/checkins?${finalParams}` : null;
460-
}, [finalParams]);
461-
462-
463-
// get data
464-
const data = useRockdAPI(queryString + "&page=" + page)?.success.data;
465-
const nextData = useRockdAPI(queryString + "&page=" + (page + 1))?.success.data;
466-
467-
// add markers for filtered checkins
468-
let coordinates = [];
469-
let lngs = [];
470-
let lats = [];
471-
472-
useEffect(() => {
473-
if(data && data.length > 0 && queryString) {
474-
setFilteredData({
475-
current: data,
476-
next: {
477-
data: nextData,
478-
page: page,
479-
setPage: setPage
480-
}
481-
});
482-
483-
data.forEach((checkin) => {
484-
coordinates.push([checkin.lng, checkin.lat]);
485-
lngs.push(checkin.lng);
486-
lats.push(checkin.lat);
487-
});
488-
489-
deletePins('.filtered_pin');
490-
491-
if (!close) {
492-
let stop = 0;
493-
coordinates.forEach((coord) => {
494-
stop++;
495-
// marker
496-
const el = document.createElement('div');
497-
el.className = 'filtered_pin';
498-
el.style.backgroundColor = 'green';
499-
el.style.borderRadius = '50%';
500-
el.style.border = '2px solid white';
501-
el.style.width = '15px';
502-
el.style.height = '15px';
503-
504-
// Create marker
505-
new mapboxgl.Marker(el)
506-
.setLngLat(coord)
507-
.addTo(map);
508-
});
509-
}
510-
511-
map.fitBounds([
512-
[ Math.max(...lngs), Math.max(...lats) ],
513-
[ Math.min(...lngs), Math.min(...lats) ]
514-
], {
515-
maxZoom: 12,
516-
duration: 0,
517-
padding: 75
518-
});
519-
} else {
520-
deletePins('.filtered_pin');
521-
522-
setFilteredData(null);
523-
}
524-
}, [data, nextData, queryString]);
525-
526-
// rest
527-
const handleInputChange = (event) => {
528-
setAutocompleteOpen(true);
529-
setInput(event.target.value);
530-
setClose(false);
531-
setPage(1);
532-
};
533-
534-
let result = null;
535-
536-
try {
537-
result = useRockdAPI("/autocomplete/" + input);
538-
} catch (e) {
539-
return null;
540-
}
541-
542-
let searchBar = h('div.search-bar', [
543-
h('input', { type: "text", placeholder: "Search name", onChange: handleInputChange }),
544-
h('div.x-icon', [
545-
h(Icon, { icon: "cross", onClick: () => {
546-
let input = document.querySelector('input');
547-
input.value = "";
548-
setAutocompleteOpen(false);
549-
setClose(true);
550-
setFilteredData(null);
551-
setPage(1);
552-
deletePins('.filtered_pin');
553-
}
554-
}),
555-
]),
556-
]);
557-
558-
const sectionConfigs = [
559-
{ label: 'People', data: peopleIds, setter: setPeople },
560-
{ label: 'Strat Name Orphans', data: stratNameOrphans, setter: setStratNameOrphans },
561-
{ label: 'Structures', data: structures, setter: setStructures },
562-
{ label: 'Lithologies', data: lithologyIds, setter: setLithologies },
563-
{ label: 'Lithology Attributes', data: lithologyAttributes, setter: setLithologyAttributes },
564-
// { label: 'Taxa', data: taxaIds, setter: setTaxa },
565-
// { label: 'Intervals', data: intervalIds, setter: setIntervals },
566-
// { label: 'Lithology Types', data: lithologyTypes, setter: setLithologyTypes },
567-
// { label: 'Lithology Classes', data: lithologyClasses, setter: setLithologyClasses },
568-
// { label: 'Strat Name Concepts', data: stratNameConcepts, setter: setStratNameConcepts },
569-
// { label: 'Minerals', data: minerals, setter: setMinerals },
570-
];
571-
572-
const sections = sectionConfigs
573-
.filter(({ data }) => data.length > 0)
574-
.map(({ label, data, setter }) =>
575-
h('div', [
576-
h('h3', label),
577-
createFilteredItems(data, setter, setPage)
578-
])
579-
);
580-
581-
const filterContainer = sections.length != 0 ? h("div.filter-container", [
582-
h('h2', "Filters"),
583-
h('ul', [
584-
sections
585-
]),
586-
]) : null;
587-
588-
if(!result || close) return h('div', {className: "autocomplete"}, [
589-
searchBar
590-
]);
591-
result = result.success.data;
592-
593-
let results;
594-
595-
if(autocompleteOpen) {
596-
const lithologies = renderSection("Lithologies", "lithologies", result?.lithologies, setLithologies, lithologyIds, setAutocompleteOpen);
597-
const strat_name_orphans = renderSection("Stratigraphic Name Orphans", "strat_name_orphans", result?.strat_name_orphans, setStratNameOrphans, stratNameOrphans, setAutocompleteOpen);
598-
const structures_items = renderSection("Structures", "structures", result?.structures, setStructures, structures, setAutocompleteOpen);
599-
const lithology_attributes = renderSection("Lithology Attributes", "lithology_attributes", result?.lithology_attributes, setLithologyAttributes, lithologyAttributes, setAutocompleteOpen);
600-
const people = renderSection("People", "people", result?.people, setPeople, peopleIds, setAutocompleteOpen);
601-
// sections commented out that don't work or don't exist
602-
// const intervals = renderSection("Intervals", "intervals", result?.intervals, setIntervals, intervalIds, setAutocompleteOpen);
603-
// const lithology_types = renderSection("Lithology Types", "lithology_types", result?.lithology_types, setLithologyTypes, lithologyTypes, setAutocompleteOpen);
604-
// const lithology_classes = renderSection("Lithology Classes", "lithology_classes", result?.lithology_classes, setLithologyClasses, lithologyClasses, setAutocompleteOpen);
605-
// const strat_name_concepts = renderSection("Stratigraphic Name Concepts", "strat_name_concepts", result?.strat_name_concepts, setStratNameConcepts, stratNameConcepts, setAutocompleteOpen);
606-
// const minerals_items = renderSection("Minerals", "minerals", result?.minerals, setMinerals, minerals, setAutocompleteOpen);
607-
// const taxa = renderSection("Taxa", "taxa", result?.taxa, setTaxa, taxaIds, setAutocompleteOpen);
608-
609-
// result
610-
results = h('div.results', [
611-
people,
612-
lithologies,
613-
lithology_attributes,
614-
strat_name_orphans,
615-
structures_items,
616-
// minerals_items,
617-
// taxa,
618-
// intervals,
619-
// strat_name_concepts,
620-
// lithology_types,
621-
// lithology_classes,
622-
]);
623-
}
624-
625-
/*
626-
useEffect(() => {
627-
setLithologyData(useRockdAPI("/proctected/checkins?lith_id=" + lithologies.map(item => item.id).join(',') + "&all=100"));
628-
}, [lithologies]);
629-
*/
630-
631-
const wrapper = h('div.autocomplete-wrapper', [
632-
filterContainer,
633-
results,
634-
]);
635-
636-
return h('div.autocomplete', [
637-
searchBar,
638-
wrapper,
639-
]);
640-
}
641-
642-
function createFilteredItems(arr, set, setPage) {
643-
return arr.map((item) => {
644-
return h("li.filter-item", [
645-
h('div', item.name),
646-
h(Icon, { className: 'red-cross', icon: "cross", style: {color: "red"}, onClick: () => {
647-
set(arr.filter((person) => person != item));
648-
setPage(1);
649-
}
650-
})
651-
])
652-
})
653-
}
654-
655-
function createFilteredNames(result, set, existing, setAutocompleteOpen) {
656-
return result.map((item) =>
657-
h('li', {
658-
onClick: () => {
659-
if (!existing.includes(item)) {
660-
setAutocompleteOpen(false);
661-
set(existing.concat([item]));
662-
}
663-
}
664-
}, item.name)
665-
)
666-
}
667-
668-
function deletePins(str) {
669-
let previous = document.querySelectorAll(str);
670-
previous.forEach((marker) => {
671-
marker.remove();
672-
});
673-
}
674-
675-
function renderSection(label, key, resultList, setFn, existingIds, setAutocompleteOpen) {
676-
return resultList?.length > 0
677-
? h(`div.${key}`, [
678-
h('h2', label),
679-
h('ul', createFilteredNames(resultList, setFn, existingIds, setAutocompleteOpen))
680-
])
681-
: null;
682-
}
683-
684-
685416
export function MapContainer({style, mapPosition, onSelectPosition, setSelectedCheckin, overlay}) {
686417
return h(
687418
"div.map-container",

0 commit comments

Comments
 (0)