|
1 | | -import { useState } from 'react' |
2 | | -import { Outlet } from 'react-router-dom' |
| 1 | +import { useEffect, useState } from 'react' |
| 2 | +import { Outlet, useLocation, useNavigate, useParams } from 'react-router-dom' |
3 | 3 |
|
4 | 4 | import { useConfig } from '@eplant/config' |
5 | 5 | import { |
6 | 6 | useActiveGeneId, |
7 | 7 | useActiveViewId, |
8 | 8 | useGeneticElements, |
9 | 9 | usePrinting, |
| 10 | + useSpecies, |
10 | 11 | } from '@eplant/state' |
11 | 12 | import Modal from '@eplant/UI/Modal' |
12 | 13 | import ErrorBoundary from '@eplant/util/ErrorBoundary' |
@@ -36,9 +37,83 @@ export function ViewContainer<T, S, A>({ ...props }) { |
36 | 37 | const [printing, setPrinting] = usePrinting() |
37 | 38 | const [viewingCitations, setViewingCitations] = useState(false) |
38 | 39 | const { views } = useConfig() |
39 | | - const [genes] = useGeneticElements() |
40 | | - const [activeGeneId] = useActiveGeneId() |
41 | | - const [activeViewId] = useActiveViewId() |
| 40 | + const navigate = useNavigate() |
| 41 | + const location = useLocation() |
| 42 | + const params = useParams() |
| 43 | + const [speciesList] = useSpecies() |
| 44 | + const [genes, setGenes] = useGeneticElements() |
| 45 | + const [activeGeneId, setActiveGeneId] = useActiveGeneId() |
| 46 | + const [activeViewId, setActiveViewId] = useActiveViewId() |
| 47 | + const [geneNotFound, setGeneNotFound] = useState(false) |
| 48 | + |
| 49 | + // On app url change, make sure loaded gene and view aligns with URL |
| 50 | + useEffect(() => { |
| 51 | + const loadGene = async (geneid: string) => { |
| 52 | + // TODO: This is super jank, should probably write some better utilities for loading genes |
| 53 | + const species = speciesList.find( |
| 54 | + (species) => species.name === 'Arabidopsis' |
| 55 | + ) |
| 56 | + const newGene = await species?.api.searchGene(geneid) |
| 57 | + if (newGene) { |
| 58 | + setGenes([...genes, newGene]) |
| 59 | + } else { |
| 60 | + setGeneNotFound(true) |
| 61 | + setActiveGeneId('') |
| 62 | + } |
| 63 | + } |
| 64 | + if (params.geneid) { |
| 65 | + if (params.geneid !== activeGeneId) { |
| 66 | + if (!genes.find((g) => g.id === params.geneid)) { |
| 67 | + loadGene(params.geneid) |
| 68 | + } |
| 69 | + if (!geneNotFound) setActiveGeneId(params.geneid) |
| 70 | + } |
| 71 | + } else { |
| 72 | + // Set active gene to first available if one is already loaded |
| 73 | + if (genes.length > 0) { |
| 74 | + setActiveGeneId(genes[0].id) |
| 75 | + } else { |
| 76 | + setActiveGeneId('') |
| 77 | + } |
| 78 | + } |
| 79 | + |
| 80 | + // Set activeview |
| 81 | + const urlView = |
| 82 | + views.find((view) => view.id === location.pathname.split('/')[1]) ?? |
| 83 | + GeneInfoViewMetadata |
| 84 | + |
| 85 | + setActiveViewId(urlView.id) |
| 86 | + }, []) |
| 87 | + |
| 88 | + // On when the activegene or view changes, update path |
| 89 | + useEffect(() => { |
| 90 | + const oldPathSegments = location.pathname |
| 91 | + .split('/') |
| 92 | + .filter((segment) => segment !== '') |
| 93 | + |
| 94 | + const newPathSegments = [] |
| 95 | + if (activeViewId) { |
| 96 | + newPathSegments.push(activeViewId) |
| 97 | + } |
| 98 | + if (activeGeneId) { |
| 99 | + newPathSegments.push(activeGeneId) |
| 100 | + } |
| 101 | + |
| 102 | + if (newPathSegments.length > 0) { |
| 103 | + let newPath |
| 104 | + if ( |
| 105 | + oldPathSegments.length > 0 && |
| 106 | + oldPathSegments[0] == newPathSegments[0] |
| 107 | + ) { |
| 108 | + // If the view is the same we want to retain quary params in url, else we can wipe |
| 109 | + // them and have URLStateManager handle things |
| 110 | + newPath = '/' + newPathSegments.join('/') + location.search |
| 111 | + } else { |
| 112 | + newPath = '/' + newPathSegments.join('/') |
| 113 | + } |
| 114 | + navigate(newPath) |
| 115 | + } |
| 116 | + }, [activeGeneId, activeViewId]) |
42 | 117 |
|
43 | 118 | // Get view and gene objects once everything resolves |
44 | 119 | const activeView = |
|
0 commit comments