First version of notes, also allowing to delete wpts
This commit is contained in:
parent
bf179a4b6d
commit
adbbb3e356
|
@ -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}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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')}
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue