First version of notes, also allowing to delete wpts

This commit is contained in:
Eric van der Vlist 2023-03-06 16:45:20 +01:00
parent bf179a4b6d
commit adbbb3e356
7 changed files with 262 additions and 53 deletions

View File

@ -5,7 +5,7 @@ import { Geolocation } from '@awesome-cordova-plugins/geolocation';
import NoteIcon from '@suid/icons-material/Note';
import style from './Note.module.css';
import WptEditDialog from '../wpt/WptEditDialog';
import WptEditDialog, { Category } from '../wpt/WptEditDialog';
import { Coordinate } from 'ol/coordinate';
interface Props {}
@ -20,6 +20,38 @@ const Note: Component<Props> = (props) => {
setOpen(true);
};
const initialWpt = () => {
const time = new Date().toISOString();
return {
$: { lat: 0, lon: 0 },
ele: undefined,
time: undefined,
magvar: undefined,
geoidheight: undefined,
name: undefined,
cmt: undefined,
desc: undefined,
src: undefined,
link: undefined,
sym: undefined,
type: undefined,
fix: undefined,
sat: undefined,
hdop: undefined,
vdop: undefined,
pdop: undefined,
ageofdgpsdata: undefined,
dgpsid: undefined,
extensions: {
address: undefined,
startTime: time,
endTime: time,
category: Category.NOTE,
subCategory: undefined,
},
};
};
return (
<>
<div
@ -38,6 +70,7 @@ const Note: Component<Props> = (props) => {
open={open}
closeHandler={() => setOpen(false)}
coordinate={coordinate}
initialWpt={initialWpt}
/>
</>
);

View File

@ -78,11 +78,19 @@ export const Wpt: Component<Props> = ({
const features = new GeoJSON().readFeatures(geo);
console.log({ caller: 'Wpt', features });
const feature = vectorSources[0].getFeatureById(wptId);
if (feature) {
vectorSources[0].removeFeature(feature);
const feature0 = vectorSources[0].getFeatureById(wptId);
if (feature0) {
vectorSources[0].removeFeature(feature0);
}
const feature1 = vectorSources[1].getFeatureById(wptId);
if (feature1) {
vectorSources[1].removeFeature(feature1);
}
if (wpt()?.extensions?.category === 'note') {
vectorSources[1].addFeatures(features);
} else {
vectorSources[0].addFeatures(features);
}
vectorSources[0].addFeatures(features);
}
});

View File

@ -1,4 +1,12 @@
import { Box, Button, Stack, TextField } from '@suid/material';
import {
Box,
Button,
FormControl,
InputLabel,
NativeSelect,
Stack,
TextField,
} from '@suid/material';
import { Component, createEffect, createSignal, Show } from 'solid-js';
import { useI18n } from '@solid-primitives/i18n';
@ -15,21 +23,38 @@ import { emptyGpx } from '../../db/gpx';
import getUri from '../../lib/ids';
import { Coordinate } from 'ol/coordinate';
export enum Category {
NOTE = 'note',
POI = 'poi',
UNKNOWN = '',
}
export enum SubCategory {
ACCOMMODATION = 'accommodation',
UNKNOWN = '',
}
interface Props {
wptId?: string;
coordinate?: () => Coordinate | undefined;
type?: string;
open: () => boolean;
closeHandler?: () => void;
initialWpt: () => Wpt;
}
const WptEditDialog: Component<Props> = (props) => {
const { wptId, closeHandler, open, coordinate, type = 'poi' } = props;
const {
wptId,
closeHandler,
open,
coordinate,
initialWpt = () => emptyWpt,
} = props;
const [t, { add, locale, dict }] = useI18n();
const wpt = !!wptId
? peekCachedSignal({ id: wptId, method: 'getWpt' })
: () => emptyWpt;
: initialWpt;
const [gpxId, setGpxId] = !wptId
? createSignal<string>(currentGpxId())
@ -108,7 +133,7 @@ const WptEditDialog: Component<Props> = (props) => {
action: 'putWpt',
params: { id: newWptId, wpt: editedWpt() },
});
setEditedWpt(undefined);
_closeHandler();
};
@ -119,6 +144,25 @@ const WptEditDialog: Component<Props> = (props) => {
return t('wpt');
};
// <TextField
// label={t('sym')}
// defaultValue={wpt()?.sym}
// onChange={(event: any, value: string) => {
// setEditedWpt({ ...editedWpt(), sym: value });
// }}
// />
// <TextField
// label={t('minZoom')}
// defaultValue={wpt()?.extensions?.['dyo:minZoom']?.toString()}
// onChange={(event: any, value: string) => {
// const extensions = {
// ...editedWpt()?.extensions,
// 'dyo:minZoom': parseFloat(value),
// };
// setEditedWpt({ ...editedWpt(), extensions });
// }}
// />
return (
<Dialog
open={open() && !!wpt()}
@ -148,24 +192,42 @@ const WptEditDialog: Component<Props> = (props) => {
setEditedWpt({ ...editedWpt(), name: value });
}}
/>
<TextField
label={t('sym')}
defaultValue={wpt()?.sym}
onChange={(event: any, value: string) => {
setEditedWpt({ ...editedWpt(), sym: value });
}}
/>
<TextField
label={t('minZoom')}
defaultValue={wpt()?.extensions?.['dyo:minZoom']?.toString()}
onChange={(event: any, value: string) => {
const extensions = {
...editedWpt()?.extensions,
'dyo:minZoom': parseFloat(value),
};
setEditedWpt({ ...editedWpt(), extensions });
}}
/>
<FormControl>
<InputLabel variant='normal' htmlFor='category'>
Type
</InputLabel>
<NativeSelect
inputProps={{
name: 'category',
id: 'category',
}}
onChange={(event: any, value: string) => {
setEditedWpt({
...editedWpt(),
extensions: { ...editedWpt().extensions, category: value },
});
}}
>
<option
value={Category.POI}
selected={editedWpt()?.extensions?.category === Category.POI}
>
Point d'intérêt
</option>
<option
value={Category.NOTE}
selected={editedWpt()?.extensions?.category === Category.NOTE}
>
Note
</option>
<option
value={undefined}
selected={!editedWpt()?.extensions?.category}
>
Autre
</option>
</NativeSelect>
</FormControl>
<TextField
label={t('gpxDesc')}
type='text'
@ -177,6 +239,34 @@ const WptEditDialog: Component<Props> = (props) => {
}}
InputProps={{ inputComponent: 'textarea' }}
/>
<TextField
label='Début'
type='datetime-local'
value={(editedWpt()?.extensions?.startTime || '').replace('Z', '')}
onChange={(event: any) => {
setEditedWpt({
...editedWpt(),
extensions: {
...editedWpt().extensions,
startTime: new Date(event.target.value).toISOString(),
},
});
}}
/>
<TextField
label='Fin'
type='datetime-local'
value={(editedWpt()?.extensions?.endTime || '').replace('Z', '')}
onChange={(event: any) => {
setEditedWpt({
...editedWpt(),
extensions: {
...editedWpt().extensions,
endTime: new Date(event.target.value).toISOString(),
},
});
}}
/>
<Stack spacing={2} direction='row' sx={{ marginTop: '20px' }}>
<Button variant='outlined' color='secondary' onClick={closeHandler}>
{t('cancel')}

