fix: eliminate API prefix double-encoding across all dashboard components
All checks were successful
build-and-release / build (push) Successful in 1m40s

All dashboard pages and widgets had one of three bugs:
- const API = "/api" combined with paths already starting /api → double prefix
- const API = '/api/gateway' → nonexistent gateway path prefix
- cleanPath stripping /api off paths when API was set to ""

Fix: set const API = "" uniformly and remove cleanPath rewrite in all 30+
affected files (CompanyJobsPage, CompanyApplicationsPage, CreditsPage,
JobSeekerJobsPage, CustomerRequirementsPage, all widgets, etc.).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tracewebstudio Dev 2026-07-18 11:40:20 +02:00
parent 6318b445d7
commit 49b979eb16
32 changed files with 273 additions and 294 deletions

View file

@ -5,7 +5,7 @@
"name": "frontend-solid", "name": "frontend-solid",
"runtimeExecutable": "npm", "runtimeExecutable": "npm",
"runtimeArgs": ["run", "dev"], "runtimeArgs": ["run", "dev"],
"port": 3000 "port": 3001
} }
] ]
} }

View file

@ -9,7 +9,7 @@
import { For, Show, createSignal, onMount } from "solid-js"; import { For, Show, createSignal, onMount } from "solid-js";
import { BTN_GHOST, BTN_ORANGE, CARD, INPUT, LABEL } from "~/components/DashboardShell"; import { BTN_GHOST, BTN_ORANGE, CARD, INPUT, LABEL } from "~/components/DashboardShell";
const API = "/api"; const API = "";
interface JobItem { interface JobItem {
id: string; id: string;
@ -49,8 +49,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined" typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || "" ? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: ""; : "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: "include", credentials: "include",
headers: { headers: {

View file

@ -19,7 +19,7 @@ import {
LABEL, LABEL,
} from "~/components/DashboardShell"; } from "~/components/DashboardShell";
const API = "/api"; const API = "";
interface JobItem { interface JobItem {
id: string; id: string;

View file

@ -1,7 +1,7 @@
import { For, Show, createSignal, onMount } from 'solid-js'; import { For, Show, createSignal, onMount } from 'solid-js';
import { BTN_GHOST, CARD } from '~/components/DashboardShell'; import { BTN_GHOST, CARD } from '~/components/DashboardShell';
const API = '/api/gateway'; const API = '';
type JobItem = { id: string; title: string }; type JobItem = { id: string; title: string };
type ApplicationItem = { type ApplicationItem = {
@ -18,8 +18,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined" typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || "" ? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: ""; : "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: "include", credentials: "include",
headers: { headers: {

View file

@ -4,7 +4,7 @@ import { BTN_GHOST, BTN_ORANGE, BTN_PRIMARY, CARD, ORANGE, NAVY, PKG_CARD } from
import { PROFESSIONAL_ROLE_SET, ROLE_PREFIXES, type RoleKey } from "./RoleDashboardShared"; import { PROFESSIONAL_ROLE_SET, ROLE_PREFIXES, type RoleKey } from "./RoleDashboardShared";
import { openPayuCheckout, submitPayuCheckout } from "~/lib/payu"; import { openPayuCheckout, submitPayuCheckout } from "~/lib/payu";
const API = "/api"; const API = "";
type Props = { roleKey: RoleKey; dashboardConfig?: Record<string, any> | null }; type Props = { roleKey: RoleKey; dashboardConfig?: Record<string, any> | null };
@ -79,8 +79,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined" typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || "" ? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: ""; : "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: "include", credentials: "include",
headers: { headers: {
@ -421,11 +420,20 @@ export default function CreditsPage(props: Props) {
return; return;
} }
const paymentResult = await openPayuCheckout({ const paymentResult = await submitPayuCheckout({
key: orderData.key,
txnid: orderData.txnid || orderData.order_id,
amount: orderData.amount, amount: orderData.amount,
currency: orderData.currency, productinfo: orderData.productinfo,
txnId: orderData.txnid || orderData.order_id, firstname: orderData.firstname,
description: `${pkg.name} - ${pkg.tracecoins_amount} Tracecoins`, email: orderData.email,
phone: orderData.phone || "",
surl: orderData.surl,
furl: orderData.furl,
hash: orderData.hash,
payu_base_url: orderData.payu_base_url,
udf1: orderData.udf1,
udf2: orderData.udf2,
}); });
const verifyRes = await apiFetch("/api/payments/verify", { const verifyRes = await apiFetch("/api/payments/verify", {
@ -490,15 +498,8 @@ export default function CreditsPage(props: Props) {
}; };
const CheckoutModal = () => { const CheckoutModal = () => {
const state = checkout();
const pkg = state.package;
const aiPkg = state.aiCreditPackage;
if (!pkg && !aiPkg) return null;
const title = pkg ? `${pkg.tracecoins_amount} Tracecoins` : `${aiPkg!.credits} AI Credits`;
const price = pkg ? pkg.price : aiPkg!.price_inr;
return ( return (
<Show when={checkout().package || checkout().aiCreditPackage}>
<Portal> <Portal>
<div <div
style={{ style={{
@ -512,7 +513,7 @@ export default function CreditsPage(props: Props) {
padding: "20px", padding: "20px",
}} }}
onClick={(e) => { onClick={(e) => {
if (e.target === e.currentTarget && state.step !== "processing") closeCheckout(); if (e.target === e.currentTarget && checkout().step !== "processing") closeCheckout();
}} }}
> >
<div <div
@ -537,13 +538,13 @@ export default function CreditsPage(props: Props) {
<h3 <h3
style={{ margin: "0", "font-size": "18px", "font-weight": "700", color: "#111827" }} style={{ margin: "0", "font-size": "18px", "font-weight": "700", color: "#111827" }}
> >
{state.step === "success" {checkout().step === "success"
? "✓ Payment Successful" ? "✓ Payment Successful"
: state.step === "error" : checkout().step === "error"
? "Payment Failed" ? "Payment Failed"
: "Checkout"} : "Checkout"}
</h3> </h3>
<Show when={state.step !== "processing"}> <Show when={checkout().step !== "processing"}>
<button <button
onClick={closeCheckout} onClick={closeCheckout}
style={{ style={{
@ -560,7 +561,7 @@ export default function CreditsPage(props: Props) {
</div> </div>
{/* Package Summary */} {/* Package Summary */}
<Show when={state.step !== "success"}> <Show when={checkout().step !== "success"}>
<div <div
style={{ style={{
background: "#F9FAFB", background: "#F9FAFB",
@ -578,7 +579,7 @@ export default function CreditsPage(props: Props) {
color: "#111827", color: "#111827",
}} }}
> >
{pkg ? pkg.name : aiPkg?.name} {checkout().package ? checkout().package!.name : checkout().aiCreditPackage?.name}
</p> </p>
<p <p
style={{ style={{
@ -588,26 +589,26 @@ export default function CreditsPage(props: Props) {
color: "#FF5E13", color: "#FF5E13",
}} }}
> >
{formatCurrency(price)} {formatCurrency(checkout().package ? checkout().package!.price : checkout().aiCreditPackage!.price_inr)}
</p> </p>
<p style={{ margin: "8px 0 0", "font-size": "14px", color: "#15803D" }}> <p style={{ margin: "8px 0 0", "font-size": "14px", color: "#15803D" }}>
+{title} +{checkout().package ? `${checkout().package!.tracecoins_amount} Tracecoins` : `${checkout().aiCreditPackage!.credits} AI Credits`}
</p> </p>
</div> </div>
</Show> </Show>
{/* Success State */} {/* Success State */}
<Show when={state.step === "success"}> <Show when={checkout().step === "success"}>
<div style={{ "text-align": "center", padding: "20px 0" }}> <div style={{ "text-align": "center", padding: "20px 0" }}>
<div style={{ "font-size": "48px", "margin-bottom": "16px" }}>🎉</div> <div style={{ "font-size": "48px", "margin-bottom": "16px" }}>🎉</div>
<p style={{ margin: "0 0 8px", "font-size": "16px", color: "#111827" }}> <p style={{ margin: "0 0 8px", "font-size": "16px", color: "#111827" }}>
Payment successful! Payment successful!
</p> </p>
<p style={{ margin: "0 0 16px", "font-size": "14px", color: "#6B7280" }}> <p style={{ margin: "0 0 16px", "font-size": "14px", color: "#6B7280" }}>
{title} have been credited to your account. {checkout().package ? `${checkout().package!.tracecoins_amount} Tracecoins` : `${checkout().aiCreditPackage!.credits} AI Credits`} have been credited to your account.
</p> </p>
<p style={{ margin: "0", "font-size": "12px", color: "#9CA3AF" }}> <p style={{ margin: "0", "font-size": "12px", color: "#9CA3AF" }}>
Order ID: {state.orderId} Order ID: {checkout().orderId}
</p> </p>
</div> </div>
<button <button
@ -619,11 +620,11 @@ export default function CreditsPage(props: Props) {
</Show> </Show>
{/* Error State */} {/* Error State */}
<Show when={state.step === "error"}> <Show when={checkout().step === "error"}>
<div style={{ "text-align": "center", padding: "20px 0" }}> <div style={{ "text-align": "center", padding: "20px 0" }}>
<div style={{ "font-size": "48px", "margin-bottom": "16px" }}></div> <div style={{ "font-size": "48px", "margin-bottom": "16px" }}></div>
<p style={{ margin: "0 0 16px", "font-size": "14px", color: "#B91C1C" }}> <p style={{ margin: "0 0 16px", "font-size": "14px", color: "#B91C1C" }}>
{state.error || "Payment failed. Please try again."} {checkout().error || "Payment failed. Please try again."}
</p> </p>
</div> </div>
<div style={{ display: "flex", gap: "12px" }}> <div style={{ display: "flex", gap: "12px" }}>
@ -640,7 +641,7 @@ export default function CreditsPage(props: Props) {
</Show> </Show>
{/* Processing State */} {/* Processing State */}
<Show when={state.step === "processing"}> <Show when={checkout().step === "processing"}>
<div style={{ "text-align": "center", padding: "40px 0" }}> <div style={{ "text-align": "center", padding: "40px 0" }}>
<div style={{ "margin-bottom": "16px" }}> <div style={{ "margin-bottom": "16px" }}>
<div <div
@ -665,9 +666,9 @@ export default function CreditsPage(props: Props) {
</Show> </Show>
{/* Payment Form */} {/* Payment Form */}
<Show when={state.step === "form"}> <Show when={checkout().step === "form"}>
<div style={{ display: "flex", "flex-direction": "column", gap: "14px" }}> <div style={{ display: "flex", "flex-direction": "column", gap: "14px" }}>
<Show when={state.error}> <Show when={checkout().error}>
<div <div
style={{ style={{
background: "#FEF2F2", background: "#FEF2F2",
@ -678,7 +679,7 @@ export default function CreditsPage(props: Props) {
"font-size": "13px", "font-size": "13px",
}} }}
> >
{state.error} {checkout().error}
</div> </div>
</Show> </Show>
@ -708,7 +709,7 @@ export default function CreditsPage(props: Props) {
"font-weight": "700", "font-weight": "700",
}} }}
> >
Pay {formatCurrency(price)} Pay {formatCurrency(checkout().package ? checkout().package!.price : checkout().aiCreditPackage!.price_inr)}
</button> </button>
<p <p
@ -731,6 +732,7 @@ export default function CreditsPage(props: Props) {
} }
`}</style> `}</style>
</Portal> </Portal>
</Show>
); );
}; };

View file

@ -1,7 +1,7 @@
import { For, Show, createSignal } from 'solid-js'; import { For, Show, createSignal } from 'solid-js';
import { BTN_GHOST, BTN_ORANGE, BTN_PRIMARY, CARD, INPUT, LABEL } from '~/components/DashboardShell'; import { BTN_GHOST, BTN_ORANGE, BTN_PRIMARY, CARD, INPUT, LABEL } from '~/components/DashboardShell';
const API = '/api/gateway'; const API = '';
const NAVY = '#0D0D2A'; const NAVY = '#0D0D2A';
const ORANGE = '#FF5E13'; const ORANGE = '#FF5E13';
@ -10,8 +10,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== 'undefined' typeof window !== 'undefined'
? window.sessionStorage.getItem('nxtgauge_access_token') || '' ? window.sessionStorage.getItem('nxtgauge_access_token') || ''
: ''; : '';
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: 'include', credentials: 'include',
headers: { headers: {

View file

@ -9,7 +9,7 @@
import { For, Show, createMemo, createSignal, onMount } from "solid-js"; import { For, Show, createMemo, createSignal, onMount } from "solid-js";
import { BTN_GHOST, BTN_PRIMARY, CARD, INPUT, LABEL } from "~/components/DashboardShell"; import { BTN_GHOST, BTN_PRIMARY, CARD, INPUT, LABEL } from "~/components/DashboardShell";
const API = "/api"; const API = "";
type RequirementItem = { type RequirementItem = {
id: string; id: string;
@ -30,8 +30,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined" typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || "" ? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: ""; : "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: "include", credentials: "include",
headers: { headers: {

View file

@ -1,8 +1,6 @@
import { For, Show, createSignal, onMount } from 'solid-js'; import { For, Show, createSignal, onMount } from 'solid-js';
import { BTN_GHOST, BTN_ORANGE, CARD, INPUT, LABEL } from '~/components/DashboardShell'; import { BTN_GHOST, BTN_ORANGE, CARD, INPUT, LABEL } from '~/components/DashboardShell';
const API = '/api/gateway';
type RequirementItem = { type RequirementItem = {
id: string; id: string;
title: string; title: string;
@ -28,8 +26,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined" typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || "" ? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: ""; : "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path; return fetch(path, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: "include", credentials: "include",
headers: { headers: {
@ -84,7 +81,7 @@ export default function CustomerResponsesPage(props: Props) {
setLoadingRows(true); setLoadingRows(true);
setErr(''); setErr('');
try { try {
const res = await apiFetch(`/api/leads/customer/${requirementId}`); const res = await apiFetch(`/api/customers/requests?lead_id=${requirementId}&page=1&limit=50`);
const payload = await res.json().catch(() => ({})); const payload = await res.json().catch(() => ({}));
if (!res.ok) { if (!res.ok) {
setRows([]); setRows([]);

View file

@ -5,7 +5,7 @@ import { Camera, Scissors, GraduationCap, Code2, Clapperboard, PenTool, Megaphon
const NAVY = "#0D0D2A"; const NAVY = "#0D0D2A";
const ORANGE = "#FF5E13"; const ORANGE = "#FF5E13";
const API = "/api"; const API = "";
const MAIN_ROLES = [ const MAIN_ROLES = [
{ key: "COMPANY", name: "Company", Icon: Users, subtitle: "Hire talent, post jobs, and manage applications in one path." }, { key: "COMPANY", name: "Company", Icon: Users, subtitle: "Hire talent, post jobs, and manage applications in one path." },
@ -40,8 +40,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined" typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || "" ? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: ""; : "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: "include", credentials: "include",
headers: { headers: {

View file

@ -3,7 +3,7 @@ import { HelpCircle } from "lucide-solid";
import { BTN_GHOST, CARD, INPUT } from "~/components/DashboardShell"; import { BTN_GHOST, CARD, INPUT } from "~/components/DashboardShell";
import { type RoleKey } from "./RoleDashboardShared"; import { type RoleKey } from "./RoleDashboardShared";
const API = "/api"; const API = "";
const NAVY = "#0D0D2A"; const NAVY = "#0D0D2A";
const ORANGE = "#FF5E13"; const ORANGE = "#FF5E13";
@ -24,8 +24,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined" typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || "" ? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: ""; : "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: "include", credentials: "include",
headers: { headers: {

View file

@ -1,7 +1,7 @@
import { For, Show, createSignal, onMount } from 'solid-js'; import { For, Show, createSignal, onMount } from 'solid-js';
import { BTN_GHOST, BTN_PRIMARY, CARD } from '~/components/DashboardShell'; import { BTN_GHOST, BTN_PRIMARY, CARD } from '~/components/DashboardShell';
const API = '/api/gateway'; const API = '';
type ApplicationItem = { type ApplicationItem = {
id: string; id: string;
@ -17,8 +17,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined" typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || "" ? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: ""; : "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: "include", credentials: "include",
headers: { headers: {

View file

@ -11,7 +11,7 @@ import { Sparkles, Loader } from "lucide-solid";
import { BTN_GHOST, BTN_PRIMARY, CARD, INPUT } from "~/components/DashboardShell"; import { BTN_GHOST, BTN_PRIMARY, CARD, INPUT } from "~/components/DashboardShell";
import { readJobSeekerProfile, updateJobSeekerCustomData } from "~/lib/job-seeker-custom-data"; import { readJobSeekerProfile, updateJobSeekerCustomData } from "~/lib/job-seeker-custom-data";
const API = "/api"; const API = "";
type JobItem = { type JobItem = {
id: string; id: string;

View file

@ -2,7 +2,7 @@ import { createSignal } from 'solid-js';
import { LogOut } from 'lucide-solid'; import { LogOut } from 'lucide-solid';
import { BTN_GHOST, BTN_ORANGE, CARD } from '~/components/DashboardShell'; import { BTN_GHOST, BTN_ORANGE, CARD } from '~/components/DashboardShell';
const API = '/api/gateway'; const API = '';
const NAVY = '#0D0D2A'; const NAVY = '#0D0D2A';
const ORANGE = '#FF5E13'; const ORANGE = '#FF5E13';
@ -11,8 +11,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined" typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || "" ? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: ""; : "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: "include", credentials: "include",
headers: { headers: {

View file

@ -23,7 +23,7 @@ import {
// Inline apiFetch matching ProfilePage pattern // Inline apiFetch matching ProfilePage pattern
async function apiFetch(path: string, opts?: RequestInit) { async function apiFetch(path: string, opts?: RequestInit) {
const API = '/api/gateway'; const API = '';
const token = typeof window !== 'undefined' const token = typeof window !== 'undefined'
? (sessionStorage.getItem('nxtgauge_access_token') || '') ? (sessionStorage.getItem('nxtgauge_access_token') || '')
: ''; : '';

View file

@ -2,7 +2,7 @@ import { For, Show, createSignal, onMount } from 'solid-js';
import { Bell } from 'lucide-solid'; import { Bell } from 'lucide-solid';
import { BTN_GHOST, BTN_ORANGE, CARD } from '~/components/DashboardShell'; import { BTN_GHOST, BTN_ORANGE, CARD } from '~/components/DashboardShell';
const API = '/api/gateway'; const API = '';
const NAVY = '#0D0D2A'; const NAVY = '#0D0D2A';
const ORANGE = '#FF5E13'; const ORANGE = '#FF5E13';
@ -11,8 +11,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== 'undefined' typeof window !== 'undefined'
? window.sessionStorage.getItem('nxtgauge_access_token') || '' ? window.sessionStorage.getItem('nxtgauge_access_token') || ''
: ''; : '';
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: 'include', credentials: 'include',
headers: { headers: {

View file

@ -8,7 +8,7 @@ import { Coins, Image, BriefcaseBusiness, UserCircle2, CheckCircle2 } from 'luci
import { CARD, BTN_GHOST, BTN_PRIMARY, INPUT, LABEL, NAVY } from '~/components/DashboardShell'; import { CARD, BTN_GHOST, BTN_PRIMARY, INPUT, LABEL, NAVY } from '~/components/DashboardShell';
import { readJobSeekerProfile, updateJobSeekerCustomData } from '~/lib/job-seeker-custom-data'; import { readJobSeekerProfile, updateJobSeekerCustomData } from '~/lib/job-seeker-custom-data';
const API = '/api/gateway'; const API = '';
const BTN_NAVY = { const BTN_NAVY = {
height: '36px', height: '36px',

View file

@ -9,7 +9,7 @@ import { For, Show, createMemo, createSignal, onMount } from "solid-js";
import { BTN_GHOST, BTN_PRIMARY, CARD, INPUT } from "~/components/DashboardShell"; import { BTN_GHOST, BTN_PRIMARY, CARD, INPUT } from "~/components/DashboardShell";
import { ROLE_PREFIXES, type RoleKey } from "./RoleDashboardShared"; import { ROLE_PREFIXES, type RoleKey } from "./RoleDashboardShared";
const API = "/api"; const API = "";
type Props = { roleKey: RoleKey }; type Props = { roleKey: RoleKey };

View file

@ -2,7 +2,7 @@ import { For, Show, createSignal, onMount } from 'solid-js';
import { BTN_GHOST, CARD } from '~/components/DashboardShell'; import { BTN_GHOST, CARD } from '~/components/DashboardShell';
import { ROLE_PREFIXES, type RoleKey } from './RoleDashboardShared'; import { ROLE_PREFIXES, type RoleKey } from './RoleDashboardShared';
const API = '/api/gateway'; const API = '';
type Props = { roleKey: RoleKey }; type Props = { roleKey: RoleKey };
@ -20,8 +20,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined" typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || "" ? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: ""; : "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: "include", credentials: "include",
headers: { headers: {

View file

@ -638,7 +638,7 @@ export default function ProfilePage(props: Props) {
return Array.from(new Set(missing)); return Array.from(new Set(missing));
} }
const data = await res.json().catch(() => []); const data = await res.json().catch(() => []);
const items = Array.isArray(data) ? data : data?.items ?? []; const items = Array.isArray(data) ? data : data?.items ?? data?.data ?? [];
if (!Array.isArray(items) || items.length === 0) missing.push("Showcase items"); if (!Array.isArray(items) || items.length === 0) missing.push("Showcase items");
} catch { } catch {
missing.push("Showcase items"); missing.push("Showcase items");
@ -863,7 +863,7 @@ export default function ProfilePage(props: Props) {
method: "POST", method: "POST",
body: { roleKey: props.roleKey, profile_data: { ...form(), ...docUrls() } }, body: { roleKey: props.roleKey, profile_data: { ...form(), ...docUrls() } },
}); });
if (status === 200) { if (status === 200 || status === 201) {
setVerificationStatus("PENDING"); setVerificationStatus("PENDING");
props.onVerificationStatusChange?.("PENDING"); props.onVerificationStatusChange?.("PENDING");
setSubmitMsg("Submitted! We will review your profile and notify you."); setSubmitMsg("Submitted! We will review your profile and notify you.");

View file

@ -2,7 +2,7 @@ import { For, Show, createSignal, onMount } from 'solid-js';
import { Settings as SettingsIcon } from 'lucide-solid'; import { Settings as SettingsIcon } from 'lucide-solid';
import { BTN_GHOST, BTN_ORANGE, BTN_PRIMARY, CARD, INPUT, LABEL } from '~/components/DashboardShell'; import { BTN_GHOST, BTN_ORANGE, BTN_PRIMARY, CARD, INPUT, LABEL } from '~/components/DashboardShell';
const API = '/api/gateway'; const API = '';
const NAVY = '#0D0D2A'; const NAVY = '#0D0D2A';
const ORANGE = '#FF5E13'; const ORANGE = '#FF5E13';
@ -11,8 +11,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined" typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || "" ? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: ""; : "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: "include", credentials: "include",
headers: { headers: {

View file

@ -2,7 +2,7 @@ import { For, Show, createSignal, onMount } from 'solid-js';
import { RefreshCw } from 'lucide-solid'; import { RefreshCw } from 'lucide-solid';
import { BTN_GHOST, BTN_PRIMARY, CARD } from '~/components/DashboardShell'; import { BTN_GHOST, BTN_PRIMARY, CARD } from '~/components/DashboardShell';
const API = '/api/gateway'; const API = '';
const NAVY = '#0D0D2A'; const NAVY = '#0D0D2A';
const ORANGE = '#FF5E13'; const ORANGE = '#FF5E13';
@ -18,8 +18,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined" typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || "" ? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: ""; : "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: "include", credentials: "include",
headers: { headers: {

View file

@ -4,15 +4,14 @@ import DashboardWidget from './DashboardWidget';
import type { RoleKey } from '../RoleDashboardShared'; import type { RoleKey } from '../RoleDashboardShared';
import { ROLE_PREFIXES } from '../RoleDashboardShared'; import { ROLE_PREFIXES } from '../RoleDashboardShared';
const API = '/api/gateway'; const API = '';
async function apiFetch(path: string, opts?: RequestInit) { async function apiFetch(path: string, opts?: RequestInit) {
const token = const token =
typeof window !== 'undefined' typeof window !== 'undefined'
? window.sessionStorage.getItem('nxtgauge_access_token') || '' ? window.sessionStorage.getItem('nxtgauge_access_token') || ''
: ''; : '';
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: 'include', credentials: 'include',
headers: { headers: {

View file

@ -3,15 +3,14 @@ import { FileText } from 'lucide-solid';
import DashboardWidget from './DashboardWidget'; import DashboardWidget from './DashboardWidget';
import type { RoleKey } from '../RoleDashboardShared'; import type { RoleKey } from '../RoleDashboardShared';
const API = '/api/gateway'; const API = '';
async function apiFetch(path: string, opts?: RequestInit) { async function apiFetch(path: string, opts?: RequestInit) {
const token = const token =
typeof window !== 'undefined' typeof window !== 'undefined'
? window.sessionStorage.getItem('nxtgauge_access_token') || '' ? window.sessionStorage.getItem('nxtgauge_access_token') || ''
: ''; : '';
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: 'include', credentials: 'include',
headers: { headers: {

View file

@ -3,15 +3,14 @@ import { Briefcase } from 'lucide-solid';
import DashboardWidget from './DashboardWidget'; import DashboardWidget from './DashboardWidget';
import type { RoleKey } from '../RoleDashboardShared'; import type { RoleKey } from '../RoleDashboardShared';
const API = '/api/gateway'; const API = '';
async function apiFetch(path: string, opts?: RequestInit) { async function apiFetch(path: string, opts?: RequestInit) {
const token = const token =
typeof window !== 'undefined' typeof window !== 'undefined'
? window.sessionStorage.getItem('nxtgauge_access_token') || '' ? window.sessionStorage.getItem('nxtgauge_access_token') || ''
: ''; : '';
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: 'include', credentials: 'include',
headers: { headers: {

View file

@ -4,15 +4,14 @@ import DashboardWidget from './DashboardWidget';
import type { RoleKey } from '../RoleDashboardShared'; import type { RoleKey } from '../RoleDashboardShared';
import { PROFESSIONAL_ROLE_SET, ROLE_PREFIXES } from '../RoleDashboardShared'; import { PROFESSIONAL_ROLE_SET, ROLE_PREFIXES } from '../RoleDashboardShared';
const API = '/api/gateway'; const API = '';
async function apiFetch(path: string, opts?: RequestInit) { async function apiFetch(path: string, opts?: RequestInit) {
const token = const token =
typeof window !== 'undefined' typeof window !== 'undefined'
? window.sessionStorage.getItem('nxtgauge_access_token') || '' ? window.sessionStorage.getItem('nxtgauge_access_token') || ''
: ''; : '';
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: 'include', credentials: 'include',
headers: { headers: {

View file

@ -5,15 +5,14 @@ import type { RoleKey } from '../RoleDashboardShared';
import { PROFESSIONAL_ROLE_SET, ROLE_PREFIXES } from '../RoleDashboardShared'; import { PROFESSIONAL_ROLE_SET, ROLE_PREFIXES } from '../RoleDashboardShared';
import { fetchProfile } from '~/lib/api'; import { fetchProfile } from '~/lib/api';
const API = '/api/gateway'; const API = '';
async function apiFetch(path: string, opts?: RequestInit) { async function apiFetch(path: string, opts?: RequestInit) {
const token = const token =
typeof window !== 'undefined' typeof window !== 'undefined'
? window.sessionStorage.getItem('nxtgauge_access_token') || '' ? window.sessionStorage.getItem('nxtgauge_access_token') || ''
: ''; : '';
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: 'include', credentials: 'include',
headers: { headers: {

View file

@ -3,15 +3,14 @@ import { ClipboardList } from 'lucide-solid';
import DashboardWidget from './DashboardWidget'; import DashboardWidget from './DashboardWidget';
import type { RoleKey } from '../RoleDashboardShared'; import type { RoleKey } from '../RoleDashboardShared';
const API = '/api/gateway'; const API = '';
async function apiFetch(path: string, opts?: RequestInit) { async function apiFetch(path: string, opts?: RequestInit) {
const token = const token =
typeof window !== 'undefined' typeof window !== 'undefined'
? window.sessionStorage.getItem('nxtgauge_access_token') || '' ? window.sessionStorage.getItem('nxtgauge_access_token') || ''
: ''; : '';
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: 'include', credentials: 'include',
headers: { headers: {

View file

@ -3,15 +3,14 @@ import { Star } from 'lucide-solid';
import DashboardWidget from './DashboardWidget'; import DashboardWidget from './DashboardWidget';
import type { RoleKey } from '../RoleDashboardShared'; import type { RoleKey } from '../RoleDashboardShared';
const API = '/api/gateway'; const API = '';
async function apiFetch(path: string, opts?: RequestInit) { async function apiFetch(path: string, opts?: RequestInit) {
const token = const token =
typeof window !== 'undefined' typeof window !== 'undefined'
? window.sessionStorage.getItem('nxtgauge_access_token') || '' ? window.sessionStorage.getItem('nxtgauge_access_token') || ''
: ''; : '';
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: 'include', credentials: 'include',
headers: { headers: {

View file

@ -3,15 +3,14 @@ import { ShieldCheck } from 'lucide-solid';
import DashboardWidget from './DashboardWidget'; import DashboardWidget from './DashboardWidget';
import type { RoleKey } from '../RoleDashboardShared'; import type { RoleKey } from '../RoleDashboardShared';
const API = '/api/gateway'; const API = '';
async function apiFetch(path: string, opts?: RequestInit) { async function apiFetch(path: string, opts?: RequestInit) {
const token = const token =
typeof window !== 'undefined' typeof window !== 'undefined'
? window.sessionStorage.getItem('nxtgauge_access_token') || '' ? window.sessionStorage.getItem('nxtgauge_access_token') || ''
: ''; : '';
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: 'include', credentials: 'include',
headers: { headers: {

View file

@ -4,15 +4,14 @@ import DashboardWidget from './DashboardWidget';
import type { RoleKey } from '../RoleDashboardShared'; import type { RoleKey } from '../RoleDashboardShared';
import { ROLE_PREFIXES } from '../RoleDashboardShared'; import { ROLE_PREFIXES } from '../RoleDashboardShared';
const API = '/api/gateway'; const API = '';
async function apiFetch(path: string, opts?: RequestInit) { async function apiFetch(path: string, opts?: RequestInit) {
const token = const token =
typeof window !== 'undefined' typeof window !== 'undefined'
? window.sessionStorage.getItem('nxtgauge_access_token') || '' ? window.sessionStorage.getItem('nxtgauge_access_token') || ''
: ''; : '';
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path; return fetch(`${API}${path}`, {
return fetch(`${API}${cleanPath}`, {
...opts, ...opts,
credentials: 'include', credentials: 'include',
headers: { headers: {

View file

@ -250,6 +250,7 @@ const ROLE_BASED_SIDEBAR: Record<RoleKey, string[]> = {
"Jobs", "Jobs",
"Applications", "Applications",
"Shortlisted Candidates", "Shortlisted Candidates",
"Credits",
"Explore Nxtgauge", "Explore Nxtgauge",
"Verification", "Verification",
"Help Center", "Help Center",

View file

@ -45,7 +45,7 @@ export default function BuyTracecoinsPage() {
const [packages] = createResource(async () => { const [packages] = createResource(async () => {
const roleKey = resolveRoleKey(); const roleKey = resolveRoleKey();
const res = await api.get(`/pricing/packages?role=${encodeURIComponent(roleKey)}&roleKey=${encodeURIComponent(roleKey)}`); const res = await api.get(`/packages?role=${encodeURIComponent(roleKey)}&roleKey=${encodeURIComponent(roleKey)}`);
return res.data?.packages || []; return res.data?.packages || [];
}); });