This commit is contained in:
Eric van der Vlist 2023-02-22 15:32:02 +01:00
parent 0434b9c626
commit 6c479eb83e
2 changed files with 249 additions and 66 deletions

View File

@ -1,6 +1,6 @@
import { createForm } from '@felte/solid';
import { Component, createEffect, Match, Show, Switch } from 'solid-js';
import { TextField, Button } from '@kobalte/core';
import { Component, createSignal, Match, Switch } from 'solid-js';
import { TextField, Button, Dialog } from '@kobalte/core';
import './style.css';
import { createServerAction$ } from 'solid-start/server';
@ -18,6 +18,10 @@ interface Props {
const Invitation: Component<Props> = (props) => {
const navigate = useNavigate();
const [openDialog, setOpenDialog] = createSignal(false);
const [status, setStatus] = createSignal<string>();
const [saving, save] = createServerAction$(async (args: any) => {
const { props, values } = args;
console.log({
@ -46,12 +50,19 @@ const Invitation: Component<Props> = (props) => {
caller: 'Invitation / dbCheck',
args,
});
let baseDbInfo;
let baseDbInfoAuth;
try {
const baseDb = new PouchDb(cloneDeep(args));
baseDbInfo = await baseDb.info();
baseDbInfoAuth = await baseDb.info();
} catch (error) {
baseDbInfo = error;
baseDbInfoAuth = { error };
}
let baseDbInfoAnon;
try {
const baseDb = new PouchDb(args.name);
baseDbInfoAnon = await baseDb.info();
} catch (error) {
baseDbInfoAnon = { error };
}
const name = `${args.name}/userdb-${toHex(args.auth.username)}`;
let userDbInfo;
@ -59,9 +70,16 @@ const Invitation: Component<Props> = (props) => {
const userDb = new PouchDb({ ...args, name });
userDbInfo = await userDb.info();
} catch (error) {
userDbInfo = error;
userDbInfo = { error };
}
return { baseDbInfo, userDbInfo, args, name };
let userDbInfoAnon;
try {
const userDb = new PouchDb(name);
userDbInfoAnon = await userDb.info();
} catch (error) {
userDbInfoAnon = { error };
}
return { baseDbInfoAuth, baseDbInfoAnon, userDbInfo, userDbInfoAnon };
});
const submitHandler = async (values: any, context: any) => {
@ -106,6 +124,19 @@ const Invitation: Component<Props> = (props) => {
data: data(),
result,
});
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);
};
console.log({
@ -114,65 +145,100 @@ const Invitation: Component<Props> = (props) => {
});
return (
<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>
<>
<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 !!
</Match>{' '}
<Match when={status() === 'OK'}>
The user is already existing.
</Match>
<Match when={status() === 'notFound'}>
The user must be created.
</Match>
<Match when={status() === 'passwordError'}>
The user seems to exist but the password is wrong.
</Match>
</Switch>
</Dialog.Description>
</Dialog.Content>
</div>
</Dialog.Portal>
</Dialog.Root>
</>
);
};

View File

@ -18,3 +18,120 @@ label {
form {
text-align: left;
}
/* Dialog */
.dialog__trigger {
appearance: none;
display: inline-flex;
justify-content: center;
align-items: center;
height: 40px;
width: auto;
outline: none;
border-radius: 6px;
padding: 0 16px;
background-color: hsl(200 98% 39%);
color: white;
font-size: 16px;
line-height: 0;
transition: 250ms background-color;
}
.dialog__trigger:hover {
background-color: hsl(201 96% 32%);
}
.dialog__trigger:focus-visible {
outline: 2px solid hsl(200 98% 39%);
outline-offset: 2px;
}
.dialog__trigger:active {
background-color: hsl(201 90% 27%);
}
.dialog__overlay {
position: fixed;
inset: 0;
z-index: 50;
background-color: rgb(0 0 0 / 0.2);
animation: overlayHide 250ms ease 100ms forwards;
}
.dialog__overlay[data-expanded] {
animation: overlayShow 250ms ease;
}
.dialog__positioner {
position: fixed;
inset: 0;
z-index: 50;
display: flex;
align-items: center;
justify-content: center;
}
.dialog__content {
z-index: 50;
max-width: min(calc(100vw - 16px), 500px);
border: 1px solid hsl(240 5% 84%);
border-radius: 6px;
padding: 16px;
background-color: white;
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
animation: contentHide 300ms ease-in forwards;
}
.dialog__content[data-expanded] {
animation: contentShow 300ms ease-out;
}
.dialog__header {
display: flex;
align-items: baseline;
justify-content: space-between;
margin-bottom: 12px;
}
.dialog__close-button {
height: 16px;
width: 16px;
color: hsl(240 5% 34%);
}
.dialog__title {
font-size: 20px;
font-weight: 500;
color: hsl(240 6% 10%);
}
.dialog__description {
font-size: 16px;
color: hsl(240 5% 26%);
}
@keyframes overlayShow {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes overlayHide {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes contentShow {
from {
opacity: 0;
transform: scale(0.96);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes contentHide {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.96);
}
}