SIWE auth, API proxy fixes, dashboard, login, usage pages

- SIWE auth flow: challenge/login/logout/me API routes + JWT middleware
- Fixed [...path] catch-all: Kubo proxy with matchRoute() + mapToKuboAPI()
- Fixed session_id → nonce field mismatch in AuthProvider
- Fixed dashboard pins crash: Kubo returns {Keys: {...}}, not array
- Added middleware route guard (307 redirect to /login)
- Added login, register, profile, usage, upload pages
- Added dashboard components (StorageGauge, FreeTierProgress)
- Added SWR hooks + AuthGuard + Providers + Toast/ErrorBoundary
- Added payment integration (smart contract ABI, tiers, tokens)
- Fixed IPNS key listing: Name/Id → name/id mapping
- Added PWA support (manifest, service worker, icons)
- Added tests for helpers, limits, search-index, wallet
This commit is contained in:
maikrolf
2026-06-28 18:31:05 +02:00
parent 1ddc89479c
commit c9432a16ba
84 changed files with 6679 additions and 1426 deletions
+9 -7
View File
@@ -2,6 +2,7 @@
import { useState } from 'react';
import { getSettings, saveSettings, resetSettings, type PortalSettings } from '@/lib/storage';
import { useTheme } from '@/lib/theme';
import PortalLayout from '@/app/layout-portal';
import {
Settings, Globe, Server, HardDrive, RefreshCw,
@@ -18,6 +19,7 @@ function formatStorageMB(mb: number): string {
/* ════════════════════════════ Page ════════════════════════════ */
export default function SettingsPage() {
const { setTheme: applyTheme } = useTheme();
const [form, setForm] = useState<PortalSettings>(() => getSettings());
const [original, setOriginal] = useState<PortalSettings>(() => getSettings());
const [saved, setSaved] = useState(false);
@@ -228,23 +230,23 @@ export default function SettingsPage() {
<div>
<label className="text-xs text-surface-400 mb-2 block">Appearance</label>
<div className="flex gap-2">
{(['dark', 'light'] as const).map(theme => (
{(['dark', 'light'] as const).map(t => (
<button
key={theme}
onClick={() => update('theme', theme)}
key={t}
onClick={() => { update('theme', t); applyTheme(t); }}
className={`flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-medium transition-colors ${
form.theme === theme
form.theme === t
? 'bg-brand-500/20 text-brand-400 border border-brand-500/30'
: 'bg-surface-900 text-surface-400 border border-surface-700 hover:border-surface-500'
}`}
>
{theme === 'dark' ? <Moon className="w-4 h-4" /> : <Sun className="w-4 h-4" />}
{theme.charAt(0).toUpperCase() + theme.slice(1)}
{t === 'dark' ? <Moon className="w-4 h-4" /> : <Sun className="w-4 h-4" />}
{t.charAt(0).toUpperCase() + t.slice(1)}
</button>
))}
</div>
<p className="mt-1.5 text-[11px] text-surface-500">
Theme preference is saved but only affects new sessions. Full theme switching coming soon.
Theme wordt direct toegepast en opgeslagen in je browser.
</p>
</div>
),