feat: wire frontend pages to tRPC APIs

- Add hooks (useAuth, useSubscription, useNotifications) for real API data
- Add auth service (login/signup) with password hashing and session support
- Replace stub auth with real tRPC calls in login/signup/onboarding pages
- Replace mock dashboard data with real API data from hooks
- Create service pages: DarkWatch, VoicePrint, SpamShield, HomeTitle, RemoveBrokers, Settings
- Update Navbar, TopBar, Sidebar with real user data and correct routes
- Add passwordHash field to users schema for credential auth
- Fix tests to work with real hooks (mock tRPC/hooks)
This commit is contained in:
2026-05-25 17:34:48 -04:00
parent eb8e57c674
commit 7cbcde6a6b
46 changed files with 2418 additions and 418 deletions

View File

@@ -0,0 +1,65 @@
import { createSignal, createResource } from "solid-js";
import { Title } from "@solidjs/meta";
import { Sidebar, TopBar } from "~/components/dashboard";
import { Button, Card, Input } from "~/components/ui";
import { useAuth, useSubscription } from "~/hooks";
import { api } from "~/lib/api";
export default function SettingsPage() {
const [sidebarOpen, setSidebarOpen] = createSignal(false);
const auth = useAuth();
const subscription = useSubscription();
const [name, setName] = createSignal(auth.user()?.name ?? "");
const [saving, setSaving] = createSignal(false);
async function saveProfile() {
setSaving(true);
try {
await api.user.update.mutate({ name: name() });
} finally {
setSaving(false);
}
}
return (
<div class="flex h-[calc(100vh-4rem)] bg-[var(--color-bg)]">
<Title>Settings ShieldAI</Title>
<Sidebar open={sidebarOpen()} onClose={() => setSidebarOpen(false)} />
<div class="flex-1 flex flex-col min-w-0">
<TopBar onMenuToggle={() => setSidebarOpen(v => !v)} />
<main class="flex-1 overflow-y-auto p-6">
<div class="max-w-2xl mx-auto">
<h1 class="text-2xl font-bold text-[var(--color-text-primary)] mb-6">Settings</h1>
<Card class="mb-6 p-4">
<h2 class="text-sm font-semibold text-[var(--color-text-primary)] mb-4">Profile</h2>
<div class="flex flex-col gap-4">
<Input
label="Name"
value={name()}
onInput={(e) => setName(e.currentTarget.value)}
/>
<Input
label="Email"
value={auth.user()?.email ?? ""}
disabled
/>
<Button onClick={saveProfile} loading={saving()}>
Save
</Button>
</div>
</Card>
<Card class="p-4">
<h2 class="text-sm font-semibold text-[var(--color-text-primary)] mb-4">Subscription</h2>
<p class="text-sm text-[var(--color-text-secondary)] mb-1">Current Plan</p>
<p class="text-lg font-semibold text-[var(--color-text-primary)]">
{(subscription.tier().charAt(0).toUpperCase() + subscription.tier().slice(1)) || "Free"}
</p>
</Card>
</div>
</main>
</div>
</div>
);
}