Implementing an 'account' dialog (WIP)

This commit is contained in:
Eric van der Vlist 2022-12-25 16:30:47 +01:00
parent 0e2ffb0cf2
commit a36c8a28a4
12 changed files with 235 additions and 22 deletions

View File

@ -0,0 +1,7 @@
.control {
opacity: 1;
position: fixed !important;
top: 0px;
margin-left: calc(100% - 35px) !important;
z-index: 1;
}

View File

@ -0,0 +1,163 @@
import { Component, createSignal, For } from 'solid-js';
import PersonIcon from '@suid/icons-material/Person';
import style from './Account.module.css';
import {
Box,
IconButton,
InputLabel,
NativeSelect,
TextField,
} from '@suid/material';
import { useI18n } from '@solid-primitives/i18n';
import Dialog from '../dialog';
import dispatch from '../../workers/dispatcher-main';
import allGpxes from '../all-gpxes';
import gpx from '../gpx';
import { cloneDeep } from 'lodash';
const Account: Component<{}> = (props) => {
const [t] = useI18n();
const [open, setOpen] = createSignal(false);
const [settings, setSettings] = createSignal<any>();
const [accounts, setAccounts] = createSignal<any>();
const [account, setAccount] = createSignal<any>({});
const handleClickOpen = async () => {
setOpen(true);
const newSettings: any = await dispatch({
action: 'getSettings',
});
setSettings(newSettings || {});
const newAccounts: any = await dispatch({
action: 'getAccounts',
});
setAccounts([
{ id: '--new--', name: t('newAccount') },
...newAccounts.rows,
]);
console.log({
caller: 'Account / handleClickOpen',
settings: settings(),
accounts: accounts(),
});
};
const handleClose = (event: any, reason?: string) => {
console.log({
caller: 'Account / handleClose',
event,
reason,
});
if (reason === undefined) {
setOpen(false);
}
};
const changeAccountHandler = (event: any) => {
const selectedAccountName = event.target.value;
const targetAccount =
accounts().filter((acc: any) => acc.name === selectedAccountName)[0] ||
{};
setAccount(cloneDeep(targetAccount));
console.log({
caller: 'Account / changeAccountHandler',
event,
selectedAccountName,
account: account(),
});
};
const changeHandlerFactory = (path: string) => (event: any) => {
const value = event.target.value;
const newAccount = cloneDeep(account());
newAccount[path] = value;
setAccount(newAccount);
console.log({
caller: 'Account / changeHandlerFactory / ' + path,
event,
value,
account: account(),
});
};
return (
<>
<div class={style.control}>
<IconButton onClick={handleClickOpen}>
<PersonIcon />
</IconButton>
</div>
<Dialog
open={open()}
title={t('account')}
closeHandler={handleClose}
fullScreen={true}
>
<Box
component='form'
sx={{
width: '100%',
'& .MuiTextField-root': { m: 1, width: '100%' },
paddingTop: '5px',
}}
noValidate
autoComplete='off'
>
<InputLabel variant='normal' htmlFor='account-chooser'>
{t('accountChooser')}
</InputLabel>
<NativeSelect
inputProps={{
name: 'account-chooser',
id: 'account-chooser',
}}
onChange={changeAccountHandler}
>
<For each={accounts()}>
{(account: any) => (
<option value={account.id} selected={account.id === ''}>
{account.name}
</option>
)}
</For>
</NativeSelect>
<TextField
label={t('accountName')}
value={account().name || ''}
onChange={changeHandlerFactory('name')}
/>
<TextField
label={t('localDb')}
value={account().localDb || ''}
onChange={changeHandlerFactory('localDb')}
/>
<TextField
label={t('remoteDbServer')}
value={account().remoteDbServer || ''}
onChange={changeHandlerFactory('remoteDbServer')}
/>
<TextField
label={t('remoteDbUser')}
value={account().remoteDbUser || ''}
onChange={changeHandlerFactory('remoteDbUser')}
/>
<TextField
label={t('remoteDbPassword')}
value={account().remoteDbPassword || ''}
onChange={changeHandlerFactory('remoteDbPassword')}
/>
</Box>
</Dialog>
</>
);
};
export default Account;

View File

@ -0,0 +1 @@
export { default } from './Account';

View File

