Update components (CaptchaCanvas, DashboardLayout, MyDashboardPage, PortfolioPage, ProfilePage), form-validation, routes (dashboard, login, signup), app.css, add e2e tests and helpers, add manual test files and config
2026-05-08 15:34:49 +02:00
|
|
|
import { type ParentProps, createMemo, createSignal, onMount } from "solid-js";
|
2026-04-10 20:20:00 +02:00
|
|
|
import { useLocation, useNavigate } from "@solidjs/router";
|
|
|
|
|
import DashboardShell from "~/components/DashboardShell";
|
|
|
|
|
|
|
|
|
|
const SIDEBAR_ITEMS = [
|
|
|
|
|
"My Dashboard",
|
|
|
|
|
"Leads",
|
|
|
|
|
"My Requests",
|
|
|
|
|
"Credits",
|
|
|
|
|
"Settings",
|
|
|
|
|
"Logout",
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const ROUTE_BY_LABEL: Record<string, string> = {
|
|
|
|
|
"my dashboard": "/dashboard",
|
|
|
|
|
leads: "/dashboard/leads",
|
|
|
|
|
"my requests": "/dashboard/requests",
|
|
|
|
|
credits: "/dashboard/credits",
|
|
|
|
|
settings: "/dashboard/settings",
|
|
|
|
|
logout: "/dashboard/logout",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function readUserName() {
|
|
|
|
|
if (typeof window === "undefined") return "User";
|
|
|
|
|
try {
|
|
|
|
|
const raw =
|
|
|
|
|
localStorage.getItem("nxtgauge_auth_user") ||
|
|
|
|
|
localStorage.getItem("nxtgauge_user");
|
|
|
|
|
if (!raw) return "User";
|
|
|
|
|
const parsed = JSON.parse(raw);
|
|
|
|
|
return parsed?.full_name || parsed?.name || parsed?.email || "User";
|
|
|
|
|
} catch {
|
|
|
|
|
return "User";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default function DashboardLayout(props: ParentProps) {
|
|
|
|
|
const location = useLocation();
|
|
|
|
|
const navigate = useNavigate();
|
Update components (CaptchaCanvas, DashboardLayout, MyDashboardPage, PortfolioPage, ProfilePage), form-validation, routes (dashboard, login, signup), app.css, add e2e tests and helpers, add manual test files and config
2026-05-08 15:34:49 +02:00
|
|
|
const [roleKey, setRoleKey] = createSignal("DEVELOPER");
|
|
|
|
|
const [userName, setUserName] = createSignal("User");
|
2026-04-10 20:20:00 +02:00
|
|
|
|
|
|
|
|
const activeSidebar = createMemo(() => {
|
|
|
|
|
const path = location.pathname || "";
|
|
|
|
|
if (path.startsWith("/dashboard/requests")) return "My Requests";
|
|
|
|
|
if (path.startsWith("/dashboard/leads")) return "Leads";
|
|
|
|
|
if (path.startsWith("/dashboard/credits")) return "Credits";
|
|
|
|
|
if (path.startsWith("/dashboard/settings")) return "Settings";
|
|
|
|
|
return "My Dashboard";
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const handleSidebarSelect = (item: string) => {
|
|
|
|
|
const target = ROUTE_BY_LABEL[item.toLowerCase()];
|
|
|
|
|
if (target) navigate(target);
|
|
|
|
|
};
|
|
|
|
|
|
Update components (CaptchaCanvas, DashboardLayout, MyDashboardPage, PortfolioPage, ProfilePage), form-validation, routes (dashboard, login, signup), app.css, add e2e tests and helpers, add manual test files and config
2026-05-08 15:34:49 +02:00
|
|
|
onMount(async () => {
|
|
|
|
|
if (typeof window === "undefined") return;
|
|
|
|
|
|
2026-04-29 09:59:41 +02:00
|
|
|
const fromUrl = new URLSearchParams(window.location.search).get("role");
|
Update components (CaptchaCanvas, DashboardLayout, MyDashboardPage, PortfolioPage, ProfilePage), form-validation, routes (dashboard, login, signup), app.css, add e2e tests and helpers, add manual test files and config
2026-05-08 15:34:49 +02:00
|
|
|
if (fromUrl && fromUrl.trim()) {
|
|
|
|
|
setRoleKey(fromUrl.trim().toUpperCase());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const storageKeys = [
|
|
|
|
|
["nxtgauge_signup_profile_v1", localStorage],
|
|
|
|
|
["nxtgauge_auth_user", localStorage],
|
|
|
|
|
["nxtgauge_user", localStorage],
|
|
|
|
|
["nxtgauge_signup_profile_v1", sessionStorage],
|
|
|
|
|
["nxtgauge_auth_user", sessionStorage],
|
|
|
|
|
["nxtgauge_user", sessionStorage],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
for (const [key, storage] of storageKeys) {
|
|
|
|
|
try {
|
|
|
|
|
const raw = storage.getItem(key);
|
|
|
|
|
if (raw) {
|
|
|
|
|
const parsed = JSON.parse(raw);
|
|
|
|
|
const candidate = String(
|
|
|
|
|
parsed?.selectedProfessionalRole || parsed?.active_role || parsed?.roleKey || parsed?.role || ""
|
|
|
|
|
)
|
|
|
|
|
.trim()
|
|
|
|
|
.toUpperCase();
|
|
|
|
|
if (candidate && candidate !== "PROFESSIONAL") {
|
|
|
|
|
setRoleKey(candidate);
|
|
|
|
|
if (parsed?.full_name || parsed?.name || parsed?.email) {
|
|
|
|
|
setUserName(parsed.full_name || parsed.name || parsed.email || "User");
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
// continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const token = sessionStorage.getItem("nxtgauge_access_token");
|
|
|
|
|
if (token) {
|
|
|
|
|
try {
|
fix: route client /api/* through /api/gateway/* proxy\n\nLogin, signup, forgot-password, dashboard, contact, help-center, and all dashboard component fetches were calling bare /api/* paths. The SolidStart server has no /api/auth/*, /api/support/*, or /api/kb/* handlers -- only /api/gateway/[...path] proxies to the Rust gateway. So those calls returned HTML (SPA catch-all), the JSON parse threw silently, and the buttons looked dead. Sign In / Sign Up / Forgot Password all appeared to be no-ops.\n\nThis routes every client-side fetch through the existing gateway proxy, matching the pattern already used by src/lib/api.ts.\n\nAlso fixes hardcoded test121 -> test111 in canonical/og:url tags across index, professionals, help-center, and RoleLandingPage.
2026-06-11 14:10:10 +05:30
|
|
|
const res = await fetch("/api/gateway/auth/session", {
|
Update components (CaptchaCanvas, DashboardLayout, MyDashboardPage, PortfolioPage, ProfilePage), form-validation, routes (dashboard, login, signup), app.css, add e2e tests and helpers, add manual test files and config
2026-05-08 15:34:49 +02:00
|
|
|
headers: {
|
|
|
|
|
Accept: "application/json",
|
|
|
|
|
Authorization: `Bearer ${token}`,
|
|
|
|
|
},
|
|
|
|
|
credentials: "include",
|
|
|
|
|
});
|
|
|
|
|
if (res.ok) {
|
|
|
|
|
const data = await res.json();
|
|
|
|
|
const role = String(data?.active_role || data?.role || "").trim().toUpperCase();
|
|
|
|
|
setRoleKey(role && role !== "PROFESSIONAL" ? role : "DEVELOPER");
|
|
|
|
|
setUserName(data?.full_name || data?.name || data?.email || "User");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
// fall through
|
|
|
|
|
}
|
2026-04-29 09:59:41 +02:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-10 20:20:00 +02:00
|
|
|
return (
|
|
|
|
|
<DashboardShell
|
|
|
|
|
sidebarItems={SIDEBAR_ITEMS}
|
|
|
|
|
activeSidebar={activeSidebar()}
|
|
|
|
|
onSidebarSelect={handleSidebarSelect}
|
2026-04-29 09:59:41 +02:00
|
|
|
roleKey={roleKey()}
|
Update components (CaptchaCanvas, DashboardLayout, MyDashboardPage, PortfolioPage, ProfilePage), form-validation, routes (dashboard, login, signup), app.css, add e2e tests and helpers, add manual test files and config
2026-05-08 15:34:49 +02:00
|
|
|
userName={userName()}
|
2026-04-10 20:20:00 +02:00
|
|
|
>
|
|
|
|
|
{props.children}
|
|
|
|
|
</DashboardShell>
|
|
|
|
|
);
|
|
|
|
|
}
|