diff --git a/src/routePlanner/index.tsx b/src/routePlanner/index.tsx index b2b292a..b57f1e3 100644 --- a/src/routePlanner/index.tsx +++ b/src/routePlanner/index.tsx @@ -1,96 +1,71 @@ -import { nanoid } from 'nanoid'; -import { useCallback, useState } from 'preact/hooks'; -import { reorderElements } from '../shared/collections'; +import { useCallback, useReducer } from 'preact/hooks'; import { Coordinates } from '../shared/types'; import { ExportComponent } from './export'; import { MapComponent } from './map'; import { MarkersComponent } from './markers'; -import { Marker, ReorderMarkersParams } from './types'; +import { ReorderMarkersParams } from './types'; import './style.css'; +import { markersReducer } from './reducer'; export const RoutePlanner = () => { - const [markers, setMarkers] = useState([]); + const [markers, dispatchMarkers] = useReducer(markersReducer, []); - const onMarkersReorder = useCallback( + const reorderMarkers = useCallback( ({ oldIndex, newIndex }: ReorderMarkersParams): void => - setMarkers((oldMarkers) => { - console.log( - `Reordering markers: from ${oldIndex} to ${newIndex}`, - ); - const newMarkers = reorderElements( - oldMarkers, - oldIndex, - newIndex, - ); - return newMarkers.map((marker, i) => ({ - ...marker, - label: `${i + 1}`, - remove: () => - onMarkersReorder({ - oldIndex: i, - newIndex: -1, - }), - ...(i - 1 >= 0 && { - moveDown: () => - onMarkersReorder({ - oldIndex: i, - newIndex: i - 1, - }), - }), - ...(i + 1 < newMarkers.length && { - moveUp: () => - onMarkersReorder({ - oldIndex: i, - newIndex: i + 1, - }), - }), - })); + dispatchMarkers({ + type: 'reorder', + data: { oldIndex, newIndex }, }), [], ); - const onMapClick = useCallback( - (coordinates: Coordinates) => { - setMarkers((markers) => [ - ...markers.slice(0, markers.length - 1), - ...markers - .slice(markers.length - 1, markers.length) - .map((marker) => ({ - ...marker, - moveUp: () => - onMarkersReorder({ - oldIndex: markers.length - 1, - newIndex: markers.length, - }), - })), - { - key: nanoid(10), - label: `${markers.length + 1}`, - remove: () => - onMarkersReorder({ - oldIndex: markers.length, - newIndex: -1, - }), - ...(markers.length && { - moveDown: () => - onMarkersReorder({ - oldIndex: markers.length, - newIndex: markers.length - 1, - }), - }), + const moveMarkerUp = useCallback( + (key: string) => + dispatchMarkers({ + type: 'moveUp', + data: { key }, + }), + [], + ); + + const moveMarkerDown = useCallback( + (key: string) => + dispatchMarkers({ + type: 'moveDown', + data: { key }, + }), + [], + ); + + const removeMarker = useCallback( + (key: string) => + dispatchMarkers({ + type: 'remove', + data: { key }, + }), + [], + ); + + const addMarker = useCallback( + (coordinates: Coordinates) => + dispatchMarkers({ + type: 'add', + data: { coordinates, + moveUp: moveMarkerUp, + moveDown: moveMarkerDown, + remove: removeMarker, }, - ]); - }, - [onMarkersReorder], + }), + [moveMarkerUp, moveMarkerDown, removeMarker], ); return (
@@ -98,7 +73,7 @@ export const RoutePlanner = () => {
- +
); diff --git a/src/routePlanner/marker.tsx b/src/routePlanner/marker.tsx index 702ba1d..fb09b0b 100644 --- a/src/routePlanner/marker.tsx +++ b/src/routePlanner/marker.tsx @@ -5,10 +5,10 @@ export const MarkerComponent = ({ marker }: MarkerProps) => {
  • {`Waypoint ${marker.label} (${marker.key.substring(0, 4)})`} - - diff --git a/src/routePlanner/reducer.ts b/src/routePlanner/reducer.ts new file mode 100644 index 0000000..be63bcb --- /dev/null +++ b/src/routePlanner/reducer.ts @@ -0,0 +1,79 @@ +import { nanoid } from 'nanoid'; +import { Marker, ReducerAction } from './types'; +import { reorderElements } from '../shared/collections'; + +const reindexMarkers = (markers: Marker[]) => + markers.map((marker, i) => { + const newLabel = `${i + 1}`; + if (marker.label === newLabel) { + return marker; + } + + return { + ...marker, + label: newLabel, + }; + }); + +export const markersReducer = ( + markers: Marker[], + action: ReducerAction, +): Marker[] => { + const type = action.type; + switch (action.type) { + case 'add': { + const key = nanoid(10); + return reindexMarkers([ + ...markers, + { + key, + label: 'placeholder', + remove: () => action.data.remove(key), + moveUp: () => action.data.moveUp(key), + moveDown: () => action.data.moveDown(key), + coordinates: action.data.coordinates, + }, + ]); + } + case 'remove': { + return reindexMarkers([ + ...markers.filter(({ key }) => key !== action.data.key), + ]); + } + case 'moveUp': { + const oldIndex = markers.findIndex( + ({ key }) => key === action.data.key, + ); + if (oldIndex < 1) { + return markers; + } + + return reindexMarkers( + reorderElements(markers, oldIndex, oldIndex - 1), + ); + } + case 'moveDown': { + const oldIndex = markers.findIndex( + ({ key }) => key === action.data.key, + ); + if (oldIndex < 0 || oldIndex + 1 >= markers.length) { + return markers; + } + + return reindexMarkers( + reorderElements(markers, oldIndex, oldIndex + 1), + ); + } + case 'reorder': { + return reindexMarkers( + reorderElements( + markers, + action.data.oldIndex, + action.data.newIndex, + ), + ); + } + default: + throw new Error(`Unsupported type ${type}`); + } +}; diff --git a/src/routePlanner/types.ts b/src/routePlanner/types.ts index 883fe87..58c3e7a 100644 --- a/src/routePlanner/types.ts +++ b/src/routePlanner/types.ts @@ -8,6 +8,26 @@ export type Marker = Waypoint & { label: string; }; +type GenericReducerAction = { + type: TType; + data: TData; +}; + +export type ReducerAction = + | GenericReducerAction< + 'add', + { + coordinates: Coordinates; + remove: (key: string) => void; + moveUp: (key: string) => void; + moveDown: (key: string) => void; + } + > + | GenericReducerAction<'remove', { key: string }> + | GenericReducerAction<'moveUp', { key: string }> + | GenericReducerAction<'moveDown', { key: string }> + | GenericReducerAction<'reorder', { oldIndex: number; newIndex: number }>; + export type ReorderMarkersParams = { oldIndex: number; newIndex: number;