119 lines
4.1 KiB
TypeScript
119 lines
4.1 KiB
TypeScript
'use client'
|
||
|
||
import { useEffect, useState } from 'react'
|
||
import { useSearchParams } from 'next/navigation'
|
||
import ListingCard from '@/components/ListingCard'
|
||
import { Heart, Share2, ClipboardCheck } from 'lucide-react'
|
||
|
||
interface Props {
|
||
allListings: any[]
|
||
locale: string
|
||
}
|
||
|
||
export default function SavedClient({ allListings, locale }: Props) {
|
||
const searchParams = useSearchParams()
|
||
const [savedIds, setSavedIds] = useState<string[]>([])
|
||
const [copied, setCopied] = useState(false)
|
||
const [isClient, setIsClient] = useState(false)
|
||
|
||
useEffect(() => {
|
||
setIsClient(true)
|
||
const paramIds = searchParams.get('ids')
|
||
|
||
if (paramIds) {
|
||
// Load shared favorites
|
||
const ids = paramIds.split(',').filter(Boolean)
|
||
setSavedIds(ids)
|
||
// Save shared list to local storage as well
|
||
localStorage.setItem('savedListingIds', JSON.stringify(ids))
|
||
} else {
|
||
// Load personal favorites from localStorage
|
||
try {
|
||
const stored = localStorage.getItem('savedListingIds')
|
||
if (stored) {
|
||
setSavedIds(JSON.parse(stored))
|
||
}
|
||
} catch (e) {
|
||
console.error('Error reading localStorage:', e)
|
||
}
|
||
}
|
||
}, [searchParams])
|
||
|
||
const handleShare = () => {
|
||
if (savedIds.length === 0) return
|
||
const shareUrl = `${window.location.origin}${window.location.pathname}?ids=${savedIds.join(',')}`
|
||
|
||
navigator.clipboard.writeText(shareUrl).then(() => {
|
||
setCopied(true)
|
||
setTimeout(() => setCopied(false), 2000)
|
||
})
|
||
}
|
||
|
||
// Filter listings matching saved IDs
|
||
const filteredListings = allListings.filter(l => savedIds.includes(l.id))
|
||
|
||
if (!isClient) {
|
||
return (
|
||
<div className="py-20 text-center font-mono text-xs text-shutter animate-pulse">
|
||
liste yükleniyor...
|
||
</div>
|
||
)
|
||
}
|
||
|
||
return (
|
||
<div className="space-y-8">
|
||
{/* Title / Action bar */}
|
||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 border-b border-dashed border-pine/8 pb-6">
|
||
<div>
|
||
<span className="text-[10px] font-mono tracking-widest text-shutter uppercase bg-paper px-3 py-1.5 rounded-full border border-pine/5">
|
||
kişisel rehberiniz
|
||
</span>
|
||
<h1 className="text-3xl font-heading font-extrabold text-pine lowercase mt-2.5">
|
||
kaydedilen <span className="text-turquoise">mekanlar</span>
|
||
</h1>
|
||
</div>
|
||
|
||
{savedIds.length > 0 && (
|
||
<button
|
||
onClick={handleShare}
|
||
className="inline-flex items-center gap-2 bg-turquoise hover:bg-turquoise/90 text-paper text-xs font-bold py-3 px-5 rounded-xl shadow-sm transition active:scale-95 duration-150 shrink-0 self-start"
|
||
>
|
||
{copied ? (
|
||
<>
|
||
<ClipboardCheck className="w-4 h-4 text-paper" />
|
||
Paylaşım Linki Kopyalandı!
|
||
</>
|
||
) : (
|
||
<>
|
||
<Share2 className="w-4 h-4 text-paper" />
|
||
Listeyi Paylaş (URL Kopyala)
|
||
</>
|
||
)}
|
||
</button>
|
||
)}
|
||
</div>
|
||
|
||
{/* Grid List */}
|
||
{filteredListings.length === 0 ? (
|
||
<div className="bg-paper border border-pine/8 rounded-3xl p-12 text-center space-y-4 max-w-xl mx-auto">
|
||
<div className="w-12 h-12 rounded-full bg-stone/50 border border-pine/5 flex items-center justify-center mx-auto text-shutter">
|
||
<Heart className="w-5 h-5 fill-transparent" />
|
||
</div>
|
||
<div>
|
||
<h3 className="font-heading font-bold text-pine lowercase text-sm">listeniz henüz boş</h3>
|
||
<p className="text-ink/65 text-xs mt-1.5 max-w-sm mx-auto leading-relaxed">
|
||
Mekan kartlarındaki kalp simgesine tıklayarak beğendiğiniz yerleri buraya ekleyebilir ve daha sonra hızlıca erişebilirsiniz.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
) : (
|
||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||
{filteredListings.map((listing) => (
|
||
<ListingCard key={listing.id} listing={listing} />
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|