fix: Consistent domain status across pages + refresh-all timezone fix

Backend:
- Fixed datetime timezone error in refresh-all endpoint
- Added _to_naive_utc() helper for PostgreSQL compatibility

Frontend:
- Watchlist now passes domain status to AnalyzePanel
- Status is consistent between Drops, Watchlist, and Sidepanel
- Shows "Available" or "Taken" status in AnalyzePanel from Watchlist
This commit is contained in:
2025-12-20 23:44:53 +01:00
parent 4995101dd1
commit 5df7d5cb96
2 changed files with 27 additions and 8 deletions

View File

@ -1,6 +1,6 @@
"""Domain management API (requires authentication)."""
import json
from datetime import datetime
from datetime import datetime, timezone
from math import ceil
from fastapi import APIRouter, HTTPException, status, Query
@ -16,6 +16,16 @@ from app.services.domain_health import get_health_checker, HealthStatus
router = APIRouter()
def _to_naive_utc(dt: datetime | None) -> datetime | None:
"""Convert timezone-aware datetime to naive UTC datetime for PostgreSQL."""
if dt is None:
return None
if dt.tzinfo is not None:
# Convert to UTC and remove timezone info
return dt.astimezone(timezone.utc).replace(tzinfo=None)
return dt
def _safe_json_loads(value: str | None, default):
if not value:
return default
@ -265,7 +275,7 @@ async def refresh_domain(
domain.status = check_result.status
domain.is_available = check_result.is_available
domain.registrar = check_result.registrar
domain.expiration_date = check_result.expiration_date
domain.expiration_date = _to_naive_utc(check_result.expiration_date)
domain.last_checked = datetime.utcnow()
# Create check record
@ -342,7 +352,7 @@ async def refresh_all_domains(
domain.status = check_result.status
domain.is_available = check_result.is_available
domain.registrar = check_result.registrar
domain.expiration_date = check_result.expiration_date
domain.expiration_date = _to_naive_utc(check_result.expiration_date)
domain.last_checked = datetime.utcnow()
# Create check record

View File

@ -147,7 +147,16 @@ const healthConfig: Record<HealthStatus, { label: string; color: string; bg: str
export default function WatchlistPage() {
const { domains, addDomain, deleteDomain, refreshDomain, updateDomain, subscription, user, logout, checkAuth } = useStore()
const { toast, showToast, hideToast } = useToast()
const openAnalyze = useAnalyzePanelStore((s) => s.open)
const openAnalyzePanel = useAnalyzePanelStore((s) => s.open)
// Wrapper to open analyze panel with domain status
const openAnalyze = useCallback((domainData: { name: string; is_available: boolean; expiration_date: string | null }) => {
openAnalyzePanel(domainData.name, {
status: domainData.is_available ? 'available' : 'taken',
deletion_date: domainData.expiration_date,
is_drop: false,
})
}, [openAnalyzePanel])
// Modal state
const [showAddModal, setShowAddModal] = useState(false)
@ -608,7 +617,7 @@ export default function WatchlistPage() {
<div className="flex items-start justify-between gap-4 mb-4">
<div className="min-w-0">
<button
onClick={() => openAnalyze(domain.name)}
onClick={() => openAnalyze(domain)}
className="text-lg font-bold text-white font-mono truncate block text-left hover:text-accent transition-colors"
>
{domain.name}
@ -667,7 +676,7 @@ export default function WatchlistPage() {
)}
<button
onClick={() => openAnalyze(domain.name)}
onClick={() => openAnalyze(domain)}
className="w-14 h-12 border border-white/10 text-white/50 flex items-center justify-center hover:text-accent hover:border-accent/30 hover:bg-accent/5 transition-all"
>
<Shield className="w-5 h-5" />
@ -695,7 +704,7 @@ export default function WatchlistPage() {
{/* Domain */}
<div className="flex items-center gap-3 min-w-0">
<button
onClick={() => openAnalyze(domain.name)}
onClick={() => openAnalyze(domain)}
className="text-sm font-bold text-white font-mono truncate group-hover:text-accent transition-colors text-left"
title="Analyze"
>
@ -792,7 +801,7 @@ export default function WatchlistPage() {
<RefreshCw className={clsx("w-4 h-4", refreshingId === domain.id && "animate-spin")} />
</button>
<button
onClick={() => openAnalyze(domain.name)}
onClick={() => openAnalyze(domain)}
title="Analyze"
className="w-10 h-10 flex items-center justify-center text-white/40 hover:text-accent border border-white/10 hover:bg-accent/10 hover:border-accent/20 transition-all"
>