Files
sitarapart/components/admin/RoomForm.tsx
T

254 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useState } from 'react'
import { useRouter } from 'next/navigation'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { createRoom, updateRoom, RoomInput } from '@/lib/actions/room'
import { uploadImageAction } from '@/lib/actions/upload'
import { Loader2 } from 'lucide-react'
import { ImageUploadModal } from '@/components/admin/ImageUploadModal'
interface RoomFormProps {
initialData?: RoomInput & { id: string }
}
export function RoomForm({ initialData }: RoomFormProps) {
const router = useRouter()
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const [formData, setFormData] = useState<RoomInput>(initialData || {
slug: '',
type: 'STUDIO_1_0',
nameTr: '',
nameEn: '',
nameDe: '',
descriptionTr: '',
descriptionEn: '',
descriptionDe: '',
capacity: 2,
price: null,
imageUrl: '',
images: [],
amenities: [],
available: true,
featured: false,
})
// Helper for comma-separated arrays
const handleArrayChange = (field: 'images' | 'amenities', value: string) => {
const arrayValue = value.split(',').map(s => s.trim()).filter(Boolean)
setFormData(prev => ({ ...prev, [field]: arrayValue }))
}
const handleMainImageComplete = (urls: string[]) => {
if (urls.length > 0) {
setFormData(prev => ({ ...prev, imageUrl: urls[0] }))
}
}
const handleGalleryComplete = (urls: string[]) => {
if (urls.length > 0) {
setFormData(prev => ({ ...prev, images: [...prev.images, ...urls] }))
}
}
const removeGalleryImage = (index: number) => {
setFormData(prev => ({
...prev,
images: prev.images.filter((_, i) => i !== index)
}))
}
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setLoading(true)
setError(null)
try {
let result
if (initialData?.id) {
result = await updateRoom(initialData.id, formData)
} else {
result = await createRoom(formData)
}
if (result?.success) {
router.push('/admin/rooms')
router.refresh()
} else {
setError(result?.error || 'Bir hata oluştu.')
}
} catch (err) {
setError('Bir hata oluştu.')
} finally {
setLoading(false)
}
}
return (
<form onSubmit={handleSubmit} className="space-y-6 max-w-4xl bg-white dark:bg-gray-950 p-6 rounded-lg border border-gray-200 dark:border-gray-800">
{error && (
<div className="bg-red-50 text-red-600 p-3 rounded-md text-sm">
{error}
</div>
)}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<label className="text-sm font-medium">Oda Tipi</label>
<select
value={formData.type}
onChange={(e) => setFormData(prev => ({ ...prev, type: e.target.value as any }))}
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
>
<option value="STUDIO_1_0">Stüdyo (1+0)</option>
<option value="SUITE_1_1">Süit (1+1)</option>
</select>
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Slug (URL)</label>
<Input
required
value={formData.slug}
onChange={(e) => setFormData(prev => ({ ...prev, slug: e.target.value }))}
placeholder="ornek-oda-1"
/>
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Ad (TR)</label>
<Input required value={formData.nameTr} onChange={(e) => setFormData(prev => ({ ...prev, nameTr: e.target.value }))} />
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Ad (EN)</label>
<Input required value={formData.nameEn} onChange={(e) => setFormData(prev => ({ ...prev, nameEn: e.target.value }))} />
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Ad (DE)</label>
<Input required value={formData.nameDe} onChange={(e) => setFormData(prev => ({ ...prev, nameDe: e.target.value }))} />
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Kapasite</label>
<Input type="number" required value={formData.capacity} onChange={(e) => setFormData(prev => ({ ...prev, capacity: parseInt(e.target.value) || 0 }))} />
</div>
<div className="space-y-2">
<label className="text-sm font-medium">Fiyat (Opsiyonel)</label>
<Input type="number" value={formData.price || ''} onChange={(e) => setFormData(prev => ({ ...prev, price: e.target.value ? parseInt(e.target.value) : null }))} />
</div>
<div className="space-y-2 md:col-span-2">
<label className="text-sm font-medium">Açıklama (TR)</label>
<textarea
required
className="flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
value={formData.descriptionTr}
onChange={(e) => setFormData(prev => ({ ...prev, descriptionTr: e.target.value }))}
/>
</div>
<div className="space-y-2 md:col-span-2">
<label className="text-sm font-medium">Açıklama (EN)</label>
<textarea
required
className="flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
value={formData.descriptionEn}
onChange={(e) => setFormData(prev => ({ ...prev, descriptionEn: e.target.value }))}
/>
</div>
<div className="space-y-2 md:col-span-2">
<label className="text-sm font-medium">Açıklama (DE)</label>
<textarea
required
className="flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
value={formData.descriptionDe}
onChange={(e) => setFormData(prev => ({ ...prev, descriptionDe: e.target.value }))}
/>
</div>
<div className="space-y-2 md:col-span-2">
<label className="text-sm font-medium">Ana Resim</label>
<ImageUploadModal
onUploadComplete={handleMainImageComplete}
multiple={false}
triggerText="Ana Resmi Yükle"
folderName={`starapart/${formData.type}`}
/>
{formData.imageUrl && (
<div className="mt-2">
<img src={formData.imageUrl} alt="Ana Resim" className="h-32 object-cover rounded-md border" />
<Input className="mt-2" value={formData.imageUrl} onChange={(e) => setFormData(prev => ({ ...prev, imageUrl: e.target.value }))} placeholder="Veya doğrudan URL girin..." />
</div>
)}
</div>
<div className="space-y-2 md:col-span-2">
<label className="text-sm font-medium">Galeri (Diğer Resimler)</label>
<ImageUploadModal
onUploadComplete={handleGalleryComplete}
multiple={true}
triggerText="Galeri İçin Çoklu Resim Yükle"
folderName={`starapart/${formData.type}`}
/>
{formData.images.length > 0 && (
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mt-4">
{formData.images.map((url, idx) => (
<div key={idx} className="relative group">
<img src={url} alt={`Gallery ${idx}`} className="h-24 w-full object-cover rounded-md border" />
<button
type="button"
onClick={() => removeGalleryImage(idx)}
className="absolute top-1 right-1 bg-red-500 text-white rounded-full p-1 opacity-0 group-hover:opacity-100 transition-opacity"
>
×
</button>
</div>
))}
</div>
)}
<Input
className="mt-2"
value={formData.images.join(', ')}
onChange={(e) => handleArrayChange('images', e.target.value)}
placeholder="Veya virgülle ayırarak URL'leri girin..."
/>
</div>
<div className="space-y-2 md:col-span-2">
<label className="text-sm font-medium">Özellikler (Amenities - Virgülle ayırın)</label>
<Input value={formData.amenities.join(', ')} onChange={(e) => handleArrayChange('amenities', e.target.value)} placeholder="Wifi, TV, Klima..." />
</div>
<div className="space-y-2 flex items-center space-x-2">
<input
type="checkbox"
id="available"
checked={formData.available}
onChange={(e) => setFormData(prev => ({ ...prev, available: e.target.checked }))}
className="h-4 w-4 rounded border-gray-300"
/>
<label htmlFor="available" className="text-sm font-medium cursor-pointer">Müsait mi?</label>
</div>
<div className="space-y-2 flex items-center space-x-2">
<input
type="checkbox"
id="featured"
checked={formData.featured}
onChange={(e) => setFormData(prev => ({ ...prev, featured: e.target.checked }))}
className="h-4 w-4 rounded border-gray-300"
/>
<label htmlFor="featured" className="text-sm font-medium cursor-pointer">Öne Çıkan (Anasayfada göster)</label>
</div>
</div>
<div className="flex justify-end space-x-4 pt-4 border-t border-gray-200 dark:border-gray-800">
<Button type="button" variant="outline" onClick={() => router.push('/admin/rooms')} disabled={loading}>İptal</Button>
<Button type="submit" disabled={loading}>
{loading ? 'Kaydediliyor...' : 'Kaydet'}
</Button>
</div>
</form>
)
}