Add reducers for places page

This commit is contained in:
viktorstrate
2021-05-02 21:49:29 +02:00
parent c992fe8933
commit 64dd907846
11 changed files with 214 additions and 77 deletions

View File

@@ -1,9 +1,8 @@
import React from 'react'
import styled from 'styled-components'
import imagePopupSrc from './image-popup.svg'
import { MediaMarker } from './MapPresentMarker'
import { PresentMarker } from './PlacesPage'
import { PlacesAction } from './placesReducer'
const Wrapper = styled.div`
width: 56px;
@@ -42,21 +41,36 @@ const PointCountCircle = styled.div`
`
type MapClusterMarkerProps = {
setPresentMarker: React.Dispatch<React.SetStateAction<PresentMarker | null>>
dispatchMarkerMedia: React.Dispatch<PlacesAction>
marker: MediaMarker
}
const MapClusterMarker = ({
marker,
setPresentMarker,
dispatchMarkerMedia,
}: MapClusterMarkerProps) => {
const thumbnail = JSON.parse(marker.thumbnail)
const presentMedia = () => {
setPresentMarker({
cluster: !!marker.cluster,
id: marker.cluster ? marker.cluster_id : marker.media_id,
// presentMarkerClicked({
// dispatchMedia: dispatchMarkerMedia,
// mediaState: markerMediaState,
// marker: {
// cluster: !!marker.cluster,
// id: marker.cluster ? marker.cluster_id : marker.media_id,
// },
// })
dispatchMarkerMedia({
type: 'replacePresentMarker',
marker: {
cluster: !!marker.cluster,
id: marker.cluster ? marker.cluster_id : marker.media_id,
},
})
// setPresentMarker({
// cluster: !!marker.cluster,
// id: marker.cluster ? marker.cluster_id : marker.media_id,
// })
}
return (

View File

@@ -1,9 +1,14 @@
import { gql } from '@apollo/client'
import React, { useEffect, useState } from 'react'
import React, { useEffect } from 'react'
import { useLazyQuery } from '@apollo/client'
import PresentView from '../../components/photoGallery/presentView/PresentView'
import type mapboxgl from 'mapbox-gl'
import { PresentMarker } from './PlacesPage'
import {
placePageQueryMedia,
placePageQueryMediaVariables,
} from './__generated__/placePageQueryMedia'
import { PlacesAction, PlacesState } from './placesReducer'
const QUERY_MEDIA = gql`
query placePageQueryMedia($mediaIDs: [ID!]!) {
@@ -37,7 +42,7 @@ const getMediaFromMarker = (map: mapboxgl.Map, presentMarker: PresentMarker) =>
if (cluster) {
const mediaSource = map.getSource('media') as mapboxgl.GeoJSONSource
mediaSource.getClusterLeaves(id, 1000, 0, (error, features) => {
mediaSource.getClusterLeaves(id as number, 1000, 0, (error, features) => {
if (error) {
reject(error)
return
@@ -65,72 +70,69 @@ export interface MediaMarker {
thumbnail: string
cluster: boolean
point_count_abbreviated: number
cluster_id: number
media_id: number
cluster_id: string
media_id: string
}
type MapPresetMarkerProps = {
map: mapboxgl.Map | null
presentMarker: PresentMarker | null
setPresentMarker: React.Dispatch<React.SetStateAction<PresentMarker | null>>
markerMediaState: PlacesState
dispatchMarkerMedia: React.Dispatch<PlacesAction>
}
const MapPresentMarker = ({
map,
presentMarker,
setPresentMarker,
markerMediaState,
dispatchMarkerMedia,
}: MapPresetMarkerProps) => {
const [mediaMarkers, setMediaMarkers] = useState<MediaMarker[] | null>(null)
const [currentIndex, setCurrentIndex] = useState(0)
const [loadMedia, { data: loadedMedia }] = useLazyQuery(QUERY_MEDIA)
const [loadMedia, { data: loadedMedia }] = useLazyQuery<
placePageQueryMedia,
placePageQueryMediaVariables
>(QUERY_MEDIA)
useEffect(() => {
const presentMarker = markerMediaState.presentMarker
if (presentMarker == null || map == null) {
setMediaMarkers(null)
dispatchMarkerMedia({
type: 'closePresentMode',
})
return
}
getMediaFromMarker(map, presentMarker).then(setMediaMarkers)
}, [presentMarker])
getMediaFromMarker(map, presentMarker).then(mediaMarkers => {
loadMedia({
variables: {
mediaIDs: mediaMarkers.map(x => x.media_id),
},
})
})
}, [markerMediaState.presentMarker])
useEffect(() => {
if (!mediaMarkers) return
setCurrentIndex(0)
loadMedia({
variables: {
mediaIDs: mediaMarkers.map(x => x.media_id),
},
const mediaList = loadedMedia?.mediaList || []
dispatchMarkerMedia({
type: 'replaceMedia',
media: mediaList,
})
}, [mediaMarkers])
if (mediaList.length > 0) {
dispatchMarkerMedia({
type: 'openPresentMode',
activeIndex: 0,
})
}
}, [loadedMedia])
if (
presentMarker == null ||
map == null ||
mediaMarkers == null ||
loadedMedia == null
) {
if (markerMediaState.presenting) {
return (
<PresentView
activeMedia={markerMediaState.media[markerMediaState.activeIndex]}
dispatchMedia={dispatchMarkerMedia}
disableSaveCloseInHistory={true}
/>
)
} else {
return null
}
return (
<PresentView
media={loadedMedia.mediaList[currentIndex]}
nextImage={() => {
setCurrentIndex(i => Math.min(mediaMarkers.length - 1, i + 1))
}}
previousImage={() => {
setCurrentIndex(i => Math.max(0, i - 1))
}}
setPresenting={presenting => {
if (!presenting) {
setCurrentIndex(0)
setPresentMarker(null)
}
}}
/>
)
}
export default MapPresentMarker

View File

@@ -1,6 +1,6 @@
import { gql, useQuery } from '@apollo/client'
import type mapboxgl from 'mapbox-gl'
import React, { useEffect, useRef, useState } from 'react'
import React, { useEffect, useReducer, useRef, useState } from 'react'
import { Helmet } from 'react-helmet'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
@@ -10,6 +10,8 @@ import MapPresentMarker from './MapPresentMarker'
// Will be bundled to dist/src/Pages/PlacesPage/PlacesPage.css
import 'mapbox-gl/dist/mapbox-gl.css'
import { urlPresentModeSetupHook } from '../../components/photoGallery/photoGalleryReducer'
import { placesReducer } from './placesReducer'
const MapWrapper = styled.div`
width: 100%;
@@ -29,7 +31,7 @@ const MAPBOX_DATA_QUERY = gql`
`
export type PresentMarker = {
id: number
id: number | string
cluster: boolean
}
@@ -37,9 +39,15 @@ const MapPage = () => {
const { t } = useTranslation()
const [mapboxLibrary, setMapboxLibrary] = useState<typeof mapboxgl | null>()
const [presentMarker, setPresentMarker] = useState<PresentMarker | null>(null)
const mapContainer = useRef<HTMLDivElement | null>(null)
const map = useRef<mapboxgl.Map | null>(null)
// const [presentMarker, setPresentMarker] = useState<PresentMarker | null>(null)
const [markerMediaState, dispatchMarkerMedia] = useReducer(placesReducer, {
presenting: false,
activeIndex: -1,
media: [],
})
const { data: mapboxData } = useQuery(MAPBOX_DATA_QUERY)
@@ -100,7 +108,7 @@ const MapPage = () => {
const updateMarkers = makeUpdateMarkers({
map: map.current,
mapboxLibrary,
setPresentMarker,
dispatchMarkerMedia,
})
map.current.on('move', updateMarkers)
@@ -127,6 +135,17 @@ const MapPage = () => {
)
}
urlPresentModeSetupHook({
dispatchMedia: dispatchMarkerMedia,
openPresentMode: event => {
console.log('OPEN PRESENT MODE MAPS')
dispatchMarkerMedia({
type: 'openPresentMode',
activeIndex: event.state.activeIndex,
})
},
})
return (
<Layout title="Places">
<Helmet>
@@ -137,8 +156,10 @@ const MapPage = () => {
</MapWrapper>
<MapPresentMarker
map={map.current}
presentMarker={presentMarker}
setPresentMarker={setPresentMarker}
markerMediaState={markerMediaState}
dispatchMarkerMedia={dispatchMarkerMedia}
// presentMarker={presentMarker}
// setPresentMarker={setPresentMarker}
/>
</Layout>
)

View File

@@ -4,7 +4,7 @@ import React from 'react'
import ReactDOM from 'react-dom'
import MapClusterMarker from './MapClusterMarker'
import { MediaMarker } from './MapPresentMarker'
import { PresentMarker } from './PlacesPage'
import { PlacesAction } from './placesReducer'
const markers: { [key: string]: mapboxgl.Marker } = {}
let markersOnScreen: typeof markers = {}
@@ -12,13 +12,14 @@ let markersOnScreen: typeof markers = {}
type makeUpdateMarkersArgs = {
map: mapboxgl.Map
mapboxLibrary: typeof mapboxgl
setPresentMarker: React.Dispatch<React.SetStateAction<PresentMarker | null>>
dispatchMarkerMedia: React.Dispatch<PlacesAction>
// setPresentMarker: React.Dispatch<React.SetStateAction<PresentMarker | null>>
}
export const makeUpdateMarkers = ({
map,
mapboxLibrary,
setPresentMarker,
dispatchMarkerMedia,
}: makeUpdateMarkersArgs) => () => {
const newMarkers: typeof markers = {}
const features = map.querySourceFeatures('media')
@@ -40,7 +41,9 @@ export const makeUpdateMarkers = ({
let marker = markers[id]
if (!marker) {
const el = createClusterPopupElement(props, setPresentMarker)
const el = createClusterPopupElement(props, {
dispatchMarkerMedia,
})
marker = markers[id] = new mapboxLibrary.Marker({
element: el,
}).setLngLat(coords)
@@ -58,13 +61,18 @@ export const makeUpdateMarkers = ({
function createClusterPopupElement(
geojsonProps: MediaMarker,
setPresentMarker: React.Dispatch<React.SetStateAction<PresentMarker | null>>
{
dispatchMarkerMedia,
}: {
dispatchMarkerMedia: React.Dispatch<PlacesAction>
}
) {
// setPresentMarker: React.Dispatch<React.SetStateAction<PresentMarker | null>>
const el = document.createElement('div')
ReactDOM.render(
<MapClusterMarker
marker={geojsonProps}
setPresentMarker={setPresentMarker}
dispatchMarkerMedia={dispatchMarkerMedia}
/>,
el
)

View File

@@ -0,0 +1,80 @@
import { PresentMarker } from './PlacesPage'
import {
PhotoGalleryState,
PhotoGalleryAction,
photoGalleryReducer,
} from './../../components/photoGallery/photoGalleryReducer'
export interface PlacesState extends PhotoGalleryState {
presentMarker?: PresentMarker
}
export type PlacesAction =
| PhotoGalleryAction
| { type: 'replacePresentMarker'; marker?: PresentMarker }
export function placesReducer(
state: PlacesState,
action: PlacesAction
): PlacesState {
switch (action.type) {
case 'replacePresentMarker':
if (
state.presentMarker &&
action.marker &&
state.presentMarker.cluster === action.marker.cluster &&
state.presentMarker.id === action.marker.id
) {
return {
...state,
presenting: true,
}
} else {
return {
...state,
presentMarker: action.marker,
}
}
default:
return photoGalleryReducer(state, action)
}
}
// export const presentMarkerClicked = ({
// dispatchMedia,
// mediaState,
// marker,
// }: {
// dispatchMedia: React.Dispatch<PlacesAction>
// mediaState: PlacesState
// marker: PresentMarker
// }) => {
// console.log(
// 'present marker clicked',
// mediaState,
// marker,
// !!mediaState.presentMarker,
// mediaState.presentMarker?.cluster === marker.cluster,
// mediaState.presentMarker?.id === marker.id
// )
// if (
// mediaState.presentMarker &&
// mediaState.presentMarker.cluster === marker.cluster &&
// mediaState.presentMarker.id === marker.id
// ) {
// console.log('EQUAL OPEN PRESENT MODE')
// history.pushState(
// { presenting: true, activeIndex: mediaState.activeIndex },
// ''
// )
// dispatchMedia({
// type: 'openPresentMode',
// activeIndex: mediaState.activeIndex,
// })
// } else {
// dispatchMedia({
// type: 'replacePresentMarker',
// marker,
// })
// }
// }

View File

@@ -65,6 +65,7 @@ export function photoGalleryReducer(
...state,
media: action.media,
activeIndex: -1,
presenting: false,
}
}
}

View File

@@ -67,11 +67,13 @@ const NavigationButton = styled(OverlayButton)<{ float: 'left' | 'right' }>`
type PresentNavigationOverlayProps = {
children?: React.ReactChild
dispatchMedia: React.Dispatch<GalleryAction>
disableSaveCloseInHistory?: boolean
}
const PresentNavigationOverlay = ({
children,
dispatchMedia,
disableSaveCloseInHistory,
}: PresentNavigationOverlayProps) => {
const [hide, setHide] = useState(true)
const onMouseMove = useRef<null | DebouncedFn<() => void>>(null)
@@ -113,7 +115,13 @@ const PresentNavigationOverlay = ({
</NavigationButton>
<ExitButton
className={hide ? 'hide' : undefined}
onClick={() => closePresentModeAction({ dispatchMedia })}
onClick={() => {
if (disableSaveCloseInHistory === true) {
dispatchMedia({ type: 'closePresentMode' })
} else {
closePresentModeAction({ dispatchMedia })
}
}}
>
<ExitIcon />
</ExitButton>

View File

@@ -26,6 +26,7 @@ type PresentViewProps = {
imageLoaded?(): void
activeMedia: PresentMediaProps_Media
dispatchMedia: React.Dispatch<GalleryAction>
disableSaveCloseInHistory?: boolean
}
const PresentView = ({
@@ -33,6 +34,7 @@ const PresentView = ({
imageLoaded,
activeMedia,
dispatchMedia,
disableSaveCloseInHistory,
}: PresentViewProps) => {
useEffect(() => {
const keyDownEvent = (e: KeyboardEvent) => {
@@ -48,8 +50,12 @@ const PresentView = ({
if (e.key == 'Escape') {
e.stopPropagation()
// dispatchMedia({ type: 'setPresenting', presenting: false })
closePresentModeAction({ dispatchMedia })
if (disableSaveCloseInHistory === true) {
dispatchMedia({ type: 'closePresentMode' })
} else {
closePresentModeAction({ dispatchMedia })
}
}
}
@@ -63,7 +69,10 @@ const PresentView = ({
return (
<StyledContainer {...className}>
<PreventScroll />
<PresentNavigationOverlay dispatchMedia={dispatchMedia}>
<PresentNavigationOverlay
dispatchMedia={dispatchMedia}
disableSaveCloseInHistory
>
<PresentMedia media={activeMedia} imageLoaded={imageLoaded} />
</PresentNavigationOverlay>
</StyledContainer>

View File

@@ -1,4 +1,4 @@
import React, { useContext } from 'react'
import React from 'react'
import { Link } from 'react-router-dom'
import styled from 'styled-components'
import { MediaThumbnail } from '../photoGallery/MediaThumbnail'
@@ -6,7 +6,6 @@ import {
toggleFavoriteAction,
useMarkFavoriteMutation,
} from '../photoGallery/photoGalleryMutations'
import { SidebarContext } from '../sidebar/Sidebar'
import {
getActiveTimelineImage,
openTimelinePresentMode,

View File

@@ -1,8 +1,6 @@
import React from 'react'
import TimelineGroupAlbum from './TimelineGroupAlbum'
import styled from 'styled-components'
import { myTimeline_myTimeline } from './__generated__/myTimeline'
import { TimelineActiveIndex } from './TimelineGallery'
import { useTranslation } from 'react-i18next'
import {
TimelineGalleryAction,

View File

@@ -4,8 +4,6 @@ import {
myTimeline_myTimeline_media,
} from './__generated__/myTimeline'
import { TimelineGroup } from './TimelineGallery'
import { UpdateSidebarFn } from '../sidebar/Sidebar'
import MediaSidebar from '../sidebar/MediaSidebar'
import { GalleryAction } from '../photoGallery/photoGalleryReducer'
export interface TimelineMediaIndex {
@@ -30,7 +28,6 @@ export function timelineGalleryReducer(
state: TimelineGalleryState,
action: TimelineGalleryAction
): TimelineGalleryState {
console.log('timeline gallery reducer', state, action)
switch (action.type) {
case 'replaceTimelineGroups': {
const dateGroupedAlbums = action.timeline.reduce((acc, val) => {