import { ui_locales } from "@ui/ui_template_locale"; export type FileSlot = "csv" | "las_laz" | "prj" | "tfw" | "tif" | "dxf"; export type UploadStatus = "pending" | "uploading" | "completed" | "failed"; export interface SlotConfig { slot: FileSlot; labelKey: keyof typeof ui_locales; icon: string; extensions: readonly string[]; isRequired: boolean; } export interface FileSlotState extends SlotConfig { file?: File; uploadSessionId?: string; uploadStatus: UploadStatus; progressBytes: number; speedMbs: number; etaSeconds: number | null; error?: string; } export interface StoredUploadSession { key: string; projectId: string; slot: FileSlot; fileName: string; fileSize: number; uploadSessionId: string; chunkSizeBytes: number; totalChunks: number; completedChunks: number; updatedAt: number; } const SLOT_CONFIGS: readonly SlotConfig[] = [ { slot: "csv", labelKey: "B03_File_Slot_PlannedRoute", icon: "⌁", extensions: [".csv"], isRequired: true, }, { slot: "las_laz", labelKey: "B03_File_Slot_PointCloud", icon: "●", extensions: [".las", ".laz"], isRequired: true, }, { slot: "prj", labelKey: "B03_File_Slot_Projection", icon: "◇", extensions: [".prj"], isRequired: true, }, { slot: "tfw", labelKey: "B03_File_Slot_RasterCoord", icon: "□", extensions: [".tfw"], isRequired: true, }, { slot: "tif", labelKey: "B03_File_Slot_TerrainDem", icon: "▧", extensions: [".tif"], isRequired: false, }, ]; export function getExtension(fileName: string): string { const index = fileName.lastIndexOf("."); return index >= 0 ? fileName.slice(index).toLowerCase() : ""; } export function formatBytes(bytes: number): string { const gb = bytes / 1024 / 1024 / 1024; if (gb >= 1) return `${gb.toFixed(2)} GB`; return `${(bytes / 1024 / 1024).toFixed(2)} MB`; } export function formatEta(seconds: number | null): string { if (seconds === null || !Number.isFinite(seconds)) return "-"; if (seconds < 60) return `${Math.ceil(seconds)}s`; return `${Math.ceil(seconds / 60)}m`; } export function makeSessionKey(projectId: string, file: File): string { return `b03_upload_${projectId}_${file.name}_${file.size}`; } export function initializeSlots(): Map { const map = new Map(); for (const config of SLOT_CONFIGS) { map.set(config.slot, { ...config, uploadStatus: "pending", progressBytes: 0, speedMbs: 0, etaSeconds: null, }); } return map; } export function createFileCardTemplate(): HTMLTemplateElement { const template = document.createElement("template"); template.id = "file-card-template"; template.innerHTML = `
`; return template; }