View File

@ -1,32 +1,106 @@
import { Component } from 'solid-js';
import { Button, IconButton } from '@suid/material';
import { Component, createSignal } from 'solid-js';
import WptIcon from '../../icons/location-pin-svgrepo-com.svg?component-solid';
import { peekCachedSignal } from '../../workers/cached-signals';
import dispatch from '../../workers/dispatcher-main';
import { useI18n } from '@solid-primitives/i18n';
import Tree from '../tree';
import WptEditButtonAndDialog from './WptEditButtonAndDialog';
import DeleteIcon from '@suid/icons-material/Delete';
import QuestionMarkIcon from '@suid/icons-material/QuestionMark';
import Alert from '../alert';
interface Props {
wptId: string;
}
const WptViewer: Component<Props> = ({ wptId }) => {
const [t, { add, locale, dict }] = useI18n();
const wpt = peekCachedSignal({ id: wptId, method: 'getWpt' });
console.log({ caller: 'WptViewer', wptId, wpt: wpt() });
const title = () => {
return wpt().name;
};
const [confirmDelete, setConfirmDelete] = createSignal(false);
const confirmDeleteHandler = () => {
console.log({
caller: 'WptViewer / confirmDeleteHandler',
wptId,
});
setConfirmDelete(true);
};
const deleteHandler = () => {
console.log({
caller: 'WptViewer / deleteHandler',
wptId,
});
dispatch({ action: 'deleteWpt', params: { id: wptId } });
setConfirmDelete(false);
};
const cancelDeleteHandler = () => {
console.log({
caller: 'WptViewer / cancelDeleteHandler',
wptId,
});
setConfirmDelete(false);
};
return (
<Tree
title={
<>
<WptIcon fill='black' width='24' height='24' viewBox='0 0 300 300' />
{title()}
<WptEditButtonAndDialog wptId={wptId} />
</>
}
content={undefined}
subTree={undefined}
/>
<>
<Tree
title={
<>
<WptIcon
fill='black'
width='24'
height='24'
viewBox='0 0 300 300'
/>
{title()}
<WptEditButtonAndDialog wptId={wptId} />
<div>
<IconButton onClick={confirmDeleteHandler}>
<DeleteIcon fill='white' />
</IconButton>
</div>
</>
}
content={undefined}
subTree={undefined}
/>
<Alert
open={confirmDelete}
closeHandler={cancelDeleteHandler}
severity='warning'
icon={<QuestionMarkIcon />}
action={
<>
<Button
color='error'
variant='contained'
size='small'
onClick={deleteHandler}
>
{t('yes')}
</Button>
<Button
color='primary'
variant='outlined'
size='small'
onclick={cancelDeleteHandler}
>
{t('no')}
</Button>
</>
}
>
{t('deleteTrack')}
</Alert>
</>
);
};

