-
- Monitor external domains you care about and manage your own portfolio in one place.
-
+
+ {/* Main Tab Switcher (Watching | My Portfolio) */}
+
+
+
+
- {/* View Tabs: Watching vs My Portfolio */}
-
-
-
- Watching
-
-
-
- My Portfolio
-
-
-
- {/* Quick Stats Pills */}
-
- {stats.available > 0 && (
-
-
- {stats.available} Available!
-
- )}
-
-
- Auto-Monitoring
+ {/* Quick Stats Pills */}
+
+ {mainTab === 'watching' && stats.available > 0 && (
+
+
+ {stats.available} Available!
+ )}
+
+
+ {mainTab === 'watching' ? 'Auto-Monitoring' : 'Verified Domains'}
- {/* Metric Grid */}
-
- 0}
- trend={stats.available > 0 ? 'up' : 'active'}
- />
- 0 ? 'up' : 'neutral'}
- />
- 0 ? 'down' : 'neutral'}
- />
- 0 ? 'down' : 'neutral'}
- />
-
+ {/* ══════════════════════════════════════════════════════════════════ */}
+ {/* WATCHING TAB CONTENT */}
+ {/* ══════════════════════════════════════════════════════════════════ */}
+ {mainTab === 'watching' && (
+ <>
+ {/* Metric Grid */}
+
+ 0}
+ trend={stats.available > 0 ? 'up' : 'active'}
+ />
+ 0 ? 'up' : 'neutral'}
+ />
+ 0 ? 'down' : 'neutral'}
+ />
+ 0 ? 'down' : 'neutral'}
+ />
+
{/* Control Bar */}
@@ -772,6 +908,383 @@ export default function WatchlistPage() {
)}
+ >
+ )}
+
+ {/* ══════════════════════════════════════════════════════════════════ */}
+ {/* MY PORTFOLIO TAB CONTENT */}
+ {/* ══════════════════════════════════════════════════════════════════ */}
+ {mainTab === 'portfolio' && (
+ <>
+ {/* Portfolio Metric Grid - uses same data as Watching */}
+
+
+ h.status === 'healthy').length}
+ subValue="Healthy"
+ icon={CheckCircle2}
+ trend="up"
+ />
+ h.status === 'critical' || h.status === 'weakening').length}
+ subValue="Need attention"
+ icon={AlertTriangle}
+ trend={Object.values(healthReports).filter(h => h.status === 'critical' || h.status === 'weakening').length > 0 ? 'down' : 'neutral'}
+ />
+ {
+ const days = getDaysUntilExpiry(d.expiration_date)
+ return days !== null && days <= 30 && days > 0
+ }).length}
+ subValue="< 30 days"
+ icon={Calendar}
+ trend={portfolioDomains.filter(d => {
+ const days = getDaysUntilExpiry(d.expiration_date)
+ return days !== null && days <= 30 && days > 0
+ }).length > 0 ? 'down' : 'neutral'}
+ />
+
+
+ {/* Control Bar - Add Domain */}
+
+
+
+ Add domains you own to track expiry & health
+
+
+ {/* Add Domain Input */}
+
+
+
+ {/* Portfolio Data Grid - uses same domains/health as Watching */}
+
+ {portfolioDomains.length === 0 ? (
+
+
+
+
+
No domains in portfolio
+
+ Add domains you own to track renewals, health status, and changes.
+
+
+
+ ) : (
+ <>
+ {/* Desktop Table - IDENTICAL to Watching tab */}
+
+
+ {/* Table Header */}
+
+
Domain
+
Health
+
Expiry
+
Last Update
+
Alerts
+
Actions
+
+
+ {/* Table Rows - uses same data/logic as Watching */}
+
+ {portfolioDomains.map((domain) => {
+ const expiryDays = getDaysUntilExpiry(domain.expiration_date)
+ const isExpiringSoon = expiryDays !== null && expiryDays <= 30 && expiryDays > 0
+ const health = healthReports[domain.id]
+ const healthConfig = health ? healthStatusConfig[health.status] : null
+
+ return (
+
+ {/* Domain */}
+
+
+
+
+
+
+
{domain.name}
+
+ {domain.registrar || 'Unknown registrar'} • Added {getTimeAgo(domain.created_at)}
+
+
+
+
+
+ {/* Health - uses SAME healthReports as Watching */}
+
+
+
+
+
+
+ {/* Expiry - uses expiration_date like Watching */}
+
+ {domain.expiration_date ? (
+
+
+
+ {expiryDays !== null ? `${expiryDays}d` : formatExpiryDate(domain.expiration_date)}
+
+
+ ) : (
+
Unknown
+ )}
+
+
+ {/* Last Update */}
+
+
+ {domain.last_checked ? getTimeAgo(domain.last_checked) : 'Never'}
+
+
+
+ {/* Alerts - uses SAME handleToggleNotify as Watching */}
+
+
+
+
+
+
+ {/* Actions - uses SAME handleRefresh/handleDelete as Watching */}
+
+
+
+
+
+
+
+
+ Sell
+
+
+
+ )
+ })}
+
+
+
+
+ {/* Mobile Cards - IDENTICAL logic to Watching */}
+
+ {portfolioDomains.map((domain) => {
+ const expiryDays = getDaysUntilExpiry(domain.expiration_date)
+ const isExpiringSoon = expiryDays !== null && expiryDays <= 30 && expiryDays > 0
+ const health = healthReports[domain.id]
+ const healthConfig = health ? healthStatusConfig[health.status] : null
+
+ return (
+
+ {/* Header */}
+
+
+
+
+
+
+
{domain.name}
+
{domain.registrar || 'Unknown registrar'}
+
+
+
+
+ {/* Info Grid - uses same data as Watching */}
+
+
+
Health
+
+
+
+
Expiry
+
+ {expiryDays !== null ? `${expiryDays}d` : '—'}
+
+
+
+
Checked
+
+ {domain.last_checked ? getTimeAgo(domain.last_checked) : '—'}
+
+
+
+
+ {/* Actions - uses SAME functions as Watching */}
+
+
+
+
+
+
+
+ Sell
+
+
+
+ )
+ })}
+
+ >
+ )}
+
+
+ {/* Portfolio Footer */}
+
+
+
+ Same monitoring as Watching tab
+
+
+
+ Get alerts for changes
+
+
+ >
+ )}
{/* Health Report Modal */}
diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx
index 497ec18..fad9ab3 100755
--- a/frontend/src/components/Sidebar.tsx
+++ b/frontend/src/components/Sidebar.tsx
@@ -21,7 +21,6 @@ import {
X,
Sparkles,
Tag,
- Briefcase,
} from 'lucide-react'
import { useState, useEffect } from 'react'
import clsx from 'clsx'
diff --git a/frontend/src/components/TerminalLayout.tsx b/frontend/src/components/TerminalLayout.tsx
index 26e9027..b5a7b2d 100755
--- a/frontend/src/components/TerminalLayout.tsx
+++ b/frontend/src/components/TerminalLayout.tsx
@@ -52,7 +52,7 @@ export function TerminalLayout({
useEffect(() => {
if (!authCheckedRef.current) {
authCheckedRef.current = true
- checkAuth()
+ checkAuth()
}
}, [checkAuth])
@@ -131,104 +131,104 @@ export function TerminalLayout({
{!hideHeaderSearch && (
<>
- {/* Quick Search */}
-
+ {/* Quick Search */}
+
- {/* Mobile Search */}
-
+ {/* Mobile Search */}
+
- {/* Notifications */}
-
-
+ {/* Notifications */}
+
+
- {/* Notifications Dropdown */}
- {notificationsOpen && (
+ {/* Notifications Dropdown */}
+ {notificationsOpen && (
Notifications
-
-
- {availableDomains.length > 0 ? (
-
- {availableDomains.slice(0, 5).map((domain) => (
- setNotificationsOpen(false)}
+ >
+
+
+
+
+ {availableDomains.length > 0 ? (
+
+ {availableDomains.slice(0, 5).map((domain) => (
+
setNotificationsOpen(false)}
className="flex items-start gap-3 p-3 hover:bg-white/5 rounded-lg transition-colors"
- >
+ >
-
-
+
+
{domain.name}
Available now!
-
-
- ))}
-
- ) : (
-
+
+
+ ))}
+
+ ) : (
+
No notifications
- We'll notify you when domains become available
-
-
- )}
+ We'll notify you when domains become available
+
-
- )}
+ )}
+
+ )}
+
- {/* Keyboard Shortcuts Hint */}
-
{}}
- className="hidden sm:flex items-center gap-1.5 px-2 py-1.5 text-xs text-foreground-subtle hover:text-foreground
- bg-foreground/5 rounded-lg border border-border/40 hover:border-border/60 transition-all"
- title="Keyboard shortcuts (?)"
- >
-
- ?
-
+ {/* Keyboard Shortcuts Hint */}
+
{}}
+ className="hidden sm:flex items-center gap-1.5 px-2 py-1.5 text-xs text-foreground-subtle hover:text-foreground
+ bg-foreground/5 rounded-lg border border-border/40 hover:border-border/60 transition-all"
+ title="Keyboard shortcuts (?)"
+ >
+
+ ?
+
>
)}