UserDashboard/utils/export.ts
Syasya 00fe939804
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m50s
new excel export
2025-08-29 20:22:30 +08:00

71 lines
2.1 KiB
TypeScript

// utils/export.ts
export type ExportParams = {
baseUrl?: string; // e.g. process.env.NEXT_PUBLIC_API_URL
site: string; // PROJ-0028
suffix?: "grid" | "solar"; // default "grid"
serial?: string | null; // device id like "01"
day?: string; // "YYYY-MM-DD" (preferred)
start?: string; // ISO string (if not using day)
end?: string; // ISO string (if not using day)
columns?: string[]; // optional list of columns
localTz?: string; // default "Asia/Kuala_Lumpur"
};
export function buildExportUrl(p: ExportParams): string {
const {
baseUrl = "",
site,
suffix = "grid",
serial,
day,
start,
end,
columns,
localTz = "Asia/Kuala_Lumpur",
} = p;
const params = new URLSearchParams();
params.set("site", site);
params.set("suffix", suffix);
params.set("local_tz", localTz);
const s = serial?.trim();
if (s) params.set("serial", s);
if (day) {
params.set("day", day); // simple whole-day export
} else {
if (!start || !end) throw new Error("Provide either day=YYYY-MM-DD or both start and end.");
params.set("start", start); // URLSearchParams will encode '+' correctly
params.set("end", end);
}
if (columns?.length) {
// backend expects ?columns=... repeated; append each
columns.forEach(c => params.append("columns", c));
}
// ensure there's a single slash join for /export/xlsx
const root = baseUrl.replace(/\/+$/, "");
return `${root}/export/xlsx?${params.toString()}`;
}
/** Parse filename from Content-Disposition (handles RFC5987 filename*) */
export function getFilenameFromCD(cd: string | null): string | null {
if (!cd) return null;
// filename*=UTF-8''encoded-name.xlsx
const star = /filename\*\s*=\s*([^']*)''([^;]+)/i.exec(cd);
if (star && star[2]) {
try {
return decodeURIComponent(star[2]);
} catch {
return star[2];
}
}
// filename="name.xlsx" OR filename=name.xlsx
const plain = /filename\s*=\s*("?)([^";]+)\1/i.exec(cd);
return plain ? plain[2] : null;
}