import React, { useState, useRef, useEffect, useCallback } from 'react'; import { useNavigate, useLocation } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { useAuth } from '@/contexts/AuthContext'; import { usePezkuwi } from '@/contexts/PezkuwiContext'; import { supabase } from '@/lib/supabase'; import { fetchUserTikis, getPrimaryRole, getTikiDisplayName, getTikiEmoji, getCitizenNFTDetails, generateCitizenNumber } from '@pezkuwi/lib/tiki'; import { getAllScores, type UserScores } from '@pezkuwi/lib/scores'; import { getKycStatus } from '@pezkuwi/lib/kyc'; import LandingPageDesktop from './landing/LandingPageDesktop'; import HeroSection from './HeroSection'; import { NetworkStats } from './NetworkStats'; import TrustScoreCalculator from './TrustScoreCalculator'; import ChainSpecs from './ChainSpecs'; import RewardDistribution from './RewardDistribution'; import { LanguageSwitcher } from './LanguageSwitcher'; import NotificationBell from './notifications/NotificationBell'; import ProposalWizard from './proposals/ProposalWizard'; import DelegationManager from './delegation/DelegationManager'; import { ForumOverview } from './forum/ForumOverview'; import { ModerationPanel } from './forum/ModerationPanel'; import { TreasuryOverview } from './treasury/TreasuryOverview'; import { FundingProposal } from './treasury/FundingProposal'; import { SpendingHistory } from './treasury/SpendingHistory'; import { MultiSigApproval } from './treasury/MultiSigApproval'; import { ExternalLink, FileEdit, Users2, MessageSquare, Wifi, WifiOff, Wallet, DollarSign, PiggyBank, History, Key, TrendingUp, ArrowRightLeft, Lock, LogIn, LayoutDashboard, Settings, Users, Droplet, Mail, Coins, Menu, X, ChevronDown, } from 'lucide-react'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { useWebSocket } from '@/contexts/WebSocketContext'; import { StakingDashboard } from './staking/StakingDashboard'; import { MultiSigWallet } from './wallet/MultiSigWallet'; import { useWallet } from '@/contexts/WalletContext'; import { PezkuwiWalletButton } from './PezkuwiWalletButton'; import { DEXDashboard } from './dex/DEXDashboard'; import { P2PDashboard } from './p2p/P2PDashboard'; import EducationPlatform from '../pages/EducationPlatform'; import { useIsMobile } from '@/hooks/use-mobile'; import MobileHomeLayout from './MobileHomeLayout'; // ── Avatar pool ── const AVATAR_POOL = [ { id: 'avatar1', emoji: 'πŸ‘¨πŸ»' }, { id: 'avatar2', emoji: 'πŸ‘¨πŸΌ' }, { id: 'avatar3', emoji: 'πŸ‘¨πŸ½' }, { id: 'avatar4', emoji: 'πŸ‘¨πŸΎ' }, { id: 'avatar5', emoji: 'πŸ‘©πŸ»' }, { id: 'avatar6', emoji: 'πŸ‘©πŸΌ' }, { id: 'avatar7', emoji: 'πŸ‘©πŸ½' }, { id: 'avatar8', emoji: 'πŸ‘©πŸΎ' }, { id: 'avatar9', emoji: 'πŸ§”πŸ»' }, { id: 'avatar10', emoji: 'πŸ§”πŸΌ' }, { id: 'avatar11', emoji: 'πŸ§”πŸ½' }, { id: 'avatar12', emoji: 'πŸ§”πŸΎ' }, { id: 'avatar13', emoji: 'πŸ‘³πŸ»β€β™‚οΈ' }, { id: 'avatar14', emoji: 'πŸ‘³πŸΌβ€β™‚οΈ' }, { id: 'avatar15', emoji: 'πŸ‘³πŸ½β€β™‚οΈ' }, { id: 'avatar16', emoji: 'πŸ§•πŸ»' }, { id: 'avatar17', emoji: 'πŸ§•πŸΌ' }, { id: 'avatar18', emoji: 'πŸ§•πŸ½' }, ]; const getEmojiFromAvatarId = (id: string) => AVATAR_POOL.find(a => a.id === id)?.emoji ?? 'πŸ‘€'; // ── App sections (mirrors MobileHomeLayout) ── interface AppItem { title: string; icon: string; imgIcon?: string; route: string; href?: string; comingSoon?: boolean; requiresAuth?: boolean; } interface AppSection { titleKey: string; emoji: string; headerBg: string; cardBg: string; iconBg: string; apps: AppItem[]; } const APP_SECTIONS: AppSection[] = [ { titleKey: 'mobile.section.finance', emoji: 'πŸ’°', headerBg: 'bg-gradient-to-r from-green-900/80 to-green-800/60', cardBg: 'bg-green-950/40 border border-green-700/30', iconBg: 'hover:bg-green-900/40', apps: [ { title: 'mobile.app.wallet', icon: 'πŸ‘›', route: '/wallet' }, { title: 'mobile.app.bank', icon: '🏦', route: '/finance/bank' }, { title: 'mobile.app.exchange', icon: 'πŸ’±', imgIcon: '/PezkuwiExchange.png', route: '/dex', href: 'https://pex.network' }, { title: 'mobile.app.dex', icon: 'πŸ”„', route: '/dex', requiresAuth: true }, { title: 'mobile.app.p2p', icon: '🀝', route: '/p2p', requiresAuth: true }, { title: 'mobile.app.b2b', icon: 'πŸ€–', route: '/bereketli', requiresAuth: true }, { title: 'mobile.app.bacZekat', icon: 'πŸ’°', route: '/finance/zekat' }, { title: 'mobile.app.launchpad', icon: 'πŸš€', route: '/launchpad' }, ], }, { titleKey: 'mobile.section.governance', emoji: 'πŸ›οΈ', headerBg: 'bg-gradient-to-r from-red-900/80 to-red-800/60', cardBg: 'bg-red-950/40 border border-red-700/30', iconBg: 'hover:bg-red-900/40', apps: [ { title: 'mobile.app.president', icon: 'πŸ‘‘', route: '/elections', requiresAuth: true }, { title: 'mobile.app.assembly', icon: 'πŸ›οΈ', route: '/governance/assembly' }, { title: 'mobile.app.vote', icon: 'πŸ—³οΈ', route: '/elections', requiresAuth: true }, { title: 'mobile.app.validators',icon: 'πŸ›‘οΈ', route: '/wallet' }, { title: 'mobile.app.justice', icon: 'βš–οΈ', route: '/governance/justice' }, { title: 'mobile.app.proposals', icon: 'πŸ“œ', route: '/citizens/government' }, { title: 'mobile.app.polls', icon: 'πŸ“Š', route: '/governance/polls' }, { title: 'mobile.app.identity', icon: 'πŸ†”', route: '/identity' }, ], }, { titleKey: 'mobile.section.social', emoji: 'πŸ’¬', headerBg: 'bg-gradient-to-r from-blue-900/80 to-blue-800/60', cardBg: 'bg-blue-950/40 border border-blue-700/30', iconBg: 'hover:bg-blue-900/40', apps: [ { title: 'mobile.app.whatsKurd', icon: 'πŸ’¬', route: '/social/whatskurd' }, { title: 'mobile.app.forum', icon: 'πŸ“°', route: '/forum' }, { title: 'mobile.app.kurdMedia', icon: 'πŸ“Ί', route: '/social/kurdmedia' }, { title: 'mobile.app.events', icon: 'πŸ“…', route: '/forum', comingSoon: true }, { title: 'mobile.app.help', icon: '❓', route: '/help' }, { title: 'mobile.app.music', icon: '🎡', route: '/forum', comingSoon: true }, { title: 'mobile.app.rewshenbir',icon: 'πŸ“‘', imgIcon: '/rewshenbir-icon.png', route: '/rewshenbir', href: 'https://rewshenbir.pezkuwi.app' }, { title: 'mobile.app.referral', icon: 'πŸ‘₯', route: '/dashboard', requiresAuth: true }, ], }, { titleKey: 'mobile.section.education', emoji: 'πŸ“š', headerBg: 'bg-gradient-to-r from-amber-900/80 to-amber-800/60', cardBg: 'bg-amber-950/40 border border-amber-700/30', iconBg: 'hover:bg-amber-900/40', apps: [ { title: 'mobile.app.university', icon: 'πŸŽ“', route: '/education/university' }, { title: 'mobile.app.perwerde', icon: 'πŸ“–', route: '/education', requiresAuth: true }, { title: 'mobile.app.certificates', icon: 'πŸ†', route: '/education/certificates' }, { title: 'mobile.app.research', icon: 'πŸ”¬', route: '/education/research' }, ], }, ]; const AppLayout: React.FC = () => { const navigate = useNavigate(); const location = useLocation(); const { user, signOut } = useAuth(); const { peopleApi, isPeopleReady, selectedAccount } = usePezkuwi(); const [showProposalWizard, setShowProposalWizard] = useState(false); const [showDelegation, setShowDelegation] = useState(false); const [showForum, setShowForum] = useState(false); const [showModeration, setShowModeration] = useState(false); const [showTreasury, setShowTreasury] = useState(false); const [treasuryTab, setTreasuryTab] = useState('overview'); const [showStaking, setShowStaking] = useState(false); const [showMultiSig, setShowMultiSig] = useState(false); const [showDEX, setShowDEX] = useState(false); const [showEducation, setShowEducation] = useState(false); const [showP2P, setShowP2P] = useState(false); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const [openMenu, setOpenMenu] = useState(null); const navRef = useRef(null); const { t } = useTranslation(); const { isConnected } = useWebSocket(); useWallet(); const isMobile = useIsMobile(); const [, _setIsAdmin] = useState(false); // Score / profile state for desktop home const [profileData, setProfileData] = useState<{ full_name?: string | null; avatar_url?: string | null; created_at?: string; } | null>(null); const [tikis, setTikis] = useState([]); const [scores, setScores] = useState({ trustScore: 0, referralScore: 0, stakingScore: 0, tikiScore: 0, totalScore: 0, }); const [kycStatus, setKycStatus] = useState('NotStarted'); const [citizenId, setCitizenId] = useState(null); const [loadingScores, setLoadingScores] = useState(false); useEffect(() => { if (!openMenu) return; const handler = (e: MouseEvent) => { if (navRef.current && !navRef.current.contains(e.target as Node)) setOpenMenu(null); }; document.addEventListener('mousedown', handler); return () => document.removeEventListener('mousedown', handler); }, [openMenu]); React.useEffect(() => { _setIsAdmin(false); }, [user]); const fetchProfile = useCallback(async () => { if (!user) return; try { const { data } = await supabase.from('profiles').select('*').eq('id', user.id).maybeSingle(); if (data) setProfileData(data); } catch { /* best-effort */ } }, [user]); const fetchBlockchainData = useCallback(async () => { if (!selectedAccount || !peopleApi || !isPeopleReady) return; setLoadingScores(true); try { const [userTikis, allScores, status] = await Promise.all([ fetchUserTikis(peopleApi, selectedAccount.address), getAllScores(peopleApi, selectedAccount.address), getKycStatus(peopleApi, selectedAccount.address), ]); setTikis(userTikis); setScores(allScores); setKycStatus(status); if (userTikis.includes('Welati')) { const nft = await getCitizenNFTDetails(peopleApi, selectedAccount.address); if (nft) { const sixDigit = generateCitizenNumber(selectedAccount.address, nft.collectionId, nft.itemId); setCitizenId(`#${nft.collectionId}-${nft.itemId}-${sixDigit}`); } } } catch { /* best-effort */ } finally { setLoadingScores(false); } }, [selectedAccount, peopleApi, isPeopleReady]); useEffect(() => { fetchProfile(); }, [fetchProfile]); useEffect(() => { if (selectedAccount && peopleApi && isPeopleReady) fetchBlockchainData(); }, [fetchBlockchainData, selectedAccount, peopleApi, isPeopleReady]); const primaryRole = tikis.length > 0 ? getPrimaryRole(tikis) : 'Visitor'; const displayName = profileData?.full_name || user?.email?.split('@')[0] || 'Heval'; const memberSince = profileData?.created_at ? new Date(profileData.created_at).toLocaleDateString('en-US', { month: 'short', year: 'numeric' }) : user?.created_at ? new Date(user.created_at).toLocaleDateString('en-US', { month: 'short', year: 'numeric' }) : 'N/A'; const avatarEmoji = profileData?.avatar_url && !profileData.avatar_url.startsWith('http') ? getEmojiFromAvatarId(profileData.avatar_url) : 'πŸ‘€'; const isFeaturePanelOpen = showDEX || showProposalWizard || showDelegation || showForum || showModeration || showTreasury || showStaking || showMultiSig || showEducation || showP2P; const currentTab = location.pathname === '/be-citizen' ? 'citizen' : location.pathname === '/dashboard' ? 'referral' : 'home'; if (isMobile && !isFeaturePanelOpen) return ; if (!user) return ; // Desktop click handler β€” maps routes to panel opens where applicable const getAppClickHandler = (app: AppItem) => { if (app.comingSoon) return () => {}; if (app.requiresAuth && !user) return () => navigate('/login'); if (app.href) return () => window.open(app.href, '_blank', 'noopener,noreferrer'); switch (app.route) { case '/dex': return () => setShowDEX(true); case '/p2p': return () => { setShowP2P(true); navigate('/p2p'); }; default: return () => navigate(app.route); } }; // Extra items added to the governance card on desktop const govExtras = [ { title: 'governance.delegation', icon: '🀝', onAction: () => setShowDelegation(true) }, { title: 'nav.forum', icon: 'πŸ“°', onAction: () => setShowForum(true) }, { title: 'nav.treasury', icon: 'πŸ’°', onAction: () => { setShowTreasury(true); setTreasuryTab('overview'); } }, { title: 'nav.moderation', icon: 'πŸ›‘οΈ', onAction: () => setShowModeration(true) }, ]; const closeAllPanels = () => { setShowDEX(false); setShowProposalWizard(false); setShowDelegation(false); setShowForum(false); setShowModeration(false); setShowTreasury(false); setShowStaking(false); setShowMultiSig(false); setShowEducation(false); setShowP2P(false); }; return (
{/* ── NAVIGATION ── */} {/* ── MOBILE MENU PANEL ── */} {mobileMenuOpen && (
setMobileMenuOpen(false)} />
{user ? ( <>
{t('nav.governance')}
{t('nav.trading')}
) : ( <> )}
)} {/* ── MAIN CONTENT ── */}
{showDEX ? (
) : showProposalWizard ? (
{ if (import.meta.env.DEV) console.log('Proposal:', p); setShowProposalWizard(false); }} onCancel={() => setShowProposalWizard(false)} />
) : showDelegation ? (
) : showForum ? (
) : showModeration ? (
) : showTreasury ? (

{t('treasury.title', 'Treasury Management')}

{t('treasury.subtitle', 'Track funds, submit proposals, and manage community resources')}

{t('treasury.overview', 'Overview')} {t('treasury.proposals', 'Funding Proposals')} {t('treasury.history', 'Spending History')} {t('treasury.approvals', 'Multi-Sig Approvals')}
) : showStaking ? (

{t('staking.title')}

{t('staking.subtitle')}

) : showMultiSig ? (

{t('multiSig.title')}

{t('multiSig.subtitle')}

) : showEducation ? (
) : showP2P ? (
) : ( /* ── LOGGED-IN DESKTOP HOME ── */ <>
{/* Greeting row */}
{avatarEmoji}

{t('mobile.greeting', 'Rojbaş')}, {displayName}

{getTikiEmoji(primaryRole)} {getTikiDisplayName(primaryRole)}
{/* Score cards (horizontal scroll) */}
navigate('/dashboard')} /> navigate('/be-citizen') : undefined} />
{/* Section cards β€” 2-column grid */}
{APP_SECTIONS.map((section, sectionIdx) => (
{/* Colored header */}

{section.emoji} {t(section.titleKey)}

{section.apps.length + (sectionIdx === 1 ? govExtras.length : 0)} apps
{/* App icon grid */}
{section.apps.map((app) => { const needsLogin = app.requiresAuth && !user; return ( ); })} {/* Governance extras: Delegation / Forum / Treasury / Moderation */} {sectionIdx === 1 && govExtras.map((ex) => ( ))}
))}
)} {/* Back-to-home button */} {isFeaturePanelOpen && (
)}
{/* ── BOTTOM TAB BAR ── */}
navigate('/')} /> navigate('/be-citizen')} accent /> navigate('/dashboard')} />
{/* ── FOOTER ── */}
); }; // ── BottomTabBtn (identical to MobileHomeLayout's TabButton) ── function BottomTabBtn({ icon, label, active, onClick, accent }: { icon: string; label: string; active: boolean; onClick: () => void; accent?: boolean; }) { return ( ); } // ── DesktopScoreCard ── function DesktopScoreCard({ icon, label, value, sub, color, onClick, actionLabel }: { icon: string; label: string; value: string; sub?: string; color: string; onClick?: () => void; actionLabel?: string; }) { return (
{icon}

{label}

{value}

{sub &&

{sub}

} {actionLabel && ( )}
); } export default AppLayout;