mirror of
https://github.com/luxfhe/research-ocp-fhe.git
synced 2026-11-03 06:05:38 +00:00
339 lines
9.6 KiB
TypeScript
339 lines
9.6 KiB
TypeScript
'use client';
|
|
|
|
import * as React from 'react';
|
|
import {
|
|
Building2,
|
|
Home,
|
|
PiggyBank,
|
|
Shield,
|
|
Loader2,
|
|
AlertCircle,
|
|
Settings,
|
|
} from 'lucide-react';
|
|
import {
|
|
Sidebar,
|
|
SidebarContent,
|
|
SidebarFooter,
|
|
SidebarGroup,
|
|
SidebarGroupContent,
|
|
SidebarGroupLabel,
|
|
SidebarHeader,
|
|
SidebarMenu,
|
|
SidebarMenuButton,
|
|
SidebarMenuItem,
|
|
SidebarSeparator,
|
|
} from '@/components/ui/sidebar';
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from '@/components/ui/select';
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
} from '@/components/ui/dropdown-menu';
|
|
import {
|
|
AlertDialog,
|
|
AlertDialogAction,
|
|
AlertDialogCancel,
|
|
AlertDialogContent,
|
|
AlertDialogDescription,
|
|
AlertDialogFooter,
|
|
AlertDialogHeader,
|
|
AlertDialogTitle,
|
|
} from '@/components/ui/alert-dialog';
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipProvider,
|
|
TooltipTrigger,
|
|
} from '@/components/ui/tooltip';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { useRole } from '@/hooks/use-role';
|
|
import { useFhevm } from '@/hooks/use-fhevm';
|
|
import { useDecryptionStore } from '@/stores/decryption-store';
|
|
import { WalletSwitcher } from '@/components/wallet-switcher';
|
|
import { useAccount } from '@/hooks/wagmi-viem-proxy/use-account';
|
|
import type { Role } from '@/stores/role-store';
|
|
|
|
// Navigation items
|
|
const navigationItems = [
|
|
{
|
|
title: 'Home',
|
|
url: '/',
|
|
icon: Home,
|
|
},
|
|
{
|
|
title: 'Companies',
|
|
url: '/company',
|
|
icon: Building2,
|
|
},
|
|
{
|
|
title: 'Investments',
|
|
url: '/investments',
|
|
icon: PiggyBank,
|
|
},
|
|
];
|
|
|
|
export function PrivateAppSidebar() {
|
|
const { address: walletAddress, chainId } = useAccount();
|
|
const { role, isOwnWallet, setRole } = useRole();
|
|
const fhevmQuery = useFhevm();
|
|
const { clearAllDecryptedData } = useDecryptionStore();
|
|
const [showClearDataDialog, setShowClearDataDialog] = React.useState(false);
|
|
|
|
const getFhevmStatus = () => {
|
|
if (!walletAddress || !chainId) {
|
|
return {
|
|
status: 'waiting' as const,
|
|
text: 'Waiting',
|
|
icon: Shield,
|
|
className: 'text-yellow-500',
|
|
};
|
|
}
|
|
|
|
if (fhevmQuery.isLoading) {
|
|
return {
|
|
status: 'loading' as const,
|
|
text: 'Loading',
|
|
icon: Loader2,
|
|
className: 'text-yellow-500 animate-spin',
|
|
};
|
|
}
|
|
|
|
if (fhevmQuery.isError) {
|
|
return {
|
|
status: 'error' as const,
|
|
text: 'Error',
|
|
icon: AlertCircle,
|
|
className: 'text-red-500',
|
|
};
|
|
}
|
|
|
|
if (fhevmQuery.data) {
|
|
return {
|
|
status: 'active' as const,
|
|
text: 'Active',
|
|
icon: Shield,
|
|
className: 'text-green-600',
|
|
};
|
|
}
|
|
|
|
return {
|
|
status: 'waiting' as const,
|
|
text: 'Waiting',
|
|
icon: Shield,
|
|
className: 'text-yellow-500',
|
|
};
|
|
};
|
|
|
|
const fhevmStatus = getFhevmStatus();
|
|
|
|
const handleRoleChange = (next: Role) => {
|
|
setRole(next);
|
|
};
|
|
|
|
const handleClearDecryptedData = () => {
|
|
clearAllDecryptedData();
|
|
setShowClearDataDialog(false);
|
|
};
|
|
|
|
const handleOpenClearDataDialog = () => {
|
|
setShowClearDataDialog(true);
|
|
};
|
|
|
|
const getRoleBadgeVariant = (role: Role) => {
|
|
switch (role) {
|
|
case 'FOUNDER':
|
|
return 'default';
|
|
case 'INVESTOR':
|
|
return 'secondary';
|
|
case 'PUBLIC':
|
|
return 'outline';
|
|
case 'ADMIN':
|
|
return 'destructive';
|
|
default:
|
|
return 'default';
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Sidebar>
|
|
<SidebarHeader>
|
|
<SidebarMenu>
|
|
<SidebarMenuItem>
|
|
<div className="flex items-center gap-2 px-2 py-1">
|
|
<Building2 className="h-6 w-6" />
|
|
<span className="font-semibold text-sidebar-foreground">
|
|
OCP-FHE Demo
|
|
</span>
|
|
</div>
|
|
</SidebarMenuItem>
|
|
</SidebarMenu>
|
|
<SidebarSeparator />
|
|
|
|
{/* Role Indicator */}
|
|
<SidebarMenu>
|
|
<SidebarMenuItem>
|
|
<div className="px-2 py-1">
|
|
<div className="flex items-center justify-between mb-2">
|
|
<label className="text-xs font-semibold text-sidebar-foreground/80">
|
|
Current Role
|
|
</label>
|
|
<Badge variant={getRoleBadgeVariant(role)} className="text-xs">
|
|
{role}
|
|
</Badge>
|
|
</div>
|
|
</div>
|
|
</SidebarMenuItem>
|
|
</SidebarMenu>
|
|
|
|
{/* Wallet Switcher */}
|
|
<WalletSwitcher />
|
|
|
|
{/* Conditional Role Selector - only show when using own wallet */}
|
|
{isOwnWallet && (
|
|
<>
|
|
<SidebarSeparator />
|
|
<SidebarMenu>
|
|
<SidebarMenuItem>
|
|
<div className="px-2 py-1">
|
|
<label className="text-xs font-semibold text-sidebar-foreground/80 mb-3 block">
|
|
Select Role
|
|
</label>
|
|
<Select
|
|
value={role}
|
|
onValueChange={v => handleRoleChange(v as Role)}
|
|
>
|
|
<SelectTrigger
|
|
aria-label="Select role"
|
|
className="uppercase h-10 font-medium border-2 hover:border-sidebar-accent transition-colors bg-sidebar-accent/10 hover:bg-sidebar-accent/20"
|
|
>
|
|
<SelectValue placeholder="ROLE" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="FOUNDER">FOUNDER</SelectItem>
|
|
<SelectItem value="INVESTOR">INVESTOR</SelectItem>
|
|
<SelectItem value="PUBLIC">PUBLIC</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</SidebarMenuItem>
|
|
</SidebarMenu>
|
|
</>
|
|
)}
|
|
</SidebarHeader>
|
|
|
|
<SidebarContent>
|
|
<SidebarGroup>
|
|
<SidebarGroupLabel>Navigation</SidebarGroupLabel>
|
|
<SidebarGroupContent>
|
|
<SidebarMenu>
|
|
{navigationItems.map(item => (
|
|
<SidebarMenuItem key={item.title}>
|
|
<SidebarMenuButton asChild>
|
|
<a href={item.url}>
|
|
<item.icon />
|
|
<span>{item.title}</span>
|
|
</a>
|
|
</SidebarMenuButton>
|
|
</SidebarMenuItem>
|
|
))}
|
|
</SidebarMenu>
|
|
</SidebarGroupContent>
|
|
</SidebarGroup>
|
|
|
|
<SidebarGroup>
|
|
<SidebarSeparator />
|
|
</SidebarGroup>
|
|
|
|
<SidebarGroup>
|
|
<SidebarGroupLabel>Settings</SidebarGroupLabel>
|
|
<SidebarGroupContent>
|
|
<SidebarMenu>
|
|
<SidebarMenuItem>
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<SidebarMenuButton className="w-full flex items-center gap-2">
|
|
<Settings className="h-5 w-5" />
|
|
<span>Settings</span>
|
|
</SidebarMenuButton>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent side="right" align="start">
|
|
<DropdownMenuItem
|
|
variant="destructive"
|
|
onSelect={handleOpenClearDataDialog}
|
|
>
|
|
Clear Decrypted Data
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</SidebarMenuItem>
|
|
</SidebarMenu>
|
|
</SidebarGroupContent>
|
|
</SidebarGroup>
|
|
</SidebarContent>
|
|
|
|
<SidebarFooter>
|
|
<TooltipProvider>
|
|
<SidebarMenu>
|
|
<SidebarMenuItem>
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<SidebarMenuButton
|
|
size="sm"
|
|
className="w-full bg-green-50/50 hover:bg-green-100/50 border border-green-200/50 hover:border-green-300/50 transition-all duration-200 mb-2"
|
|
>
|
|
<fhevmStatus.icon
|
|
className={`h-3 w-3 ${fhevmStatus.className}`}
|
|
/>
|
|
<span className="text-xs font-medium text-green-700">
|
|
FHEVM {fhevmStatus.text}
|
|
</span>
|
|
</SidebarMenuButton>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="right" className="max-w-xs">
|
|
<p className="text-sm">
|
|
FHEVM allows the app to privately interact with encrypted
|
|
blockchain data
|
|
</p>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
</SidebarMenuItem>
|
|
</SidebarMenu>
|
|
</TooltipProvider>
|
|
</SidebarFooter>
|
|
|
|
{/* Separate AlertDialog for Clear Decrypted Data */}
|
|
<AlertDialog
|
|
open={showClearDataDialog}
|
|
onOpenChange={setShowClearDataDialog}
|
|
>
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>Clear Decrypted Data</AlertDialogTitle>
|
|
<AlertDialogDescription>
|
|
This will permanently remove all locally stored decrypted data
|
|
from your browser. You will need to decrypt the data again when
|
|
viewing encrypted information. This action cannot be undone.
|
|
</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
<AlertDialogFooter>
|
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
<AlertDialogAction
|
|
onClick={handleClearDecryptedData}
|
|
className="bg-destructive hover:bg-destructive/90"
|
|
>
|
|
Clear Data
|
|
</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
</Sidebar>
|
|
);
|
|
}
|