+ {/* Top Row */}
+
-
- {/* Right: Stats */}
-
+
-
+
+ Watchlist
+
+
+ {stats.total} domains
+ {stats.available} available
+
- Watchlist - {stats.total} -
-
-
-
+
-
- {stats.available}
- Available
-
-
- {stats.expiring}
- Expiring
+ {/* Stats Grid */}
+
+
+
+ {stats.total}
+ Tracked
+
+
+ {stats.available}
+ Available
+
+
{stats.expiring}
+ Expiring
+
- {[
- { value: 'all', label: 'All', count: stats.total },
- { value: 'available', label: 'Available', count: stats.available },
- { value: 'expiring', label: 'Expiring', count: stats.expiring },
- ].map((item) => (
-
- ))}
-
-
-
-
+ {/* ═══════════════════════════════════════════════════════════════════════ */}
+ {/* ADD DOMAIN */}
+ {/* ═══════════════════════════════════════════════════════════════════════ */}
+
+
+
+
+ {/* ═══════════════════════════════════════════════════════════════════════ */}
+ {/* FILTERS */}
+ {/* ═══════════════════════════════════════════════════════════════════════ */}
+
+
+ {[
+ { value: 'all', label: 'All', count: stats.total },
+ { value: 'available', label: 'Available', count: stats.available },
+ { value: 'expiring', label: 'Expiring', count: stats.expiring },
+ ].map((item) => (
+
+ ))}
- ) : (
-
- {/* Table Header */}
-
+
-
-
- {/* Rows */}
- {filteredDomains.map((domain) => {
- const health = healthReports[domain.id]
- const healthStatus = health?.status || 'unknown'
- const config = healthConfig[healthStatus]
- const days = getDaysUntilExpiry(domain.expiration_date)
+
+
+ {/* ═══════════════════════════════════════════════════════════════════════ */}
+ {/* DESKTOP HEADER */}
+ {/* ═══════════════════════════════════════════════════════════════════════ */}
+ Domain
- Status
- Health
- Expires
- Alert
- Actions
-
+
+
+
+ Domain Surveillance
+
- return (
-
- {/* Mobile */}
-
-
+ {!filteredDomains.length ? (
+
-
+
+
+ {/* ═══════════════════════════════════════════════════════════════════════ */}
+ {/* DOMAIN LIST */}
+ {/* ═══════════════════════════════════════════════════════════════════════ */}
+
-
- {domain.name}
+
+
+ + Watchlist + {stats.total} +
+
+
+
+
+ {stats.available}
+ Available
+
+
+ {stats.expiring}
+ Expiring
+
+
+
+ ) : (
+ No domains in your watchlist
+Add a domain above to start monitoring
+
+ {filteredDomains.map((domain) => {
+ const health = healthReports[domain.id]
+ const healthStatus = health?.status || 'unknown'
+ const config = healthConfig[healthStatus]
+ const days = getDaysUntilExpiry(domain.expiration_date)
+
+ return (
+
+ {/* Mobile Row */}
+
-
- {/* Desktop */}
-
+
-
-
+
-
- {domain.is_available ? 'Available' : 'Taken'}
-
-
+
+
+
+ {domain.is_available ? (
+
+ ) : (
+
+ )}
+
+
+
+ {domain.name}
+
+ {domain.registrar || 'Unknown registrar'}
+
+
+
+ {domain.is_available ? 'AVAIL' : 'TAKEN'}
+
+
+
- {formatExpiryDate(domain.expiration_date)}
+
+ {/* Actions */}
+
+ {/* Desktop Row */}
+
-
+
+ { setSelectedDomain(domain.id); handleHealthCheck(domain.id) }}
+ className="w-24 flex items-center gap-1.5 hover:opacity-80 transition-opacity shrink-0"
+ >
+ {loadingHealth[domain.id] ? (
+
+ ) : (
+ <>
+
+ {config.label}
+ >
+ )}
+
+
+ {/* Expires */}
+ handleToggleNotify(domain.id, domain.notify_on_available)}
+ disabled={togglingNotifyId === domain.id}
+ className={clsx(
+ "w-8 h-8 flex items-center justify-center border transition-colors shrink-0",
+ domain.notify_on_available
+ ? "text-accent border-accent/20 bg-accent/10"
+ : "text-white/20 border-white/10 hover:text-white/40"
+ )}
+ >
+ {togglingNotifyId === domain.id ? (
+
+ ) : domain.notify_on_available ? (
+
+ ) : (
+
+ )}
+
+
+ {/* Actions */}
+
+
+
+
+
+ {/* Status */}
+
+ {domain.is_available ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ {domain.name}
+
+ {domain.registrar || 'Unknown'}
+
+
+
+ {domain.is_available ? 'AVAIL' : 'TAKEN'}
+
+
+
+ {/* Health */}
+
+ {days !== null && days <= 30 && days > 0 ? (
+ {days}d
+ ) : (
+ formatExpiryDate(domain.expiration_date)
+ )}
+
+
+ {/* Alert */}
+
+ handleRefresh(domain.id)}
+ disabled={refreshingId === domain.id}
+ className="w-7 h-7 flex items-center justify-center text-white/20 hover:text-white border border-white/10 hover:bg-white/5 transition-all"
+ >
+
+
+ handleDelete(domain.id, domain.name)}
+ disabled={deletingId === domain.id}
+ className="w-7 h-7 flex items-center justify-center text-white/20 hover:text-rose-400 border border-white/10 hover:border-rose-400/20 hover:bg-rose-500/10 transition-all"
+ >
+ {deletingId === domain.id ? (
+
+ ) : (
+
+ )}
- {/* Domain */}
- { setSelectedDomain(domain.id); handleHealthCheck(domain.id) }}
- className="flex items-center gap-1.5 hover:opacity-80 transition-opacity"
- >
- {loadingHealth[domain.id] ? (
-
- ) : (
- <>
-
- {config.label}
- >
- )}
-
-
- {/* Expires */}
- handleToggleNotify(domain.id, domain.notify_on_available)}
- disabled={togglingNotifyId === domain.id}
- className={clsx(
- "w-6 h-6 flex items-center justify-center transition-colors",
- domain.notify_on_available ? "text-accent" : "text-white/20 hover:text-white/40"
- )}
- >
- {togglingNotifyId === domain.id ? (
-
- ) : domain.notify_on_available ? (
-
- ) : (
-
- )}
-
-
- {/* Actions */}
-
+ )}
+
+
+ {/* ═══════════════════════════════════════════════════════════════════════ */}
+ {/* MOBILE BOTTOM NAV */}
+ {/* ═══════════════════════════════════════════════════════════════════════ */}
+
+
+ {/* ═══════════════════════════════════════════════════════════════════════ */}
+ {/* MOBILE DRAWER */}
+ {/* ═══════════════════════════════════════════════════════════════════════ */}
+ {menuOpen && (
+
-
- {domain.name}
-
-
-
-
-
- {/* Status */}
-
-
- {domain.is_available ? 'Available' : 'Taken'}
-
-
-
- {/* Health */}
-
- {days !== null && days <= 30 && days > 0 ? (
- {days} days
- ) : (
- formatExpiryDate(domain.expiration_date)
- )}
-
-
- {/* Alert */}
-
- handleRefresh(domain.id)}
- disabled={refreshingId === domain.id}
- className="w-7 h-7 flex items-center justify-center text-white/20 hover:text-white hover:bg-white/5 transition-all"
- >
-
-
- handleDelete(domain.id, domain.name)}
- disabled={deletingId === domain.id}
- className="w-7 h-7 flex items-center justify-center text-white/20 hover:text-rose-400 hover:bg-rose-500/10 transition-all"
- >
- {deletingId === domain.id ? (
-
- ) : (
-
- )}
-
-
+ )
+ })}
+
+
setMenuOpen(false)}
+ />
+
+
)}
-
- {/* ═══════════════════════════════════════════════════════════════════════ */}
- {/* HEALTH MODAL */}
- {/* ═══════════════════════════════════════════════════════════════════════ */}
- {selectedDomainData && (
-
+
+
+ setMenuOpen(false)}
+ className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/60 hover:text-white active:bg-white/5 transition-all"
+ >
+
+
+
+
+
+
+
- )
- })}
+
+
POUNCE
+Terminal v1.0
+ {drawerNavSections.map((section) => (
+
+
+
+
+ ))}
+
+
+
+ {section.title}
+
+
+ {section.items.map((item: any) => (
+ setMenuOpen(false)}
+ className="flex items-center gap-3 px-4 py-2.5 text-white/60 active:text-white active:bg-white/[0.03] transition-colors border-l-2 border-transparent active:border-accent"
+ >
+
+ {item.label}
+ {item.isNew && (
+ NEW
+ )}
+
+ ))}
+
+
+ setMenuOpen(false)}
+ className="flex items-center gap-3 py-2.5 text-white/50 active:text-white transition-colors"
+ >
+
+ Settings
+
+
+ {user?.is_admin && (
+ setMenuOpen(false)}
+ className="flex items-center gap-3 py-2.5 text-amber-500/70 active:text-amber-400 transition-colors"
+ >
+
+ Admin
+
+ )}
+
+
+
+ Upgrade
+
+ )}
+
+ { logout(); setMenuOpen(false) }}
+ className="flex items-center justify-center gap-2 w-full py-2 border border-white/10 text-white/40 text-[10px] font-mono uppercase tracking-wider active:bg-white/5 transition-all"
+ >
+
+ Sign out
+
+
+
+
+
+ {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 tracking-wider active:scale-[0.98] transition-all mb-2"
+ >
+
+
+
+
+
+ + {user?.name || user?.email?.split('@')[0] || 'User'} +
+{tierName}
+ setSelectedDomain(null)}
- >
+ {/* ═══════════════════════════════════════════════════════════════════════ */}
+ {/* HEALTH MODAL */}
+ {/* ═══════════════════════════════════════════════════════════════════════ */}
+ {selectedDomainData && (
e.stopPropagation()}
+ className="fixed inset-0 z-[110] flex items-center justify-center p-4 bg-black/80"
+ onClick={() => setSelectedDomain(null)}
>
- {/* Header */}
-
- setSelectedDomain(null)} className="text-white/30 hover:text-white p-1">
-
-
-
-
- {/* Content */}
-
-
- Health Report
-
-
- {/* Domain */}
-
-
{selectedDomainData.name}
-
-
- {healthConfig[selectedHealth?.status || 'unknown'].label}
-
- {selectedHealth?.score !== undefined && (
- Score: {selectedHealth.score}/100
- )}
+
e.stopPropagation()}
+ >
+ {/* Header */}
+
+ setSelectedDomain(null)} className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/40 hover:text-white">
+
+
- {/* Checks */}
- {selectedHealth ? (
-
+
+ Health Report
+
- {/* DNS */}
- }
+
)
-}
\ No newline at end of file
+}
- DNS Resolution
- {selectedHealth.dns?.has_a || selectedHealth.dns?.has_ns ? (
-
- )}
-
+ )}
+
+
+ {toast &&
-
- OK
-
- ) : selectedHealth.dns?.error ? (
-
-
- Error
-
- ) : (
-
-
- Failed
-
+ {/* Content */}
+
+ {/* Domain */}
+
-
+
{selectedDomainData.name}
+
+
+ {healthConfig[selectedHealth?.status || 'unknown'].label}
+
+ {selectedHealth?.score !== undefined && (
+ Score: {selectedHealth.score}/100
)}
-
- {/* HTTP */}
-
-
- Run Health Check
- >
+ handleHealthCheck(selectedDomainData.id)}
+ disabled={loadingHealth[selectedDomainData.id]}
+ className="w-full py-3 bg-accent text-black text-xs font-bold uppercase tracking-wider hover:bg-white transition-colors flex items-center justify-center gap-2"
+ >
+ {loadingHealth[selectedDomainData.id] ? (
+
+ ) : (
+ <>
+
+ Run Check
+ >
+ )}
+
+
- HTTP Reachable
- {selectedHealth.http?.error && (
-
+
+ {/* Checks */}
+ {selectedHealth ? (
+ {selectedHealth.http.error}
+
+ {/* DNS */}
+
-
- {/* SSL */}
-
+ DNS
+ {selectedHealth.dns?.has_a || selectedHealth.dns?.has_ns ? (
+
- {selectedHealth.http?.is_reachable ? (
-
+
+ OK
+
+ ) : (
+
+
+ FAIL
+
)}
-
- OK
-
- ) : selectedHealth.http?.error === 'timeout' ? (
-
-
- Timeout
-
- ) : (
-
-
- Failed
-
- )}
-
- handleHealthCheck(selectedDomainData.id)}
- disabled={loadingHealth[selectedDomainData.id]}
- className="w-full py-3 bg-accent text-black text-sm font-semibold hover:bg-white transition-colors flex items-center justify-center gap-2"
- >
- {loadingHealth[selectedDomainData.id] ? (
-
+
+ {/* Parked */}
+
) : (
- <>
-
- SSL Certificate
- {selectedHealth.ssl?.error && (
-
-
- {/* Parked */}
- {selectedHealth.ssl.error}
+ + {/* HTTP */} +
+ HTTP
+ {selectedHealth.http?.is_reachable ? (
+
- {selectedHealth.ssl?.has_certificate ? (
-
+
+ OK
+
+ ) : (
+
+
+ {selectedHealth.http?.error || 'FAIL'}
+
)}
-
- Valid
-
- ) : selectedHealth.ssl?.error ? (
-
-
- Error
-
- ) : (
-
-
- Missing
-
- )}
-
- Not Parked
- {!selectedHealth.dns?.is_parked && !selectedHealth.http?.is_parked ? (
-
-
- {/* Network warning if HTTP/SSL failed with timeout */}
- {(selectedHealth.http?.error === 'timeout' || selectedHealth.ssl?.error?.includes('timeout')) && (
-
-
- OK
-
- ) : (
-
-
- Parked
-
- )}
-
-
- ) : (
- - ⚠️ Network issue: Server could not reach this domain. This may be a firewall or routing problem. -
+ + {/* SSL */} +
+ SSL
+ {selectedHealth.ssl?.has_certificate ? (
+
- )}
-
+
+ VALID
+
+ ) : (
+
+
+ MISSING
+
+ )}
- Click the button below to run a health check
-
- )}
-
- {/* Refresh Button */}
-
+ NOT PARKED
+ {!selectedHealth.dns?.is_parked && !selectedHealth.http?.is_parked ? (
+
+
+
+ OK
+
+ ) : (
+
+
+ PARKED
+
+ )}
+
+ Run health check to see results
+
)}
-
+
+ {/* Refresh Button */}
+