feat(worker): login-only client (admin creates users)
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
import { createContext, useCallback, useContext, useState, type ReactNode } from 'react';
|
||||
import { clearToken, getToken } from '../lib/auth-storage';
|
||||
import { signIn as apiSignIn, signUp as apiSignUp } from '../lib/api';
|
||||
import { signIn as apiSignIn } from '../lib/api';
|
||||
|
||||
interface AuthContextValue {
|
||||
isAuthed: boolean;
|
||||
signIn: (email: string, password: string) => Promise<void>;
|
||||
signUp: (email: string, password: string) => Promise<void>;
|
||||
signOut: () => void;
|
||||
}
|
||||
|
||||
@@ -19,25 +18,13 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
setIsAuthed(true);
|
||||
}, []);
|
||||
|
||||
const signUp = useCallback(
|
||||
async (email: string, password: string) => {
|
||||
// Register, then sign in to obtain the bearer token.
|
||||
await apiSignUp(email, password);
|
||||
await apiSignIn(email, password);
|
||||
setIsAuthed(true);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const signOut = useCallback(() => {
|
||||
clearToken();
|
||||
setIsAuthed(false);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{ isAuthed, signIn, signUp, signOut }}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
<AuthContext.Provider value={{ isAuthed, signIn, signOut }}>{children}</AuthContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ export const API_URL = import.meta.env.VITE_API_URL ?? 'http://localhost:3000';
|
||||
export class ApiError extends Error {
|
||||
constructor(
|
||||
public status: number,
|
||||
message: string,
|
||||
message: string
|
||||
) {
|
||||
super(message);
|
||||
this.name = 'ApiError';
|
||||
@@ -35,13 +35,3 @@ export async function signIn(email: string, password: string): Promise<void> {
|
||||
if (!token) throw new ApiError(500, 'Geen token ontvangen');
|
||||
setToken(token);
|
||||
}
|
||||
|
||||
// Sign up affordance for testing: POST /api/auth/sign-up/email.
|
||||
export async function signUp(email: string, password: string): Promise<void> {
|
||||
const res = await fetch(`${API_URL}/api/auth/sign-up/email`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email, password, name: email.split('@')[0] || 'Worker' }),
|
||||
});
|
||||
if (!res.ok) throw new ApiError(res.status, 'Registreren mislukt');
|
||||
}
|
||||
|
||||
@@ -1,30 +1,21 @@
|
||||
import { useState, type FormEvent } from 'react';
|
||||
import { useAuth } from '../auth/AuthContext';
|
||||
|
||||
type Mode = 'signin' | 'signup';
|
||||
|
||||
export default function Login() {
|
||||
const { signIn, signUp } = useAuth();
|
||||
const [mode, setMode] = useState<Mode>('signin');
|
||||
const { signIn } = useAuth();
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [busy, setBusy] = useState(false);
|
||||
|
||||
const submitLabel = mode === 'signin' ? 'Inloggen' : 'Registreren';
|
||||
|
||||
async function handleSubmit(e: FormEvent) {
|
||||
e.preventDefault();
|
||||
setError(null);
|
||||
setBusy(true);
|
||||
try {
|
||||
if (mode === 'signin') {
|
||||
await signIn(email, password);
|
||||
} else {
|
||||
await signUp(email, password);
|
||||
}
|
||||
await signIn(email, password);
|
||||
} catch {
|
||||
setError(mode === 'signin' ? 'Inloggen mislukt' : 'Registreren mislukt');
|
||||
setError('Inloggen mislukt');
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
@@ -49,26 +40,16 @@ export default function Login() {
|
||||
<input
|
||||
className="field-input"
|
||||
type="password"
|
||||
autoComplete={mode === 'signin' ? 'current-password' : 'new-password'}
|
||||
autoComplete="current-password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
/>
|
||||
</label>
|
||||
{error && <p className="login-error">{error}</p>}
|
||||
<button className="btn-primary" type="submit" disabled={busy}>
|
||||
{submitLabel}
|
||||
Inloggen
|
||||
</button>
|
||||
</form>
|
||||
<button
|
||||
className="login-toggle"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setMode((m) => (m === 'signin' ? 'signup' : 'signin'));
|
||||
setError(null);
|
||||
}}
|
||||
>
|
||||
{mode === 'signin' ? 'Nog geen account? Registreren' : 'Al een account? Inloggen'}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user