ce0cc6fbf0
- Added user registration and login functionality with JWT authentication. - Created auth controller, service, and module in the backend. - Implemented user model and user products management. - Integrated NextAuth for session management on the frontend. - Added middleware for protecting routes and handling public access. - Updated frontend API routes to include authorization headers. - Enhanced recipe and user product models to support ownership and visibility. - Created registration and login pages in the frontend. - Added necessary types for NextAuth session management.
91 lines
2.9 KiB
TypeScript
91 lines
2.9 KiB
TypeScript
'use client';
|
|
|
|
import { useState, FormEvent } from 'react';
|
|
import { signIn } from 'next-auth/react';
|
|
import { useRouter, useSearchParams } from 'next/navigation';
|
|
|
|
export default function LoginPage() {
|
|
const router = useRouter();
|
|
const searchParams = useSearchParams();
|
|
const callbackUrl = searchParams.get('callbackUrl') ?? '/';
|
|
|
|
const [username, setUsername] = useState('');
|
|
const [password, setPassword] = useState('');
|
|
const [error, setError] = useState('');
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
async function handleSubmit(e: FormEvent) {
|
|
e.preventDefault();
|
|
setError('');
|
|
setLoading(true);
|
|
const result = await signIn('credentials', {
|
|
username,
|
|
password,
|
|
redirect: false,
|
|
});
|
|
setLoading(false);
|
|
if (result?.error) {
|
|
setError('Felaktigt användarnamn eller lösenord');
|
|
} else {
|
|
router.push(callbackUrl);
|
|
router.refresh();
|
|
}
|
|
}
|
|
|
|
return (
|
|
<main style={{ maxWidth: 400, margin: '80px auto', padding: '0 1rem' }}>
|
|
<h1 style={{ marginBottom: '1.5rem' }}>Logga in</h1>
|
|
<form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
|
|
<div>
|
|
<label htmlFor="username" style={{ display: 'block', marginBottom: 4 }}>
|
|
Användarnamn
|
|
</label>
|
|
<input
|
|
id="username"
|
|
type="text"
|
|
value={username}
|
|
onChange={(e) => setUsername(e.target.value)}
|
|
required
|
|
autoComplete="username"
|
|
style={{ width: '100%', padding: '8px 12px', borderRadius: 6, border: '1px solid #ccc', fontSize: '1rem' }}
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label htmlFor="password" style={{ display: 'block', marginBottom: 4 }}>
|
|
Lösenord
|
|
</label>
|
|
<input
|
|
id="password"
|
|
type="password"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
required
|
|
autoComplete="current-password"
|
|
style={{ width: '100%', padding: '8px 12px', borderRadius: 6, border: '1px solid #ccc', fontSize: '1rem' }}
|
|
/>
|
|
</div>
|
|
{error && <p style={{ color: 'red', margin: 0 }}>{error}</p>}
|
|
<button
|
|
type="submit"
|
|
disabled={loading}
|
|
style={{
|
|
padding: '10px',
|
|
background: '#2563eb',
|
|
color: 'white',
|
|
border: 'none',
|
|
borderRadius: 6,
|
|
fontSize: '1rem',
|
|
cursor: loading ? 'not-allowed' : 'pointer',
|
|
opacity: loading ? 0.7 : 1,
|
|
}}
|
|
>
|
|
{loading ? 'Loggar in...' : 'Logga in'}
|
|
</button>
|
|
<p style={{ textAlign: 'center', fontSize: '0.9rem' }}>
|
|
Inget konto? <a href="/register">Skapa konto</a>
|
|
</p>
|
|
</form>
|
|
</main>
|
|
);
|
|
}
|