'use client' import { useActionState, useEffect, useState } from 'react' import Swal from 'sweetalert2' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' import { updateProfile, type Profile, type ProfileFormState } from './actions' function getSwalThemeOptions() { const isDark = document.documentElement.classList.contains('dark') return isDark ? { background: '#111827', color: '#f3f4f6' } : { background: '#ffffff', color: '#111827' } } const MAX_AVATAR_BYTES = 5 * 1024 * 1024 function showToast(icon: 'success' | 'error', title: string) { void Swal.fire({ ...getSwalThemeOptions(), toast: true, position: 'top-end', showConfirmButton: false, timer: 2200, timerProgressBar: true, icon, title, }) } function showErrorDialog(title: string, text?: string) { void Swal.fire({ ...getSwalThemeOptions(), icon: 'error', title, text, confirmButtonText: 'Tamam', }) } export default function ProfileClient({ initialProfile }: { initialProfile: Profile }) { const [state, formAction, pending] = useActionState(updateProfile, {}) const [avatarFilePreviewUrl, setAvatarFilePreviewUrl] = useState('') useEffect(() => { if (state.success) showToast('success', 'Profil güncellendi') }, [state.success]) useEffect(() => { if (state.error) showToast('error', state.error) }, [state.error]) const profile = state.profile ?? initialProfile const avatarSrc = avatarFilePreviewUrl || profile.avatar_url || '' useEffect(() => { return () => { if (avatarFilePreviewUrl.startsWith('blob:')) URL.revokeObjectURL(avatarFilePreviewUrl) } }, [avatarFilePreviewUrl]) function onAvatarFileChange(file: File | null) { if (!file) { console.log('[profile:avatar] dosya seçimi temizlendi') setAvatarFilePreviewUrl('') return } console.log('[profile:avatar] dosya seçildi (henüz yüklenmedi)', { name: file.name, type: file.type, size: file.size, }) if (!file.type.startsWith('image/')) { showToast('error', 'Lütfen geçerli bir görsel seçin') return } if (file.size > MAX_AVATAR_BYTES) { showErrorDialog( 'Dosya çok büyük', `Avatar en fazla 5 MB olabilir (seçilen: ${(file.size / (1024 * 1024)).toFixed(2)} MB).`, ) return } const previewUrl = URL.createObjectURL(file) setAvatarFilePreviewUrl(previewUrl) } return (
Profilim Ad, soyad ve avatar bilgilerinizi güncelleyin.
{ const fd = new FormData(event.currentTarget) const f = fd.get('avatar') if (f instanceof File && f.size > MAX_AVATAR_BYTES) { event.preventDefault() showErrorDialog( 'Dosya çok büyük', `Avatar en fazla 5 MB olabilir (seçilen: ${(f.size / (1024 * 1024)).toFixed(2)} MB). Sunucu gönderim limiti de 5 MB.`, ) return } const hidden = String(fd.get('avatar_url') ?? '') console.log('[profile:avatar] form gönderiliyor', { hasFile: f instanceof File && f.size > 0, file: f instanceof File && f.size > 0 ? { name: f.name, type: f.type, size: f.size } : null, avatar_url_hidden_preview: hidden.slice(0, 120), }) }} >
{(profile.first_name?.[0] ?? 'U') + (profile.last_name?.[0] ?? '')}
void onAvatarFileChange(event.target.files?.[0] ?? null)} />

Görsel, form submit edildiğinde sunucuya yüklenir ve profile kaydedilir.

) }