2025-04-15 16:28:03 +05:30
|
|
|
import React from 'react';
|
|
|
|
|
import { Link } from 'react-router-dom';
|
2025-07-30 13:22:06 +05:30
|
|
|
import { useAuth } from '@/contexts/useAuth';
|
|
|
|
|
import { useForum } from '@/contexts/useForum';
|
2025-04-15 16:28:03 +05:30
|
|
|
import { Button } from '@/components/ui/button';
|
2025-04-22 10:39:32 +05:30
|
|
|
import { Badge } from '@/components/ui/badge';
|
2025-04-24 17:35:31 +05:30
|
|
|
import { ShieldCheck, LogOut, Terminal, Wifi, WifiOff, AlertTriangle, CheckCircle, Key, RefreshCw, CircleSlash } from 'lucide-react';
|
|
|
|
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
|
2025-04-15 16:28:03 +05:30
|
|
|
|
|
|
|
|
const Header = () => {
|
2025-04-24 16:30:50 +05:30
|
|
|
const {
|
|
|
|
|
currentUser,
|
|
|
|
|
isAuthenticated,
|
|
|
|
|
verificationStatus,
|
|
|
|
|
connectWallet,
|
|
|
|
|
disconnectWallet,
|
|
|
|
|
verifyOrdinal,
|
|
|
|
|
delegateKey,
|
|
|
|
|
isDelegationValid,
|
|
|
|
|
delegationTimeRemaining
|
|
|
|
|
} = useAuth();
|
2025-04-22 10:39:32 +05:30
|
|
|
const { isNetworkConnected, isRefreshing } = useForum();
|
2025-04-15 16:28:03 +05:30
|
|
|
|
|
|
|
|
const handleConnect = async () => {
|
|
|
|
|
await connectWallet();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleDisconnect = () => {
|
|
|
|
|
disconnectWallet();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleVerify = async () => {
|
|
|
|
|
await verifyOrdinal();
|
|
|
|
|
};
|
2025-04-24 14:31:00 +05:30
|
|
|
|
2025-04-24 16:30:50 +05:30
|
|
|
const handleDelegateKey = async () => {
|
|
|
|
|
await delegateKey();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const formatDelegationTime = () => {
|
|
|
|
|
if (!isDelegationValid()) return null;
|
|
|
|
|
|
|
|
|
|
const timeRemaining = delegationTimeRemaining();
|
|
|
|
|
const hours = Math.floor(timeRemaining / (1000 * 60 * 60));
|
|
|
|
|
const minutes = Math.floor((timeRemaining % (1000 * 60 * 60)) / (1000 * 60));
|
2025-04-24 17:35:31 +05:30
|
|
|
|
|
|
|
|
return `${hours}h ${minutes}m`;
|
2025-04-24 16:30:50 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const renderDelegationButton = () => {
|
2025-04-24 17:35:31 +05:30
|
|
|
if (verificationStatus !== 'verified-owner') return null;
|
2025-04-24 16:30:50 +05:30
|
|
|
|
|
|
|
|
const hasValidDelegation = isDelegationValid();
|
|
|
|
|
const timeRemaining = formatDelegationTime();
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Tooltip>
|
|
|
|
|
<TooltipTrigger asChild>
|
|
|
|
|
<Button
|
|
|
|
|
variant={hasValidDelegation ? "outline" : "default"}
|
|
|
|
|
size="sm"
|
2025-04-24 17:35:31 +05:30
|
|
|
className="flex items-center gap-1 text-xs px-2 h-7"
|
2025-04-24 16:30:50 +05:30
|
|
|
onClick={handleDelegateKey}
|
|
|
|
|
>
|
2025-04-24 17:35:31 +05:30
|
|
|
<Key className="w-3 h-3" />
|
2025-04-24 16:30:50 +05:30
|
|
|
{hasValidDelegation
|
2025-04-24 17:35:31 +05:30
|
|
|
? <span>KEY ACTIVE ({timeRemaining})</span>
|
|
|
|
|
: <span>DELEGATE KEY</span>}
|
2025-04-24 16:30:50 +05:30
|
|
|
</Button>
|
|
|
|
|
</TooltipTrigger>
|
2025-04-24 17:35:31 +05:30
|
|
|
<TooltipContent className="max-w-[260px] text-sm">
|
2025-04-24 16:30:50 +05:30
|
|
|
{hasValidDelegation ? (
|
2025-04-24 17:35:31 +05:30
|
|
|
<p>Browser key active for ~{timeRemaining}. Wallet signatures not needed for most actions.</p>
|
2025-04-24 16:30:50 +05:30
|
|
|
) : (
|
2025-04-24 17:35:31 +05:30
|
|
|
<p>Delegate a browser key for 24h to avoid constant wallet signing.</p>
|
2025-04-24 16:30:50 +05:30
|
|
|
)}
|
|
|
|
|
</TooltipContent>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2025-04-24 14:31:00 +05:30
|
|
|
const renderAccessBadge = () => {
|
|
|
|
|
if (verificationStatus === 'unverified') {
|
|
|
|
|
return (
|
2025-04-24 17:35:31 +05:30
|
|
|
<Tooltip>
|
|
|
|
|
<TooltipTrigger asChild>
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={handleVerify}
|
|
|
|
|
className="flex items-center gap-1 text-xs px-2 h-7 border-destructive text-destructive hover:bg-destructive/10"
|
|
|
|
|
>
|
|
|
|
|
<AlertTriangle className="w-3 h-3" />
|
|
|
|
|
<span>[UNVERIFIED] Verify</span>
|
|
|
|
|
</Button>
|
|
|
|
|
</TooltipTrigger>
|
|
|
|
|
<TooltipContent className="max-w-[260px] text-sm">
|
|
|
|
|
<p className="font-semibold mb-1">Action Required</p>
|
|
|
|
|
<p>Verify your Ordinal ownership to enable posting, commenting, and voting.</p>
|
|
|
|
|
</TooltipContent>
|
|
|
|
|
</Tooltip>
|
2025-04-24 14:31:00 +05:30
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (verificationStatus === 'verifying') {
|
|
|
|
|
return (
|
|
|
|
|
<Badge
|
|
|
|
|
variant="outline"
|
2025-04-24 17:35:31 +05:30
|
|
|
className="flex items-center gap-1 text-xs px-2 h-7"
|
2025-04-24 14:31:00 +05:30
|
|
|
>
|
|
|
|
|
<RefreshCw className="w-3 h-3 animate-spin" />
|
2025-04-24 17:35:31 +05:30
|
|
|
<span>[VERIFYING...]</span>
|
2025-04-24 14:31:00 +05:30
|
|
|
</Badge>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (verificationStatus === 'verified-none') {
|
|
|
|
|
return (
|
2025-04-24 17:35:31 +05:30
|
|
|
<Tooltip>
|
|
|
|
|
<TooltipTrigger asChild>
|
|
|
|
|
<Badge
|
|
|
|
|
variant="secondary"
|
|
|
|
|
className="flex items-center gap-1 cursor-help text-xs px-2 h-7"
|
|
|
|
|
>
|
|
|
|
|
<CircleSlash className="w-3 h-3" />
|
|
|
|
|
<span>[VERIFIED | READ-ONLY]</span>
|
|
|
|
|
</Badge>
|
|
|
|
|
</TooltipTrigger>
|
|
|
|
|
<TooltipContent className="max-w-[260px] text-sm">
|
|
|
|
|
<p className="font-semibold mb-1">Wallet Verified - No Ordinals</p>
|
|
|
|
|
<p>No Ordinal Operators found. Read-only access granted.</p>
|
|
|
|
|
<Button size="sm" variant="link" onClick={handleVerify} className="p-0 h-auto mt-1 text-xs">Verify Again?</Button>
|
|
|
|
|
</TooltipContent>
|
|
|
|
|
</Tooltip>
|
2025-04-24 14:31:00 +05:30
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-24 17:35:31 +05:30
|
|
|
// Verified - Ordinal Owner
|
2025-04-24 14:31:00 +05:30
|
|
|
if (verificationStatus === 'verified-owner') {
|
|
|
|
|
return (
|
2025-04-24 17:35:31 +05:30
|
|
|
<Tooltip>
|
|
|
|
|
<TooltipTrigger asChild>
|
|
|
|
|
<Badge
|
|
|
|
|
variant="default"
|
|
|
|
|
className="flex items-center gap-1 cursor-help text-xs px-2 h-7 bg-primary text-primary-foreground"
|
|
|
|
|
>
|
|
|
|
|
<CheckCircle className="w-3 h-3" />
|
|
|
|
|
<span>[OWNER ✔]</span>
|
|
|
|
|
</Badge>
|
|
|
|
|
</TooltipTrigger>
|
|
|
|
|
<TooltipContent className="max-w-[260px] text-sm">
|
|
|
|
|
<p className="font-semibold mb-1">Ordinal Owner Verified!</p>
|
|
|
|
|
<p>Full forum access granted.</p>
|
|
|
|
|
<Button size="sm" variant="link" onClick={handleVerify} className="p-0 h-auto mt-1 text-xs">Verify Again?</Button>
|
|
|
|
|
</TooltipContent>
|
|
|
|
|
</Tooltip>
|
2025-04-24 14:31:00 +05:30
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
};
|
2025-04-15 16:28:03 +05:30
|
|
|
|
|
|
|
|
return (
|
2025-04-24 17:35:31 +05:30
|
|
|
<header className="border-b border-cyber-muted bg-cyber-dark fixed top-0 left-0 right-0 z-50 h-16">
|
|
|
|
|
<div className="container mx-auto px-4 h-full flex justify-between items-center">
|
2025-04-15 16:28:03 +05:30
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
|
<Terminal className="text-cyber-accent w-6 h-6" />
|
|
|
|
|
<Link to="/" className="text-xl font-bold text-glow text-cyber-accent">
|
|
|
|
|
OpChan
|
|
|
|
|
</Link>
|
2025-04-24 17:35:31 +05:30
|
|
|
|
2025-04-15 16:28:03 +05:30
|
|
|
</div>
|
|
|
|
|
|
2025-04-24 17:35:31 +05:30
|
|
|
<div className="flex gap-3 items-center">
|
2025-04-22 10:39:32 +05:30
|
|
|
<Tooltip>
|
|
|
|
|
<TooltipTrigger asChild>
|
2025-04-24 17:35:31 +05:30
|
|
|
<Badge
|
|
|
|
|
variant={isNetworkConnected ? "default" : "destructive"}
|
|
|
|
|
className="flex items-center gap-1 text-xs px-2 h-7 cursor-help"
|
|
|
|
|
>
|
|
|
|
|
{isNetworkConnected ? (
|
|
|
|
|
<>
|
|
|
|
|
<Wifi className="w-3 h-3" />
|
|
|
|
|
<span>WAKU: Connected</span>
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
<WifiOff className="w-3 h-3" />
|
|
|
|
|
<span>WAKU: Offline</span>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</Badge>
|
2025-04-22 10:39:32 +05:30
|
|
|
</TooltipTrigger>
|
2025-04-24 17:35:31 +05:30
|
|
|
<TooltipContent className="text-sm">
|
|
|
|
|
<p>{isNetworkConnected ? "Waku network connection active." : "Waku network connection lost."}</p>
|
2025-04-22 10:39:32 +05:30
|
|
|
{isRefreshing && <p>Refreshing data...</p>}
|
|
|
|
|
</TooltipContent>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
|
2025-04-15 16:28:03 +05:30
|
|
|
{!currentUser ? (
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={handleConnect}
|
2025-04-24 17:35:31 +05:30
|
|
|
className="text-xs px-2 h-7"
|
2025-04-15 16:28:03 +05:30
|
|
|
>
|
|
|
|
|
Connect Wallet
|
|
|
|
|
</Button>
|
|
|
|
|
) : (
|
2025-04-24 17:35:31 +05:30
|
|
|
<div className="flex gap-2 items-center">
|
2025-04-24 14:31:00 +05:30
|
|
|
{renderAccessBadge()}
|
2025-04-24 16:30:50 +05:30
|
|
|
{renderDelegationButton()}
|
2025-04-24 17:35:31 +05:30
|
|
|
<Tooltip>
|
|
|
|
|
<TooltipTrigger asChild>
|
|
|
|
|
<span className="hidden md:flex items-center text-xs text-muted-foreground cursor-default px-2 h-7">
|
|
|
|
|
{currentUser.address.slice(0, 5)}...{currentUser.address.slice(-4)}
|
|
|
|
|
</span>
|
|
|
|
|
</TooltipTrigger>
|
|
|
|
|
<TooltipContent className="text-sm">
|
|
|
|
|
<p>{currentUser.address}</p>
|
|
|
|
|
</TooltipContent>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
<Tooltip>
|
|
|
|
|
<TooltipTrigger asChild>
|
|
|
|
|
<Button
|
|
|
|
|
variant="ghost"
|
|
|
|
|
size="icon"
|
|
|
|
|
onClick={handleDisconnect}
|
|
|
|
|
className="w-7 h-7"
|
|
|
|
|
>
|
|
|
|
|
<LogOut className="w-4 h-4" />
|
|
|
|
|
</Button>
|
|
|
|
|
</TooltipTrigger>
|
|
|
|
|
<TooltipContent className="text-sm">Disconnect Wallet</TooltipContent>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
</div>
|
2025-04-15 16:28:03 +05:30
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</header>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default Header;
|