checking username availability

This commit is contained in:
balzack 2024-08-12 20:07:21 +02:00
parent 7deb3cac2c
commit 5e145f8950
6 changed files with 98 additions and 37 deletions

View File

@ -47,6 +47,12 @@
margin: 4px; margin: 4px;
} }
.hidden {
width: 50%;
margin: 4px;
opacity: 0;
}
.title { .title {
position: absolute; position: absolute;
top: 0; top: 0;

View File

@ -84,7 +84,6 @@ export function Access() {
{state.mode === 'account' && ( {state.mode === 'account' && (
<> <>
<Title order={3}>{state.strings.login}</Title> <Title order={3}>{state.strings.login}</Title>
<Space h="md" />
<Button <Button
size="compact-sm" size="compact-sm"
variant="transparent" variant="transparent"
@ -92,6 +91,7 @@ export function Access() {
> >
{state.host} {state.host}
</Button> </Button>
<Space h="md" />
<TextInput <TextInput
className={classes.input} className={classes.input}
size="md" size="md"
@ -144,7 +144,6 @@ export function Access() {
{state.mode === 'reset' && ( {state.mode === 'reset' && (
<> <>
<Title order={3}>{state.strings.accessAccount}</Title> <Title order={3}>{state.strings.accessAccount}</Title>
<Space h="md" />
<Button <Button
size="compact-sm" size="compact-sm"
variant="transparent" variant="transparent"
@ -152,6 +151,7 @@ export function Access() {
> >
{state.host} {state.host}
</Button> </Button>
<Space h="md" />
<TextInput <TextInput
className={classes.input} className={classes.input}
size="md" size="md"
@ -184,8 +184,8 @@ export function Access() {
)} )}
{state.mode === 'create' && ( {state.mode === 'create' && (
<> <>
<Title order={3}>{state.strings.createAccount}</Title>
<Space h="md" /> <Space h="md" />
<Title order={3}>{state.strings.createAccount}</Title>
<Button <Button
size="compact-sm" size="compact-sm"
variant="transparent" variant="transparent"
@ -193,20 +193,20 @@ export function Access() {
> >
{state.host} {state.host}
</Button> </Button>
{(state.available === 0 || !state.availableSet) && ( <Space h="md" />
<TextInput <TextInput
className={classes.input} className={
size="md" state.available === 0 ? classes.input : classes.hidden
value={state.token} }
disabled={!state.availableSet} size="md"
leftSectionPointerEvents="none" value={state.token}
leftSection={<IconKey />} leftSectionPointerEvents="none"
placeholder={state.strings.resetCode} leftSection={<IconKey />}
onChange={(event) => placeholder={state.strings.accessCode}
actions.setToken(event.currentTarget.value) onChange={(event) =>
} actions.setToken(event.currentTarget.value)
/> }
)} />
<TextInput <TextInput
className={classes.input} className={classes.input}
size="md" size="md"
@ -216,6 +216,7 @@ export function Access() {
onChange={(event) => onChange={(event) =>
actions.setUsername(event.currentTarget.value) actions.setUsername(event.currentTarget.value)
} }
error={state.taken ? true : false}
/> />
<PasswordInput <PasswordInput
className={classes.input} className={classes.input}
@ -236,7 +237,17 @@ export function Access() {
} }
/> />
<Space h="md" /> <Space h="md" />
<Button variant="filled" className={classes.submit}> <Button
variant="filled"
className={classes.submit}
onClick={login}
disabled={
state.taken ||
!state.username ||
!state.password ||
state.password !== state.confirm
}
>
{state.strings.create} {state.strings.create}
</Button> </Button>
<Button <Button
@ -251,7 +262,6 @@ export function Access() {
{state.mode === 'admin' && ( {state.mode === 'admin' && (
<> <>
<Title order={3}>{state.strings.admin}</Title> <Title order={3}>{state.strings.admin}</Title>
<Space h="md" />
<Button <Button
size="compact-sm" size="compact-sm"
variant="transparent" variant="transparent"
@ -259,6 +269,7 @@ export function Access() {
> >
{state.host} {state.host}
</Button> </Button>
<Space h="md" />
<PasswordInput <PasswordInput
className={classes.input} className={classes.input}
size="md" size="md"

View File

@ -4,7 +4,8 @@ import { AppContext } from '../context/AppContext'
import { ContextType } from '../context/ContextType' import { ContextType } from '../context/ContextType'
export function useAccess() { export function useAccess() {
const debounce = useRef(setTimeout(() => {}, 0)) const debounceAvailable = useRef(setTimeout(() => {}, 0))
const debounceTaken = useRef(setTimeout(() => {}, 0))
const app = useContext(AppContext) as ContextType const app = useContext(AppContext) as ContextType
const settings = useContext(SettingsContext) as ContextType const settings = useContext(SettingsContext) as ContextType
const [state, setState] = useState({ const [state, setState] = useState({
@ -23,7 +24,7 @@ export function useAccess() {
secure: false, secure: false,
host: '', host: '',
available: 0, available: 0,
availableSet: false, taken: false,
themes: settings.state.themes, themes: settings.state.themes,
languages: settings.state.languages, languages: settings.state.languages,
}) })
@ -48,31 +49,58 @@ export function useAccess() {
setUrl(`${protocol}//${host}`) setUrl(`${protocol}//${host}`)
}, []) }, [])
useEffect(() => {
const { username, token, host, secure, mode } = state
if (mode === 'create') {
checkTaken(username, token, host, secure)
getAvailable(host, secure)
}
}, [state.mode, state.username, state.token, state.host, state.secure])
const setUrl = (node: string) => { const setUrl = (node: string) => {
try { try {
const url = new URL(node) const url = new URL(node)
const { protocol, host } = url const { protocol, host } = url
getAvailable(host, protocol === 'https:')
updateState({ node, host, secure: protocol === 'https:' }) updateState({ node, host, secure: protocol === 'https:' })
} catch (err) { } catch (err) {
console.log(err) console.log(err)
const { protocol, host } = location const { protocol, host } = location
getAvailable(host, protocol === 'https:')
updateState({ node, host, secure: protocol === 'https:' }) updateState({ node, host, secure: protocol === 'https:' })
} }
} }
const getAvailable = (node: string, secure: boolean) => { const getAvailable = (node: string, secure: boolean) => {
updateState({ availableSet: false }) clearTimeout(debounceAvailable.current)
clearTimeout(debounce.current) debounceAvailable.current = setTimeout(async () => {
debounce.current = setTimeout(async () => {
try { try {
const available = await app.actions.getAvailable(node, secure) const available = await app.actions.getAvailable(node, secure)
updateState({ available, availableSet: true }) updateState({ available })
} catch (err) { } catch (err) {
console.log(err) console.log(err)
updateState({ available: 0 })
} }
}, 1000) }, 2000)
}
const checkTaken = (
username: string,
token: string,
node: string,
secure: boolean
) => {
updateState({ taken: false })
clearTimeout(debounceTaken.current)
debounceTaken.current = setTimeout(async () => {
const available = await app.actions.getUsername(
username,
token,
node,
secure
)
updateState({ taken: !available })
console.log('TAKEN: ', taken)
}, 2000)
} }
useEffect(() => { useEffect(() => {
@ -94,6 +122,8 @@ export function useAccess() {
}, },
setUsername: (username: string) => { setUsername: (username: string) => {
updateState({ username }) updateState({ username })
const { token, host, secure } = state
checkTaken(username, token, host, secure)
}, },
setPassword: (password: string) => { setPassword: (password: string) => {
updateState({ password }) updateState({ password })
@ -133,7 +163,7 @@ export function useAccess() {
}, },
adminLogin: async () => { adminLogin: async () => {
const { password, host, secure, code } = state const { password, host, secure, code } = state
await app.actions.adminLogin(host, secure, password, code) await app.actions.adminLogin(password, host, secure, code)
}, },
} }

View File

@ -78,7 +78,7 @@ export function useAppContext() {
version: '0.0.1', version: '0.0.1',
appName: 'databag', appName: 'databag',
} }
const session = sdk.current.create( const session = await sdk.current.create(
handle, handle,
password, password,
node, node,
@ -100,12 +100,20 @@ export function useAppContext() {
version: '0.0.1', version: '0.0.1',
appName: 'databag', appName: 'databag',
} }
const session = sdk.current.access(node, secure, token, params) const session = await sdk.current.access(node, secure, token, params)
updateState({ session }) updateState({ session })
}, },
getAvailable: async (node: string, secure: boolean) => { getAvailable: async (node: string, secure: boolean) => {
return await sdk.current.available(node, secure) return await sdk.current.available(node, secure)
}, },
getUsername: async (
username: string,
token: string,
node: string,
secure: boolean
) => {
return await sdk.current.username(username, token, node, secure)
},
adminLogin: async ( adminLogin: async (
token: string, token: string,
node: string, node: string,

View File

@ -1,9 +1,10 @@
import React from 'react' import React, { useContext } from 'react'
import { Button } from '@mantine/core'
import { AppContext } from '../context/AppContext'
import { ContextType } from '../context/ContextType'
export function Node() { export function Node() {
return ( const app = useContext(AppContext) as ContextType
<div>
<span>Node</span> return <Button onClick={app.actions.adminLogout}>Node Logout</Button>
</div>
)
} }

View File

@ -9,6 +9,7 @@ import { setAccess } from './net/setAccess';
import { addAccount } from './net/addAccount'; import { addAccount } from './net/addAccount';
import { setAdmin } from './net/setAdmin'; import { setAdmin } from './net/setAdmin';
import { getAvailable } from './net/getAvailable'; import { getAvailable } from './net/getAvailable';
import { getUsername } from './net/getUsername';
import type { Session, Node, Bot, SqlStore, WebStore, Crypto, Logging } from './api'; import type { Session, Node, Bot, SqlStore, WebStore, Crypto, Logging } from './api';
import type { SessionParams } from './types'; import type { SessionParams } from './types';
import type { Login } from './entities'; import type { Login } from './entities';
@ -45,6 +46,10 @@ export class DatabagSDK {
return await getAvailable(node, secure); return await getAvailable(node, secure);
} }
public async username(name: string, token: string, node: string, secure: boolean): Promise<boolean> {
return await getUsername(name, token, node, secure);
}
public async login(handle: string, password: string, node: string, secure: boolean, mfaCode: string | null, params: SessionParams): Promise<Session> { public async login(handle: string, password: string, node: string, secure: boolean, mfaCode: string | null, params: SessionParams): Promise<Session> {
const { appName, version, deviceId, deviceToken, pushType, notifications } = params; const { appName, version, deviceId, deviceToken, pushType, notifications } = params;
const { guid, appToken, created, pushSupported } = await setLogin(node, secure, handle, password, mfaCode, appName, version, deviceId, deviceToken, pushType, notifications); const { guid, appToken, created, pushSupported } = await setLogin(node, secure, handle, password, mfaCode, appName, version, deviceId, deviceToken, pushType, notifications);