fix: TypeScript error in Portfolio health reports
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled

This commit is contained in:
2025-12-14 09:16:09 +01:00
parent 909cf21d6e
commit e027e51288

View File

@ -169,18 +169,18 @@ export default function PortfolioPage() {
api.checkDomain(domain.domain) api.checkDomain(domain.domain)
.then(() => { .then(() => {
// Simulate health report - in production this would come from backend // Simulate health report - in production this would come from backend
setHealthReports(prev => ({ const simulatedReport: DomainHealthReport = {
...prev, domain: domain.domain,
[domain.id]: { checked_at: new Date().toISOString(),
domain_id: domain.id, score: Math.floor(Math.random() * 40) + 60, // Simulated score 60-100
checked_at: new Date().toISOString(), status: 'healthy' as HealthStatus,
score: Math.floor(Math.random() * 40) + 60, // Simulated score 60-100 signals: [],
status: 'healthy' as HealthStatus, recommendations: [],
dns: { has_a: true, has_ns: true, is_parked: false }, dns: { has_a: true, has_ns: true, has_mx: false, nameservers: [], is_parked: false },
http: { is_reachable: true, status_code: 200, is_parked: false }, http: { is_reachable: true, status_code: 200, is_parked: false },
ssl: { has_certificate: true }, ssl: { has_certificate: true },
} as DomainHealthReport }
})) setHealthReports(prev => ({ ...prev, [domain.id]: simulatedReport }))
}) })
.catch(() => {}) .catch(() => {})
.finally(() => { .finally(() => {
@ -195,18 +195,18 @@ export default function PortfolioPage() {
try { try {
await api.checkDomain(domainName) await api.checkDomain(domainName)
// Simulated - in production, this would return real health data // Simulated - in production, this would return real health data
setHealthReports(prev => ({ const simulatedReport: DomainHealthReport = {
...prev, domain: domainName,
[domainId]: { checked_at: new Date().toISOString(),
domain_id: domainId, score: Math.floor(Math.random() * 40) + 60,
checked_at: new Date().toISOString(), status: 'healthy' as HealthStatus,
score: Math.floor(Math.random() * 40) + 60, signals: [],
status: 'healthy' as HealthStatus, recommendations: [],
dns: { has_a: true, has_ns: true, is_parked: false }, dns: { has_a: true, has_ns: true, has_mx: false, nameservers: [], is_parked: false },
http: { is_reachable: true, status_code: 200, is_parked: false }, http: { is_reachable: true, status_code: 200, is_parked: false },
ssl: { has_certificate: true }, ssl: { has_certificate: true },
} as DomainHealthReport }
})) setHealthReports(prev => ({ ...prev, [domainId]: simulatedReport }))
showToast('Health check complete', 'success') showToast('Health check complete', 'success')
} catch { } catch {
showToast('Health check failed', 'error') showToast('Health check failed', 'error')
@ -388,14 +388,14 @@ export default function PortfolioPage() {
<div className="flex items-center gap-2 text-[10px] font-mono text-white/40"> <div className="flex items-center gap-2 text-[10px] font-mono text-white/40">
<span>{stats.total} domains</span> <span>{stats.total} domains</span>
</div> </div>
</div> </div>
{/* Stats Grid - Extended with Health */} {/* Stats Grid - Extended with Health */}
<div className="grid grid-cols-5 gap-1.5"> <div className="grid grid-cols-5 gap-1.5">
<div className="bg-white/[0.02] border border-white/[0.08] p-2"> <div className="bg-white/[0.02] border border-white/[0.08] p-2">
<div className="text-base font-bold text-white tabular-nums">{stats.active}</div> <div className="text-base font-bold text-white tabular-nums">{stats.active}</div>
<div className="text-[8px] font-mono text-white/30 uppercase tracking-wider">Active</div> <div className="text-[8px] font-mono text-white/30 uppercase tracking-wider">Active</div>
</div> </div>
<div className="bg-accent/[0.05] border border-accent/20 p-2"> <div className="bg-accent/[0.05] border border-accent/20 p-2">
<div className="text-base font-bold text-accent tabular-nums">{formatCurrency(summary?.total_value || 0).replace('$', '').slice(0, 6)}</div> <div className="text-base font-bold text-accent tabular-nums">{formatCurrency(summary?.total_value || 0).replace('$', '').slice(0, 6)}</div>
<div className="text-[8px] font-mono text-accent/60 uppercase tracking-wider">Value</div> <div className="text-[8px] font-mono text-accent/60 uppercase tracking-wider">Value</div>
@ -485,7 +485,7 @@ export default function PortfolioPage() {
{item.label} ({item.count}) {item.label} ({item.count})
</button> </button>
))} ))}
</div> </div>
{/* Add Domain Button - RIGHT */} {/* Add Domain Button - RIGHT */}
<button <button
@ -602,14 +602,14 @@ export default function PortfolioPage() {
<Clock className="w-3 h-3 text-white/30" /> <Clock className="w-3 h-3 text-white/30" />
<span className={isRenewingSoon ? "text-orange-400 font-bold" : "text-white/40"}> <span className={isRenewingSoon ? "text-orange-400 font-bold" : "text-white/40"}>
{isRenewingSoon ? `${daysUntilRenewal}d` : formatDate(domain.renewal_date)} {isRenewingSoon ? `${daysUntilRenewal}d` : formatDate(domain.renewal_date)}
</span> </span>
</div> </div>
)} )}
</div> </div>
{/* Alert Toggles - Mobile */} {/* Alert Toggles - Mobile */}
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<button <button
onClick={() => handleToggleEmailAlert(domain.id, false)} onClick={() => handleToggleEmailAlert(domain.id, false)}
className="w-7 h-7 flex items-center justify-center text-white/30 hover:text-accent border border-white/[0.06]" className="w-7 h-7 flex items-center justify-center text-white/30 hover:text-accent border border-white/[0.06]"
title="Email alerts" title="Email alerts"
@ -619,7 +619,7 @@ export default function PortfolioPage() {
<button <button
onClick={() => handleToggleSmsAlert(domain.id, false)} onClick={() => handleToggleSmsAlert(domain.id, false)}
disabled={!canUseSmsAlerts} disabled={!canUseSmsAlerts}
className={clsx( className={clsx(
"w-7 h-7 flex items-center justify-center border border-white/[0.06]", "w-7 h-7 flex items-center justify-center border border-white/[0.06]",
canUseSmsAlerts ? "text-white/30 hover:text-accent" : "text-white/10" canUseSmsAlerts ? "text-white/30 hover:text-accent" : "text-white/10"
)} )}
@ -659,8 +659,8 @@ export default function PortfolioPage() {
className="flex-1 py-2 bg-blue-400/10 border border-blue-400/20 text-blue-400 text-[10px] font-bold uppercase flex items-center justify-center gap-1" className="flex-1 py-2 bg-blue-400/10 border border-blue-400/20 text-blue-400 text-[10px] font-bold uppercase flex items-center justify-center gap-1"
> >
<ShieldAlert className="w-3 h-3" />Verify <ShieldAlert className="w-3 h-3" />Verify
</button> </button>
) )
)} )}
<button <button
onClick={() => setSelectedDomain(domain)} onClick={() => setSelectedDomain(domain)}
@ -718,19 +718,19 @@ export default function PortfolioPage() {
return <Loader2 className="w-4 h-4 text-white/30 animate-spin" /> return <Loader2 className="w-4 h-4 text-white/30 animate-spin" />
} }
if (!health) { if (!health) {
return ( return (
<button <button
onClick={() => handleRefreshHealth(domain.id, domain.domain)} onClick={() => handleRefreshHealth(domain.id, domain.domain)}
className="text-white/30 hover:text-white" className="text-white/30 hover:text-white"
title="Run health check" title="Run health check"
> >
<Activity className="w-4 h-4" /> <Activity className="w-4 h-4" />
</button> </button>
) )
} }
const config = healthConfig[health.status] const config = healthConfig[health.status]
return ( return (
<button <button
onClick={() => setShowHealthDetail(domain.id)} onClick={() => setShowHealthDetail(domain.id)}
className={clsx("flex items-center gap-1 px-1.5 py-0.5 text-[10px] font-mono border", config.bg, config.color)} className={clsx("flex items-center gap-1 px-1.5 py-0.5 text-[10px] font-mono border", config.bg, config.color)}
title={`Score: ${health.score}/100`} title={`Score: ${health.score}/100`}
@ -739,7 +739,7 @@ export default function PortfolioPage() {
health.status === 'critical' ? <WifiOff className="w-3 h-3" /> : health.status === 'critical' ? <WifiOff className="w-3 h-3" /> :
<AlertCircle className="w-3 h-3" />} <AlertCircle className="w-3 h-3" />}
{health.score} {health.score}
</button> </button>
) )
})() })()
) : ( ) : (
@ -782,15 +782,15 @@ export default function PortfolioPage() {
<span className="text-white/20"></span> <span className="text-white/20"></span>
) : ( ) : (
<> <>
<button <button
onClick={() => handleToggleEmailAlert(domain.id, false)} onClick={() => handleToggleEmailAlert(domain.id, false)}
disabled={togglingAlerts[domain.id]} disabled={togglingAlerts[domain.id]}
className="w-6 h-6 flex items-center justify-center text-white/30 hover:text-accent border border-transparent hover:border-accent/20 transition-all" className="w-6 h-6 flex items-center justify-center text-white/30 hover:text-accent border border-transparent hover:border-accent/20 transition-all"
title="Email alerts" title="Email alerts"
> >
<Mail className="w-3 h-3" /> <Mail className="w-3 h-3" />
</button> </button>
<button <button
onClick={() => handleToggleSmsAlert(domain.id, false)} onClick={() => handleToggleSmsAlert(domain.id, false)}
disabled={togglingAlerts[domain.id] || !canUseSmsAlerts} disabled={togglingAlerts[domain.id] || !canUseSmsAlerts}
className={clsx( className={clsx(
@ -802,7 +802,7 @@ export default function PortfolioPage() {
title={canUseSmsAlerts ? "SMS alerts" : "SMS alerts require Tycoon"} title={canUseSmsAlerts ? "SMS alerts" : "SMS alerts require Tycoon"}
> >
{canUseSmsAlerts ? <Smartphone className="w-3 h-3" /> : <Lock className="w-3 h-3" />} {canUseSmsAlerts ? <Smartphone className="w-3 h-3" /> : <Lock className="w-3 h-3" />}
</button> </button>
</> </>
)} )}
</div> </div>
@ -834,12 +834,12 @@ export default function PortfolioPage() {
{!domain.is_sold && ( {!domain.is_sold && (
domain.is_dns_verified ? ( domain.is_dns_verified ? (
canListForSale && ( canListForSale && (
<Link <Link
href={`/terminal/listing?domain=${encodeURIComponent(domain.domain)}`} href={`/terminal/listing?domain=${encodeURIComponent(domain.domain)}`}
className="h-7 px-2.5 flex items-center gap-1.5 text-amber-400 text-[10px] font-bold uppercase tracking-wide border border-amber-400/30 bg-amber-400/10 hover:bg-amber-400/20 transition-all" className="h-7 px-2.5 flex items-center gap-1.5 text-amber-400 text-[10px] font-bold uppercase tracking-wide border border-amber-400/30 bg-amber-400/10 hover:bg-amber-400/20 transition-all"
> >
<Tag className="w-3 h-3" />Sell <Tag className="w-3 h-3" />Sell
</Link> </Link>
) )
) : ( ) : (
<button <button
@ -853,14 +853,14 @@ export default function PortfolioPage() {
{/* Secondary Actions - Icon Buttons */} {/* Secondary Actions - Icon Buttons */}
<div className="flex items-center gap-0.5 ml-1"> <div className="flex items-center gap-0.5 ml-1">
<button <button
onClick={() => setSelectedDomain(domain)} onClick={() => setSelectedDomain(domain)}
title="Edit Details" title="Edit Details"
className="w-7 h-7 flex items-center justify-center text-white/30 hover:text-white border border-transparent hover:border-white/10 hover:bg-white/5 transition-all rounded-sm" className="w-7 h-7 flex items-center justify-center text-white/30 hover:text-white border border-transparent hover:border-white/10 hover:bg-white/5 transition-all rounded-sm"
> >
<Edit3 className="w-3.5 h-3.5" /> <Edit3 className="w-3.5 h-3.5" />
</button> </button>
<button <button
onClick={() => handleRefreshValue(domain.id)} onClick={() => handleRefreshValue(domain.id)}
disabled={refreshingId === domain.id} disabled={refreshingId === domain.id}
title="Refresh Valuation" title="Refresh Valuation"
@ -875,8 +875,8 @@ export default function PortfolioPage() {
className="w-7 h-7 flex items-center justify-center text-white/30 hover:text-rose-400 border border-transparent hover:border-rose-400/20 hover:bg-rose-500/10 transition-all rounded-sm disabled:opacity-30" className="w-7 h-7 flex items-center justify-center text-white/30 hover:text-rose-400 border border-transparent hover:border-rose-400/20 hover:bg-rose-500/10 transition-all rounded-sm disabled:opacity-30"
> >
{deletingId === domain.id ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Trash2 className="w-3.5 h-3.5" />} {deletingId === domain.id ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Trash2 className="w-3.5 h-3.5" />}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@ -900,7 +900,7 @@ export default function PortfolioPage() {
<button onClick={() => setMenuOpen(true)} className="flex-1 flex flex-col items-center justify-center gap-0.5 text-white/40"> <button onClick={() => setMenuOpen(true)} className="flex-1 flex flex-col items-center justify-center gap-0.5 text-white/40">
<Menu className="w-5 h-5" /><span className="text-[9px] font-mono uppercase tracking-wider">Menu</span> <Menu className="w-5 h-5" /><span className="text-[9px] font-mono uppercase tracking-wider">Menu</span>
</button> </button>
</div> </div>
</nav> </nav>
{/* MOBILE DRAWER */} {/* MOBILE DRAWER */}
@ -930,7 +930,7 @@ export default function PortfolioPage() {
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Activity className="w-4 h-4 text-accent" /> <Activity className="w-4 h-4 text-accent" />
<span className="text-xs font-mono text-accent uppercase tracking-wider">Health Report</span> <span className="text-xs font-mono text-accent uppercase tracking-wider">Health Report</span>
</div> </div>
<button onClick={() => setShowHealthDetail(null)} className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/40 hover:text-white"> <button onClick={() => setShowHealthDetail(null)} className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/40 hover:text-white">
<X className="w-4 h-4" /> <X className="w-4 h-4" />
</button> </button>
@ -943,8 +943,8 @@ export default function PortfolioPage() {
<div className={clsx("flex items-center gap-2 px-3 py-1.5 border", config.bg)}> <div className={clsx("flex items-center gap-2 px-3 py-1.5 border", config.bg)}>
<span className={clsx("text-lg font-bold font-mono", config.color)}>{health.score}</span> <span className={clsx("text-lg font-bold font-mono", config.color)}>{health.score}</span>
<span className={clsx("text-[10px] font-mono uppercase", config.color)}>{config.label}</span> <span className={clsx("text-[10px] font-mono uppercase", config.color)}>{config.label}</span>
</div> </div>
</div> </div>
{/* Health Checks */} {/* Health Checks */}
<div className="space-y-2"> <div className="space-y-2">
@ -954,7 +954,7 @@ export default function PortfolioPage() {
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Globe className="w-4 h-4 text-white/40" /> <Globe className="w-4 h-4 text-white/40" />
<span className="text-sm text-white/70">DNS Resolution</span> <span className="text-sm text-white/70">DNS Resolution</span>
</div> </div>
{health.dns?.has_a || health.dns?.has_ns ? ( {health.dns?.has_a || health.dns?.has_ns ? (
<span className="text-accent text-[10px] font-mono uppercase">OK</span> <span className="text-accent text-[10px] font-mono uppercase">OK</span>
) : ( ) : (
@ -1002,12 +1002,12 @@ export default function PortfolioPage() {
{/* Last Check */} {/* Last Check */}
<div className="flex items-center justify-between text-[10px] font-mono text-white/30"> <div className="flex items-center justify-between text-[10px] font-mono text-white/30">
<span>Last checked: {formatTimeAgo(health.checked_at)}</span> <span>Last checked: {formatTimeAgo(health.checked_at)}</span>
<button <button
onClick={() => { handleRefreshHealth(domain.id, domain.domain); setShowHealthDetail(null) }} onClick={() => { handleRefreshHealth(domain.id, domain.domain); setShowHealthDetail(null) }}
className="text-accent hover:underline" className="text-accent hover:underline"
> >
Refresh Refresh
</button> </button>
</div> </div>
</div> </div>
</div> </div>
@ -1046,7 +1046,7 @@ export default function PortfolioPage() {
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<div className="w-6 h-6 bg-accent/10 flex items-center justify-center text-accent text-xs font-bold shrink-0">1</div> <div className="w-6 h-6 bg-accent/10 flex items-center justify-center text-accent text-xs font-bold shrink-0">1</div>
<div className="text-sm text-white/70">Point your nameservers to ns.pounce.ch</div> <div className="text-sm text-white/70">Point your nameservers to ns.pounce.ch</div>
</div> </div>
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<div className="w-6 h-6 bg-accent/10 flex items-center justify-center text-accent text-xs font-bold shrink-0">2</div> <div className="w-6 h-6 bg-accent/10 flex items-center justify-center text-accent text-xs font-bold shrink-0">2</div>
<div className="text-sm text-white/70">We analyze visitor intent and route traffic</div> <div className="text-sm text-white/70">We analyze visitor intent and route traffic</div>
@ -1058,20 +1058,20 @@ export default function PortfolioPage() {
</div> </div>
<div className="pt-2"> <div className="pt-2">
<button <button
onClick={() => setShowYieldModal(null)} onClick={() => setShowYieldModal(null)}
className="w-full py-3 bg-white/5 border border-white/10 text-white/40 text-sm font-mono" className="w-full py-3 bg-white/5 border border-white/10 text-white/40 text-sm font-mono"
> >
Notify me when available Notify me when available
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
)} )}
{toast && <Toast message={toast.message} type={toast.type} onClose={hideToast} />} {toast && <Toast message={toast.message} type={toast.type} onClose={hideToast} />}
</div> </div>
) )
} }
@ -1121,18 +1121,18 @@ function AddDomainModal({ onClose, onSuccess }: { onClose: () => void; onSuccess
<form onSubmit={handleSubmit} className="p-4 space-y-4"> <form onSubmit={handleSubmit} className="p-4 space-y-4">
{error && <div className="p-2 bg-rose-500/10 border border-rose-500/20 text-rose-400 text-xs">{error}</div>} {error && <div className="p-2 bg-rose-500/10 border border-rose-500/20 text-rose-400 text-xs">{error}</div>}
<div> <div>
<label className="block text-[9px] font-mono text-white/40 uppercase mb-1.5">Domain *</label> <label className="block text-[9px] font-mono text-white/40 uppercase mb-1.5">Domain *</label>
<input type="text" value={domain} onChange={(e) => setDomain(e.target.value)} required <input type="text" value={domain} onChange={(e) => setDomain(e.target.value)} required
className="w-full px-3 py-2.5 bg-white/5 border border-white/10 text-white text-sm font-mono placeholder:text-white/20 outline-none focus:border-accent/50" placeholder="example.com" /> className="w-full px-3 py-2.5 bg-white/5 border border-white/10 text-white text-sm font-mono placeholder:text-white/20 outline-none focus:border-accent/50" placeholder="example.com" />
</div> </div>
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
<div> <div>
<label className="block text-[9px] font-mono text-white/40 uppercase mb-1.5">Purchase Price (USD)</label> <label className="block text-[9px] font-mono text-white/40 uppercase mb-1.5">Purchase Price (USD)</label>
<input type="number" value={purchasePrice} onChange={(e) => setPurchasePrice(e.target.value)} min="0" <input type="number" value={purchasePrice} onChange={(e) => setPurchasePrice(e.target.value)} min="0"
className="w-full px-3 py-2.5 bg-white/5 border border-white/10 text-white text-sm font-mono placeholder:text-white/20 outline-none focus:border-accent/50" placeholder="0" /> className="w-full px-3 py-2.5 bg-white/5 border border-white/10 text-white text-sm font-mono placeholder:text-white/20 outline-none focus:border-accent/50" placeholder="0" />
</div> </div>
<div> <div>
<label className="block text-[9px] font-mono text-white/40 uppercase mb-1.5">Purchase Date</label> <label className="block text-[9px] font-mono text-white/40 uppercase mb-1.5">Purchase Date</label>
<input type="date" value={purchaseDate} onChange={(e) => setPurchaseDate(e.target.value)} <input type="date" value={purchaseDate} onChange={(e) => setPurchaseDate(e.target.value)}
@ -1163,9 +1163,9 @@ function AddDomainModal({ onClose, onSuccess }: { onClose: () => void; onSuccess
<button type="button" onClick={onClose} className="flex-1 py-2.5 border border-white/10 text-white/60 text-xs font-mono uppercase">Cancel</button> <button type="button" onClick={onClose} className="flex-1 py-2.5 border border-white/10 text-white/60 text-xs font-mono uppercase">Cancel</button>
<button type="submit" disabled={loading || !domain.trim()} className="flex-1 flex items-center justify-center gap-2 py-2.5 bg-accent text-black text-xs font-bold uppercase disabled:opacity-50"> <button type="submit" disabled={loading || !domain.trim()} className="flex-1 flex items-center justify-center gap-2 py-2.5 bg-accent text-black text-xs font-bold uppercase disabled:opacity-50">
{loading ? <Loader2 className="w-4 h-4 animate-spin" /> : <Plus className="w-4 h-4" />}Add {loading ? <Loader2 className="w-4 h-4 animate-spin" /> : <Plus className="w-4 h-4" />}Add
</button> </button>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
) )
@ -1205,30 +1205,30 @@ function DomainDetailModal({ domain, onClose, onUpdate, canListForSale }: { doma
<div className="flex items-center justify-between p-4 border-b border-white/[0.08]"> <div className="flex items-center justify-between p-4 border-b border-white/[0.08]">
<div className="flex items-center gap-2"><BarChart3 className="w-4 h-4 text-accent" /><span className="text-xs font-mono text-accent uppercase tracking-wider">Domain Details</span></div> <div className="flex items-center gap-2"><BarChart3 className="w-4 h-4 text-accent" /><span className="text-xs font-mono text-accent uppercase tracking-wider">Domain Details</span></div>
<button onClick={onClose} className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/40"><X className="w-4 h-4" /></button> <button onClick={onClose} className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/40"><X className="w-4 h-4" /></button>
</div> </div>
<div className="p-4 space-y-4"> <div className="p-4 space-y-4">
{/* Domain Header */} {/* Domain Header */}
<div className="text-center py-4 border-b border-white/[0.08]"> <div className="text-center py-4 border-b border-white/[0.08]">
<h2 className="text-xl font-bold font-mono text-white">{domain.domain}</h2> <h2 className="text-xl font-bold font-mono text-white">{domain.domain}</h2>
<p className="text-xs font-mono text-white/40 mt-1">{domain.registrar || 'Unknown registrar'}</p> <p className="text-xs font-mono text-white/40 mt-1">{domain.registrar || 'Unknown registrar'}</p>
</div> </div>
{/* Stats Grid */} {/* Stats Grid */}
<div className="grid grid-cols-3 gap-3"> <div className="grid grid-cols-3 gap-3">
<div className="p-3 bg-white/[0.02] border border-white/[0.08] text-center"> <div className="p-3 bg-white/[0.02] border border-white/[0.08] text-center">
<div className="text-lg font-bold text-white font-mono">{formatCurrency(domain.purchase_price)}</div> <div className="text-lg font-bold text-white font-mono">{formatCurrency(domain.purchase_price)}</div>
<div className="text-[9px] font-mono text-white/30 uppercase">Purchased</div> <div className="text-[9px] font-mono text-white/30 uppercase">Purchased</div>
</div> </div>
<div className="p-3 bg-accent/[0.05] border border-accent/20 text-center"> <div className="p-3 bg-accent/[0.05] border border-accent/20 text-center">
<div className="text-lg font-bold text-accent font-mono">{formatCurrency(domain.estimated_value)}</div> <div className="text-lg font-bold text-accent font-mono">{formatCurrency(domain.estimated_value)}</div>
<div className="text-[9px] font-mono text-accent/60 uppercase">Est. Value</div> <div className="text-[9px] font-mono text-accent/60 uppercase">Est. Value</div>
</div> </div>
<div className={clsx("p-3 border text-center", (domain.roi || 0) >= 0 ? "bg-accent/[0.05] border-accent/20" : "bg-rose-500/[0.05] border-rose-500/20")}> <div className={clsx("p-3 border text-center", (domain.roi || 0) >= 0 ? "bg-accent/[0.05] border-accent/20" : "bg-rose-500/[0.05] border-rose-500/20")}>
<div className={clsx("text-lg font-bold font-mono", (domain.roi || 0) >= 0 ? "text-accent" : "text-rose-400")}>{formatROI(domain.roi)}</div> <div className={clsx("text-lg font-bold font-mono", (domain.roi || 0) >= 0 ? "text-accent" : "text-rose-400")}>{formatROI(domain.roi)}</div>
<div className="text-[9px] font-mono text-white/30 uppercase">ROI</div> <div className="text-[9px] font-mono text-white/30 uppercase">ROI</div>
</div>
</div> </div>
</div>
{/* Dates */} {/* Dates */}
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
@ -1310,13 +1310,13 @@ function SellModal({ onClose, onConfirm }: { onClose: () => void; onConfirm: (da
<label className="block text-[9px] font-mono text-white/40 uppercase mb-1.5">Sale Date</label> <label className="block text-[9px] font-mono text-white/40 uppercase mb-1.5">Sale Date</label>
<input type="date" value={saleDate} onChange={(e) => setSaleDate(e.target.value)} <input type="date" value={saleDate} onChange={(e) => setSaleDate(e.target.value)}
className="w-full px-3 py-2.5 bg-white/5 border border-white/10 text-white text-sm font-mono outline-none focus:border-accent/50" /> className="w-full px-3 py-2.5 bg-white/5 border border-white/10 text-white text-sm font-mono outline-none focus:border-accent/50" />
</div> </div>
<div> <div>
<label className="block text-[9px] font-mono text-white/40 uppercase mb-1.5">Sale Price (USD) *</label> <label className="block text-[9px] font-mono text-white/40 uppercase mb-1.5">Sale Price (USD) *</label>
<input type="number" value={salePrice} onChange={(e) => setSalePrice(e.target.value)} min="0" required <input type="number" value={salePrice} onChange={(e) => setSalePrice(e.target.value)} min="0" required
className="w-full px-3 py-2.5 bg-white/5 border border-white/10 text-white text-sm font-mono outline-none focus:border-accent/50" placeholder="0" /> className="w-full px-3 py-2.5 bg-white/5 border border-white/10 text-white text-sm font-mono outline-none focus:border-accent/50" placeholder="0" />
</div>
</div> </div>
</div>
<div className="flex gap-3"> <div className="flex gap-3">
<button onClick={onClose} className="flex-1 py-2.5 border border-white/10 text-white/60 text-xs font-mono uppercase">Cancel</button> <button onClick={onClose} className="flex-1 py-2.5 border border-white/10 text-white/60 text-xs font-mono uppercase">Cancel</button>
<button onClick={() => onConfirm(saleDate, parseFloat(salePrice) || 0)} disabled={!salePrice} className="flex-1 py-2.5 bg-accent text-black text-xs font-bold uppercase disabled:opacity-50">Confirm</button> <button onClick={() => onConfirm(saleDate, parseFloat(salePrice) || 0)} disabled={!salePrice} className="flex-1 py-2.5 bg-accent text-black text-xs font-bold uppercase disabled:opacity-50">Confirm</button>
@ -1336,12 +1336,12 @@ function MobileDrawer({ user, tierName, TierIcon, sections, onClose, onLogout }:
<div className="absolute inset-0 bg-black/80" onClick={onClose} /> <div className="absolute inset-0 bg-black/80" onClick={onClose} />
<div className="absolute top-0 right-0 bottom-0 w-[80%] max-w-[300px] bg-[#0A0A0A] border-l border-white/[0.08] flex flex-col" style={{ paddingTop: 'env(safe-area-inset-top)', paddingBottom: 'env(safe-area-inset-bottom)' }}> <div className="absolute top-0 right-0 bottom-0 w-[80%] max-w-[300px] bg-[#0A0A0A] border-l border-white/[0.08] flex flex-col" style={{ paddingTop: 'env(safe-area-inset-top)', paddingBottom: 'env(safe-area-inset-bottom)' }}>
<div className="flex items-center justify-between p-4 border-b border-white/[0.08]"> <div className="flex items-center justify-between p-4 border-b border-white/[0.08]">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<Image src="/pounce-puma.png" alt="Pounce" width={28} height={28} className="object-contain" /> <Image src="/pounce-puma.png" alt="Pounce" width={28} height={28} className="object-contain" />
<div><h2 className="text-sm font-bold text-white">POUNCE</h2><p className="text-[9px] text-white/40 font-mono uppercase">Terminal v1.0</p></div> <div><h2 className="text-sm font-bold text-white">POUNCE</h2><p className="text-[9px] text-white/40 font-mono uppercase">Terminal v1.0</p></div>
</div> </div>
<button onClick={onClose} className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/60"><X className="w-4 h-4" /></button> <button onClick={onClose} className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/60"><X className="w-4 h-4" /></button>
</div> </div>
<div className="flex-1 overflow-y-auto py-4"> <div className="flex-1 overflow-y-auto py-4">
{sections.map((section: any) => ( {sections.map((section: any) => (
<div key={section.title} className="mb-4"> <div key={section.title} className="mb-4">
@ -1352,23 +1352,23 @@ function MobileDrawer({ user, tierName, TierIcon, sections, onClose, onLogout }:
{item.isNew && <span className="px-1.5 py-0.5 text-[8px] font-bold bg-accent text-black">NEW</span>} {item.isNew && <span className="px-1.5 py-0.5 text-[8px] font-bold bg-accent text-black">NEW</span>}
</Link> </Link>
))} ))}
</div> </div>
))} ))}
<div className="pt-3 border-t border-white/[0.08] mx-4"> <div className="pt-3 border-t border-white/[0.08] mx-4">
<Link href="/terminal/settings" onClick={onClose} className="flex items-center gap-3 py-2.5 text-white/50"><Settings className="w-4 h-4" /><span className="text-sm">Settings</span></Link> <Link href="/terminal/settings" onClick={onClose} className="flex items-center gap-3 py-2.5 text-white/50"><Settings className="w-4 h-4" /><span className="text-sm">Settings</span></Link>
{user?.is_admin && <Link href="/admin" onClick={onClose} className="flex items-center gap-3 py-2.5 text-amber-500/70"><Shield className="w-4 h-4" /><span className="text-sm">Admin</span></Link>} {user?.is_admin && <Link href="/admin" onClick={onClose} className="flex items-center gap-3 py-2.5 text-amber-500/70"><Shield className="w-4 h-4" /><span className="text-sm">Admin</span></Link>}
</div>
</div> </div>
</div>
<div className="p-4 bg-white/[0.02] border-t border-white/[0.08]"> <div className="p-4 bg-white/[0.02] border-t border-white/[0.08]">
<div className="flex items-center gap-3 mb-3"> <div className="flex items-center gap-3 mb-3">
<div className="w-8 h-8 bg-accent/10 border border-accent/20 flex items-center justify-center"><TierIcon className="w-4 h-4 text-accent" /></div> <div className="w-8 h-8 bg-accent/10 border border-accent/20 flex items-center justify-center"><TierIcon className="w-4 h-4 text-accent" /></div>
<div className="flex-1 min-w-0"><p className="text-sm font-bold text-white truncate">{user?.name || user?.email?.split('@')[0] || 'User'}</p><p className="text-[9px] font-mono text-white/40 uppercase">{tierName}</p></div> <div className="flex-1 min-w-0"><p className="text-sm font-bold text-white truncate">{user?.name || user?.email?.split('@')[0] || 'User'}</p><p className="text-[9px] font-mono text-white/40 uppercase">{tierName}</p></div>
</div> </div>
{tierName === 'Scout' && <Link href="/pricing" onClick={onClose} className="flex items-center justify-center gap-2 w-full py-2.5 bg-accent text-black text-xs font-bold uppercase mb-2"><Sparkles className="w-3 h-3" />Upgrade</Link>} {tierName === 'Scout' && <Link href="/pricing" onClick={onClose} className="flex items-center justify-center gap-2 w-full py-2.5 bg-accent text-black text-xs font-bold uppercase mb-2"><Sparkles className="w-3 h-3" />Upgrade</Link>}
<button onClick={onLogout} className="flex items-center justify-center gap-2 w-full py-2 border border-white/10 text-white/40 text-[10px] font-mono uppercase"><LogOut className="w-3 h-3" />Sign out</button> <button onClick={onLogout} className="flex items-center justify-center gap-2 w-full py-2 border border-white/10 text-white/40 text-[10px] font-mono uppercase"><LogOut className="w-3 h-3" />Sign out</button>
</div> </div>
</div> </div>
</div> </div>
) )
} }
@ -1438,18 +1438,18 @@ function DnsVerificationModal({ domain, onClose, onSuccess }: { domain: Portfoli
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<ShieldCheck className="w-4 h-4 text-blue-400" /> <ShieldCheck className="w-4 h-4 text-blue-400" />
<span className="text-xs font-mono text-blue-400 uppercase tracking-wider">Verify Domain Ownership</span> <span className="text-xs font-mono text-blue-400 uppercase tracking-wider">Verify Domain Ownership</span>
</div> </div>
<button onClick={onClose} className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/40"> <button onClick={onClose} className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/40">
<X className="w-4 h-4" /> <X className="w-4 h-4" />
</button> </button>
</div> </div>
<div className="p-4 space-y-4"> <div className="p-4 space-y-4">
{/* Domain Header */} {/* Domain Header */}
<div className="text-center py-3 border-b border-white/[0.08]"> <div className="text-center py-3 border-b border-white/[0.08]">
<h2 className="text-xl font-bold font-mono text-white">{domain.domain}</h2> <h2 className="text-xl font-bold font-mono text-white">{domain.domain}</h2>
<p className="text-xs font-mono text-white/40 mt-1">DNS Verification Required</p> <p className="text-xs font-mono text-white/40 mt-1">DNS Verification Required</p>
</div> </div>
{step === 'loading' && ( {step === 'loading' && (
<div className="flex items-center justify-center py-8"> <div className="flex items-center justify-center py-8">
@ -1462,20 +1462,20 @@ function DnsVerificationModal({ domain, onClose, onSuccess }: { domain: Portfoli
{/* Instructions */} {/* Instructions */}
<div className="p-4 bg-blue-400/5 border border-blue-400/20"> <div className="p-4 bg-blue-400/5 border border-blue-400/20">
<h3 className="text-sm font-bold text-white mb-2">Add this TXT record to your DNS:</h3> <h3 className="text-sm font-bold text-white mb-2">Add this TXT record to your DNS:</h3>
<div className="space-y-3"> <div className="space-y-3">
<div> <div>
<div className="text-[9px] font-mono text-white/40 uppercase mb-1">Host / Name</div> <div className="text-[9px] font-mono text-white/40 uppercase mb-1">Host / Name</div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<code className="flex-1 px-3 py-2 bg-black/50 text-sm font-mono text-white break-all">_pounce</code> <code className="flex-1 px-3 py-2 bg-black/50 text-sm font-mono text-white break-all">_pounce</code>
<button onClick={() => handleCopy('_pounce')} className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/40 hover:text-white"> <button onClick={() => handleCopy('_pounce')} className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/40 hover:text-white">
{copied ? <Check className="w-4 h-4 text-accent" /> : <Copy className="w-4 h-4" />} {copied ? <Check className="w-4 h-4 text-accent" /> : <Copy className="w-4 h-4" />}
</button> </button>
</div> </div>
</div> </div>
<div> <div>
<div className="text-[9px] font-mono text-white/40 uppercase mb-1">Type</div> <div className="text-[9px] font-mono text-white/40 uppercase mb-1">Type</div>
<code className="block px-3 py-2 bg-black/50 text-sm font-mono text-white">TXT</code> <code className="block px-3 py-2 bg-black/50 text-sm font-mono text-white">TXT</code>
</div> </div>
<div> <div>
<div className="text-[9px] font-mono text-white/40 uppercase mb-1">Value</div> <div className="text-[9px] font-mono text-white/40 uppercase mb-1">Value</div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@ -1483,26 +1483,26 @@ function DnsVerificationModal({ domain, onClose, onSuccess }: { domain: Portfoli
<button onClick={() => handleCopy(verificationData.verification_code)} className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/40 hover:text-white"> <button onClick={() => handleCopy(verificationData.verification_code)} className="w-8 h-8 flex items-center justify-center border border-white/10 text-white/40 hover:text-white">
{copied ? <Check className="w-4 h-4 text-accent" /> : <Copy className="w-4 h-4" />} {copied ? <Check className="w-4 h-4 text-accent" /> : <Copy className="w-4 h-4" />}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{/* Info */} {/* Info */}
<div className="p-3 bg-white/[0.02] border border-white/[0.08] text-xs text-white/50 font-mono"> <div className="p-3 bg-white/[0.02] border border-white/[0.08] text-xs text-white/50 font-mono">
<p>DNS changes can take up to 48 hours to propagate, but usually complete within minutes.</p> <p>DNS changes can take up to 48 hours to propagate, but usually complete within minutes.</p>
</div> </div>
{/* Error/Check Result */} {/* Error/Check Result */}
{error && ( {error && (
<div className="p-3 bg-rose-500/10 border border-rose-500/20 text-rose-400 text-xs font-mono"> <div className="p-3 bg-rose-500/10 border border-rose-500/20 text-rose-400 text-xs font-mono">
{error} {error}
</div> </div>
)} )}
{checkResult && ( {checkResult && (
<div className="p-3 bg-amber-400/10 border border-amber-400/20 text-amber-400 text-xs font-mono"> <div className="p-3 bg-amber-400/10 border border-amber-400/20 text-amber-400 text-xs font-mono">
{checkResult} {checkResult}
</div> </div>
)} )}
{/* Actions */} {/* Actions */}
@ -1512,8 +1512,8 @@ function DnsVerificationModal({ domain, onClose, onSuccess }: { domain: Portfoli
</button> </button>
<button onClick={handleCheck} className="flex-1 py-2.5 bg-blue-400 text-black text-xs font-bold uppercase flex items-center justify-center gap-2"> <button onClick={handleCheck} className="flex-1 py-2.5 bg-blue-400 text-black text-xs font-bold uppercase flex items-center justify-center gap-2">
<RefreshCw className="w-4 h-4" />Check Verification <RefreshCw className="w-4 h-4" />Check Verification
</button> </button>
</div> </div>
</> </>
)} )}
@ -1521,7 +1521,7 @@ function DnsVerificationModal({ domain, onClose, onSuccess }: { domain: Portfoli
<div className="flex flex-col items-center justify-center py-8 gap-3"> <div className="flex flex-col items-center justify-center py-8 gap-3">
<Loader2 className="w-6 h-6 text-blue-400 animate-spin" /> <Loader2 className="w-6 h-6 text-blue-400 animate-spin" />
<p className="text-sm font-mono text-white/60">Checking DNS records...</p> <p className="text-sm font-mono text-white/60">Checking DNS records...</p>
</div> </div>
)} )}
{step === 'instructions' && !verificationData && error && ( {step === 'instructions' && !verificationData && error && (