import { useState } from 'react';
import { useForum } from '@opchan/react';
import { useAuth } from '@opchan/react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { WalletWizard } from '@/components/ui/wallet-wizard';
import Header from '@/components/Header';
import {
Loader2,
User,
Shield,
CheckCircle,
AlertTriangle,
XCircle,
Settings,
Copy,
Globe,
Edit3,
Save,
X,
} from 'lucide-react';
import { EDisplayPreference, EVerificationStatus } from '@opchan/core';
import { useToast } from '@/hooks/use-toast';
export default function ProfilePage() {
const forum = useForum();
const { updateProfile } = forum.user;
const { refresh } = forum.content;
const { toast } = useToast();
// Get current user from auth context for the address
const { currentUser, delegationInfo } = useAuth();
const [isEditing, setIsEditing] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const [callSign, setCallSign] = useState('');
const [displayPreference, setDisplayPreference] = useState(
EDisplayPreference.WALLET_ADDRESS
);
const [walletWizardOpen, setWalletWizardOpen] = useState(false);
// Copy to clipboard function
const copyToClipboard = async (text: string, label: string) => {
try {
await navigator.clipboard.writeText(text);
toast({
title: 'Copied!',
description: `${label} copied to clipboard`,
});
} catch {
toast({
title: 'Copy Failed',
description: 'Failed to copy to clipboard',
variant: 'destructive',
});
}
};
if (!currentUser) {
return (
Connect Required
Please connect your wallet to view your profile.
);
}
const handleSave = async () => {
if (!callSign.trim()) {
toast({
title: 'Invalid Input',
description: 'Call sign cannot be empty.',
variant: 'destructive',
});
return;
}
// Basic validation for call sign
if (callSign.length < 3 || callSign.length > 20) {
toast({
title: 'Invalid Call Sign',
description: 'Call sign must be between 3 and 20 characters.',
variant: 'destructive',
});
return;
}
if (!/^[a-zA-Z0-9_-]+$/.test(callSign)) {
toast({
title: 'Invalid Call Sign',
description:
'Call sign can only contain letters, numbers, underscores, and hyphens.',
variant: 'destructive',
});
return;
}
setIsSubmitting(true);
try {
const success = await updateProfile({
callSign: callSign.trim(),
displayPreference,
});
if (success) {
await refresh();
setIsEditing(false);
toast({
title: 'Profile Updated',
description: 'Your profile has been updated successfully.',
});
}
} catch {
toast({
title: 'Update Failed',
description: 'Failed to update profile. Please try again.',
variant: 'destructive',
});
} finally {
setIsSubmitting(false);
}
};
const handleCancel = () => {
// Reset to the same data source as display for consistency
const currentCallSign = currentUser.callSign || currentUser.callSign || '';
const currentDisplayPreference =
currentUser.displayPreference ||
currentUser.displayPreference ||
EDisplayPreference.WALLET_ADDRESS;
setCallSign(currentCallSign);
setDisplayPreference(currentDisplayPreference);
setIsEditing(false);
};
const getVerificationIcon = () => {
// Use verification level from UserIdentityService (central database store)
switch (currentUser.verificationStatus) {
case EVerificationStatus.ENS_ORDINAL_VERIFIED:
return ;
case EVerificationStatus.WALLET_CONNECTED:
return ;
case EVerificationStatus.WALLET_UNCONNECTED:
return ;
default:
return ;
}
};
const getVerificationText = () => {
// Use verification level from UserIdentityService (central database store)
switch (currentUser.verificationStatus) {
case EVerificationStatus.ENS_ORDINAL_VERIFIED:
return 'Owns ENS or Ordinal';
case EVerificationStatus.WALLET_CONNECTED:
return 'Connected Wallet';
case EVerificationStatus.WALLET_UNCONNECTED:
return 'Unconnected Wallet';
default:
return 'Unknown';
}
};
const getVerificationColor = () => {
// Use verification level from UserIdentityService (central database store)
switch (currentUser.verificationStatus) {
case EVerificationStatus.ENS_ORDINAL_VERIFIED:
return 'bg-green-100 text-green-800 border-green-200';
case EVerificationStatus.WALLET_CONNECTED:
return 'bg-blue-100 text-blue-800 border-blue-200';
case EVerificationStatus.WALLET_UNCONNECTED:
return 'bg-yellow-100 text-yellow-800 border-yellow-200';
default:
return 'bg-gray-100 text-gray-800 border-gray-200';
}
};
return (
{/* Page Header */}
Profile
Manage your account settings and preferences
{/* Two-Card Layout: User Profile + Security Status */}
{/* User Profile Card - Primary (2/3 width) */}
User Profile
{!isEditing && (
)}
{/* Identity Section */}
{currentUser.displayName}
{/* Show ENS name if available */}
{currentUser.ensDetails?.ensName && (
ENS: {currentUser.ensDetails?.ensName}
)}
{/* Show Ordinal details if available */}
{currentUser.ordinalDetails && (
Ordinal:{' '}
{currentUser.ordinalDetails.ordinalDetails}
)}
{/* Show fallback if neither ENS nor Ordinal */}
{!currentUser.ensDetails?.ensName &&
!currentUser.ordinalDetails?.ordinalDetails && (
No ENS or Ordinal verification
)}
{getVerificationIcon()}
{getVerificationText()}
{/* Wallet Section */}
Wallet Information
{currentUser.address.slice(0, 8)}...
{currentUser.address.slice(-6)}
{currentUser.walletType}
{/* Settings Section */}
Profile Settings
{isEditing ? (
setCallSign(e.target.value)}
placeholder="Enter your call sign"
className="bg-cyber-dark/50 border-cyber-muted/30 text-cyber-light"
disabled={isSubmitting}
/>
) : (
{currentUser.callSign ||
currentUser.callSign ||
'Not set'}
)}
3-20 characters, letters, numbers, underscores, and
hyphens only
{isEditing ? (
) : (
{(currentUser.displayPreference ||
displayPreference) ===
EDisplayPreference.CALL_SIGN
? 'Call Sign (when available)'
: 'Wallet Address'}
)}
{/* Action Buttons */}
{isEditing && (
)}
{/* Security Status Card - Secondary (1/3 width) */}
Security
{delegationInfo.hasDelegation && (
)}
{/* Delegation Status */}
Delegation
{delegationInfo.isValid ? 'Active' : 'Inactive'}
{/* Expiry Date */}
{delegationInfo.expiresAt && (
Valid until
{delegationInfo.expiresAt.toLocaleDateString()}
)}
{/* Signature Status */}
Signature
{delegationInfo.isValid ? 'Valid' : 'Not signed'}
{/* Browser Public Key */}
{delegationInfo.publicKey
? `${delegationInfo.publicKey.slice(0, 12)}...${delegationInfo.publicKey.slice(-8)}`
: 'Not delegated'}
{delegationInfo.publicKey && (
)}
{/* Warning for expired delegation */}
{!delegationInfo.isValid && delegationInfo.hasDelegation && (
Delegation expired. Renew to continue using your
browser key.
)}
{/* Wallet Wizard */}
setWalletWizardOpen(false)}
/>
);
}