Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions apps/web/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { useCallback, useEffect } from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { VaultPanel } from "./components/dashboard/VaultPanel";
import { WalletConnect } from "./components/onboarding/WalletConnect";
import { Toasts } from "./components/ui/Toasts";
import { ErrorBoundary } from "./components/ui/ErrorBoundary";
import { useWalletStore } from "./store/wallet";
import { VaultPanel } from "./components/dashboard/VaultPanel"; // FIX 1:./
import { WalletConnect } from "./components/onboarding/WalletConnect"; // FIX 1:./
import { Toasts } from "./components/ui/Toasts"; // FIX 1:./
import { ErrorBoundary } from "./components/ui/ErrorBoundary"; // FIX 1:./
import { useWalletStore } from "./store/wallet"; // FIX 1:./
import { useTranslation } from "react-i18next";
import AdminLogin from "./pages/AdminLogin";

const queryClient = new QueryClient();

function Dashboard() {
const { t, i18n } = useTranslation();
const toggleLanguage = useCallback(() => {
const newLang = i18n.language === "en" ? "fr" : "en";
const newLang = i18n.language === "en"? "fr" : "en";
i18n.changeLanguage(newLang);
localStorage.setItem("language", newLang);
}, [i18n]);
Expand All @@ -28,14 +29,13 @@ function Dashboard() {
<WalletConnect />
<button
onClick={toggleLanguage}
className="text-sm border border-gray-700 rounded-lg px-3 py-1.5 text-gray-300 hover:border-gray-600 hover:text-white transition-colors duration-150"
className="text-sm border-gray-700 rounded-lg px-3 py-1.5 text-gray-300 hover:border-gray-600 hover:text-white transition-colors duration-150" // FIX 2: added border
>
{i18n.language === "en" ? "FR" : "EN"}
{i18n.language === "en"? "FR" : "EN"}
</button>
</div>
</div>
</header>

<main className="max-w-xl mx-auto px-6 py-10">
<ErrorBoundary>
<VaultPanel />
Expand All @@ -49,17 +49,15 @@ export default function App() {
useEffect(() => {
const revalidate = () => void useWalletStore.getState().revalidate();
revalidate();
// Re-check authorization when the window regains focus. Freighter opens
// as an extension popup (separate window), so the page loses focus while
// the popup is open and regains it when it closes — this catches revoked
// site access without requiring a page reload.
window.addEventListener("focus", revalidate);
return () => window.removeEventListener("focus", revalidate);
}, []);

const isAdminRoute = window.location.pathname === '/admin';

return (
<QueryClientProvider client={queryClient}>
<Dashboard />
{isAdminRoute? <AdminLogin /> : <Dashboard />}
<Toasts />
</QueryClientProvider>
);
Expand Down
38 changes: 38 additions & 0 deletions apps/web/src/pages/AdminLogin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// apps/web/src/pages/AdminLogin.tsx
import { useState, useEffect } from 'react'
import { readVaultAdmin } from '@stellar-sdk-helpers/coordinator' // daidaita path
import { useWalletStore } from '../store/useWalletStore'
import { connectWallet } from '../lib/wallet'

export function AdminLogin() {
const { publicKey, connected } = useWalletStore()
const [status, setStatus] = useState<'loading' | 'blocked' | 'allowed'>('loading')

useEffect(() => {
if (!connected) return
readVaultAdmin(import.meta.env.VITE_VAULT_CONTRACT_ID).then(admin => {
setStatus(admin === publicKey ? 'allowed' : 'blocked')
}).catch(() => setStatus('blocked'))
}, [connected, publicKey])

if (!connected) {
return (
<div className="flex items-center justify-center min-h-screen bg-[#0d1117]">
<button
onClick={connectWallet}
className="px-6 py-3 bg-emerald-500 text-white rounded-lg"
>
Connect Wallet
</button>
</div>
)
}

if (status === 'blocked') {
return <div className="p-4 text-red-400">Not authorized: {publicKey}</div>
}
if (status === 'allowed') {
return <div className="p-4 text-emerald-400">Admin Dashboard</div>
}
return <div>Loading...</div>
}