11
src/db/types.d.ts vendored
View File

@ -42,17 +42,6 @@ interface Bounds_ {
maxlon: number;
}
export enum Category {
NOTE = 'note',
POI = 'poi',
UNKNOWN = '',
}
export enum SubCategory {
ACCOMMODATION = 'accommodation',
UNKNOWN = '',
}
interface Extensions {
'dyo:speed'?: number;
'dyo:course'?: number;

View File

@ -1,6 +1,6 @@
import getUri from '../lib/ids';
import { putNewGpx } from './gpx';
import { get, put } from './lib';
import { get, getFamily, put } from './lib';
export const emptyWpt: Wpt = {
$: { lat: 0, lon: 0 },
@ -62,3 +62,17 @@ export const getWpt = async (params: any) => {
const doc = await get(id);
return doc.doc;
};
export const deleteWpt = async (params: any) => {
const { id } = params;
const docs = await getFamily(id, { include_docs: false });
console.log({ caller: 'deleteWpt' }, id, docs);
const deletedDocs = docs.rows.reverse().map((doc: any) => ({
_deleted: true,
_id: doc.id,
_rev: doc.value.rev,
}));
console.log({ caller: 'deleteWpt' }, id, docs, deletedDocs);
await db.bulkDocs(deletedDocs);
return id;
};

View File

@ -26,7 +26,7 @@ import { getState, setState } from '../db/state';
import { deleteTrk, getTrk, putNewTrk } from '../db/trk';
import { putTrkpt } from '../db/trkpt';
import { getTrkseg, appendTrkpt } from '../db/trkseg';
import { getWpt, putWpt } from '../db/wpt';
import { getWpt, putWpt, deleteWpt } from '../db/wpt';
import { until } from '../lib/async-wait';
//const self = globalThis as unknown as WorkerGlobalScope;
@ -57,6 +57,7 @@ onmessage = async function (e) {
deleteTrk,
deleteRte,
deleteWpt,
getState,
setState,