implemented label editing

main
Inga 🏳‍🌈 6 months ago
parent 9bf8c03c1d
commit 7b95b70a10
  1. 7
      .eslintrc.cjs
  2. 2
      src/routePlanner/map.tsx
  3. 15
      src/routePlanner/marker.tsx
  4. 3
      src/routePlanner/style.css
  5. 30
      src/routePlanner/types.ts
  6. 182
      src/routePlanner/useMarkers.test.ts
  7. 71
      src/routePlanner/useMarkers.ts

@ -22,12 +22,9 @@ module.exports = {
'error', 'error',
{ ignoreArrowShorthand: true }, { ignoreArrowShorthand: true },
], ],
/*'@typescript-eslint/no-invalid-void-type': [ '@typescript-eslint/restrict-template-expressions': [
'error', 'error',
{ allowAsThisParameter: true }, { allowNever: true },
], ],
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',*/
}, },
}; };

@ -85,7 +85,7 @@ export const MapComponent = ({ markers, onMapClick }: MapProps) => {
permanent: true, permanent: true,
direction: 'center', direction: 'center',
className: 'text', className: 'text',
content: marker.label, content: marker.shortLabel,
}, },
circle, circle,
) )

@ -1,15 +1,24 @@
import { useCallback } from 'preact/hooks';
import { MarkerProps } from './types'; import { MarkerProps } from './types';
export const MarkerComponent = ({ marker, isFirst, isLast }: MarkerProps) => { export const MarkerComponent = ({ marker, isFirst, isLast }: MarkerProps) => {
const changeLongLabel = useCallback(() => {
const newLongLabel = prompt('Enter new label', marker.longLabel);
if (newLongLabel?.length) {
marker.changeLongLabel(newLongLabel);
}
}, [marker]);
return ( return (
<li key={marker.key}> <li key={marker.key}>
{`Waypoint ${marker.label} (${marker.key.substring(0, 4)})`} {`Waypoint ${marker.shortLabel} (${marker.longLabel})`}
<span class="buttons"> <span class="buttons">
<button onClick={changeLongLabel}></button>
<button onClick={marker.moveUp} disabled={isFirst}> <button onClick={marker.moveUp} disabled={isFirst}>
🔼
</button> </button>
<button onClick={marker.moveDown} disabled={isLast}> <button onClick={marker.moveDown} disabled={isLast}>
🔽
</button> </button>
<button onClick={marker.remove}>🗑</button> <button onClick={marker.remove}>🗑</button>
</span> </span>

@ -20,7 +20,7 @@ section.route-planner > section.markers {
} }
section.route-planner > section.markers ol { section.route-planner > section.markers ol {
padding: 0 padding: 0;
} }
section.route-planner > section.markers li::before { section.route-planner > section.markers li::before {
@ -45,6 +45,7 @@ section.route-planner > section.markers li .buttons {
section.route-planner > section.markers li button { section.route-planner > section.markers li button {
background: transparent; background: transparent;
border: 0; border: 0;
color: white;
cursor: pointer; cursor: pointer;
} }

@ -5,29 +5,17 @@ export type Marker = Waypoint & {
remove: () => void; remove: () => void;
moveUp: () => void; moveUp: () => void;
moveDown: () => void; moveDown: () => void;
label: string; changeLongLabel: (newLongLabel: string) => void;
/**
* Should be at most 1-2 characters (to be displayed on map markers), can change at any time
*/
shortLabel: string;
/**
* Displayed in the list, should only change when explicitly requested by user
*/
longLabel: string;
}; };
type GenericReducerAction<TType extends string, TData> = {
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 = { export type ReorderMarkersParams = {
oldIndex: number; oldIndex: number;
newIndex: number; newIndex: number;

@ -1,6 +1,10 @@
import t from 'tap'; import t from 'tap';
import { Marker, ReducerAction } from './types'; import { Marker } from './types';
import { createChangeStateMethods, markersReducer } from './useMarkers.js'; import {
ReducerAction,
createChangeStateMethods,
markersReducer,
} from './useMarkers.js';
// Testing entire `useMarkers` custom hook would require us to create test preact components here // Testing entire `useMarkers` custom hook would require us to create test preact components here
// and render them into virtual DOM and check the results, which is just too much hassle // and render them into virtual DOM and check the results, which is just too much hassle
@ -38,9 +42,11 @@ const createReducersWithFivePoints = () => {
const markerPattern = { const markerPattern = {
key: String, key: String,
longLabel: String,
moveUp: Function, moveUp: Function,
moveDown: Function, moveDown: Function,
remove: Function, remove: Function,
changeLongLabel: Function,
}; };
void t.test('reducer', (t) => { void t.test('reducer', (t) => {
@ -58,11 +64,11 @@ void t.test('reducer methods', (t) => {
void t.test('create markers with correct labels', (t) => { void t.test('create markers with correct labels', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates1 },
{ ...markerPattern, label: '2', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates2 },
{ ...markerPattern, label: '3', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates3 },
{ ...markerPattern, label: '4', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates4 },
{ ...markerPattern, label: '5', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '5', coordinates: coordinates5 },
]); ]);
t.end(); t.end();
}); });
@ -71,10 +77,10 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.getMarkers()[0]?.remove(); reducers.getMarkers()[0]?.remove();
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates2 },
{ ...markerPattern, label: '2', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates3 },
{ ...markerPattern, label: '3', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates4 },
{ ...markerPattern, label: '4', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates5 },
]); ]);
t.end(); t.end();
}); });
@ -83,10 +89,10 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.getMarkers()[2]?.remove(); reducers.getMarkers()[2]?.remove();
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates1 },
{ ...markerPattern, label: '2', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates2 },
{ ...markerPattern, label: '3', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates4 },
{ ...markerPattern, label: '4', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates5 },
]); ]);
t.end(); t.end();
}); });
@ -95,10 +101,10 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.getMarkers()[4]?.remove(); reducers.getMarkers()[4]?.remove();
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates1 },
{ ...markerPattern, label: '2', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates2 },
{ ...markerPattern, label: '3', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates3 },
{ ...markerPattern, label: '4', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates4 },
]); ]);
t.end(); t.end();
}); });
@ -107,11 +113,11 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.getMarkers()[0]?.moveUp(); reducers.getMarkers()[0]?.moveUp();
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates1 },
{ ...markerPattern, label: '2', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates2 },
{ ...markerPattern, label: '3', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates3 },
{ ...markerPattern, label: '4', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates4 },
{ ...markerPattern, label: '5', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '5', coordinates: coordinates5 },
]); ]);
t.end(); t.end();
}); });
@ -120,11 +126,11 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.getMarkers()[0]?.moveDown(); reducers.getMarkers()[0]?.moveDown();
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates2 },
{ ...markerPattern, label: '2', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates1 },
{ ...markerPattern, label: '3', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates3 },
{ ...markerPattern, label: '4', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates4 },
{ ...markerPattern, label: '5', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '5', coordinates: coordinates5 },
]); ]);
t.end(); t.end();
}); });
@ -133,11 +139,11 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.getMarkers()[1]?.moveUp(); reducers.getMarkers()[1]?.moveUp();
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates2 },
{ ...markerPattern, label: '2', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates1 },
{ ...markerPattern, label: '3', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates3 },
{ ...markerPattern, label: '4', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates4 },
{ ...markerPattern, label: '5', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '5', coordinates: coordinates5 },
]); ]);
t.end(); t.end();
}); });
@ -146,11 +152,11 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.getMarkers()[1]?.moveDown(); reducers.getMarkers()[1]?.moveDown();
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates1 },
{ ...markerPattern, label: '2', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates3 },
{ ...markerPattern, label: '3', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates2 },
{ ...markerPattern, label: '4', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates4 },
{ ...markerPattern, label: '5', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '5', coordinates: coordinates5 },
]); ]);
t.end(); t.end();
}); });
@ -159,11 +165,11 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.getMarkers()[2]?.moveUp(); reducers.getMarkers()[2]?.moveUp();
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates1 },
{ ...markerPattern, label: '2', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates3 },
{ ...markerPattern, label: '3', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates2 },
{ ...markerPattern, label: '4', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates4 },
{ ...markerPattern, label: '5', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '5', coordinates: coordinates5 },
]); ]);
t.end(); t.end();
}); });
@ -172,11 +178,11 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.getMarkers()[2]?.moveDown(); reducers.getMarkers()[2]?.moveDown();
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates1 },
{ ...markerPattern, label: '2', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates2 },
{ ...markerPattern, label: '3', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates4 },
{ ...markerPattern, label: '4', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates3 },
{ ...markerPattern, label: '5', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '5', coordinates: coordinates5 },
]); ]);
t.end(); t.end();
}); });
@ -185,11 +191,11 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.getMarkers()[3]?.moveUp(); reducers.getMarkers()[3]?.moveUp();
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates1 },
{ ...markerPattern, label: '2', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates2 },
{ ...markerPattern, label: '3', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates4 },
{ ...markerPattern, label: '4', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates3 },
{ ...markerPattern, label: '5', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '5', coordinates: coordinates5 },
]); ]);
t.end(); t.end();
}); });
@ -198,11 +204,11 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.getMarkers()[3]?.moveDown(); reducers.getMarkers()[3]?.moveDown();
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates1 },
{ ...markerPattern, label: '2', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates2 },
{ ...markerPattern, label: '3', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates3 },
{ ...markerPattern, label: '4', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates5 },
{ ...markerPattern, label: '5', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '5', coordinates: coordinates4 },
]); ]);
t.end(); t.end();
}); });
@ -211,11 +217,11 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.getMarkers()[4]?.moveUp(); reducers.getMarkers()[4]?.moveUp();
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates1 },
{ ...markerPattern, label: '2', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates2 },
{ ...markerPattern, label: '3', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates3 },
{ ...markerPattern, label: '4', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates5 },
{ ...markerPattern, label: '5', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '5', coordinates: coordinates4 },
]); ]);
t.end(); t.end();
}); });
@ -224,11 +230,11 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.getMarkers()[4]?.moveDown(); reducers.getMarkers()[4]?.moveDown();
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates1 },
{ ...markerPattern, label: '2', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates2 },
{ ...markerPattern, label: '3', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates3 },
{ ...markerPattern, label: '4', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates4 },
{ ...markerPattern, label: '5', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '5', coordinates: coordinates5 },
]); ]);
t.end(); t.end();
}); });
@ -237,11 +243,11 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.reorderMarkers({ oldIndex: 1, newIndex: 3 }); reducers.reorderMarkers({ oldIndex: 1, newIndex: 3 });
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates1 },
{ ...markerPattern, label: '2', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates3 },
{ ...markerPattern, label: '3', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates4 },
{ ...markerPattern, label: '4', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates2 },
{ ...markerPattern, label: '5', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '5', coordinates: coordinates5 },
]); ]);
t.end(); t.end();
}); });
@ -250,11 +256,29 @@ void t.test('reducer methods', (t) => {
const reducers = createReducersWithFivePoints(); const reducers = createReducersWithFivePoints();
reducers.reorderMarkers({ oldIndex: 3, newIndex: 1 }); reducers.reorderMarkers({ oldIndex: 3, newIndex: 1 });
t.matchOnlyStrict(reducers.getMarkers(), [ t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, label: '1', coordinates: coordinates1 }, { ...markerPattern, shortLabel: '1', coordinates: coordinates1 },
{ ...markerPattern, label: '2', coordinates: coordinates4 }, { ...markerPattern, shortLabel: '2', coordinates: coordinates4 },
{ ...markerPattern, label: '3', coordinates: coordinates2 }, { ...markerPattern, shortLabel: '3', coordinates: coordinates2 },
{ ...markerPattern, label: '4', coordinates: coordinates3 }, { ...markerPattern, shortLabel: '4', coordinates: coordinates3 },
{ ...markerPattern, label: '5', coordinates: coordinates5 }, { ...markerPattern, shortLabel: '5', coordinates: coordinates5 },
]);
t.end();
});
void t.test('renames marker', (t) => {
const reducers = createReducersWithFivePoints();
reducers.getMarkers()[2]?.changeLongLabel('new label');
t.matchOnlyStrict(reducers.getMarkers(), [
{ ...markerPattern, shortLabel: '1', coordinates: coordinates1 },
{ ...markerPattern, shortLabel: '2', coordinates: coordinates2 },
{
...markerPattern,
shortLabel: '3',
coordinates: coordinates3,
longLabel: 'new label',
},
{ ...markerPattern, shortLabel: '4', coordinates: coordinates4 },
{ ...markerPattern, shortLabel: '5', coordinates: coordinates5 },
]); ]);
t.end(); t.end();
}); });

