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 NoteIcon from '@suid/icons-material/Note';
|
||||||
|
|
||||||
import style from './Note.module.css';
|
import style from './Note.module.css';
|
||||||
import WptEditDialog from '../wpt/WptEditDialog';
|
import WptEditDialog, { Category } from '../wpt/WptEditDialog';
|
||||||
import { Coordinate } from 'ol/coordinate';
|
import { Coordinate } from 'ol/coordinate';
|
||||||
|
|
||||||
interface Props {}
|
interface Props {}
|
||||||
|
@ -20,6 +20,38 @@ const Note: Component<Props> = (props) => {
|
||||||
setOpen(true);
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
|
@ -38,6 +70,7 @@ const Note: Component<Props> = (props) => {
|
||||||
open={open}
|
open={open}
|
||||||
closeHandler={() => setOpen(false)}
|
closeHandler={() => setOpen(false)}
|
||||||
coordinate={coordinate}
|
coordinate={coordinate}
|
||||||
|
initialWpt={initialWpt}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -78,12 +78,20 @@ export const Wpt: Component<Props> = ({
|
||||||
|
|
||||||
const features = new GeoJSON().readFeatures(geo);
|
const features = new GeoJSON().readFeatures(geo);
|
||||||
console.log({ caller: 'Wpt', features });
|
console.log({ caller: 'Wpt', features });
|
||||||
const feature = vectorSources[0].getFeatureById(wptId);
|
const feature0 = vectorSources[0].getFeatureById(wptId);
|
||||||
if (feature) {
|
if (feature0) {
|
||||||
vectorSources[0].removeFeature(feature);
|
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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
|
|
|
@ -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 { Component, createEffect, createSignal, Show } from 'solid-js';
|
||||||
import { useI18n } from '@solid-primitives/i18n';
|
import { useI18n } from '@solid-primitives/i18n';
|
||||||
|
|
||||||
|
@ -15,21 +23,38 @@ import { emptyGpx } from '../../db/gpx';
|
||||||
import getUri from '../../lib/ids';
|
import getUri from '../../lib/ids';
|
||||||
import { Coordinate } from 'ol/coordinate';
|
import { Coordinate } from 'ol/coordinate';
|
||||||
|
|
||||||
|
export enum Category {
|
||||||
|
NOTE = 'note',
|
||||||
|
POI = 'poi',
|
||||||
|
UNKNOWN = '',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum SubCategory {
|
||||||
|
ACCOMMODATION = 'accommodation',
|
||||||
|
UNKNOWN = '',
|
||||||
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
wptId?: string;
|
wptId?: string;
|
||||||
coordinate?: () => Coordinate | undefined;
|
coordinate?: () => Coordinate | undefined;
|
||||||
type?: string;
|
|
||||||
open: () => boolean;
|
open: () => boolean;
|
||||||
closeHandler?: () => void;
|
closeHandler?: () => void;
|
||||||
|
initialWpt: () => Wpt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const WptEditDialog: Component<Props> = (props) => {
|
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 [t, { add, locale, dict }] = useI18n();
|
||||||
|
|
||||||
const wpt = !!wptId
|
const wpt = !!wptId
|
||||||
? peekCachedSignal({ id: wptId, method: 'getWpt' })
|
? peekCachedSignal({ id: wptId, method: 'getWpt' })
|
||||||
: () => emptyWpt;
|
: initialWpt;
|
||||||
|
|
||||||
const [gpxId, setGpxId] = !wptId
|
const [gpxId, setGpxId] = !wptId
|
||||||
? createSignal<string>(currentGpxId())
|
? createSignal<string>(currentGpxId())
|
||||||
|
@ -108,7 +133,7 @@ const WptEditDialog: Component<Props> = (props) => {
|
||||||
action: 'putWpt',
|
action: 'putWpt',
|
||||||
params: { id: newWptId, wpt: editedWpt() },
|
params: { id: newWptId, wpt: editedWpt() },
|
||||||
});
|
});
|
||||||
|
setEditedWpt(undefined);
|
||||||
_closeHandler();
|
_closeHandler();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -119,6 +144,25 @@ const WptEditDialog: Component<Props> = (props) => {
|
||||||
return t('wpt');
|
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 (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={open() && !!wpt()}
|
open={open() && !!wpt()}
|
||||||
|
@ -148,24 +192,42 @@ const WptEditDialog: Component<Props> = (props) => {
|
||||||
setEditedWpt({ ...editedWpt(), name: value });
|
setEditedWpt({ ...editedWpt(), name: value });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<FormControl>
|
||||||
label={t('sym')}
|
<InputLabel variant='normal' htmlFor='category'>
|
||||||
defaultValue={wpt()?.sym}
|
Type
|
||||||
onChange={(event: any, value: string) => {
|
</InputLabel>
|
||||||
setEditedWpt({ ...editedWpt(), sym: value });
|
<NativeSelect
|
||||||
|
inputProps={{
|
||||||
|
name: 'category',
|
||||||
|
id: 'category',
|
||||||
}}
|
}}
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label={t('minZoom')}
|
|
||||||
defaultValue={wpt()?.extensions?.['dyo:minZoom']?.toString()}
|
|
||||||
onChange={(event: any, value: string) => {
|
onChange={(event: any, value: string) => {
|
||||||
const extensions = {
|
setEditedWpt({
|
||||||
...editedWpt()?.extensions,
|
...editedWpt(),
|
||||||
'dyo:minZoom': parseFloat(value),
|
extensions: { ...editedWpt().extensions, category: value },
|
||||||
};
|
});
|
||||||
setEditedWpt({ ...editedWpt(), extensions });
|
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
<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
|
<TextField
|
||||||
label={t('gpxDesc')}
|
label={t('gpxDesc')}
|
||||||
type='text'
|
type='text'
|
||||||
|
@ -177,6 +239,34 @@ const WptEditDialog: Component<Props> = (props) => {
|
||||||
}}
|
}}
|
||||||
InputProps={{ inputComponent: 'textarea' }}
|
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' }}>
|
<Stack spacing={2} direction='row' sx={{ marginTop: '20px' }}>
|
||||||
<Button variant='outlined' color='secondary' onClick={closeHandler}>
|
<Button variant='outlined' color='secondary' onClick={closeHandler}>
|
||||||
{t('cancel')}
|
{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 WptIcon from '../../icons/location-pin-svgrepo-com.svg?component-solid';
|
||||||
import { peekCachedSignal } from '../../workers/cached-signals';
|
import { peekCachedSignal } from '../../workers/cached-signals';
|
||||||
|
import dispatch from '../../workers/dispatcher-main';
|
||||||
|
import { useI18n } from '@solid-primitives/i18n';
|
||||||
import Tree from '../tree';
|
import Tree from '../tree';
|
||||||
import WptEditButtonAndDialog from './WptEditButtonAndDialog';
|
import WptEditButtonAndDialog from './WptEditButtonAndDialog';
|
||||||
|
import DeleteIcon from '@suid/icons-material/Delete';
|
||||||
|
import QuestionMarkIcon from '@suid/icons-material/QuestionMark';
|
||||||
|
import Alert from '../alert';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
wptId: string;
|
wptId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const WptViewer: Component<Props> = ({ wptId }) => {
|
const WptViewer: Component<Props> = ({ wptId }) => {
|
||||||
|
const [t, { add, locale, dict }] = useI18n();
|
||||||
const wpt = peekCachedSignal({ id: wptId, method: 'getWpt' });
|
const wpt = peekCachedSignal({ id: wptId, method: 'getWpt' });
|
||||||
console.log({ caller: 'WptViewer', wptId, wpt: wpt() });
|
console.log({ caller: 'WptViewer', wptId, wpt: wpt() });
|
||||||
const title = () => {
|
const title = () => {
|
||||||
return wpt().name;
|
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 (
|
return (
|
||||||
|
<>
|
||||||
<Tree
|
<Tree
|
||||||
title={
|
title={
|
||||||
<>
|
<>
|
||||||
<WptIcon fill='black' width='24' height='24' viewBox='0 0 300 300' />
|
<WptIcon
|
||||||
|
fill='black'
|
||||||
|
width='24'
|
||||||
|
height='24'
|
||||||
|
viewBox='0 0 300 300'
|
||||||
|
/>
|
||||||
{title()}
|
{title()}
|
||||||
<WptEditButtonAndDialog wptId={wptId} />
|
<WptEditButtonAndDialog wptId={wptId} />
|
||||||
|
<div>
|
||||||
|
<IconButton onClick={confirmDeleteHandler}>
|
||||||
|
<DeleteIcon fill='white' />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
content={undefined}
|
content={undefined}
|
||||||
subTree={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;
|
maxlon: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Category {
|
|
||||||
NOTE = 'note',
|
|
||||||
POI = 'poi',
|
|
||||||
UNKNOWN = '',
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum SubCategory {
|
|
||||||
ACCOMMODATION = 'accommodation',
|
|
||||||
UNKNOWN = '',
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Extensions {
|
interface Extensions {
|
||||||
'dyo:speed'?: number;
|
'dyo:speed'?: number;
|
||||||
'dyo:course'?: number;
|
'dyo:course'?: number;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import getUri from '../lib/ids';
|
import getUri from '../lib/ids';
|
||||||
import { putNewGpx } from './gpx';
|
import { putNewGpx } from './gpx';
|
||||||
import { get, put } from './lib';
|
import { get, getFamily, put } from './lib';
|
||||||
|
|
||||||
export const emptyWpt: Wpt = {
|
export const emptyWpt: Wpt = {
|
||||||
$: { lat: 0, lon: 0 },
|
$: { lat: 0, lon: 0 },
|
||||||
|
@ -62,3 +62,17 @@ export const getWpt = async (params: any) => {
|
||||||
const doc = await get(id);
|
const doc = await get(id);
|
||||||
return doc.doc;
|
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 { deleteTrk, getTrk, putNewTrk } from '../db/trk';
|
||||||
import { putTrkpt } from '../db/trkpt';
|
import { putTrkpt } from '../db/trkpt';
|
||||||
import { getTrkseg, appendTrkpt } from '../db/trkseg';
|
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';
|
import { until } from '../lib/async-wait';
|
||||||
|
|
||||||
//const self = globalThis as unknown as WorkerGlobalScope;
|
//const self = globalThis as unknown as WorkerGlobalScope;
|
||||||
|
@ -57,6 +57,7 @@ onmessage = async function (e) {
|
||||||
|
|
||||||
deleteTrk,
|
deleteTrk,
|
||||||
deleteRte,
|
deleteRte,
|
||||||
|
deleteWpt,
|
||||||
|
|
||||||
getState,
|
getState,
|
||||||
setState,
|
setState,
|
||||||
|
|
Loading…
Reference in New Issue