feat: enhance profile page and authentication with user avatar support
- Updated `next.config.ts` to allow images from various external sources, including LinkedIn and GitHub. - Refactored `ProfilePage` to improve layout and display user avatar, name, and role more prominently. - Enhanced `AuthButton` to show user avatar if available, improving user experience. - Updated authentication logic in `auth.ts` to include user avatar and role in session management. - Extended JWT type definitions to support new user fields (firstName, lastName, avatar, role) for better user data handling.
This commit is contained in:
@@ -2,6 +2,46 @@ import type { NextConfig } from "next";
|
|||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
output: 'standalone',
|
output: 'standalone',
|
||||||
|
images: {
|
||||||
|
remotePatterns: [
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: 'media.licdn.com',
|
||||||
|
port: '',
|
||||||
|
pathname: '/**',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: 'avatars.githubusercontent.com',
|
||||||
|
port: '',
|
||||||
|
pathname: '/**',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: 'lh3.googleusercontent.com',
|
||||||
|
port: '',
|
||||||
|
pathname: '/**',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: 'cdn.discordapp.com',
|
||||||
|
port: '',
|
||||||
|
pathname: '/**',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: 'images.unsplash.com',
|
||||||
|
port: '',
|
||||||
|
pathname: '/**',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: 'via.placeholder.com',
|
||||||
|
port: '',
|
||||||
|
pathname: '/**',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
turbopack: {
|
turbopack: {
|
||||||
rules: {
|
rules: {
|
||||||
'*.sql': ['raw'],
|
'*.sql': ['raw'],
|
||||||
|
|||||||
@@ -140,138 +140,228 @@ export default function ProfilePage() {
|
|||||||
<Header title="TowerControl" subtitle="Profil utilisateur" />
|
<Header title="TowerControl" subtitle="Profil utilisateur" />
|
||||||
|
|
||||||
<div className="container mx-auto px-4 py-8">
|
<div className="container mx-auto px-4 py-8">
|
||||||
<div className="max-w-2xl mx-auto">
|
<div className="max-w-4xl mx-auto">
|
||||||
{/* Informations générales */}
|
{/* Header avec avatar et infos principales */}
|
||||||
<div className="bg-[var(--card)] rounded-lg p-6 mb-6">
|
<div className="bg-gradient-to-r from-[var(--primary)]/10 to-[var(--accent)]/10 rounded-xl p-8 mb-8 border border-[var(--primary)]/20">
|
||||||
<h2 className="text-xl font-mono font-bold text-[var(--foreground)] mb-4">
|
<div className="flex flex-col md:flex-row items-center md:items-start gap-6">
|
||||||
Informations générales
|
{/* Avatar section */}
|
||||||
</h2>
|
<div className="flex-shrink-0">
|
||||||
|
{profile.avatar ? (
|
||||||
<div className="space-y-4">
|
<div className="relative">
|
||||||
<div>
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
<label className="block text-sm font-medium text-[var(--muted-foreground)] mb-1">
|
<img
|
||||||
Email
|
src={profile.avatar}
|
||||||
</label>
|
alt="Avatar"
|
||||||
<div className="text-[var(--foreground)] bg-[var(--input)] px-3 py-2 rounded-md">
|
className="w-24 h-24 rounded-full object-cover border-4 border-[var(--primary)]/30 shadow-lg"
|
||||||
{profile.email}
|
/>
|
||||||
</div>
|
<div className="absolute -bottom-2 -right-2 w-8 h-8 bg-[var(--success)] rounded-full border-4 border-[var(--card)] flex items-center justify-center">
|
||||||
<p className="text-xs text-[var(--muted-foreground)] mt-1">
|
<svg className="w-4 h-4 text-white" fill="currentColor" viewBox="0 0 20 20">
|
||||||
L'email ne peut pas être modifié
|
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
||||||
</p>
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="w-24 h-24 rounded-full bg-[var(--primary)]/20 border-4 border-[var(--primary)]/30 flex items-center justify-center">
|
||||||
|
<svg className="w-12 h-12 text-[var(--primary)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
{/* User info */}
|
||||||
<label className="block text-sm font-medium text-[var(--muted-foreground)] mb-1">
|
<div className="flex-1 text-center md:text-left">
|
||||||
Rôle
|
<h1 className="text-3xl font-mono font-bold text-[var(--foreground)] mb-2">
|
||||||
</label>
|
{profile.name || `${profile.firstName || ''} ${profile.lastName || ''}`.trim() || profile.email}
|
||||||
<div className="text-[var(--foreground)] bg-[var(--input)] px-3 py-2 rounded-md">
|
</h1>
|
||||||
{profile.role}
|
<p className="text-[var(--muted-foreground)] text-lg mb-4">{profile.email}</p>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div className="flex flex-wrap gap-4 justify-center md:justify-start">
|
||||||
<label className="block text-sm font-medium text-[var(--muted-foreground)] mb-1">
|
<div className="flex items-center gap-2 px-3 py-1 bg-[var(--card)] rounded-full border border-[var(--border)]">
|
||||||
Membre depuis
|
<div className="w-2 h-2 bg-[var(--success)] rounded-full"></div>
|
||||||
</label>
|
<span className="text-sm font-medium text-[var(--foreground)]">{profile.role}</span>
|
||||||
<div className="text-[var(--foreground)] bg-[var(--input)] px-3 py-2 rounded-md">
|
</div>
|
||||||
{new Date(profile.createdAt).toLocaleDateString('fr-FR')}
|
<div className="flex items-center gap-2 px-3 py-1 bg-[var(--card)] rounded-full border border-[var(--border)]">
|
||||||
</div>
|
<svg className="w-4 h-4 text-[var(--muted-foreground)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
</div>
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||||
|
</svg>
|
||||||
{profile.lastLoginAt && (
|
<span className="text-sm text-[var(--muted-foreground)]">
|
||||||
<div>
|
Membre depuis {new Date(profile.createdAt).toLocaleDateString('fr-FR')}
|
||||||
<label className="block text-sm font-medium text-[var(--muted-foreground)] mb-1">
|
</span>
|
||||||
Dernière connexion
|
|
||||||
</label>
|
|
||||||
<div className="text-[var(--foreground)] bg-[var(--input)] px-3 py-2 rounded-md">
|
|
||||||
{new Date(profile.lastLoginAt).toLocaleString('fr-FR')}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Formulaire de modification */}
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
<form onSubmit={handleSubmit} className="bg-[var(--card)] rounded-lg p-6">
|
{/* Informations générales */}
|
||||||
<h2 className="text-xl font-mono font-bold text-[var(--foreground)] mb-4">
|
<div className="bg-[var(--card)] rounded-xl p-6 border border-[var(--border)]">
|
||||||
Modifier le profil
|
<h2 className="text-xl font-mono font-bold text-[var(--foreground)] mb-6 flex items-center gap-2">
|
||||||
</h2>
|
<svg className="w-5 h-5 text-[var(--primary)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
Informations générales
|
||||||
|
</h2>
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div>
|
<div className="flex items-center gap-3 p-3 bg-[var(--input)] rounded-lg border border-[var(--border)]">
|
||||||
<label htmlFor="firstName" className="block text-sm font-medium text-[var(--foreground)] mb-2">
|
<svg className="w-5 h-5 text-[var(--muted-foreground)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
Prénom
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 12a4 4 0 10-8 0 4 4 0 008 0zm0 0v1.5a2.5 2.5 0 005 0V12a9 9 0 10-9 9m4.5-1.206a8.959 8.959 0 01-4.5 1.207" />
|
||||||
</label>
|
</svg>
|
||||||
<Input
|
<div>
|
||||||
id="firstName"
|
<div className="text-[var(--foreground)] font-medium">{profile.email}</div>
|
||||||
value={formData.firstName}
|
<div className="text-xs text-[var(--muted-foreground)]">Email principal</div>
|
||||||
onChange={(e) => handleChange('firstName', e.target.value)}
|
</div>
|
||||||
placeholder="Votre prénom"
|
</div>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div className="flex items-center gap-3 p-3 bg-[var(--input)] rounded-lg border border-[var(--border)]">
|
||||||
<label htmlFor="lastName" className="block text-sm font-medium text-[var(--foreground)] mb-2">
|
<svg className="w-5 h-5 text-[var(--muted-foreground)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
Nom de famille
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
</label>
|
</svg>
|
||||||
<Input
|
<div>
|
||||||
id="lastName"
|
<div className="text-[var(--foreground)] font-medium">{profile.role}</div>
|
||||||
value={formData.lastName}
|
<div className="text-xs text-[var(--muted-foreground)]">Rôle utilisateur</div>
|
||||||
onChange={(e) => handleChange('lastName', e.target.value)}
|
</div>
|
||||||
placeholder="Votre nom de famille"
|
</div>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
{profile.lastLoginAt && (
|
||||||
<label htmlFor="name" className="block text-sm font-medium text-[var(--foreground)] mb-2">
|
<div className="flex items-center gap-3 p-3 bg-[var(--input)] rounded-lg border border-[var(--border)]">
|
||||||
Nom d'affichage (optionnel)
|
<svg className="w-5 h-5 text-[var(--muted-foreground)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
</label>
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
<Input
|
</svg>
|
||||||
id="name"
|
<div>
|
||||||
value={formData.name}
|
<div className="text-[var(--foreground)] font-medium">
|
||||||
onChange={(e) => handleChange('name', e.target.value)}
|
{new Date(profile.lastLoginAt).toLocaleString('fr-FR')}
|
||||||
placeholder="Nom d'affichage personnalisé"
|
</div>
|
||||||
/>
|
<div className="text-xs text-[var(--muted-foreground)]">Dernière connexion</div>
|
||||||
<p className="text-xs text-[var(--muted-foreground)] mt-1">
|
</div>
|
||||||
Si vide, sera généré automatiquement à partir du prénom et nom
|
</div>
|
||||||
</p>
|
)}
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label htmlFor="avatar" className="block text-sm font-medium text-[var(--foreground)] mb-2">
|
|
||||||
URL de l'avatar (optionnel)
|
|
||||||
</label>
|
|
||||||
<Input
|
|
||||||
id="avatar"
|
|
||||||
value={formData.avatar}
|
|
||||||
onChange={(e) => handleChange('avatar', e.target.value)}
|
|
||||||
placeholder="https://example.com/avatar.jpg"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{error && (
|
{/* Formulaire de modification */}
|
||||||
<div className="mt-4 text-[var(--destructive)] text-sm">
|
<div className="bg-[var(--card)] rounded-xl p-6 border border-[var(--border)]">
|
||||||
{error}
|
<h2 className="text-xl font-mono font-bold text-[var(--foreground)] mb-6 flex items-center gap-2">
|
||||||
</div>
|
<svg className="w-5 h-5 text-[var(--primary)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
)}
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||||
|
</svg>
|
||||||
|
Modifier le profil
|
||||||
|
</h2>
|
||||||
|
|
||||||
{success && (
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
<div className="mt-4 text-[var(--success)] text-sm">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
{success}
|
<div>
|
||||||
</div>
|
<label htmlFor="firstName" className="block text-sm font-medium text-[var(--foreground)] mb-2">
|
||||||
)}
|
Prénom
|
||||||
|
</label>
|
||||||
|
<Input
|
||||||
|
id="firstName"
|
||||||
|
value={formData.firstName}
|
||||||
|
onChange={(e) => handleChange('firstName', e.target.value)}
|
||||||
|
placeholder="Votre prénom"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="mt-6">
|
<div>
|
||||||
<Button
|
<label htmlFor="lastName" className="block text-sm font-medium text-[var(--foreground)] mb-2">
|
||||||
type="submit"
|
Nom de famille
|
||||||
disabled={isPending}
|
</label>
|
||||||
className="w-full"
|
<Input
|
||||||
>
|
id="lastName"
|
||||||
{isPending ? 'Sauvegarde...' : 'Sauvegarder les modifications'}
|
value={formData.lastName}
|
||||||
</Button>
|
onChange={(e) => handleChange('lastName', e.target.value)}
|
||||||
|
placeholder="Votre nom de famille"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label htmlFor="name" className="block text-sm font-medium text-[var(--foreground)] mb-2">
|
||||||
|
Nom d'affichage (optionnel)
|
||||||
|
</label>
|
||||||
|
<Input
|
||||||
|
id="name"
|
||||||
|
value={formData.name}
|
||||||
|
onChange={(e) => handleChange('name', e.target.value)}
|
||||||
|
placeholder="Nom d'affichage personnalisé"
|
||||||
|
/>
|
||||||
|
<p className="text-xs text-[var(--muted-foreground)] mt-1">
|
||||||
|
Si vide, sera généré automatiquement à partir du prénom et nom
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label htmlFor="avatar" className="block text-sm font-medium text-[var(--foreground)] mb-2">
|
||||||
|
URL de l'avatar (optionnel)
|
||||||
|
</label>
|
||||||
|
<Input
|
||||||
|
id="avatar"
|
||||||
|
value={formData.avatar}
|
||||||
|
onChange={(e) => handleChange('avatar', e.target.value)}
|
||||||
|
placeholder="https://example.com/avatar.jpg"
|
||||||
|
/>
|
||||||
|
{formData.avatar && (
|
||||||
|
<div className="mt-2 flex items-center gap-2">
|
||||||
|
<span className="text-xs text-[var(--muted-foreground)]">Aperçu:</span>
|
||||||
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
|
<img
|
||||||
|
src={formData.avatar}
|
||||||
|
alt="Aperçu avatar"
|
||||||
|
className="w-8 h-8 rounded-full object-cover border border-[var(--border)]"
|
||||||
|
onError={(e) => {
|
||||||
|
e.currentTarget.style.display = 'none'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="flex items-center gap-2 p-3 bg-[var(--destructive)]/10 border border-[var(--destructive)]/30 rounded-lg">
|
||||||
|
<svg className="w-5 h-5 text-[var(--destructive)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
<span className="text-[var(--destructive)] text-sm">{error}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{success && (
|
||||||
|
<div className="flex items-center gap-2 p-3 bg-[var(--success)]/10 border border-[var(--success)]/30 rounded-lg">
|
||||||
|
<svg className="w-5 h-5 text-[var(--success)]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
<span className="text-[var(--success)] text-sm">{success}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="pt-4">
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
disabled={isPending}
|
||||||
|
className="w-full bg-[var(--primary)] hover:bg-[var(--primary)]/90 text-[var(--primary-foreground)]"
|
||||||
|
>
|
||||||
|
{isPending ? (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<svg className="w-4 h-4 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||||
|
</svg>
|
||||||
|
Sauvegarde...
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||||
|
</svg>
|
||||||
|
Sauvegarder les modifications
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -36,9 +36,18 @@ export function AuthButton() {
|
|||||||
className="p-1 h-auto"
|
className="p-1 h-auto"
|
||||||
title={`Profil - ${session.user?.email}`}
|
title={`Profil - ${session.user?.email}`}
|
||||||
>
|
>
|
||||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
{session.user?.avatar ? (
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
// eslint-disable-next-line @next/next/no-img-element
|
||||||
</svg>
|
<img
|
||||||
|
src={session.user.avatar}
|
||||||
|
alt="Avatar"
|
||||||
|
className="w-4 h-4 rounded-full object-cover"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => signOut({ callbackUrl: '/login' })}
|
onClick={() => signOut({ callbackUrl: '/login' })}
|
||||||
|
|||||||
@@ -59,12 +59,20 @@ export const authOptions: NextAuthOptions = {
|
|||||||
async jwt({ token, user }) {
|
async jwt({ token, user }) {
|
||||||
if (user) {
|
if (user) {
|
||||||
token.id = user.id
|
token.id = user.id
|
||||||
|
token.firstName = user.firstName
|
||||||
|
token.lastName = user.lastName
|
||||||
|
token.avatar = user.avatar
|
||||||
|
token.role = user.role
|
||||||
}
|
}
|
||||||
return token
|
return token
|
||||||
},
|
},
|
||||||
async session({ session, token }) {
|
async session({ session, token }) {
|
||||||
if (token && session.user) {
|
if (token && session.user) {
|
||||||
session.user.id = token.id as string
|
session.user.id = token.id as string
|
||||||
|
session.user.firstName = token.firstName as string | undefined
|
||||||
|
session.user.lastName = token.lastName as string | undefined
|
||||||
|
session.user.avatar = token.avatar as string | undefined
|
||||||
|
session.user.role = token.role as string
|
||||||
}
|
}
|
||||||
return session
|
return session
|
||||||
},
|
},
|
||||||
|
|||||||
4
src/types/next-auth.d.ts
vendored
4
src/types/next-auth.d.ts
vendored
@@ -28,5 +28,9 @@ declare module "next-auth" {
|
|||||||
declare module "next-auth/jwt" {
|
declare module "next-auth/jwt" {
|
||||||
interface JWT {
|
interface JWT {
|
||||||
id: string
|
id: string
|
||||||
|
firstName?: string
|
||||||
|
lastName?: string
|
||||||
|
avatar?: string
|
||||||
|
role: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user