300 lines
9.8 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 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>
)
}