feat: Consistent domain status across all pages
Backend: - Added DROPPING_SOON status to DomainStatus enum - Added deletion_date field to Domain model - domain_checker now returns DROPPING_SOON for pending delete - Track endpoint copies status and deletion_date from drop Frontend: - Watchlist shows "TRANSITION" status for dropping_soon domains - AnalyzePanel shows consistent status from Watchlist - Status display unified between Drops, Watchlist, and Panel
This commit is contained in:
@ -326,3 +326,5 @@ Empfehlungen:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -284,12 +284,22 @@ async def api_track_drop(
|
||||
}
|
||||
|
||||
try:
|
||||
# Map drop status to Domain status
|
||||
status_map = {
|
||||
'available': DomainStatus.AVAILABLE,
|
||||
'dropping_soon': DomainStatus.DROPPING_SOON,
|
||||
'taken': DomainStatus.TAKEN,
|
||||
'unknown': DomainStatus.UNKNOWN,
|
||||
}
|
||||
domain_status = status_map.get(drop.availability_status, DomainStatus.UNKNOWN)
|
||||
|
||||
# Add to watchlist with notification enabled
|
||||
domain = Domain(
|
||||
user_id=current_user.id,
|
||||
name=full_domain,
|
||||
status=DomainStatus.AVAILABLE if drop.availability_status == 'available' else DomainStatus.UNKNOWN,
|
||||
status=domain_status,
|
||||
is_available=drop.availability_status == 'available',
|
||||
deletion_date=drop.deletion_date, # Copy deletion date for countdown
|
||||
notify_on_available=True, # Enable notification!
|
||||
)
|
||||
db.add(domain)
|
||||
|
||||
@ -11,6 +11,7 @@ class DomainStatus(str, Enum):
|
||||
"""Domain availability status."""
|
||||
AVAILABLE = "available"
|
||||
TAKEN = "taken"
|
||||
DROPPING_SOON = "dropping_soon" # In transition/pending delete
|
||||
ERROR = "error"
|
||||
UNKNOWN = "unknown"
|
||||
|
||||
@ -32,6 +33,7 @@ class Domain(Base):
|
||||
# WHOIS data (optional)
|
||||
registrar: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
||||
expiration_date: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
deletion_date: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) # When domain will be fully deleted
|
||||
|
||||
# User relationship
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False)
|
||||
|
||||
@ -197,11 +197,11 @@ class DomainChecker:
|
||||
)
|
||||
|
||||
if is_pending_delete:
|
||||
logger.info(f"{domain} is pending delete (status: {domain_status})")
|
||||
logger.info(f"{domain} is in transition/pending delete (status: {domain_status})")
|
||||
return DomainCheckResult(
|
||||
domain=domain,
|
||||
status=DomainStatus.AVAILABLE,
|
||||
is_available=True,
|
||||
status=DomainStatus.DROPPING_SOON, # In transition, not yet available
|
||||
is_available=False, # Not yet registrable
|
||||
check_method="rdap_custom",
|
||||
raw_data={"rdap_status": domain_status, "note": "pending_delete"},
|
||||
)
|
||||
|
||||
@ -150,10 +150,18 @@ export default function WatchlistPage() {
|
||||
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 }) => {
|
||||
const openAnalyze = useCallback((domainData: { name: string; status: string; is_available: boolean; expiration_date: string | null; deletion_date?: string | null }) => {
|
||||
// Map domain status to drop status format
|
||||
const statusMap: Record<string, 'available' | 'dropping_soon' | 'taken' | 'unknown'> = {
|
||||
'available': 'available',
|
||||
'dropping_soon': 'dropping_soon',
|
||||
'taken': 'taken',
|
||||
'error': 'unknown',
|
||||
'unknown': 'unknown',
|
||||
}
|
||||
openAnalyzePanel(domainData.name, {
|
||||
status: domainData.is_available ? 'available' : 'taken',
|
||||
deletion_date: domainData.expiration_date,
|
||||
status: statusMap[domainData.status] || (domainData.is_available ? 'available' : 'taken'),
|
||||
deletion_date: domainData.deletion_date || domainData.expiration_date,
|
||||
is_drop: false,
|
||||
})
|
||||
}, [openAnalyzePanel])
|
||||
@ -607,6 +615,16 @@ export default function WatchlistPage() {
|
||||
const config = healthConfig[healthStatus]
|
||||
const days = getDaysUntilExpiry(domain.expiration_date)
|
||||
|
||||
// Domain status display config (consistent with DropsTab)
|
||||
const domainStatus = domain.status || (domain.is_available ? 'available' : 'taken')
|
||||
const statusConfig = {
|
||||
available: { label: 'AVAIL', color: 'text-accent', bg: 'bg-accent/5 border-accent/20' },
|
||||
dropping_soon: { label: 'TRANSITION', color: 'text-amber-400', bg: 'bg-amber-400/5 border-amber-400/20' },
|
||||
taken: { label: 'TAKEN', color: 'text-white/40', bg: 'bg-white/5 border-white/10' },
|
||||
error: { label: 'ERROR', color: 'text-rose-400', bg: 'bg-rose-400/5 border-rose-400/20' },
|
||||
unknown: { label: 'CHECK', color: 'text-white/30', bg: 'bg-white/5 border-white/5' },
|
||||
}[domainStatus] || { label: 'UNKNOWN', color: 'text-white/30', bg: 'bg-white/5 border-white/5' }
|
||||
|
||||
return (
|
||||
<div
|
||||
key={domain.id}
|
||||
@ -633,11 +651,9 @@ export default function WatchlistPage() {
|
||||
<div className="text-right shrink-0">
|
||||
<div className={clsx(
|
||||
"text-[10px] font-mono px-2 py-0.5 mt-1 inline-block border",
|
||||
domain.is_available
|
||||
? "text-accent bg-accent/5 border-accent/20"
|
||||
: "text-white/30 bg-white/5 border-white/5"
|
||||
statusConfig.color, statusConfig.bg
|
||||
)}>
|
||||
{domain.is_available ? 'AVAIL' : 'TAKEN'}
|
||||
{statusConfig.label}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -719,11 +735,9 @@ export default function WatchlistPage() {
|
||||
<div className="flex justify-center">
|
||||
<span className={clsx(
|
||||
"text-[10px] font-mono font-bold uppercase px-2.5 py-1.5 border",
|
||||
domain.is_available
|
||||
? "text-accent bg-accent/10 border-accent/30"
|
||||
: "text-white/40 bg-white/5 border-white/10"
|
||||
statusConfig.color, statusConfig.bg
|
||||
)}>
|
||||
{domain.is_available ? 'AVAIL' : 'TAKEN'}
|
||||
{statusConfig.label}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user