diff --git a/web/src/App.tsx b/web/src/App.tsx index 9d851330..4e62cb72 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -69,6 +69,7 @@ const BankPage = lazy(() => import('@/pages/finance/BankPage')); const AssemblyPage = lazy(() => import('@/pages/governance/AssemblyPage')); const JusticePage = lazy(() => import('@/pages/governance/JusticePage')); const PollsPage = lazy(() => import('@/pages/governance/PollsPage')); +const WhatsKURDPage = lazy(() => import('@/pages/social/WhatsKURDPage')); // Network pages const Mainnet = lazy(() => import('@/pages/networks/Mainnet')); @@ -236,6 +237,7 @@ function App() { } /> } /> } /> + } /> } /> } /> } /> diff --git a/web/src/components/MobileHomeLayout.tsx b/web/src/components/MobileHomeLayout.tsx index d999d89f..7439b29a 100644 --- a/web/src/components/MobileHomeLayout.tsx +++ b/web/src/components/MobileHomeLayout.tsx @@ -81,7 +81,7 @@ const APP_SECTIONS: AppSection[] = [ emoji: '๐Ÿ’ฌ', borderColor: 'border-l-blue-500', apps: [ - { title: 'mobile.app.whatsKurd', icon: '๐Ÿ’ฌ', route: '/message', comingSoon: true }, + { title: 'mobile.app.whatsKurd', icon: '๐Ÿ’ฌ', route: '/social/whatskurd' }, { title: 'mobile.app.forum', icon: '๐Ÿ“ฐ', route: '/forum' }, { title: 'mobile.app.kurdMedia', icon: '๐Ÿ“บ', route: '/forum', comingSoon: true }, { title: 'mobile.app.events', icon: '๐Ÿ“…', route: '/forum', comingSoon: true }, diff --git a/web/src/pages/social/WhatsKURDPage.tsx b/web/src/pages/social/WhatsKURDPage.tsx new file mode 100644 index 00000000..5e71f33f --- /dev/null +++ b/web/src/pages/social/WhatsKURDPage.tsx @@ -0,0 +1,187 @@ +import { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { usePezkuwi } from '@/contexts/PezkuwiContext'; +import { useMessaging } from '@/hooks/useMessaging'; +import { KeySetup } from '@/components/messaging/KeySetup'; +import { InboxMessage } from '@/components/messaging/InboxMessage'; +import { ComposeDialog } from '@/components/messaging/ComposeDialog'; +import { Loader2 } from 'lucide-react'; + +export default function WhatsKURDPage() { + const navigate = useNavigate(); + const { t } = useTranslation(); + const { peopleApi, isPeopleReady, selectedAccount } = usePezkuwi(); + + const { + palletReady, + isKeyRegistered, + isKeyUnlocked, + decryptedMessages, + era, + sendCount, + loading, + sending, + registering, + setupKey, + unlockKey, + sendMessage, + refreshInbox, + } = useMessaging(); + + const [composeOpen, setComposeOpen] = useState(false); + const [currentBlock, setCurrentBlock] = useState(0); + + useEffect(() => { + if (!peopleApi || !isPeopleReady) return; + let unsub: (() => void) | undefined; + const subscribe = async () => { + try { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + unsub = await (peopleApi.rpc.chain as any).subscribeNewHeads( + (header: { number: { toNumber: () => number } }) => { + setCurrentBlock(header.number.toNumber()); + } + ); + } catch { + try { + const header = await peopleApi.rpc.chain.getHeader(); + setCurrentBlock(header.number.toNumber()); + } catch { /* ignore */ } + } + }; + subscribe(); + return () => { unsub?.(); }; + }, [peopleApi, isPeopleReady]); + + const canCompose = isKeyRegistered && isKeyUnlocked && palletReady; + + return ( +
+ {/* Header */} +
+
+ + {t('mobile.section.social', 'Social')} +
+
+
+

๐Ÿ’ฌ whatsKURD

+

{t('messaging.title', 'Encrypted Messenger')}

+
+ +
+ + {/* Era / stats */} + {selectedAccount && ( +
+ Era {era} + ยท + {decryptedMessages.length} {t('messaging.messages', 'messages')} + ยท + {sendCount}/50 {t('messaging.sent', 'sent')} +
+ )} +
+ +
+ + {/* No wallet */} + {!selectedAccount && ( +
+ ๐Ÿ‘› +

{t('messaging.connectWallet', 'Connect Wallet')}

+

{t('messaging.connectWalletDesc', 'Connect your wallet to use encrypted messaging.')}

+
+ )} + + {/* API loading */} + {selectedAccount && !isPeopleReady && ( +
+ +
+ )} + + {selectedAccount && isPeopleReady && ( + <> + {/* Pallet not ready */} + {!loading && !palletReady && ( +
+ โš ๏ธ +

+ {t('messaging.palletNotReady', 'Messaging pallet is not yet available on People Chain. A runtime upgrade is required.')} +

+
+ )} + + {/* Key setup */} + {palletReady && ( + + )} + + {/* Inbox */} + {loading ? ( +
+ +
+ ) : decryptedMessages.length === 0 ? ( +
+ ๐Ÿ“ญ +

{t('messaging.emptyInbox', 'No messages yet.')}

+ {canCompose && ( + + )} +
+ ) : ( +
+ {decryptedMessages.map((msg, i) => ( + + ))} +
+ )} + + )} +
+ + {/* FAB โ€” compose button */} + {canCompose && ( + + )} + + + +
+
+ ); +}