support for filtering and updating caliber
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import { API_BASE, getToken, qs } from "./auth";
|
||||
import type {
|
||||
AdminProductRow,
|
||||
PageResponse,
|
||||
PlatformDto,
|
||||
ProductStatus,
|
||||
ProductVisibility,
|
||||
} from "./types";
|
||||
|
||||
async function authedFetch(url: string, init?: RequestInit) {
|
||||
const token = getToken();
|
||||
const res = await fetch(url, {
|
||||
credentials: "include",
|
||||
cache: "no-store",
|
||||
...(init ?? {}),
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
...(init?.headers ?? {}),
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
} as any,
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
export async function fetchAdminRoles(params: Record<string, any>) {
|
||||
const res = await authedFetch(
|
||||
`${API_BASE}/api/v1/admin/products/roles?${qs(params)}`
|
||||
);
|
||||
if (!res.ok) throw new Error(`Failed to load roles (${res.status}): ${await res.text()}`);
|
||||
return (await res.json()) as string[];
|
||||
}
|
||||
|
||||
export async function fetchAdminCalibers(params: Record<string, any>) {
|
||||
const res = await authedFetch(
|
||||
`${API_BASE}/api/v1/admin/products/calibers?${qs(params)}`
|
||||
);
|
||||
if (!res.ok) throw new Error(`Failed to load calibers (${res.status}): ${await res.text()}`);
|
||||
return (await res.json()) as string[];
|
||||
}
|
||||
|
||||
export async function fetchAdminProducts(params: Record<string, any>) {
|
||||
const res = await authedFetch(
|
||||
`${API_BASE}/api/v1/admin/products?${qs(params)}`
|
||||
);
|
||||
if (!res.ok) throw new Error(`Failed to load admin products (${res.status}): ${await res.text()}`);
|
||||
return (await res.json()) as PageResponse<AdminProductRow>;
|
||||
}
|
||||
|
||||
export async function fetchPlatforms() {
|
||||
const res = await fetch(`${API_BASE}/api/platforms`, {
|
||||
method: "GET",
|
||||
headers: { Accept: "application/json" },
|
||||
cache: "no-store",
|
||||
});
|
||||
|
||||
if (!res.ok) throw new Error(`Failed to load platforms (${res.status}): ${await res.text()}`);
|
||||
const all = (await res.json()) as PlatformDto[];
|
||||
return all.filter((p) => p.is_active);
|
||||
}
|
||||
|
||||
export async function bulkUpdate(
|
||||
productIds: number[],
|
||||
set: Partial<{
|
||||
visibility: ProductVisibility;
|
||||
status: ProductStatus;
|
||||
builderEligible: boolean;
|
||||
adminLocked: boolean;
|
||||
adminNote: string;
|
||||
platform: string;
|
||||
platformLocked: boolean;
|
||||
caliber: string;
|
||||
caliberGroup: string;
|
||||
caliberLocked: boolean;
|
||||
forceCaliberUpdate: boolean;
|
||||
partRole: string;
|
||||
partRoleLocked: boolean;
|
||||
classificationReason: "Admin bulk override";
|
||||
}>
|
||||
) {
|
||||
const token = getToken();
|
||||
|
||||
const res = await fetch(`${API_BASE}/api/v1/admin/products/bulk`, {
|
||||
method: "PATCH",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify({ productIds, ...set }),
|
||||
});
|
||||
|
||||
if (!res.ok) throw new Error(`Bulk update failed (${res.status}): ${await res.text()}`);
|
||||
|
||||
return (await res.json()) as { updatedCount: number; skippedLockedCount: number };
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
export const API_BASE =
|
||||
process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8080";
|
||||
|
||||
export function getCookie(name: string): string | null {
|
||||
if (typeof document === "undefined") return null;
|
||||
const match = document.cookie.match(
|
||||
new RegExp(
|
||||
"(^| )" + name.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + "=([^;]+)"
|
||||
)
|
||||
);
|
||||
return match ? decodeURIComponent(match[2]) : null;
|
||||
}
|
||||
|
||||
export function getToken(): string | null {
|
||||
if (typeof window === "undefined") return null;
|
||||
|
||||
const ls = localStorage.getItem("ballistic_auth_token");
|
||||
if (ls && ls.trim().length > 0) return ls;
|
||||
|
||||
const ck = getCookie("bb_access_token");
|
||||
if (ck && ck.trim().length > 0) return ck;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function qs(params: Record<string, any>) {
|
||||
const sp = new URLSearchParams();
|
||||
Object.entries(params).forEach(([k, v]) => {
|
||||
if (v === undefined || v === null || v === "") return;
|
||||
sp.set(k, String(v));
|
||||
});
|
||||
return sp.toString();
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
export type ProductVisibility = "PUBLIC" | "HIDDEN";
|
||||
export type ProductStatus = "ACTIVE" | "DISABLED" | "ARCHIVED";
|
||||
|
||||
export type AdminProductRow = {
|
||||
id: number;
|
||||
uuid: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
platform: string | null;
|
||||
partRole: string | null;
|
||||
brandName: string | null;
|
||||
importStatus: string | null;
|
||||
caliber: string | null;
|
||||
caliberGroup: string | null;
|
||||
caliberLocked: boolean;
|
||||
visibility: ProductVisibility;
|
||||
status: ProductStatus;
|
||||
builderEligible: boolean;
|
||||
adminLocked: boolean;
|
||||
adminNote: string | null;
|
||||
mainImageUrl: string | null;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
};
|
||||
|
||||
export type PageResponse<T> = {
|
||||
content: T[];
|
||||
totalElements: number;
|
||||
totalPages: number;
|
||||
number: number;
|
||||
size: number;
|
||||
};
|
||||
|
||||
export type AdminFilters = {
|
||||
q: string;
|
||||
platform: string;
|
||||
partRole: string;
|
||||
caliber: string;
|
||||
visibility: ProductVisibility | "";
|
||||
status: ProductStatus | "";
|
||||
builderEligible: "" | "true" | "false";
|
||||
adminLocked: "" | "true" | "false";
|
||||
};
|
||||
|
||||
export type PlatformDto = {
|
||||
id: number;
|
||||
key: string;
|
||||
label: string;
|
||||
is_active: boolean;
|
||||
};
|
||||
|
||||
export const initialFilters: AdminFilters = {
|
||||
q: "",
|
||||
platform: "",
|
||||
partRole: "",
|
||||
caliber: "",
|
||||
visibility: "",
|
||||
status: "",
|
||||
builderEligible: "",
|
||||
adminLocked: "",
|
||||
};
|
||||
Reference in New Issue
Block a user