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:
yves.gugger
2025-12-10 11:50:48 +01:00
parent 18d50e96f4
commit f83dde870b
2 changed files with 179 additions and 121 deletions

View File

@ -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,

View File

@ -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">