189 lines
5.5 KiB
TypeScript
189 lines
5.5 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect, FormEvent } from 'react';
|
|
|
|
type Profile = {
|
|
id: number;
|
|
username: string;
|
|
email: string;
|
|
firstName: string | null;
|
|
lastName: string | null;
|
|
};
|
|
|
|
export default function ProfileClient() {
|
|
const [profile, setProfile] = useState<Profile | null>(null);
|
|
const [form, setForm] = useState({ firstName: '', lastName: '', email: '' });
|
|
const [loading, setLoading] = useState(true);
|
|
const [saving, setSaving] = useState(false);
|
|
const [success, setSuccess] = useState(false);
|
|
const [error, setError] = useState('');
|
|
|
|
useEffect(() => {
|
|
fetch('/api/profile')
|
|
.then((r) => r.json())
|
|
.then((data: Profile) => {
|
|
setProfile(data);
|
|
setForm({
|
|
firstName: data.firstName ?? '',
|
|
lastName: data.lastName ?? '',
|
|
email: data.email,
|
|
});
|
|
})
|
|
.finally(() => setLoading(false));
|
|
}, []);
|
|
|
|
async function handleSubmit(e: FormEvent) {
|
|
e.preventDefault();
|
|
setError('');
|
|
setSuccess(false);
|
|
setSaving(true);
|
|
try {
|
|
const res = await fetch('/api/profile', {
|
|
method: 'PATCH',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
firstName: form.firstName || null,
|
|
lastName: form.lastName || null,
|
|
email: form.email,
|
|
}),
|
|
});
|
|
if (!res.ok) {
|
|
const data = await res.json().catch(() => ({}));
|
|
setError(data.message ?? 'Kunde inte spara ändringar');
|
|
} else {
|
|
setSuccess(true);
|
|
}
|
|
} catch {
|
|
setError('Något gick fel');
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
}
|
|
|
|
const inputStyle: React.CSSProperties = {
|
|
width: '100%',
|
|
padding: '10px 12px',
|
|
borderRadius: 6,
|
|
border: '1px solid #ddd',
|
|
fontSize: '1rem',
|
|
boxSizing: 'border-box',
|
|
};
|
|
|
|
const labelStyle: React.CSSProperties = {
|
|
display: 'block',
|
|
marginBottom: 6,
|
|
fontWeight: 500,
|
|
fontSize: '0.9rem',
|
|
color: '#444',
|
|
};
|
|
|
|
if (loading) {
|
|
return <p style={{ color: '#666' }}>Laddar profil...</p>;
|
|
}
|
|
|
|
return (
|
|
<div style={{ maxWidth: 480 }}>
|
|
{/* Initialer/avatar */}
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem', marginBottom: '2rem' }}>
|
|
<div
|
|
style={{
|
|
width: 64,
|
|
height: 64,
|
|
borderRadius: '50%',
|
|
background: '#2563eb',
|
|
color: 'white',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
fontSize: '1.5rem',
|
|
fontWeight: 700,
|
|
flexShrink: 0,
|
|
}}
|
|
>
|
|
{profile?.username?.charAt(0).toUpperCase()}
|
|
</div>
|
|
<div>
|
|
<div style={{ fontWeight: 600, fontSize: '1.1rem' }}>{profile?.username}</div>
|
|
<div style={{ color: '#666', fontSize: '0.9rem' }}>{profile?.email}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: '1.25rem' }}>
|
|
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1rem' }}>
|
|
<div>
|
|
<label htmlFor="firstName" style={labelStyle}>Förnamn</label>
|
|
<input
|
|
id="firstName"
|
|
type="text"
|
|
value={form.firstName}
|
|
onChange={(e) => setForm((f) => ({ ...f, firstName: e.target.value }))}
|
|
style={inputStyle}
|
|
maxLength={100}
|
|
autoComplete="given-name"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label htmlFor="lastName" style={labelStyle}>Efternamn</label>
|
|
<input
|
|
id="lastName"
|
|
type="text"
|
|
value={form.lastName}
|
|
onChange={(e) => setForm((f) => ({ ...f, lastName: e.target.value }))}
|
|
style={inputStyle}
|
|
maxLength={100}
|
|
autoComplete="family-name"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label htmlFor="email" style={labelStyle}>E-post</label>
|
|
<input
|
|
id="email"
|
|
type="email"
|
|
value={form.email}
|
|
onChange={(e) => setForm((f) => ({ ...f, email: e.target.value }))}
|
|
required
|
|
style={inputStyle}
|
|
autoComplete="email"
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label style={labelStyle}>Användarnamn</label>
|
|
<input
|
|
type="text"
|
|
value={profile?.username ?? ''}
|
|
disabled
|
|
style={{ ...inputStyle, background: '#f5f5f5', color: '#888', cursor: 'not-allowed' }}
|
|
/>
|
|
<p style={{ fontSize: '0.8rem', color: '#999', margin: '4px 0 0' }}>
|
|
Användarnamn kan inte ändras
|
|
</p>
|
|
</div>
|
|
|
|
{error && <p style={{ color: '#dc2626', margin: 0 }}>{error}</p>}
|
|
{success && <p style={{ color: '#16a34a', margin: 0 }}>Ändringarna sparades!</p>}
|
|
|
|
<button
|
|
type="submit"
|
|
disabled={saving}
|
|
style={{
|
|
padding: '10px',
|
|
background: '#2563eb',
|
|
color: 'white',
|
|
border: 'none',
|
|
borderRadius: 6,
|
|
fontSize: '1rem',
|
|
cursor: saving ? 'not-allowed' : 'pointer',
|
|
opacity: saving ? 0.7 : 1,
|
|
fontWeight: 500,
|
|
}}
|
|
>
|
|
{saving ? 'Sparar...' : 'Spara ändringar'}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|