2023-02-21 20:11:03 +00:00
|
|
|
import { createForm } from '@felte/solid';
|
2023-02-22 14:32:02 +00:00
|
|
|
import { Component, createSignal, Match, Switch } from 'solid-js';
|
|
|
|
import { TextField, Button, Dialog } from '@kobalte/core';
|
2023-02-21 12:05:28 +00:00
|
|
|
|
2023-02-21 20:11:03 +00:00
|
|
|
import './style.css';
|
|
|
|
import { createServerAction$ } from 'solid-start/server';
|
|
|
|
import PouchDb from 'pouchdb';
|
|
|
|
import { v4 as uuid } from 'uuid';
|
2023-02-22 10:19:10 +00:00
|
|
|
import { put } from '~/lib/db';
|
|
|
|
import { useNavigate } from 'solid-start';
|
2023-02-22 13:54:41 +00:00
|
|
|
import { toHex } from '~/lib/to-hex';
|
|
|
|
import { cloneDeep } from 'lodash';
|
2023-02-22 17:24:06 +00:00
|
|
|
import Password, { UsernamePassword } from '../password/Password';
|
2023-02-21 10:23:35 +00:00
|
|
|
|
2023-02-22 10:19:10 +00:00
|
|
|
interface Props {
|
|
|
|
values?: any;
|
|
|
|
}
|
2023-02-21 10:23:35 +00:00
|
|
|
|
|
|
|
const Invitation: Component<Props> = (props) => {
|
2023-02-22 10:19:10 +00:00
|
|
|
const navigate = useNavigate();
|
|
|
|
|
2023-02-22 14:32:02 +00:00
|
|
|
const [openDialog, setOpenDialog] = createSignal(false);
|
2023-02-22 17:24:06 +00:00
|
|
|
const [openUsernamePasswordDialog, setOpenUserNamePasswordDialog] =
|
|
|
|
createSignal(false);
|
2023-02-22 14:32:02 +00:00
|
|
|
|
|
|
|
const [status, setStatus] = createSignal<string>();
|
|
|
|
|
2023-02-22 10:19:10 +00:00
|
|
|
const [saving, save] = createServerAction$(async (args: any) => {
|
|
|
|
const { props, values } = args;
|
|
|
|
console.log({
|
|
|
|
caller: 'Invitation / save',
|
|
|
|
props,
|
|
|
|
values,
|
|
|
|
args,
|
2023-02-22 10:58:56 +00:00
|
|
|
id: props.values?._id,
|
2023-02-22 10:19:10 +00:00
|
|
|
});
|
2023-02-21 20:11:03 +00:00
|
|
|
const db = new PouchDb('.db');
|
2023-02-22 10:58:56 +00:00
|
|
|
const id = props.values?._id ?? `invitation/${uuid()}`;
|
2023-02-22 10:19:10 +00:00
|
|
|
await put({
|
|
|
|
db,
|
|
|
|
doc: {
|
|
|
|
_id: id,
|
|
|
|
date: new Date().toISOString(),
|
|
|
|
type: 'invitation',
|
|
|
|
...values,
|
|
|
|
},
|
2023-02-21 12:38:43 +00:00
|
|
|
});
|
2023-02-21 15:12:52 +00:00
|
|
|
return id;
|
2023-02-21 12:38:43 +00:00
|
|
|
});
|
|
|
|
|
2023-02-22 13:54:41 +00:00
|
|
|
const [dbChecking, dbCheck] = createServerAction$(async (args: any) => {
|
|
|
|
console.log({
|
|
|
|
caller: 'Invitation / dbCheck',
|
|
|
|
args,
|
|
|
|
});
|
2023-02-22 14:32:02 +00:00
|
|
|
let baseDbInfoAuth;
|
2023-02-22 13:54:41 +00:00
|
|
|
try {
|
|
|
|
const baseDb = new PouchDb(cloneDeep(args));
|
2023-02-22 14:32:02 +00:00
|
|
|
baseDbInfoAuth = await baseDb.info();
|
|
|
|
} catch (error) {
|
|
|
|
baseDbInfoAuth = { error };
|
|
|
|
}
|
|
|
|
let baseDbInfoAnon;
|
|
|
|
try {
|
|
|
|
const baseDb = new PouchDb(args.name);
|
|
|
|
baseDbInfoAnon = await baseDb.info();
|
2023-02-22 13:54:41 +00:00
|
|
|
} catch (error) {
|
2023-02-22 14:32:02 +00:00
|
|
|
baseDbInfoAnon = { error };
|
2023-02-22 13:54:41 +00:00
|
|
|
}
|
|
|
|
const name = `${args.name}/userdb-${toHex(args.auth.username)}`;
|
|
|
|
let userDbInfo;
|
|
|
|
try {
|
|
|
|
const userDb = new PouchDb({ ...args, name });
|
|
|
|
userDbInfo = await userDb.info();
|
|
|
|
} catch (error) {
|
2023-02-22 14:32:02 +00:00
|
|
|
userDbInfo = { error };
|
2023-02-22 13:54:41 +00:00
|
|
|
}
|
2023-02-22 14:32:02 +00:00
|
|
|
let userDbInfoAnon;
|
|
|
|
try {
|
|
|
|
const userDb = new PouchDb(name);
|
|
|
|
userDbInfoAnon = await userDb.info();
|
|
|
|
} catch (error) {
|
|
|
|
userDbInfoAnon = { error };
|
|
|
|
}
|
|
|
|
return { baseDbInfoAuth, baseDbInfoAnon, userDbInfo, userDbInfoAnon };
|
2023-02-22 13:54:41 +00:00
|
|
|
});
|
|
|
|
|
2023-02-22 10:19:10 +00:00
|
|
|
const submitHandler = async (values: any, context: any) => {
|
2023-02-21 10:23:35 +00:00
|
|
|
console.log({
|
2023-02-21 20:11:03 +00:00
|
|
|
caller: 'Invitation / submitHandler',
|
2023-02-21 10:23:35 +00:00
|
|
|
props,
|
|
|
|
values,
|
|
|
|
context,
|
|
|
|
});
|
2023-02-22 10:19:10 +00:00
|
|
|
const id = await save({ values, props });
|
|
|
|
if (!props.values) {
|
|
|
|
navigate(`/invitations/${encodeURIComponent(id)}`);
|
|
|
|
}
|
2023-02-21 10:23:35 +00:00
|
|
|
};
|
|
|
|
|
2023-02-22 10:58:56 +00:00
|
|
|
const cancelHandler = () => {
|
|
|
|
navigate(`/invitations/`);
|
|
|
|
};
|
|
|
|
|
|
|
|
const deleteHandler = async () => {
|
|
|
|
console.log({
|
|
|
|
caller: 'Invitation / deleteHandler',
|
|
|
|
props,
|
|
|
|
});
|
|
|
|
await save({ props, values: { _deleted: true } });
|
|
|
|
navigate(`/invitations/`);
|
|
|
|
};
|
|
|
|
|
2023-02-22 13:54:41 +00:00
|
|
|
const { form, data } = createForm({
|
2023-02-22 10:19:10 +00:00
|
|
|
onSubmit: submitHandler,
|
|
|
|
initialValues: props?.values,
|
|
|
|
});
|
|
|
|
|
2023-02-22 13:54:41 +00:00
|
|
|
const dbCheckHandler = async () => {
|
|
|
|
const result = await dbCheck({
|
|
|
|
name: data('database'),
|
|
|
|
auth: { username: data('username'), password: data('password') },
|
|
|
|
});
|
|
|
|
console.log({
|
|
|
|
caller: 'Invitation / dbCheckHandler',
|
|
|
|
props,
|
|
|
|
data: data(),
|
|
|
|
result,
|
|
|
|
});
|
2023-02-22 14:32:02 +00:00
|
|
|
if (result.baseDbInfoAnon.error) {
|
|
|
|
setStatus('baseError');
|
|
|
|
} else if (!result.userDbInfo.error) {
|
|
|
|
setStatus('OK');
|
|
|
|
} else if (
|
|
|
|
result.userDbInfoAnon.error.reason ===
|
|
|
|
'You are not authorized to access this db.'
|
|
|
|
) {
|
|
|
|
setStatus('passwordError');
|
|
|
|
} else {
|
|
|
|
setStatus('notFound');
|
|
|
|
}
|
|
|
|
setOpenDialog(true);
|
2023-02-22 13:54:41 +00:00
|
|
|
};
|
|
|
|
|
2023-02-22 14:45:52 +00:00
|
|
|
const createUserHandler = async () => {
|
|
|
|
console.log({
|
|
|
|
caller: 'Invitation / createUserHandler',
|
|
|
|
props,
|
|
|
|
data: data(),
|
|
|
|
});
|
2023-02-22 17:24:06 +00:00
|
|
|
setOpenUserNamePasswordDialog(true);
|
|
|
|
};
|
|
|
|
|
|
|
|
const usernamePasswordHandler = async (
|
|
|
|
usernamePassword: UsernamePassword
|
|
|
|
) => {
|
|
|
|
console.log({
|
|
|
|
caller: 'Invitation / usernamePasswordHandler',
|
|
|
|
props,
|
|
|
|
usernamePassword,
|
|
|
|
});
|
|
|
|
setOpenUserNamePasswordDialog(false);
|
2023-02-22 14:45:52 +00:00
|
|
|
};
|
|
|
|
|
2023-02-22 10:19:10 +00:00
|
|
|
console.log({
|
|
|
|
caller: 'Invitation ',
|
|
|
|
props,
|
|
|
|
});
|
2023-02-21 10:23:35 +00:00
|
|
|
|
|
|
|
return (
|
2023-02-22 14:32:02 +00:00
|
|
|
<>
|
|
|
|
<form use:form>
|
|
|
|
<TextField.Root>
|
|
|
|
<TextField.Label>Mail address</TextField.Label>
|
|
|
|
<TextField.Input
|
|
|
|
type='mail'
|
|
|
|
name='mail'
|
|
|
|
required={true}
|
|
|
|
placeholder='Email address'
|
|
|
|
/>
|
|
|
|
<TextField.ErrorMessage>
|
|
|
|
Please provide a valid URL
|
|
|
|
</TextField.ErrorMessage>
|
|
|
|
</TextField.Root>
|
|
|
|
<TextField.Root>
|
|
|
|
<TextField.Label>Database</TextField.Label>
|
|
|
|
<TextField.Input
|
|
|
|
type='url'
|
|
|
|
name='database'
|
|
|
|
required={true}
|
|
|
|
placeholder='Database URL'
|
|
|
|
/>
|
|
|
|
<TextField.ErrorMessage>
|
|
|
|
Please provide a valid URL
|
|
|
|
</TextField.ErrorMessage>
|
|
|
|
</TextField.Root>
|
|
|
|
<TextField.Root>
|
|
|
|
<TextField.Label>User name</TextField.Label>
|
|
|
|
<TextField.Input
|
|
|
|
type='text'
|
|
|
|
name='username'
|
|
|
|
required={true}
|
|
|
|
placeholder='user name'
|
|
|
|
/>
|
|
|
|
</TextField.Root>
|
|
|
|
<TextField.Root>
|
|
|
|
<TextField.Label>Password</TextField.Label>
|
|
|
|
<TextField.Input
|
|
|
|
type='text'
|
|
|
|
name='password'
|
|
|
|
required={true}
|
|
|
|
placeholder='Password'
|
|
|
|
autocomplete='off'
|
|
|
|
/>
|
|
|
|
<TextField.ErrorMessage>
|
|
|
|
Please provide a valid password
|
|
|
|
</TextField.ErrorMessage>
|
|
|
|
</TextField.Root>
|
|
|
|
<Switch>
|
|
|
|
<Match when={!!props.values}>
|
|
|
|
<Button.Root type='submit'>Save</Button.Root>
|
|
|
|
<Button.Root onclick={deleteHandler}>Delete</Button.Root>
|
|
|
|
</Match>
|
|
|
|
<Match when={!props.values}>
|
|
|
|
<Button.Root type='submit'>Create</Button.Root>
|
|
|
|
</Match>
|
|
|
|
</Switch>
|
|
|
|
<Button.Root onclick={dbCheckHandler}>DB check</Button.Root>
|
|
|
|
<Button.Root onclick={cancelHandler}>Cancel</Button.Root>
|
|
|
|
</form>
|
|
|
|
<Dialog.Root isOpen={openDialog()} onOpenChange={setOpenDialog}>
|
|
|
|
<Dialog.Portal>
|
|
|
|
<Dialog.Overlay class='dialog__overlay' />
|
|
|
|
<div class='dialog__positioner'>
|
|
|
|
<Dialog.Content class='dialog__content'>
|
|
|
|
<div class='dialog__header'>
|
|
|
|
<Dialog.Title class='dialog__title'>
|
|
|
|
Database check
|
|
|
|
</Dialog.Title>
|
|
|
|
<Dialog.CloseButton class='dialog__close-button'>
|
|
|
|
X
|
|
|
|
</Dialog.CloseButton>
|
|
|
|
</div>
|
|
|
|
<Dialog.Description class='dialog__description'>
|
|
|
|
<Switch>
|
|
|
|
<Match when={status() === 'baseError'}>
|
|
|
|
The database address seems to be wrong !!
|
2023-02-22 14:45:52 +00:00
|
|
|
</Match>
|
2023-02-22 14:32:02 +00:00
|
|
|
<Match when={status() === 'OK'}>
|
|
|
|
The user is already existing.
|
|
|
|
</Match>
|
|
|
|
<Match when={status() === 'notFound'}>
|
2023-02-22 14:45:52 +00:00
|
|
|
<div>The user must be created.</div>
|
|
|
|
<Button.Root onclick={createUserHandler}>
|
|
|
|
Create user
|
|
|
|
</Button.Root>
|
2023-02-22 14:32:02 +00:00
|
|
|
</Match>
|
|
|
|
<Match when={status() === 'passwordError'}>
|
2023-02-22 14:45:52 +00:00
|
|
|
<div>
|
|
|
|
The user seems to exist but the password is wrong.
|
|
|
|
</div>
|
|
|
|
<Button.Root onclick={createUserHandler}>
|
|
|
|
Update password
|
|
|
|
</Button.Root>
|
2023-02-22 14:32:02 +00:00
|
|
|
</Match>
|
|
|
|
</Switch>
|
|
|
|
</Dialog.Description>
|
|
|
|
</Dialog.Content>
|
|
|
|
</div>
|
|
|
|
</Dialog.Portal>
|
|
|
|
</Dialog.Root>
|
2023-02-22 17:24:06 +00:00
|
|
|
<Password
|
|
|
|
open={openUsernamePasswordDialog}
|
|
|
|
setOpen={setOpenUserNamePasswordDialog}
|
|
|
|
url={data('database')}
|
|
|
|
usernamePassword={usernamePasswordHandler}
|
|
|
|
/>
|
2023-02-22 14:32:02 +00:00
|
|
|
</>
|
2023-02-21 10:23:35 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default Invitation;
|