fix: API routing + Landing page improvements
API FIX:
- Fixed /listings/my returning 404
- Moved /my endpoint BEFORE /{slug} dynamic route
- FastAPI now correctly matches /my before treating it as slug
LANDING PAGE:
- Added visual transitions between sections
- Improved 'Beyond Hunting' section with better styling
- Added background patterns and gradient transitions
- Enhanced feature cards with corner accents
- Better visual flow between sections
This commit is contained in:
@ -255,6 +255,53 @@ async def browse_listings(
|
||||
return responses
|
||||
|
||||
|
||||
# ============== Authenticated Endpoints (before dynamic routes!) ==============
|
||||
|
||||
@router.get("/my", response_model=List[ListingResponse])
|
||||
async def get_my_listings(
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Get current user's listings."""
|
||||
result = await db.execute(
|
||||
select(DomainListing)
|
||||
.where(DomainListing.user_id == current_user.id)
|
||||
.order_by(DomainListing.created_at.desc())
|
||||
)
|
||||
listings = list(result.scalars().all())
|
||||
|
||||
return [
|
||||
ListingResponse(
|
||||
id=listing.id,
|
||||
domain=listing.domain,
|
||||
slug=listing.slug,
|
||||
title=listing.title,
|
||||
description=listing.description,
|
||||
asking_price=listing.asking_price,
|
||||
min_offer=listing.min_offer,
|
||||
currency=listing.currency,
|
||||
price_type=listing.price_type,
|
||||
pounce_score=listing.pounce_score,
|
||||
estimated_value=listing.estimated_value,
|
||||
verification_status=listing.verification_status,
|
||||
is_verified=listing.is_verified,
|
||||
status=listing.status,
|
||||
show_valuation=listing.show_valuation,
|
||||
allow_offers=listing.allow_offers,
|
||||
view_count=listing.view_count,
|
||||
inquiry_count=listing.inquiry_count,
|
||||
public_url=listing.public_url,
|
||||
created_at=listing.created_at,
|
||||
published_at=listing.published_at,
|
||||
seller_verified=current_user.is_verified,
|
||||
seller_member_since=current_user.created_at,
|
||||
)
|
||||
for listing in listings
|
||||
]
|
||||
|
||||
|
||||
# ============== Public Dynamic Routes ==============
|
||||
|
||||
@router.get("/{slug}", response_model=ListingPublicResponse)
|
||||
async def get_listing_by_slug(
|
||||
slug: str,
|
||||
@ -381,7 +428,7 @@ async def submit_inquiry(
|
||||
}
|
||||
|
||||
|
||||
# ============== Authenticated Endpoints ==============
|
||||
# ============== Listing Management (Authenticated) ==============
|
||||
|
||||
@router.post("", response_model=ListingResponse)
|
||||
async def create_listing(
|
||||
@ -485,49 +532,6 @@ async def create_listing(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/my", response_model=List[ListingResponse])
|
||||
async def get_my_listings(
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Get current user's listings."""
|
||||
result = await db.execute(
|
||||
select(DomainListing)
|
||||
.where(DomainListing.user_id == current_user.id)
|
||||
.order_by(DomainListing.created_at.desc())
|
||||
)
|
||||
listings = list(result.scalars().all())
|
||||
|
||||
return [
|
||||
ListingResponse(
|
||||
id=listing.id,
|
||||
domain=listing.domain,
|
||||
slug=listing.slug,
|
||||
title=listing.title,
|
||||
description=listing.description,
|
||||
asking_price=listing.asking_price,
|
||||
min_offer=listing.min_offer,
|
||||
currency=listing.currency,
|
||||
price_type=listing.price_type,
|
||||
pounce_score=listing.pounce_score,
|
||||
estimated_value=listing.estimated_value,
|
||||
verification_status=listing.verification_status,
|
||||
is_verified=listing.is_verified,
|
||||
status=listing.status,
|
||||
show_valuation=listing.show_valuation,
|
||||
allow_offers=listing.allow_offers,
|
||||
view_count=listing.view_count,
|
||||
inquiry_count=listing.inquiry_count,
|
||||
public_url=listing.public_url,
|
||||
created_at=listing.created_at,
|
||||
published_at=listing.published_at,
|
||||
seller_verified=current_user.is_verified,
|
||||
seller_member_since=current_user.created_at,
|
||||
)
|
||||
for listing in listings
|
||||
]
|
||||
|
||||
|
||||
@router.get("/{id}/inquiries", response_model=List[InquiryResponse])
|
||||
async def get_listing_inquiries(
|
||||
id: int,
|
||||
|
||||
@ -370,98 +370,152 @@ export default function HomePage() {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* New Features: For Sale + Sniper Alerts */}
|
||||
<section className="relative py-20 sm:py-28 px-4 sm:px-6 bg-background-secondary/30 border-y border-border/50">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="text-center max-w-3xl mx-auto mb-12 sm:mb-16">
|
||||
<span className="text-sm font-semibold text-accent uppercase tracking-wider">New Features</span>
|
||||
<h2 className="mt-4 font-display text-3xl sm:text-4xl md:text-5xl tracking-[-0.03em] text-foreground">
|
||||
More than hunting.
|
||||
{/* Transition Element */}
|
||||
<div className="relative h-24 sm:h-32">
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-background to-background-secondary/50" />
|
||||
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||
<div className="w-px h-16 bg-gradient-to-b from-transparent via-accent/30 to-transparent" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Beyond Hunting: Sell & Alert */}
|
||||
<section className="relative py-16 sm:py-24 px-4 sm:px-6 bg-background-secondary/50">
|
||||
{/* Subtle background pattern */}
|
||||
<div className="absolute inset-0 pointer-events-none overflow-hidden">
|
||||
<div className="absolute top-0 left-1/4 w-96 h-96 bg-accent/[0.02] rounded-full blur-[100px]" />
|
||||
<div className="absolute bottom-0 right-1/4 w-96 h-96 bg-accent/[0.02] rounded-full blur-[100px]" />
|
||||
</div>
|
||||
|
||||
<div className="relative max-w-7xl mx-auto">
|
||||
{/* Section Header - Left aligned for flow */}
|
||||
<div className="mb-12 sm:mb-16">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="w-2 h-2 bg-accent rounded-full animate-pulse" />
|
||||
<span className="text-sm font-semibold text-accent uppercase tracking-wider">Beyond Hunting</span>
|
||||
</div>
|
||||
<h2 className="font-display text-3xl sm:text-4xl md:text-5xl tracking-[-0.03em] text-foreground max-w-2xl">
|
||||
Buy. Sell. Get alerted.
|
||||
</h2>
|
||||
<p className="mt-4 text-lg text-foreground-muted max-w-xl">
|
||||
Pounce isn't just for finding domains. It's your complete domain business platform.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-6 lg:gap-8">
|
||||
{/* For Sale Marketplace */}
|
||||
<div className="group relative p-8 sm:p-10 bg-gradient-to-br from-accent/10 to-accent/5
|
||||
border border-accent/30 rounded-3xl hover:border-accent/50 transition-all duration-500">
|
||||
<div className="flex items-start gap-4 mb-6">
|
||||
<div className="w-14 h-14 bg-accent/20 border border-accent/30 rounded-2xl flex items-center justify-center">
|
||||
<Tag className="w-6 h-6 text-accent" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-xl font-display text-foreground mb-1">Sell Your Domains</h3>
|
||||
<p className="text-sm text-accent">Marketplace</p>
|
||||
<div className="group relative p-8 sm:p-10 bg-gradient-to-br from-accent/10 via-accent/5 to-transparent
|
||||
border border-accent/20 rounded-3xl hover:border-accent/40 transition-all duration-500
|
||||
backdrop-blur-sm">
|
||||
{/* Corner accent */}
|
||||
<div className="absolute top-0 right-0 w-24 h-24 bg-accent/10 rounded-bl-[100px] rounded-tr-3xl" />
|
||||
|
||||
<div className="relative">
|
||||
<div className="flex items-start gap-4 mb-6">
|
||||
<div className="w-14 h-14 bg-accent/20 border border-accent/30 rounded-2xl flex items-center justify-center shadow-lg shadow-accent/10">
|
||||
<Tag className="w-6 h-6 text-accent" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-xl font-display text-foreground mb-1">Sell Your Domains</h3>
|
||||
<p className="text-sm text-accent font-medium">Marketplace</p>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-foreground-muted mb-6 leading-relaxed">
|
||||
Create professional "For Sale" landing pages with one click.
|
||||
<span className="text-foreground font-medium"> DNS verification</span> proves ownership.
|
||||
Buyers contact you directly through Pounce.
|
||||
</p>
|
||||
<ul className="space-y-3 text-sm mb-8">
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<div className="w-6 h-6 rounded-full bg-accent/10 flex items-center justify-center">
|
||||
<Shield className="w-3.5 h-3.5 text-accent" />
|
||||
</div>
|
||||
<span>Verified Owner badge</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<div className="w-6 h-6 rounded-full bg-accent/10 flex items-center justify-center">
|
||||
<BarChart3 className="w-3.5 h-3.5 text-accent" />
|
||||
</div>
|
||||
<span>Pounce Score valuation</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<div className="w-6 h-6 rounded-full bg-accent/10 flex items-center justify-center">
|
||||
<Lock className="w-3.5 h-3.5 text-accent" />
|
||||
</div>
|
||||
<span>Secure contact form</span>
|
||||
</li>
|
||||
</ul>
|
||||
<Link
|
||||
href="/buy"
|
||||
className="inline-flex items-center gap-2 px-5 py-2.5 bg-accent text-background font-medium rounded-xl hover:bg-accent-hover transition-all"
|
||||
>
|
||||
Browse Marketplace
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</Link>
|
||||
</div>
|
||||
<p className="text-foreground-muted mb-6 leading-relaxed">
|
||||
Create professional "For Sale" landing pages with one click.
|
||||
<span className="text-foreground"> DNS verification</span> proves ownership.
|
||||
Buyers contact you directly through Pounce.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm mb-6">
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<Shield className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>Verified Owner badge</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<BarChart3 className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>Pounce Score valuation</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<Lock className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>Secure contact form</span>
|
||||
</li>
|
||||
</ul>
|
||||
<Link
|
||||
href="/buy"
|
||||
className="inline-flex items-center gap-2 text-accent hover:text-accent-hover font-medium transition-colors"
|
||||
>
|
||||
Browse Marketplace
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Sniper Alerts */}
|
||||
<div className="group relative p-8 sm:p-10 bg-gradient-to-br from-foreground/5 to-foreground/0
|
||||
border border-border rounded-3xl hover:border-accent/30 transition-all duration-500">
|
||||
<div className="flex items-start gap-4 mb-6">
|
||||
<div className="w-14 h-14 bg-foreground/10 border border-border rounded-2xl flex items-center justify-center">
|
||||
<Target className="w-6 h-6 text-foreground" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-xl font-display text-foreground mb-1">Sniper Alerts</h3>
|
||||
<p className="text-sm text-foreground-muted">Hyper-Personalized</p>
|
||||
</div>
|
||||
<div className="group relative p-8 sm:p-10 bg-gradient-to-br from-foreground/[0.03] to-transparent
|
||||
border border-border rounded-3xl hover:border-accent/30 transition-all duration-500
|
||||
backdrop-blur-sm">
|
||||
{/* Decorative element */}
|
||||
<div className="absolute top-6 right-6 flex gap-1">
|
||||
<div className="w-2 h-2 rounded-full bg-accent/50 animate-pulse" />
|
||||
<div className="w-2 h-2 rounded-full bg-accent/30 animate-pulse delay-100" />
|
||||
<div className="w-2 h-2 rounded-full bg-accent/20 animate-pulse delay-200" />
|
||||
</div>
|
||||
|
||||
<div className="relative">
|
||||
<div className="flex items-start gap-4 mb-6">
|
||||
<div className="w-14 h-14 bg-foreground/10 border border-border rounded-2xl flex items-center justify-center">
|
||||
<Target className="w-6 h-6 text-foreground" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-xl font-display text-foreground mb-1">Sniper Alerts</h3>
|
||||
<p className="text-sm text-foreground-muted">Hyper-Personalized</p>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-foreground-muted mb-6 leading-relaxed">
|
||||
Ultra-specific filters that notify you <span className="text-foreground font-medium">exactly</span> when matching domains appear.
|
||||
<span className="italic"> "4-letter .com under $500 without numbers"</span> — we've got you.
|
||||
</p>
|
||||
<ul className="space-y-3 text-sm mb-8">
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<div className="w-6 h-6 rounded-full bg-foreground/5 flex items-center justify-center">
|
||||
<Filter className="w-3.5 h-3.5 text-accent" />
|
||||
</div>
|
||||
<span>Custom TLD, length, price filters</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<div className="w-6 h-6 rounded-full bg-foreground/5 flex items-center justify-center">
|
||||
<Bell className="w-3.5 h-3.5 text-accent" />
|
||||
</div>
|
||||
<span>Email & SMS alerts</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<div className="w-6 h-6 rounded-full bg-foreground/5 flex items-center justify-center">
|
||||
<Zap className="w-3.5 h-3.5 text-accent" />
|
||||
</div>
|
||||
<span>Real-time auction matching</span>
|
||||
</li>
|
||||
</ul>
|
||||
<Link
|
||||
href="/command/alerts"
|
||||
className="inline-flex items-center gap-2 px-5 py-2.5 border border-border text-foreground font-medium rounded-xl hover:border-accent hover:text-accent transition-all"
|
||||
>
|
||||
Set Up Alerts
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</Link>
|
||||
</div>
|
||||
<p className="text-foreground-muted mb-6 leading-relaxed">
|
||||
Ultra-specific filters that notify you <span className="text-foreground">exactly</span> when matching domains appear.
|
||||
"4-letter .com under $500 without numbers" — we've got you.
|
||||
</p>
|
||||
<ul className="space-y-2 text-sm mb-6">
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<Filter className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>Custom TLD, length, price filters</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<Bell className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>Email & SMS alerts</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-foreground-subtle">
|
||||
<Zap className="w-4 h-4 text-accent flex-shrink-0" />
|
||||
<span>Real-time auction matching</span>
|
||||
</li>
|
||||
</ul>
|
||||
<Link
|
||||
href="/command/alerts"
|
||||
className="inline-flex items-center gap-2 text-foreground-muted hover:text-foreground font-medium transition-colors"
|
||||
>
|
||||
Set Up Alerts
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Transition to TLDs */}
|
||||
<div className="relative h-16 sm:h-24 bg-background-secondary/50">
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-background-secondary/50 to-background" />
|
||||
</div>
|
||||
|
||||
{/* Trending TLDs Section */}
|
||||
<section className="relative py-20 sm:py-28 px-4 sm:px-6">
|
||||
|
||||
Reference in New Issue
Block a user