Untitled
unknown
typescript
4 years ago
3.6 kB
4
Indexable
import React, { FC, ReactNode } from 'react'; import { observer } from 'mobx-react-lite'; import { getParent } from 'mobx-state-tree'; import { POIInstance } from 'models/POI.model'; import { useStore } from 'hooks/useStore'; import { StoreName } from 'stores/storeName'; import { ActiveSection } from 'types/Sidebar'; import type { StageType } from 'models/Stage.model'; import { useScrollToRef } from 'hooks/useScrolltoRef'; import { POIType } from 'types/POI'; import { ReactComponent as PodcastIcon } from 'svg/podcast.svg'; import { ReactComponent as CityLargeIcon } from 'svg/city-large.svg'; import { ReactComponent as CitySmallIcon } from 'svg/city-small.svg'; import { ReactComponent as StarIcon } from 'svg/star.svg'; import { ReactComponent as EuroregionIcon } from 'svg/euroregion.svg'; import { Wrapper } from './styles'; import { ActiveStage } from 'components/ActiveStage'; const POITypeToIconMapper: Record<POIType, ReactNode> = { [POIType.PODCAST]: <PodcastIcon />, [POIType.CITY_LARGE]: <CityLargeIcon />, [POIType.CITY_SMALL]: <CitySmallIcon />, [POIType.STAR]: <StarIcon />, [POIType.EUROREGION]: <EuroregionIcon />, }; interface Props { stageId: string; POI: POIInstance; } export const Poi: FC<Props> = observer(({ POI }) => { const { setActivePOI, activePOI, setActiveSection } = useStore( StoreName.SIDEBAR, ); const { activeStage, setActiveStage } = useStore(StoreName.MAP); const { isMobileUp } = useStore(StoreName.UI); const parentStage = getParent<StageType>(POI, 2); const coordinates = isMobileUp ? POI.coordinates : POI.coordinatesMobile; const scrollToRef = useScrollToRef(); const now = new Date(); const isPOIVisible = POI.scheduledAt === undefined || (POI.scheduledAt instanceof Date && now > POI.scheduledAt) || !!localStorage.getItem('showAllPOIs'); if (!isPOIVisible || !coordinates) { return null; } return ( <Wrapper isActive={POI === activePOI} type={POI.type} onClick={() => { setActivePOI(POI); setActiveSection(ActiveSection.POI); if (activeStage !== parentStage) { scrollToRef(parentStage.ref); setActiveStage(parentStage); } }} style={{ top: `${coordinates.y}%`, left: `${coordinates.x}%`, }} > {POITypeToIconMapper[POI.type]} </Wrapper> ); }); // nested entities that are meaningful logic-wise |-MapStore |-activeStage |-stages: Stage[] | |-POIs : POI[] | |... |... // It is idiomatic for Redux to accept only raw/serializable data // In the code: how do you express the relationship between nested Domain Objects // (as in logically meaningful objects as oposed to DDD strict meaning) <Poi POI={POIData} /> POIData { id: 'poiId' } // in the "within <POI />" you would have to reverse lookup the POI by it's ID and // then check whether it is nested within activeStageId and // Another approach to take would be to pass the logic down from the point where you initially connect to Redux <Poi onClick={onClick} POI={POIData}/> the on Click is defined when we are still in scope of Stage onPOIClick = (clickedPoi) => { const currentlyActiveStage = useSelector(getCurrentlyActiveStage); const didThePOIClickOccurInCurrentlyActiveStage = !!currentlyActiveStage.POIs.find(poi => poi.id === clickedPoi.id) if(didThePOIClickOccurInCurrentlyActiveStage) { ... } else { ... } } <Stage onPOIClick={onPOIClick} /> // alternatively you could normalise the data thus adding an another layer of complexity // I.E normalizr or redux-orm
Editor is loading...