From 64dd907846d8ba6accda171bfbe022d457db4fde Mon Sep 17 00:00:00 2001 From: viktorstrate Date: Sun, 2 May 2021 21:49:29 +0200 Subject: [PATCH] Add reducers for places page --- ui/src/Pages/PlacesPage/MapClusterMarker.tsx | 28 ++++-- ui/src/Pages/PlacesPage/MapPresentMarker.tsx | 96 ++++++++++--------- ui/src/Pages/PlacesPage/PlacesPage.tsx | 33 +++++-- .../PlacesPage/mapboxHelperFunctions.tsx | 20 ++-- ui/src/Pages/PlacesPage/placesReducer.ts | 80 ++++++++++++++++ .../photoGallery/photoGalleryReducer.tsx | 1 + .../presentView/PresentNavigationOverlay.tsx | 10 +- .../photoGallery/presentView/PresentView.tsx | 15 ++- .../timelineGallery/TimelineGroupAlbum.tsx | 3 +- .../timelineGallery/TimelineGroupDate.tsx | 2 - .../timelineGalleryReducer.tsx | 3 - 11 files changed, 214 insertions(+), 77 deletions(-) create mode 100644 ui/src/Pages/PlacesPage/placesReducer.ts diff --git a/ui/src/Pages/PlacesPage/MapClusterMarker.tsx b/ui/src/Pages/PlacesPage/MapClusterMarker.tsx index 40165d72..47d0eb8e 100644 --- a/ui/src/Pages/PlacesPage/MapClusterMarker.tsx +++ b/ui/src/Pages/PlacesPage/MapClusterMarker.tsx @@ -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> + dispatchMarkerMedia: React.Dispatch 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 ( diff --git a/ui/src/Pages/PlacesPage/MapPresentMarker.tsx b/ui/src/Pages/PlacesPage/MapPresentMarker.tsx index defddf17..2ffb15ef 100644 --- a/ui/src/Pages/PlacesPage/MapPresentMarker.tsx +++ b/ui/src/Pages/PlacesPage/MapPresentMarker.tsx @@ -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> + markerMediaState: PlacesState + dispatchMarkerMedia: React.Dispatch } const MapPresentMarker = ({ map, - presentMarker, - setPresentMarker, + markerMediaState, + dispatchMarkerMedia, }: MapPresetMarkerProps) => { - const [mediaMarkers, setMediaMarkers] = useState(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 ( + + ) + } else { return null } - - return ( - { - 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 diff --git a/ui/src/Pages/PlacesPage/PlacesPage.tsx b/ui/src/Pages/PlacesPage/PlacesPage.tsx index 9e8b2b20..4f82bc2d 100644 --- a/ui/src/Pages/PlacesPage/PlacesPage.tsx +++ b/ui/src/Pages/PlacesPage/PlacesPage.tsx @@ -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() - const [presentMarker, setPresentMarker] = useState(null) const mapContainer = useRef(null) const map = useRef(null) + // const [presentMarker, setPresentMarker] = useState(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 ( @@ -137,8 +156,10 @@ const MapPage = () => { ) diff --git a/ui/src/Pages/PlacesPage/mapboxHelperFunctions.tsx b/ui/src/Pages/PlacesPage/mapboxHelperFunctions.tsx index 86dd9656..dad9147c 100644 --- a/ui/src/Pages/PlacesPage/mapboxHelperFunctions.tsx +++ b/ui/src/Pages/PlacesPage/mapboxHelperFunctions.tsx @@ -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> + dispatchMarkerMedia: React.Dispatch + // setPresentMarker: React.Dispatch> } 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> + { + dispatchMarkerMedia, + }: { + dispatchMarkerMedia: React.Dispatch + } ) { + // setPresentMarker: React.Dispatch> const el = document.createElement('div') ReactDOM.render( , el ) diff --git a/ui/src/Pages/PlacesPage/placesReducer.ts b/ui/src/Pages/PlacesPage/placesReducer.ts new file mode 100644 index 00000000..b59287f0 --- /dev/null +++ b/ui/src/Pages/PlacesPage/placesReducer.ts @@ -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 +// 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, +// }) +// } +// } diff --git a/ui/src/components/photoGallery/photoGalleryReducer.tsx b/ui/src/components/photoGallery/photoGalleryReducer.tsx index 21aff5ba..c64e90e7 100644 --- a/ui/src/components/photoGallery/photoGalleryReducer.tsx +++ b/ui/src/components/photoGallery/photoGalleryReducer.tsx @@ -65,6 +65,7 @@ export function photoGalleryReducer( ...state, media: action.media, activeIndex: -1, + presenting: false, } } } diff --git a/ui/src/components/photoGallery/presentView/PresentNavigationOverlay.tsx b/ui/src/components/photoGallery/presentView/PresentNavigationOverlay.tsx index 6c6da07f..5e235b3c 100644 --- a/ui/src/components/photoGallery/presentView/PresentNavigationOverlay.tsx +++ b/ui/src/components/photoGallery/presentView/PresentNavigationOverlay.tsx @@ -67,11 +67,13 @@ const NavigationButton = styled(OverlayButton)<{ float: 'left' | 'right' }>` type PresentNavigationOverlayProps = { children?: React.ReactChild dispatchMedia: React.Dispatch + disableSaveCloseInHistory?: boolean } const PresentNavigationOverlay = ({ children, dispatchMedia, + disableSaveCloseInHistory, }: PresentNavigationOverlayProps) => { const [hide, setHide] = useState(true) const onMouseMove = useRef void>>(null) @@ -113,7 +115,13 @@ const PresentNavigationOverlay = ({ closePresentModeAction({ dispatchMedia })} + onClick={() => { + if (disableSaveCloseInHistory === true) { + dispatchMedia({ type: 'closePresentMode' }) + } else { + closePresentModeAction({ dispatchMedia }) + } + }} > diff --git a/ui/src/components/photoGallery/presentView/PresentView.tsx b/ui/src/components/photoGallery/presentView/PresentView.tsx index 9671f2a1..e90d5560 100644 --- a/ui/src/components/photoGallery/presentView/PresentView.tsx +++ b/ui/src/components/photoGallery/presentView/PresentView.tsx @@ -26,6 +26,7 @@ type PresentViewProps = { imageLoaded?(): void activeMedia: PresentMediaProps_Media dispatchMedia: React.Dispatch + 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 ( - + diff --git a/ui/src/components/timelineGallery/TimelineGroupAlbum.tsx b/ui/src/components/timelineGallery/TimelineGroupAlbum.tsx index b97b80b9..05783278 100644 --- a/ui/src/components/timelineGallery/TimelineGroupAlbum.tsx +++ b/ui/src/components/timelineGallery/TimelineGroupAlbum.tsx @@ -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, diff --git a/ui/src/components/timelineGallery/TimelineGroupDate.tsx b/ui/src/components/timelineGallery/TimelineGroupDate.tsx index a785d68c..9925575a 100644 --- a/ui/src/components/timelineGallery/TimelineGroupDate.tsx +++ b/ui/src/components/timelineGallery/TimelineGroupDate.tsx @@ -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, diff --git a/ui/src/components/timelineGallery/timelineGalleryReducer.tsx b/ui/src/components/timelineGallery/timelineGalleryReducer.tsx index ce097659..bea1fd76 100644 --- a/ui/src/components/timelineGallery/timelineGalleryReducer.tsx +++ b/ui/src/components/timelineGallery/timelineGalleryReducer.tsx @@ -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) => {