This commit is contained in:
2026-06-11 13:25:26 +03:00
parent b931ee64d4
commit 60b48ca5e8
60 changed files with 12302 additions and 0 deletions
@@ -0,0 +1,158 @@
'use client'
import { useActionState, useState, useRef } from 'react'
import { saveSettings } from './actions'
import Image from 'next/image'
import { Upload, X, Loader2 } from 'lucide-react'
export default function SettingsForm({
defaultRestaurantName,
defaultLocation,
defaultLogoUrl,
}: {
defaultRestaurantName: string
defaultLocation: string
defaultLogoUrl: string
}) {
const [state, action, isPending] = useActionState(saveSettings, undefined)
const [logoUrl, setLogoUrl] = useState(defaultLogoUrl)
const [uploading, setUploading] = useState(false)
const [uploadError, setUploadError] = useState('')
const fileInputRef = useRef<HTMLInputElement>(null)
async function handleFileChange(e: React.ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0]
if (!file) return
if (file.size > 5 * 1024 * 1024) {
setUploadError("Dosya boyutu 5MB'ı geçemez.")
return
}
setUploadError('')
setUploading(true)
try {
const fd = new FormData()
fd.append('file', file)
const res = await fetch('/api/upload', { method: 'POST', body: fd })
const data = await res.json()
if (!res.ok) throw new Error(data.error || 'Yükleme başarısız')
setLogoUrl(data.url)
} catch (err: any) {
setUploadError(err.message || 'Logo yüklenirken hata oluştu.')
} finally {
setUploading(false)
}
}
return (
<form action={action} className="space-y-6">
{state?.success && (
<div className="bg-green-50 text-green-700 p-3 rounded-lg text-sm">
{state.message}
</div>
)}
{state?.error && (
<div className="bg-red-50 text-red-700 p-3 rounded-lg text-sm">
{state.error}
</div>
)}
{/* Logo Upload */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Site Logosu
</label>
<div className="flex items-start gap-4">
{/* Preview */}
<div className="relative w-40 h-20 rounded-xl overflow-hidden border-2 border-gray-200 bg-stone-900 flex items-center justify-center flex-shrink-0">
{logoUrl ? (
<>
<Image
src={logoUrl}
alt="Logo önizleme"
fill
className="object-contain p-2"
/>
<button
type="button"
onClick={() => { setLogoUrl(''); if (fileInputRef.current) fileInputRef.current.value = '' }}
className="absolute top-1 right-1 bg-red-500 text-white rounded-full p-0.5 hover:bg-red-600 transition-colors"
>
<X size={12} />
</button>
</>
) : (
<span className="text-xs text-gray-400 text-center px-2">Logo yok<br />(varsayılan kullanılır)</span>
)}
</div>
{/* Upload button */}
<div className="flex flex-col gap-2 justify-center h-20">
<button
type="button"
onClick={() => fileInputRef.current?.click()}
disabled={uploading}
className="flex items-center gap-2 px-4 py-2 border-2 border-dashed border-gray-300 rounded-lg text-sm text-gray-600 hover:border-blue-400 hover:text-blue-600 transition-colors disabled:opacity-50"
>
{uploading
? <><Loader2 size={16} className="animate-spin" /> Yükleniyor...</>
: <><Upload size={16} /> Logo Yükle</>
}
</button>
<p className="text-xs text-gray-500">PNG, SVG, WEBP Maks. 5MB</p>
{uploadError && <p className="text-xs text-red-600">{uploadError}</p>}
</div>
</div>
<input
ref={fileInputRef}
type="file"
accept="image/*"
className="hidden"
onChange={handleFileChange}
/>
<input type="hidden" name="logo_url" value={logoUrl} />
</div>
<hr className="border-gray-100" />
{/* Restaurant Name */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Restoran / Mekan Adı
</label>
<input
type="text"
name="restaurant_name"
defaultValue={defaultRestaurantName}
required
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
/>
</div>
{/* Location */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Konum Bilgisi
</label>
<input
type="text"
name="location"
defaultValue={defaultLocation}
required
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
/>
</div>
<button
type="submit"
disabled={isPending || uploading}
className="bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-6 rounded-lg transition-colors disabled:opacity-70"
>
{isPending ? 'Kaydediliyor...' : 'Kaydet'}
</button>
</form>
)
}