import { render } from "solid-js/web"; import { Router, Route, useLocation, useNavigate, type RouteSectionProps } from "@solidjs/router"; import { createResource, createSignal, createEffect, Show } from "solid-js"; import { WatchlistDrawer, ChatSidebar } from "./components/WatchlistChat"; import { ThemeToggle, useAuth, AuthButton, ButuhLogin } from "./components/auth"; import { Button } from "./components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./components/ui/card"; import { TextField, TextFieldInput } from "./components/ui/text-field"; import { api, AUTH_EXPIRED_EVENT } from "./lib/api"; import Dashboard from "./pages/Dashboard"; import Routines from "./pages/Routines"; import Screener from "./pages/Screener"; import Alerts from "./pages/Alerts"; import Report from "./pages/Report"; import Portfolio from "./pages/Portfolio"; import "./styles/globals.css"; const NAV_ALL = [ { href: "/", icon: "πŸ“Š", label: "Dashboard" }, { href: "/routines", icon: "πŸ—“οΈ", label: "Routines" }, { href: "/screener", icon: "πŸ”", label: "Screener" }, { href: "/alerts", icon: "πŸ””", label: "Alerts" }, { href: "/portfolio", icon: "πŸ’Ό", label: "Portfolio" }, ]; function Nav(props: { loggedIn: boolean }) { const loc = useLocation(); // Belum login: hanya Dashboard yg terlihat (fitur lain di-hide). const items = () => props.loggedIn ? NAV_ALL : NAV_ALL.slice(0, 1); return ( ); } function MobileNav(props: { loggedIn: boolean }) { const loc = useLocation(); const items = () => props.loggedIn ? NAV_ALL : NAV_ALL.slice(0, 1); return ( ); } function TickerSearch(props: { loggedIn: boolean }) { const nav = useNavigate(); const [q, setQ] = createSignal(""); const go = () => { const t = q().toUpperCase().trim(); // Report butuh login: arahkan yg belum login ke /login. if (t) nav(props.loggedIn ? `/report/${t}` : "/login"); }; return (
{ e.preventDefault(); go(); }}> setQ(e.currentTarget.value)} />
); } function LoginPage() { const err = () => new URLSearchParams(window.location.search).get("error"); const [mode, setMode] = createSignal<"masuk" | "daftar">("masuk"); const [username, setUsername] = createSignal(""); const [password, setPassword] = createSignal(""); const [busy, setBusy] = createSignal(false); const [formErr, setFormErr] = createSignal(""); const [version] = createResource(() => api.version().catch(() => null)); async function submit(e: Event) { e.preventDefault(); setFormErr(""); setBusy(true); try { if (mode() === "daftar") await api.signup(username().trim(), password()); else await api.login(username().trim(), password()); window.location.href = "/"; } catch (e2) { setFormErr(String(e2)); } finally { setBusy(false); } } return (
Masuk ke FlowSight πŸ‘‹ Daftar gratis pakai username + password β€” watchlist, notifikasi, dan report jadi milik kamu sendiri.

Login gagal: {err()}

setUsername(e.currentTarget.value)} autocomplete="username" /> setPassword(e.currentTarget.value)} autocomplete={mode() === "daftar" ? "new-password" : "current-password"} />

{formErr()}

); } function Shell(props: RouteSectionProps) { const { me, refetch } = useAuth(); const nav = useNavigate(); // Any 401 on a gated API while logged in β†’ session expired; go to login. createEffect(() => { const h = () => { if (me()) { refetch(); nav("/login"); } }; window.addEventListener(AUTH_EXPIRED_EVENT, h); return () => window.removeEventListener(AUTH_EXPIRED_EVENT, h); }); const logout = async () => { try { await api.logout(); } catch { /* server gone β€” clear locally anyway */ } refetch(); nav("/"); }; return (
); } // Gate: bungkus halaman fitur β€” belum login tampilkan ButuhLogin. export function Gate(props: { fitur: string; children: import("solid-js").JSX.Element }) { const { me } = useAuth(); return ( Memeriksa login…

}> }> {props.children}
); } render( () => ( ), document.getElementById("root")!, );