@ -27,28 +27,14 @@ const Dialog: Component<{
backgroundColor: 'rgba(14, 116, 144, 0.7)',
color: 'white',
clear: 'both',
paddingRight: '20px',
margin: '0',
paddingLeft: '0',
}}
>
<Grid container spacing={2} alignItems='center'>
<Grid item xs={11}>
{props.title}
</Grid>
<Grid
item
xs={1}
sx={{
alignSelf: 'right',
marginRight: '0px',
paddingRight: '0px',
paddingTop: '16px',
}}
>
<IconButton onClick={props.closeHandler}>
<CloseIcon />
</IconButton>
</Grid>
</Grid>
<IconButton onClick={props.closeHandler}>
<CloseIcon />
</IconButton>
{props.title}
</DialogTitle>
<DialogContent sx={{ width: 'calc(100% - 60px)' }}>
{props.children}

View File

@ -40,6 +40,7 @@ import dispatch from '../../workers/dispatcher-main';
import { debounce } from 'lodash';
import { AndroidFullScreen } from '@awesome-cordova-plugins/android-full-screen';
import Account from '../account';
const [getState, setState] = createSignal({
lon: 0,
@ -271,6 +272,7 @@ const Map: Component = () => {
<GpxImport />
<MapTileProvider />
<GpxDialog />
<Account />
<AllGpxes map={getMap} />
<Infos />
</div>

11
src/db/account.ts Normal file
View File

@ -0,0 +1,11 @@
import { getFamily, put } from './lib';
import getUri from '../lib/ids';
export const getAccounts = async () => {
return await getFamily('account', {}, true);
};
export const putAccount = async (name: string, account: any) => {
const uri = getUri('account', name);
return await put(uri, 'account', (_: any) => account, {}, true);
};

View File

@ -36,8 +36,9 @@ export const put = async (
}
};
export const getFamily = async (key: string, options: any = {}) => {
return await db.allDocs({
export const getFamily = async (key: string, options: any = {}, local: boolean = false) => {
const targetDb = local ? localDb : db;
return await targetDb.allDocs({
startkey: key,
endkey: key + '\ufff0',
...options,

14
src/db/settings.ts Normal file
View File

@ -0,0 +1,14 @@
import { get, put } from './lib';
export const getSettings = async () => {
try {
return await get('settings', true);
} catch (err) {
console.error({ caller: 'getSettings', err });
return undefined;
}
};
export const putSettings = async (settings: any) => {
return await put('settings', 'settings', (_: any) => settings, {}, true);
};

View File

@ -52,6 +52,15 @@ const dict = {
gpxPauseRecording: 'Suspend recording',
ResumeRecording: 'Resume recording',
StopRecording: 'Stop recording',
account: 'User account',
newAccount: '-- new account --',
accountChooser: 'Choose an account',
accountName: 'Account name',
localDb: 'Local database name',
remoteDbServer: 'Remote database server URL',
remoteDbUser: 'Remote database user',
remoteDbPassword: 'Remote database password',
};
export default dict;

View File

@ -57,6 +57,15 @@ const dict = {
gpxPauseRecording: "Mettre l'enregistrement en pause",
gpxResumeRecording: "Reprendre l'enregistrement",
gpxStopRecording: "Arrêter l'enregistrement",
account: 'Compte utilisateur',
newAccount: '-- nouveau compte --',
accountChooser: 'Choisissez un compte',
accountName: 'Nom du compte',
localDb: 'Nom de la base de données locale',
remoteDbServer: 'Adresse du serveur de base de données distant',
remoteDbUser: 'Utilisateur de la base de données distante',
remoteDbPassword: 'Mot de passe de la base de données distante',
};
export default dict;

View File

@ -26,6 +26,8 @@ const coding = {
const routes = {
dbdef: route('dbdef', coding),
state: route('state', coding),
account: route('account/:account', coding),
settings: route('settings', coding),
gpx: route('gpx/:gpx', coding),
wpt: route('gpx/:gpx/1wpt/:wpt', coding),

View File

@ -1,5 +1,6 @@
/// <reference lib="webworker" />
import { initDb } from '../db';
import { getAccounts, putAccount } from '../db/account';
import { cancelWatch, getAndWatch } from '../db/change-handler';
import {
putNewGpx,
@ -11,6 +12,7 @@ import {
getAllGpxes,
getAllGpxesWithSummary,
} from '../db/gpx';
import { getSettings, putSettings } from '../db/settings';
import { getState, setState } from '../db/state';
import { getTrk, putNewTrk } from '../db/trk';
import { getTrkseg, appendTrkpt } from '../db/trkseg';
@ -43,6 +45,12 @@ onmessage = async function (e) {
getAndWatch,
cancelWatch,
getSettings,
putSettings,
getAccounts,
putAccount,
};
console.log({ caller: 'dispatcher-worker / onmessage', e });