'use client'
import { useEffect, useState, useCallback } from 'react'
import { useSearchParams } from 'next/navigation'
import { useStore } from '@/lib/store'
import { api } from '@/lib/api'
import { Sidebar } from '@/components/Sidebar'
import {
Plus, Shield, Eye, MessageSquare, ExternalLink, Loader2, Trash2,
CheckCircle, AlertCircle, Copy, DollarSign, X, Tag, Sparkles,
TrendingUp, Gavel, Target, Menu, Settings, LogOut, Crown, Zap, Coins, Check
} from 'lucide-react'
import Link from 'next/link'
import Image from 'next/image'
import clsx from 'clsx'
// ============================================================================
// TYPES
// ============================================================================
interface Listing {
id: number
domain: string
slug: string
title: string | null
description: string | null
asking_price: number | null
min_offer: number | null
currency: string
price_type: string
pounce_score: number | null
verification_status: string
is_verified: boolean
status: string
view_count: number
inquiry_count: number
public_url: string
created_at: string
}
// ============================================================================
// MAIN PAGE
// ============================================================================
export default function MyListingsPage() {
const { subscription, user, logout, checkAuth } = useStore()
const searchParams = useSearchParams()
const prefillDomain = searchParams.get('domain')
const [listings, setListings] = useState
([])
const [loading, setLoading] = useState(true)
const [showCreateModal, setShowCreateModal] = useState(false)
const [deletingId, setDeletingId] = useState(null)
const [menuOpen, setMenuOpen] = useState(false)
const tier = subscription?.tier || 'scout'
const listingLimits: Record = { scout: 0, trader: 5, tycoon: 50 }
const maxListings = listingLimits[tier] || 0
const canAddMore = listings.length < maxListings
const isTycoon = tier === 'tycoon'
const activeListings = listings.filter(l => l.status === 'active').length
const totalViews = listings.reduce((sum, l) => sum + l.view_count, 0)
const totalInquiries = listings.reduce((sum, l) => sum + l.inquiry_count, 0)
useEffect(() => { checkAuth() }, [checkAuth])
useEffect(() => { if (prefillDomain) setShowCreateModal(true) }, [prefillDomain])
const loadListings = useCallback(async () => {
setLoading(true)
try {
const data = await api.getMyListings()
setListings(data)
} catch (err) { console.error(err) }
finally { setLoading(false) }
}, [])
useEffect(() => { loadListings() }, [loadListings])
const handleDelete = async (id: number, domain: string) => {
if (!confirm(`Delete listing for ${domain}?`)) return
setDeletingId(id)
try {
await api.deleteListing(id)
await loadListings()
} catch (err: any) { alert(err.message || 'Failed') }
finally { setDeletingId(null) }
}
const mobileNavItems = [
{ href: '/terminal/radar', label: 'Radar', icon: Target, active: false },
{ href: '/terminal/market', label: 'Market', icon: Gavel, active: false },
{ href: '/terminal/watchlist', label: 'Watch', icon: Eye, active: false },
{ href: '/terminal/intel', label: 'Intel', icon: TrendingUp, active: false },
]
const tierName = subscription?.tier_name || subscription?.tier || 'Scout'
const TierIcon = tierName === 'Tycoon' ? Crown : tierName === 'Trader' ? TrendingUp : Zap
const drawerNavSections = [
{ title: 'Discover', items: [
{ href: '/terminal/radar', label: 'Radar', icon: Target },
{ href: '/terminal/market', label: 'Market', icon: Gavel },
{ href: '/terminal/intel', label: 'Intel', icon: TrendingUp },
]},
{ title: 'Manage', items: [
{ href: '/terminal/watchlist', label: 'Watchlist', icon: Eye },
{ href: '/terminal/sniper', label: 'Sniper', icon: Target },
]},
{ title: 'Monetize', items: [
{ href: '/terminal/yield', label: 'Yield', icon: Coins },
{ href: '/terminal/listing', label: 'For Sale', icon: Tag, active: true },
]}
]
return (
{/* MOBILE HEADER */}
{listings.length}/{maxListings}
{/* DESKTOP HEADER */}
For Sale
{listings.length}/{maxListings}
{/* ADD BUTTON MOBILE */}
{/* CONTENT */}
{loading ? (
) : listings.length === 0 ? (
No listings yet
Create your first listing
) : (
{/* Header */}
Domain
Price
Status
Views
Leads
Actions
{listings.map((listing) => (
{/* Mobile */}
{listing.is_verified ? : }
{listing.domain}
{listing.status}
${listing.asking_price?.toLocaleString() || 'Negotiable'}
{listing.view_count} views · {listing.inquiry_count} leads
View
{/* Desktop */}
{listing.is_verified ? : }
{listing.domain}
{isTycoon && Featured}
${listing.asking_price?.toLocaleString() || '—'}
{listing.status}
{listing.view_count}
{listing.inquiry_count}
))}
)}
{!canAddMore && (
Listing Limit Reached
Upgrade for more listings
Upgrade
)}
{/* MOBILE BOTTOM NAV */}
{/* DRAWER */}
{menuOpen && (
setMenuOpen(false)} />
{drawerNavSections.map((section) => (
{section.items.map((item: any) => (
setMenuOpen(false)} className={clsx("flex items-center gap-3 px-4 py-2.5 border-l-2 border-transparent", item.active ? "text-accent border-accent bg-white/[0.02]" : "text-white/60")}>
{item.label}
))}
))}
setMenuOpen(false)} className="flex items-center gap-3 py-2.5 text-white/50">Settings
{user?.is_admin && setMenuOpen(false)} className="flex items-center gap-3 py-2.5 text-amber-500/70">Admin}
{user?.name || user?.email?.split('@')[0] || 'User'}
{tierName}
{tierName === 'Scout' &&
setMenuOpen(false)} className="flex items-center justify-center gap-2 w-full py-2.5 bg-accent text-black text-xs font-bold uppercase mb-2">
Upgrade}
)}
{/* CREATE MODAL */}
{showCreateModal && (
setShowCreateModal(false)}
onSuccess={() => { loadListings(); setShowCreateModal(false) }}
prefillDomain={prefillDomain || ''}
/>
)}
)
}
// ============================================================================
// CREATE MODAL (simplified)
// ============================================================================
function CreateListingModal({ onClose, onSuccess, prefillDomain }: { onClose: () => void; onSuccess: () => void; prefillDomain: string }) {
const [domain, setDomain] = useState(prefillDomain)
const [price, setPrice] = useState('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
if (!domain.trim()) return
setLoading(true)
setError(null)
try {
await api.createListing({ domain: domain.trim(), asking_price: price ? parseFloat(price) : null, currency: 'USD', price_type: price ? 'fixed' : 'negotiable' })
onSuccess()
} catch (err: any) { setError(err.message || 'Failed') }
finally { setLoading(false) }
}
return (
)
}