tubearchivist/frontend/src/pages/Login.tsx

199 lines
5.4 KiB
TypeScript

import { useEffect, useState } from 'react';
import Routes from '../configuration/routes/RouteList';
import { useNavigate } from 'react-router-dom';
import Colours from '../configuration/colours/Colours';
import Button from '../components/Button';
import signIn from '../api/actions/signIn';
import loadAuth from '../api/loader/loadAuth';
const Login = () => {
const navigate = useNavigate();
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [saveLogin, setSaveLogin] = useState(false);
const [waitingForBackend, setWaitingForBackend] = useState(false);
const [waitedCount, setWaitedCount] = useState(0);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const handleSubmit = async (event: { preventDefault: () => void }) => {
event.preventDefault();
if (waitingForBackend) {
return false;
}
setErrorMessage(null);
const loginResponse = await signIn(username, password, saveLogin);
const signedIn = loginResponse.status === 204;
if (signedIn) {
navigate(Routes.Home);
} else {
const data = await loginResponse.json();
setErrorMessage(data?.error || 'Unknown Error');
navigate(Routes.Login);
}
};
useEffect(() => {
let retryCount = 0;
const backendCheckInterval = setInterval(async () => {
try {
const auth = await loadAuth();
const authData = await auth.json();
if (auth.status === 403) {
setWaitingForBackend(false);
clearInterval(backendCheckInterval);
}
if (authData.response === 'pong') {
setWaitingForBackend(false);
clearInterval(backendCheckInterval);
navigate(Routes.Home);
}
} catch (error) {
console.log('Checking backend availability: ', error);
retryCount += 1;
setWaitedCount(retryCount);
setWaitingForBackend(true);
}
}, 1000);
return () => {
clearInterval(backendCheckInterval);
};
}, [navigate]);
return (
<>
<title>TA | Welcome</title>
<Colours />
<div className="boxed-content login-page">
<img alt="tube-archivist-logo" />
<h1>Tube Archivist</h1>
<h2>Your Self Hosted YouTube Media Server</h2>
{errorMessage !== null && (
<p className="danger-zone">
Failed to login.
<br />
{errorMessage}
</p>
)}
<form onSubmit={handleSubmit}>
<input
type="text"
name="username"
id="id_username"
placeholder="Username"
autoComplete="username"
maxLength={150}
required={true}
value={username}
onChange={event => setUsername(event.target.value)}
/>
<br />
<input
type="password"
name="password"
id="id_password"
placeholder="Password"
autoComplete="current-password"
required={true}
value={password}
onChange={event => setPassword(event.target.value)}
/>
<br />
<p>
Remember me:{' '}
<input
type="checkbox"
name="remember_me"
id="id_remember_me"
checked={saveLogin}
onChange={() => {
setSaveLogin(!saveLogin);
}}
/>
</p>
<input type="hidden" name="next" value={Routes.Home} />
{waitingForBackend && (
<>
<p>
Waiting for backend{' '}
<div className="lds-ring" style={{ color: 'var(--accent-font-dark)' }}>
<div />
</div>
</p>
</>
)}
{!waitingForBackend && <Button label="Login" type="submit" />}
</form>
{waitedCount > 10 && (
<div className="info-box">
<div className="info-box-item">
<h2>Having issues?</h2>
<div className="help-text left-align">
<p>Please verify that you setup your environment correctly:</p>
<ul>
<li
onClick={() => {
navigator.clipboard.writeText(`TA_HOST=${window.location.origin}`);
}}
>
TA_HOST={window.location.origin}
</li>
<li
onClick={() => {
navigator.clipboard.writeText('REDIS_CON=redis://archivist-redis:6379');
}}
>
REDIS_CON=redis://archivist-redis:6379
</li>
</ul>
</div>
</div>
</div>
)}
<p className="login-links">
<span>
<a href="https://github.com/tubearchivist/tubearchivist" target="_blank">
Github
</a>
</span>{' '}
<span>
<a href="https://github.com/tubearchivist/tubearchivist#donate" target="_blank">
Donate
</a>
</span>
</p>
</div>
<div className="footer-colors">
<div className="col-1"></div>
<div className="col-2"></div>
<div className="col-3"></div>
</div>
</>
);
};
export default Login;