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

@@ -1,26 +1,85 @@
import { MetaProvider, Title } from "@solidjs/meta";
import { Router } from "@solidjs/router";
import { Router, useLocation, Navigate } from "@solidjs/router";
import { FileRoutes } from "@solidjs/start/router";
import { Suspense } from "solid-js";
import { Show, Suspense } from "solid-js";
import { ThemeProvider } from "./lib/theme";
import { ClerkProvider } from "clerk-solidjs/start";
import { ClerkLoaded, ClerkLoading, useAuth } from "clerk-solidjs";
import { AppShell } from "./components/layout";
import { ToastProvider } from "./components/ui";
import "./app.css";
const PROTECTED_PATHS = ["/dashboard", "/onboarding"];
function pathMatches(pathname: string, prefixes: string[]): boolean {
return prefixes.some(
(p) => pathname === p || pathname.startsWith(p + "/"),
);
}
function RouteGuard() {
const location = useLocation();
const auth = useAuth();
const redirect = () => {
const pathname = location.pathname;
if (
auth.isLoaded() &&
!auth.isSignedIn() &&
pathMatches(pathname, PROTECTED_PATHS)
) {
return "/login";
}
return undefined;
};
return (
<Show when={redirect()} keyed>
{(to) => <Navigate href={to} />}
</Show>
);
}
function ClerkApp(props: { children: any }) {
return (
<ClerkProvider
publishableKey={import.meta.env.VITE_CLERK_PUBLISHABLE_KEY}
>
<Suspense>
<ClerkLoaded>
<RouteGuard />
</ClerkLoaded>
<ClerkLoading>
<div class="h-16 animate-pulse bg-[var(--color-bg-secondary)]" />
</ClerkLoading>
</Suspense>
<Suspense>{props.children}</Suspense>
</ClerkProvider>
);
}
export default function App() {
return (
<ThemeProvider>
<ToastProvider>
<Router
root={(props) => (
<AppShell>
<Suspense>{props.children}</Suspense>
</AppShell>
)}
>
<FileRoutes />
</Router>
</ToastProvider>
</ThemeProvider>
<MetaProvider>
<Title>ShieldAI</Title>
<ThemeProvider>
<ToastProvider>
<Router
root={(props) => (
<ClerkApp>
<AppShell>
<Suspense>{props.children}</Suspense>
</AppShell>
</ClerkApp>
)}
>
<FileRoutes />
</Router>
</ToastProvider>
</ThemeProvider>
</MetaProvider>
);
}