300 lines
9.8 KiB
TypeScript
300 lines
9.8 KiB
TypeScript
'use client'
|
||
|
||
import React, { useEffect, useState } from 'react'
|
||
import { useSession } from 'next-auth/react'
|
||
import { useRouter } from 'next/navigation'
|
||
import Link from 'next/link'
|
||
import Cookies from 'js-cookie'
|
||
|
||
interface Address {
|
||
id: string
|
||
street: string
|
||
city: string
|
||
postcode: string
|
||
order: number
|
||
}
|
||
|
||
interface Route {
|
||
id: string
|
||
name: string | null
|
||
status: string
|
||
addresses: Address[]
|
||
}
|
||
|
||
interface PageProps {
|
||
params: Promise<{ id: string }>
|
||
}
|
||
|
||
export default function EditRoutePage({ params }: PageProps) {
|
||
const routeId = React.use(params).id
|
||
const router = useRouter()
|
||
const { data: session, status } = useSession()
|
||
const [route, setRoute] = useState<Route | null>(null)
|
||
const [loading, setLoading] = useState(true)
|
||
const [error, setError] = useState<string | null>(null)
|
||
const [currentAddress, setCurrentAddress] = useState('')
|
||
const [suggestedAddresses, setSuggestedAddresses] = useState<string[]>([])
|
||
const [isSaving, setIsSaving] = useState(false)
|
||
const [messages, setMessages] = useState<any>(null)
|
||
|
||
useEffect(() => {
|
||
const loadMessages = async () => {
|
||
const lang = Cookies.get('NEXT_LOCALE') || 'de'
|
||
const messages = await import(`@/messages/${lang}.json`)
|
||
setMessages(messages.default)
|
||
}
|
||
loadMessages()
|
||
}, [])
|
||
|
||
useEffect(() => {
|
||
fetchRoute()
|
||
}, [routeId])
|
||
|
||
const fetchRoute = async () => {
|
||
try {
|
||
const response = await fetch(`/api/routes/${routeId}`, {
|
||
credentials: 'include'
|
||
})
|
||
|
||
if (!response.ok) {
|
||
throw new Error(messages?.editRoute?.notFound || 'Rota bulunamadı')
|
||
}
|
||
|
||
const data = await response.json()
|
||
setRoute(data)
|
||
} catch (err) {
|
||
console.error('Rota getirme hatası:', err)
|
||
setError(err instanceof Error ? err.message : messages?.editRoute?.error || 'Rota yüklenirken bir hata oluştu')
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
const fetchAddressSuggestions = async (term: string) => {
|
||
if (term.length < 3) {
|
||
setSuggestedAddresses([])
|
||
return
|
||
}
|
||
|
||
try {
|
||
const response = await fetch(`/api/address-suggestions?q=${encodeURIComponent(term)}`)
|
||
if (!response.ok) {
|
||
throw new Error(messages?.editRoute?.noResults || 'Adres önerileri alınamadı')
|
||
}
|
||
const suggestions = await response.json()
|
||
setSuggestedAddresses(suggestions)
|
||
} catch (error) {
|
||
console.error('Adres önerileri hatası:', error)
|
||
}
|
||
}
|
||
|
||
const handleAddAddress = () => {
|
||
if (!route || !currentAddress.trim()) return
|
||
|
||
// Adresi parçalara ayır
|
||
const parts = currentAddress.split(',').map(part => part.trim())
|
||
const streetPart = parts[0] || ''
|
||
const locationPart = parts[1] || ''
|
||
|
||
// Posta kodu ve şehir bilgisini ayır
|
||
const locationMatch = locationPart.match(/(\d{4})\s+([^0]+)/)
|
||
const postcode = locationMatch ? locationMatch[1] : ''
|
||
const city = locationMatch ? locationMatch[2].replace(/\s*0+$/, '').trim() : '' // Sondaki 0000'ları temizle
|
||
|
||
const newAddresses = [...route.addresses, {
|
||
id: `temp-${Date.now()}`,
|
||
street: streetPart,
|
||
city: city,
|
||
postcode: postcode,
|
||
order: route.addresses.length
|
||
}]
|
||
|
||
setRoute({ ...route, addresses: newAddresses })
|
||
setCurrentAddress('')
|
||
setSuggestedAddresses([])
|
||
}
|
||
|
||
const handleRemoveAddress = (index: number) => {
|
||
if (!route) return
|
||
|
||
const newAddresses = route.addresses.filter((_, i) => i !== index)
|
||
// Sıralamayı güncelle
|
||
newAddresses.forEach((addr, i) => {
|
||
addr.order = i
|
||
})
|
||
|
||
setRoute({ ...route, addresses: newAddresses })
|
||
}
|
||
|
||
const handleMoveAddress = (index: number, direction: 'up' | 'down') => {
|
||
if (!route) return
|
||
|
||
const newAddresses = [...route.addresses]
|
||
if (direction === 'up' && index > 0) {
|
||
[newAddresses[index], newAddresses[index - 1]] = [newAddresses[index - 1], newAddresses[index]]
|
||
} else if (direction === 'down' && index < newAddresses.length - 1) {
|
||
[newAddresses[index], newAddresses[index + 1]] = [newAddresses[index + 1], newAddresses[index]]
|
||
}
|
||
|
||
// Sıralamayı güncelle
|
||
newAddresses.forEach((addr, i) => {
|
||
addr.order = i
|
||
})
|
||
|
||
setRoute({ ...route, addresses: newAddresses })
|
||
}
|
||
|
||
const handleSave = async () => {
|
||
if (!route) return
|
||
|
||
setIsSaving(true)
|
||
try {
|
||
const response = await fetch(`/api/routes/${routeId}`, {
|
||
method: 'PUT',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
credentials: 'include',
|
||
body: JSON.stringify({
|
||
addresses: route.addresses
|
||
})
|
||
})
|
||
|
||
if (!response.ok) {
|
||
throw new Error(messages?.editRoute?.saveError || 'Rota güncellenemedi')
|
||
}
|
||
|
||
router.push('/dashboard/routes')
|
||
} catch (err) {
|
||
console.error('Rota güncelleme hatası:', err)
|
||
setError(err instanceof Error ? err.message : messages?.editRoute?.saveError || 'Rota güncellenirken bir hata oluştu')
|
||
} finally {
|
||
setIsSaving(false)
|
||
}
|
||
}
|
||
|
||
if (!messages || status === 'loading' || loading) {
|
||
return (
|
||
<div className="min-h-screen flex items-center justify-center">
|
||
<div className="animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-indigo-500"></div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
if (status === 'unauthenticated') {
|
||
router.push('/auth/login')
|
||
return null
|
||
}
|
||
|
||
if (error || !route) {
|
||
return (
|
||
<div className="min-h-screen flex items-center justify-center">
|
||
<div className="text-center">
|
||
<h2 className="text-2xl font-bold mb-4">{messages.common.error}</h2>
|
||
<p className="text-red-600">{error || messages.editRoute.notFound}</p>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
return (
|
||
<div className="min-h-screen bg-gray-100 py-6">
|
||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||
<div className="flex justify-between items-center mb-8">
|
||
<h1 className="text-3xl font-bold text-gray-900">{messages.editRoute.title}</h1>
|
||
<div className="flex space-x-4">
|
||
<Link
|
||
href="/dashboard/routes"
|
||
className="bg-gray-500 text-white px-4 py-2 rounded-md hover:bg-gray-600"
|
||
>
|
||
{messages.editRoute.cancel}
|
||
</Link>
|
||
<button
|
||
onClick={handleSave}
|
||
disabled={isSaving}
|
||
className="bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 disabled:opacity-50"
|
||
>
|
||
{isSaving ? messages.editRoute.saving : messages.editRoute.save}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-white shadow rounded-lg p-6">
|
||
<div className="space-y-6">
|
||
{/* Adres Arama */}
|
||
<div className="relative">
|
||
<input
|
||
type="text"
|
||
value={currentAddress}
|
||
onChange={(e) => {
|
||
setCurrentAddress(e.target.value)
|
||
fetchAddressSuggestions(e.target.value)
|
||
}}
|
||
className="w-full p-3 border-2 border-gray-300 rounded-lg text-gray-800 font-medium placeholder-gray-500 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 transition-colors duration-200"
|
||
placeholder={messages.editRoute.searchPlaceholder}
|
||
/>
|
||
{suggestedAddresses.length > 0 && (
|
||
<ul className="absolute z-10 w-full bg-white border-2 border-gray-200 rounded-lg mt-1 shadow-lg divide-y divide-gray-100">
|
||
{suggestedAddresses.map((address, index) => (
|
||
<li
|
||
key={index}
|
||
className="px-4 py-3 hover:bg-indigo-50 cursor-pointer text-gray-800 font-medium transition-colors duration-150"
|
||
onClick={() => {
|
||
setCurrentAddress(address)
|
||
setSuggestedAddresses([])
|
||
}}
|
||
>
|
||
{address}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
)}
|
||
</div>
|
||
|
||
{/* Adres Listesi */}
|
||
<div className="space-y-4">
|
||
<h3 className="text-lg font-medium text-gray-900">{messages.editRoute.addresses}</h3>
|
||
<ul className="space-y-3">
|
||
{route.addresses.map((address, index) => (
|
||
<li
|
||
key={address.id}
|
||
className="p-4 bg-gray-50 rounded-lg border-2 border-gray-200 flex justify-between items-center"
|
||
>
|
||
<span className="text-gray-800 font-medium">
|
||
{index + 1}. {address.street}
|
||
</span>
|
||
<div className="flex items-center space-x-2">
|
||
<button
|
||
onClick={() => handleMoveAddress(index, 'up')}
|
||
disabled={index === 0}
|
||
className="p-2 text-gray-600 hover:text-gray-900 disabled:opacity-50"
|
||
title={messages.editRoute.moveUp}
|
||
>
|
||
↑
|
||
</button>
|
||
<button
|
||
onClick={() => handleMoveAddress(index, 'down')}
|
||
disabled={index === route.addresses.length - 1}
|
||
className="p-2 text-gray-600 hover:text-gray-900 disabled:opacity-50"
|
||
title={messages.editRoute.moveDown}
|
||
>
|
||
↓
|
||
</button>
|
||
<button
|
||
onClick={() => handleRemoveAddress(index)}
|
||
className="p-2 text-red-600 hover:text-red-900"
|
||
title={messages.editRoute.delete}
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|