@ -2,37 +2,74 @@ import { nanoid } from 'nanoid';
import { Dispatch, useMemo, useReducer } from 'preact/hooks'; import { Dispatch, useMemo, useReducer } from 'preact/hooks';
import { reorderElements } from '../shared/collections.js'; import { reorderElements } from '../shared/collections.js';
import { Coordinates } from '../shared/types'; import { Coordinates } from '../shared/types';
import { Marker, ReducerAction, ReorderMarkersParams } from './types'; import { Marker, ReorderMarkersParams } from './types';
type GenericReducerAction<TType extends string, TData> = {
type: TType;
data: TData;
};
type GenericMarkerChangeReducerAction<TType extends string, TData = unknown> = {
type: TType;
data: TData & { key: string };
};
export type ReducerAction =
| GenericReducerAction<
'add',
{
coordinates: Coordinates;
remove: (key: string) => void;
moveUp: (key: string) => void;
moveDown: (key: string) => void;
changeLongLabel: (key: string, newLongLabel: string) => void;
}
>
| GenericMarkerChangeReducerAction<'remove'>
| GenericMarkerChangeReducerAction<'moveUp'>
| GenericMarkerChangeReducerAction<'moveDown'>
| GenericMarkerChangeReducerAction<
'changeLongLabel',
{ newLongLabel: string }
>
| GenericReducerAction<'reorder', { oldIndex: number; newIndex: number }>;
const reindexMarkers = (markers: Marker[]) => const reindexMarkers = (markers: Marker[]) =>
markers.map((marker, i) => { markers.map((marker, i) => {
const newLabel = `${i + 1}`; const newShortLabel = `${i + 1}`;
if (marker.label === newLabel) { if (marker.shortLabel === newShortLabel) {
return marker; return marker;
} }
return { return {
...marker, ...marker,
label: newLabel, shortLabel: newShortLabel,
}; };
}); });
const handleDefaultCase = (discriminator: never): never => {
throw new Error(`Unsupported type ${discriminator}`);
};
export const markersReducer = ( export const markersReducer = (
markers: Marker[], markers: Marker[],
action: ReducerAction, action: ReducerAction,
): Marker[] => { ): Marker[] => {
const type = action.type; const type = action.type;
switch (action.type) { switch (type) {
case 'add': { case 'add': {
const key = nanoid(10); const key = nanoid(10);
return reindexMarkers([ return reindexMarkers([
...markers, ...markers,
{ {
key, key,
label: 'placeholder', shortLabel: 'placeholder',
longLabel: key.substring(0, 4),
remove: () => action.data.remove(key), remove: () => action.data.remove(key),
moveUp: () => action.data.moveUp(key), moveUp: () => action.data.moveUp(key),
moveDown: () => action.data.moveDown(key), moveDown: () => action.data.moveDown(key),
changeLongLabel: (newLongLabel: string) =>
action.data.changeLongLabel(key, newLongLabel),
coordinates: action.data.coordinates, coordinates: action.data.coordinates,
}, },
]); ]);
@ -66,6 +103,18 @@ export const markersReducer = (
reorderElements(markers, oldIndex, oldIndex + 1), reorderElements(markers, oldIndex, oldIndex + 1),
); );
} }
case 'changeLongLabel': {
return markers.map((marker) => {
if (marker.key !== action.data.key) {
return marker;
}
return {
...marker,
longLabel: action.data.newLongLabel,
};
});
}
case 'reorder': { case 'reorder': {
return reindexMarkers( return reindexMarkers(
reorderElements( reorderElements(
@ -76,7 +125,7 @@ export const markersReducer = (
); );
} }
default: default:
throw new Error(`Unsupported type ${type}`); return handleDefaultCase(type);
} }
}; };
@ -110,6 +159,12 @@ export const createChangeStateMethods = (
data: { key }, data: { key },
}); });
const changeMarkerLongLabel = (key: string, newLongLabel: string) =>
dispatchMarkers({
type: 'changeLongLabel',
data: { key, newLongLabel },
});
const addMarker = (coordinates: Coordinates) => const addMarker = (coordinates: Coordinates) =>
dispatchMarkers({ dispatchMarkers({
type: 'add', type: 'add',
@ -118,6 +173,7 @@ export const createChangeStateMethods = (
moveUp: moveMarkerUp, moveUp: moveMarkerUp,
moveDown: moveMarkerDown, moveDown: moveMarkerDown,
remove: removeMarker, remove: removeMarker,
changeLongLabel: changeMarkerLongLabel,
}, },
}); });
@ -127,6 +183,7 @@ export const createChangeStateMethods = (
moveMarkerDown, moveMarkerDown,
removeMarker, removeMarker,
addMarker, addMarker,
changeMarkerLongLabel,
}; };
}; };

Loading…
Cancel
Save