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",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "dev"],
"port": 3000
"port": 3001
}
]
}

View file

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

View file

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

View file

@ -1,7 +1,7 @@
import { For, Show, createSignal, onMount } from 'solid-js';
import { BTN_GHOST, CARD } from '~/components/DashboardShell';
const API = '/api/gateway';
const API = '';
type JobItem = { id: string; title: string };
type ApplicationItem = {
@ -18,8 +18,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path;
return fetch(`${API}${cleanPath}`, {
return fetch(`${API}${path}`, {
...opts,
credentials: "include",
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 { openPayuCheckout, submitPayuCheckout } from "~/lib/payu";
const API = "/api";
const API = "";
type Props = { roleKey: RoleKey; dashboardConfig?: Record<string, any> | null };
@ -79,8 +79,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path;
return fetch(`${API}${cleanPath}`, {
return fetch(`${API}${path}`, {
...opts,
credentials: "include",
headers: {
@ -421,11 +420,20 @@ export default function CreditsPage(props: Props) {
return;
}
const paymentResult = await openPayuCheckout({
const paymentResult = await submitPayuCheckout({
key: orderData.key,
txnid: orderData.txnid || orderData.order_id,
amount: orderData.amount,
currency: orderData.currency,
txnId: orderData.txnid || orderData.order_id,
description: `${pkg.name} - ${pkg.tracecoins_amount} Tracecoins`,
productinfo: orderData.productinfo,
firstname: orderData.firstname,
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", {
@ -490,247 +498,241 @@ export default function CreditsPage(props: Props) {
};
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 (
<Portal>
<div
style={{
position: "fixed",
inset: "0",
background: "rgba(0,0,0,0.5)",
display: "flex",
"align-items": "center",
"justify-content": "center",
"z-index": "1000",
padding: "20px",
}}
onClick={(e) => {
if (e.target === e.currentTarget && state.step !== "processing") closeCheckout();
}}
>
<Show when={checkout().package || checkout().aiCreditPackage}>
<Portal>
<div
style={{
background: "#fff",
"border-radius": "16px",
padding: "24px",
"max-width": "420px",
width: "100%",
"box-shadow": "0 20px 60px rgba(0,0,0,0.2)",
position: "fixed",
inset: "0",
background: "rgba(0,0,0,0.5)",
display: "flex",
"align-items": "center",
"justify-content": "center",
"z-index": "1000",
padding: "20px",
}}
onClick={(e) => {
if (e.target === e.currentTarget && checkout().step !== "processing") closeCheckout();
}}
>
{/* Header */}
<div
style={{
display: "flex",
"justify-content": "space-between",
"align-items": "center",
"margin-bottom": "20px",
background: "#fff",
"border-radius": "16px",
padding: "24px",
"max-width": "420px",
width: "100%",
"box-shadow": "0 20px 60px rgba(0,0,0,0.2)",
}}
>
<h3
style={{ margin: "0", "font-size": "18px", "font-weight": "700", color: "#111827" }}
>
{state.step === "success"
? "✓ Payment Successful"
: state.step === "error"
? "Payment Failed"
: "Checkout"}
</h3>
<Show when={state.step !== "processing"}>
<button
onClick={closeCheckout}
style={{
background: "none",
border: "none",
cursor: "pointer",
"font-size": "24px",
color: "#9CA3AF",
}}
>
×
</button>
</Show>
</div>
{/* Package Summary */}
<Show when={state.step !== "success"}>
{/* Header */}
<div
style={{
background: "#F9FAFB",
"border-radius": "12px",
padding: "16px",
display: "flex",
"justify-content": "space-between",
"align-items": "center",
"margin-bottom": "20px",
}}
>
<p style={{ margin: "0 0 8px", "font-size": "13px", color: "#6B7280" }}>Package</p>
<p
style={{
margin: "0 0 4px",
"font-size": "16px",
"font-weight": "700",
color: "#111827",
}}
<h3
style={{ margin: "0", "font-size": "18px", "font-weight": "700", color: "#111827" }}
>
{pkg ? pkg.name : aiPkg?.name}
</p>
<p
style={{
margin: "0",
"font-size": "24px",
"font-weight": "800",
color: "#FF5E13",
}}
>
{formatCurrency(price)}
</p>
<p style={{ margin: "8px 0 0", "font-size": "14px", color: "#15803D" }}>
+{title}
</p>
</div>
</Show>
{/* Success State */}
<Show when={state.step === "success"}>
<div style={{ "text-align": "center", padding: "20px 0" }}>
<div style={{ "font-size": "48px", "margin-bottom": "16px" }}>🎉</div>
<p style={{ margin: "0 0 8px", "font-size": "16px", color: "#111827" }}>
Payment successful!
</p>
<p style={{ margin: "0 0 16px", "font-size": "14px", color: "#6B7280" }}>
{title} have been credited to your account.
</p>
<p style={{ margin: "0", "font-size": "12px", color: "#9CA3AF" }}>
Order ID: {state.orderId}
</p>
</div>
<button
onClick={closeCheckout}
style={{ ...BTN_PRIMARY, width: "100%", "margin-top": "16px" }}
>
Done
</button>
</Show>
{/* Error State */}
<Show when={state.step === "error"}>
<div style={{ "text-align": "center", padding: "20px 0" }}>
<div style={{ "font-size": "48px", "margin-bottom": "16px" }}></div>
<p style={{ margin: "0 0 16px", "font-size": "14px", color: "#B91C1C" }}>
{state.error || "Payment failed. Please try again."}
</p>
</div>
<div style={{ display: "flex", gap: "12px" }}>
<button
onClick={() => setCheckout((c) => ({ ...c, step: "form", error: "" }))}
style={{ ...BTN_GHOST, flex: "1" }}
>
Try Again
</button>
<button onClick={closeCheckout} style={{ ...BTN_PRIMARY, flex: "1" }}>
Cancel
</button>
</div>
</Show>
{/* Processing State */}
<Show when={state.step === "processing"}>
<div style={{ "text-align": "center", padding: "40px 0" }}>
<div style={{ "margin-bottom": "16px" }}>
<div
{checkout().step === "success"
? "✓ Payment Successful"
: checkout().step === "error"
? "Payment Failed"
: "Checkout"}
</h3>
<Show when={checkout().step !== "processing"}>
<button
onClick={closeCheckout}
style={{
width: "48px",
height: "48px",
border: "4px solid #E5E7EB",
"border-top-color": "#FF5E13",
"border-radius": "50%",
animation: "spin 1s linear infinite",
margin: "0 auto",
}}
/>
</div>
<p style={{ margin: "0", "font-size": "16px", color: "#111827" }}>
Processing Payment...
</p>
<p style={{ margin: "8px 0 0", "font-size": "13px", color: "#6B7280" }}>
Please wait while we process your payment.
</p>
</div>
</Show>
{/* Payment Form */}
<Show when={state.step === "form"}>
<div style={{ display: "flex", "flex-direction": "column", gap: "14px" }}>
<Show when={state.error}>
<div
style={{
background: "#FEF2F2",
border: "1px solid #FECACA",
"border-radius": "8px",
padding: "12px",
color: "#B91C1C",
"font-size": "13px",
background: "none",
border: "none",
cursor: "pointer",
"font-size": "24px",
color: "#9CA3AF",
}}
>
{state.error}
</div>
×
</button>
</Show>
</div>
{/* PayU Notice */}
{/* Package Summary */}
<Show when={checkout().step !== "success"}>
<div
style={{
background: "#FFF7ED",
border: "1px solid #FDBA74",
"border-radius": "8px",
padding: "12px",
"font-size": "13px",
color: "#9A3412",
background: "#F9FAFB",
"border-radius": "12px",
padding: "16px",
"margin-bottom": "20px",
}}
>
PayU Secure Checkout will open in a secure page. Cancelled or failed
payments will not be credited.
<p style={{ margin: "0 0 8px", "font-size": "13px", color: "#6B7280" }}>Package</p>
<p
style={{
margin: "0 0 4px",
"font-size": "16px",
"font-weight": "700",
color: "#111827",
}}
>
{checkout().package ? checkout().package!.name : checkout().aiCreditPackage?.name}
</p>
<p
style={{
margin: "0",
"font-size": "24px",
"font-weight": "800",
color: "#FF5E13",
}}
>
{formatCurrency(checkout().package ? checkout().package!.price : checkout().aiCreditPackage!.price_inr)}
</p>
<p style={{ margin: "8px 0 0", "font-size": "14px", color: "#15803D" }}>
+{checkout().package ? `${checkout().package!.tracecoins_amount} Tracecoins` : `${checkout().aiCreditPackage!.credits} AI Credits`}
</p>
</div>
</Show>
{/* Pay Button */}
{/* Success State */}
<Show when={checkout().step === "success"}>
<div style={{ "text-align": "center", padding: "20px 0" }}>
<div style={{ "font-size": "48px", "margin-bottom": "16px" }}>🎉</div>
<p style={{ margin: "0 0 8px", "font-size": "16px", color: "#111827" }}>
Payment successful!
</p>
<p style={{ margin: "0 0 16px", "font-size": "14px", color: "#6B7280" }}>
{checkout().package ? `${checkout().package!.tracecoins_amount} Tracecoins` : `${checkout().aiCreditPackage!.credits} AI Credits`} have been credited to your account.
</p>
<p style={{ margin: "0", "font-size": "12px", color: "#9CA3AF" }}>
Order ID: {checkout().orderId}
</p>
</div>
<button
onClick={processPayment}
style={{
...BTN_PRIMARY,
width: "100%",
padding: "14px",
"font-size": "15px",
"font-weight": "700",
}}
onClick={closeCheckout}
style={{ ...BTN_PRIMARY, width: "100%", "margin-top": "16px" }}
>
Pay {formatCurrency(price)}
Done
</button>
</Show>
<p
style={{
margin: "0",
"font-size": "11px",
color: "#9CA3AF",
"text-align": "center",
}}
>
Secure payment powered by PayU
</p>
</div>
</Show>
{/* Error State */}
<Show when={checkout().step === "error"}>
<div style={{ "text-align": "center", padding: "20px 0" }}>
<div style={{ "font-size": "48px", "margin-bottom": "16px" }}></div>
<p style={{ margin: "0 0 16px", "font-size": "14px", color: "#B91C1C" }}>
{checkout().error || "Payment failed. Please try again."}
</p>
</div>
<div style={{ display: "flex", gap: "12px" }}>
<button
onClick={() => setCheckout((c) => ({ ...c, step: "form", error: "" }))}
style={{ ...BTN_GHOST, flex: "1" }}
>
Try Again
</button>
<button onClick={closeCheckout} style={{ ...BTN_PRIMARY, flex: "1" }}>
Cancel
</button>
</div>
</Show>
{/* Processing State */}
<Show when={checkout().step === "processing"}>
<div style={{ "text-align": "center", padding: "40px 0" }}>
<div style={{ "margin-bottom": "16px" }}>
<div
style={{
width: "48px",
height: "48px",
border: "4px solid #E5E7EB",
"border-top-color": "#FF5E13",
"border-radius": "50%",
animation: "spin 1s linear infinite",
margin: "0 auto",
}}
/>
</div>
<p style={{ margin: "0", "font-size": "16px", color: "#111827" }}>
Processing Payment...
</p>
<p style={{ margin: "8px 0 0", "font-size": "13px", color: "#6B7280" }}>
Please wait while we process your payment.
</p>
</div>
</Show>
{/* Payment Form */}
<Show when={checkout().step === "form"}>
<div style={{ display: "flex", "flex-direction": "column", gap: "14px" }}>
<Show when={checkout().error}>
<div
style={{
background: "#FEF2F2",
border: "1px solid #FECACA",
"border-radius": "8px",
padding: "12px",
color: "#B91C1C",
"font-size": "13px",
}}
>
{checkout().error}
</div>
</Show>
{/* PayU Notice */}
<div
style={{
background: "#FFF7ED",
border: "1px solid #FDBA74",
"border-radius": "8px",
padding: "12px",
"font-size": "13px",
color: "#9A3412",
}}
>
PayU Secure Checkout will open in a secure page. Cancelled or failed
payments will not be credited.
</div>
{/* Pay Button */}
<button
onClick={processPayment}
style={{
...BTN_PRIMARY,
width: "100%",
padding: "14px",
"font-size": "15px",
"font-weight": "700",
}}
>
Pay {formatCurrency(checkout().package ? checkout().package!.price : checkout().aiCreditPackage!.price_inr)}
</button>
<p
style={{
margin: "0",
"font-size": "11px",
color: "#9CA3AF",
"text-align": "center",
}}
>
Secure payment powered by PayU
</p>
</div>
</Show>
</div>
</div>
</div>
<style>{`
@keyframes spin {
to { transform: rotate(360deg); }
}
`}</style>
</Portal>
<style>{`
@keyframes spin {
to { transform: rotate(360deg); }
}
`}</style>
</Portal>
</Show>
);
};

View file

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

View file

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

View file

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

View file

@ -5,7 +5,7 @@ import { Camera, Scissors, GraduationCap, Code2, Clapperboard, PenTool, Megaphon
const NAVY = "#0D0D2A";
const ORANGE = "#FF5E13";
const API = "/api";
const API = "";
const MAIN_ROLES = [
{ 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"
? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path;
return fetch(`${API}${cleanPath}`, {
return fetch(`${API}${path}`, {
...opts,
credentials: "include",
headers: {

View file

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

View file

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

View file

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

View file

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

View file

@ -23,7 +23,7 @@ import {
// Inline apiFetch matching ProfilePage pattern
async function apiFetch(path: string, opts?: RequestInit) {
const API = '/api/gateway';
const API = '';
const token = typeof window !== 'undefined'
? (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 { BTN_GHOST, BTN_ORANGE, CARD } from '~/components/DashboardShell';
const API = '/api/gateway';
const API = '';
const NAVY = '#0D0D2A';
const ORANGE = '#FF5E13';
@ -11,8 +11,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== 'undefined'
? window.sessionStorage.getItem('nxtgauge_access_token') || ''
: '';
const cleanPath = path.startsWith('/api/') ? path.slice(4) : path;
return fetch(`${API}${cleanPath}`, {
return fetch(`${API}${path}`, {
...opts,
credentials: 'include',
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 { readJobSeekerProfile, updateJobSeekerCustomData } from '~/lib/job-seeker-custom-data';
const API = '/api/gateway';
const API = '';
const BTN_NAVY = {
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 { ROLE_PREFIXES, type RoleKey } from "./RoleDashboardShared";
const API = "/api";
const API = "";
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 { ROLE_PREFIXES, type RoleKey } from './RoleDashboardShared';
const API = '/api/gateway';
const API = '';
type Props = { roleKey: RoleKey };
@ -20,8 +20,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path;
return fetch(`${API}${cleanPath}`, {
return fetch(`${API}${path}`, {
...opts,
credentials: "include",
headers: {

View file

@ -638,7 +638,7 @@ export default function ProfilePage(props: Props) {
return Array.from(new Set(missing));
}
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");
} catch {
missing.push("Showcase items");
@ -863,7 +863,7 @@ export default function ProfilePage(props: Props) {
method: "POST",
body: { roleKey: props.roleKey, profile_data: { ...form(), ...docUrls() } },
});
if (status === 200) {
if (status === 200 || status === 201) {
setVerificationStatus("PENDING");
props.onVerificationStatusChange?.("PENDING");
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 { BTN_GHOST, BTN_ORANGE, BTN_PRIMARY, CARD, INPUT, LABEL } from '~/components/DashboardShell';
const API = '/api/gateway';
const API = '';
const NAVY = '#0D0D2A';
const ORANGE = '#FF5E13';
@ -11,8 +11,7 @@ async function apiFetch(path: string, opts?: RequestInit) {
typeof window !== "undefined"
? window.sessionStorage.getItem("nxtgauge_access_token") || ""
: "";
const cleanPath = path.startsWith("/api/") ? path.slice(4) : path;
return fetch(`${API}${cleanPath}`, {
return fetch(`${API}${path}`, {
...opts,
credentials: "include",
headers: {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -45,7 +45,7 @@ export default function BuyTracecoinsPage() {
const [packages] = createResource(async () => {
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 || [];
});