dyomedea/src/components/gpx-dialog/GpxDialog.tsx

254 lines
7.0 KiB
TypeScript

import { useI18n } from '@solid-primitives/i18n';
import {
Box,
Button,
FormControlLabel,
IconButton,
Radio,
RadioGroup,
SvgIcon,
TextField,
} from '@suid/material';
import { cloneDeep, isPlainObject } from 'lodash';
import { Component, createSignal, Show } from 'solid-js';
import { newEmptyGpx } from '../../db/gpx';
import { peekCachedSignal } from '../../workers/cached-signals';
import dispatch from '../../workers/dispatcher-main';
import Dialog from '../dialog';
import GpxChooser from '../gpx-chooser';
import GpxIcon from '../gpx/GpxIcon';
//import GpxesIcon from '../../icons/adventure-journey-location-svgrepo-com.svg';
import style from './GpxDialog.module.css';
import {
getTagValue,
getTagsFromObj,
setTagValue,
setTagsIntoObj,
} from '../../lib/tags/tags';
export const [currentGpxId, setCurrentGpxId] = createSignal<string>('new');
const GpxDialog: Component<{}> = (props) => {
const [t] = useI18n();
const [open, setOpen] = createSignal(false);
const [selectedGpxId, setSelectedGpxId] = createSignal<string>('');
const [gpx, setGpx] = createSignal<Gpx>();
const [currentAccount, setCurrentAccount] = createSignal<any>();
console.log({ caller: 'GpxDialog', currentGpxId: currentGpxId() });
const fetchGpx = (gpxId: string) => {
if (gpxId === 'new' || !gpxId) {
return newEmptyGpx();
}
const newGpx = peekCachedSignal({
id: gpxId,
action: 'getGpx',
});
return newGpx();
};
dispatch({ action: 'getCurrentAccount' }).then((currentAccount: any) => {
console.log({ caller: 'GpxDialog / currentAccount', currentAccount });
setCurrentAccount(currentAccount);
setCurrentGpxId(currentAccount.currentGpxId || 'new');
setSelectedGpxId(currentAccount.currentGpxId || 'new');
});
const handleClickOpen = async () => {
setOpen(true);
setGpx(fetchGpx(currentGpxId()) as Gpx);
console.log({
caller: 'GpxDialog / handleClickOpen',
currentGpxId: currentGpxId(),
gpx: gpx(),
});
};
const handleClose = (event: any, reason?: string) => {
console.log({
caller: 'GpxDialog / handleClose',
event,
reason,
});
if (reason === undefined) {
setOpen(false);
}
};
const gpxChangeHandler = async (gpxId: string) => {
setSelectedGpxId(gpxId);
setGpx(fetchGpx(gpxId) as Gpx);
console.log({
caller: 'GpxDialog / gpxChangeHandler',
gpxId,
gpx: gpx(),
});
};
const gpxNameChangeHandler = (event: any) => {
const newGpx: Gpx = cloneDeep(gpx()) as Gpx;
if (newGpx.metadata === undefined) {
newGpx.metadata = {};
}
newGpx.metadata.name = event.target.value;
setGpx(newGpx);
console.log({
caller: 'GpxDialog / gpxNameChangeHandler',
value: event.target.value,
gpx: gpx(),
});
};
const gpxDescChangeHandler = (event: any) => {
const newGpx: Gpx = cloneDeep(gpx()) as Gpx;
if (newGpx.metadata === undefined) {
newGpx.metadata = {};
}
newGpx.metadata.desc = event.target.value;
setGpx(newGpx);
console.log({
caller: 'GpxDialog / gpxDescChangeHandler',
value: event.target.value,
gpx: gpx(),
});
};
const gpxToChangeHandler = (event: any) => {
const newGpx: Gpx = cloneDeep(gpx()) as Gpx;
if (!isPlainObject(newGpx.extensions)) {
newGpx.extensions = {};
}
newGpx.extensions.to = event.target.value;
setGpx(newGpx);
console.log({
caller: 'GpxDialog / gpxToChangeHandler',
value: event.target.value,
gpx: gpx(),
newGpx,
});
};
const gpxTimeChangeHandler = (event: any) => {
const newGpx: Gpx = cloneDeep(gpx()) as Gpx;
if (newGpx.metadata === undefined) {
newGpx.metadata = {};
}
newGpx.metadata.time = new Date(event.target.value).toISOString();
setGpx(newGpx);
console.log({
caller: 'GpxDialog / gpxTimeChangeHandler',
value: event.target.value,
gpx: gpx(),
});
};
const getGpxTagValue = (tagName: string, defaultValue: string) => {
return getTagValue(getTagsFromObj(gpx()), tagName) || defaultValue;
};
const gpxLocomotionChangeHandler = (event: any) => {
const newGpx: Gpx = cloneDeep(gpx()) as Gpx;
const tags = getTagsFromObj(newGpx);
setTagValue(tags, 'locomotion', event.target.value);
setTagsIntoObj(newGpx, tags);
setGpx(newGpx);
};
const saveHandler = async (event: any) => {
const id = (await dispatch({
action: 'putGpx',
params: {
id: selectedGpxId(),
gpx: gpx(),
},
})) as string;
setCurrentGpxId(id);
setOpen(false);
await dispatch({
action: 'putCurrentAccount',
params: {
account: { ...currentAccount(), currentGpxId: currentGpxId() },
},
});
};
return (
<>
<div class={style.control}>
<IconButton onClick={handleClickOpen}>
<GpxIcon />
</IconButton>
</div>
<Dialog
open={open()}
title={t('gpxDialog')}
closeHandler={handleClose}
fullScreen={true}
>
<Box
component='form'
sx={{
width: '100%',
'& .MuiTextField-root': { m: 1, width: '100%' },
paddingTop: '5px',
}}
noValidate
autoComplete='off'
>
<GpxChooser gpxId={selectedGpxId} setGpxId={gpxChangeHandler} />
<Show when={gpx() != undefined}>
<TextField
label={t('gpxName')}
value={gpx()?.metadata?.name || ''}
onChange={gpxNameChangeHandler}
/>
<TextField
label={t('gpxTime')}
type='datetime-local'
value={(gpx()?.metadata?.time || '').replace('Z', '')}
onChange={gpxTimeChangeHandler}
/>
<TextField
label={t('gpxDesc')}
multiline={true}
rows={5}
value={gpx()?.metadata?.desc || ''}
onChange={gpxDescChangeHandler}
InputProps={{ inputComponent: 'textarea' }}
/>
<div>Locomotion</div>
<RadioGroup
value={getGpxTagValue('locomotion', 'hiking')}
onChange={gpxLocomotionChangeHandler}
>
<FormControlLabel
value='hiking'
control={<Radio />}
label='Hiking'
></FormControlLabel>
<FormControlLabel
value='cycling'
control={<Radio />}
label='Cycling'
></FormControlLabel>
</RadioGroup>
<TextField
label={t('gpxTo')}
multiline={true}
rows={5}
value={gpx()?.extensions?.to || ''}
onChange={gpxToChangeHandler}
InputProps={{ inputComponent: 'textarea' }}
/>
<Button variant='contained' onClick={saveHandler}>
{t('gpxSave')}
</Button>
</Show>
</Box>
</Dialog>
</>
);
};
export default GpxDialog;