87 lines
3.4 KiB
TypeScript
87 lines
3.4 KiB
TypeScript
import { useEffect, useRef, useState, type SyntheticEvent } from 'react'
|
|
import { login } from '../../api/connections'
|
|
import type { LoginRequest, ServiceType } from '../../types/connection'
|
|
import { uiText } from '../../text/uiText'
|
|
import '../ui/Modal.scss'
|
|
|
|
interface Props {
|
|
serviceType: ServiceType
|
|
label: string
|
|
onClose: () => void
|
|
onSuccess: () => void
|
|
}
|
|
|
|
export function ConnectModal({ serviceType, label, onClose, onSuccess }: Readonly<Props>) {
|
|
const [appUrl, setAppUrl] = useState('')
|
|
const [username, setUsername] = useState('')
|
|
const [password, setPassword] = useState('')
|
|
const [loading, setLoading] = useState(false)
|
|
const [error, setError] = useState<string | null>(null)
|
|
const firstInputRef = useRef<HTMLInputElement>(null)
|
|
|
|
const dialogRef = useRef<HTMLDialogElement>(null)
|
|
|
|
useEffect(() => {
|
|
const dialog = dialogRef.current
|
|
if (!dialog) return
|
|
|
|
dialog.showModal()
|
|
firstInputRef.current?.focus()
|
|
|
|
const handleCancel = (e: Event) => {
|
|
e.preventDefault()
|
|
onClose()
|
|
}
|
|
dialog.addEventListener('cancel', handleCancel)
|
|
return () => dialog.removeEventListener('cancel', handleCancel)
|
|
}, [onClose])
|
|
|
|
const handleSubmit = async (e: SyntheticEvent<HTMLFormElement>) => {
|
|
e.preventDefault()
|
|
setError(null)
|
|
setLoading(true)
|
|
try {
|
|
const req: LoginRequest = { appUrl, serviceType, username, password, stayLoggedIn: true }
|
|
await login(req)
|
|
onSuccess()
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : uiText.connections.connectModal.loginFailed)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<dialog className="modal" ref={dialogRef}>
|
|
<div className="modal__header">
|
|
<h2 className="modal__title" id="modal-title">{uiText.connections.connectModal.title(label)}</h2>
|
|
<button className="modal__close" onClick={onClose} aria-label={uiText.modal.closeAriaLabel}>{uiText.modal.closeSymbol}</button>
|
|
</div>
|
|
<form className="modal__form" onSubmit={handleSubmit}>
|
|
<div className="modal__field">
|
|
<label className="modal__label" htmlFor="appUrl">{uiText.connections.connectModal.appUrlLabel}</label>
|
|
<input id="appUrl" ref={firstInputRef} className="modal__input" type="url"
|
|
placeholder={uiText.connections.connectModal.appUrlPlaceholder}
|
|
value={appUrl} onChange={e => setAppUrl(e.target.value)} required />
|
|
</div>
|
|
<div className="modal__field">
|
|
<label className="modal__label" htmlFor="username">{uiText.connections.connectModal.usernameLabel}</label>
|
|
<input id="username" className="modal__input" type="text"
|
|
autoComplete="username"
|
|
value={username} onChange={e => setUsername(e.target.value)} required />
|
|
</div>
|
|
<div className="modal__field">
|
|
<label className="modal__label" htmlFor="password">{uiText.connections.connectModal.passwordLabel}</label>
|
|
<input id="password" className="modal__input" type="password"
|
|
autoComplete="current-password"
|
|
value={password} onChange={e => setPassword(e.target.value)} required />
|
|
</div>
|
|
{error && <p className="modal__error">{error}</p>}
|
|
<button className="modal__submit" type="submit" disabled={loading}>
|
|
{loading ? uiText.connections.connectModal.connectingButton : uiText.connections.connectModal.connectButton}
|
|
</button>
|
|
</form>
|
|
</dialog>
|
|
)
|
|
}
|