'use strict'; const API_PREFIX = '/api'; let __boxStatusCache = null; let __boxStatusFetchedAt = 0; function stripPhotoDataUrl(value) { if (Array.isArray(value)) { return value.map((item) => stripPhotoDataUrl(item)); } if (!value || typeof value !== 'object') { return value; } const clone = {}; for (const [key, child] of Object.entries(value)) { if (key === 'photoDataUrl') continue; clone[key] = stripPhotoDataUrl(child); } return clone; } async function parseApiResponse(response) { let payload = null; try { payload = await response.json(); } catch { payload = null; } if (!response.ok) { throw new Error(payload?.error || payload?.message || `Request failed with HTTP ${response.status}`); } return payload; } async function apiRequest(path, options = {}) { const response = await fetch(`${API_PREFIX}${path}`, { method: options.method || 'GET', headers: { ...(options.rawBody ? {} : { 'Content-Type': 'application/json' }), ...(options.headers || {}), }, ...(options.body !== undefined ? { body: options.body } : {}), }); return parseApiResponse(response); } async function getBoxStatus(options = {}) { const { force = false } = options; if (__boxStatusCache && !force && (Date.now() - __boxStatusFetchedAt) < 10000) { return __boxStatusCache; } const payload = await apiRequest('/box/status', { method: 'GET' }); __boxStatusCache = payload?.status || {}; __boxStatusFetchedAt = Date.now(); return __boxStatusCache; } function buildMissingConfigMessage(status = {}) { if (!status.hasAuth) { return 'Box authentication is not configured on the backend. Open settings.html and save the Box integration first.'; } if (!status.hasIntakeFolderId) { return 'Incoming intake folder ID is not configured. Open settings.html and save the Box integration first.'; } return 'Box is not configured on the backend. Open settings.html and save the Box integration first.'; } async function testBoxConnection() { try { const payload = await apiRequest('/box/test-connection', { method: 'POST', body: JSON.stringify({}), }); __boxStatusCache = null; __boxStatusFetchedAt = 0; return payload; } catch (error) { return { ok: false, error: error.message }; } } async function uploadPhoto(file, caseId) { if (!file) { throw new Error('Photo file is required.'); } const status = await getBoxStatus(); if (!status.configured) { throw new Error(buildMissingConfigMessage(status)); } const payload = await apiRequest(`/box/upload-photo?caseId=${encodeURIComponent(caseId)}`, { method: 'POST', rawBody: true, headers: { 'Content-Type': file.type || 'application/octet-stream', }, body: file, }); return { fileId: payload.fileId || '', sharedLink: payload.sharedLink || null, photoUrl: payload.photoUrl || '', }; } async function uploadSidecar(metadata, caseId) { const status = await getBoxStatus(); if (!status.configured) { throw new Error(buildMissingConfigMessage(status)); } const payload = await apiRequest('/box/upload-sidecar', { method: 'POST', body: JSON.stringify({ caseId, metadata: stripPhotoDataUrl(metadata || {}), }), }); return { fileId: payload.fileId || '', sidecarPayload: payload.sidecarPayload || null, }; } async function submitToBox(photoFile, metadata) { const providedCaseId = metadata && typeof metadata.caseId === 'string' ? metadata.caseId.trim() : ''; const randomSuffix = Math.random() .toString(36) .toUpperCase() .replace(/[^A-Z]/g, '') .slice(0, 4) .padEnd(4, 'X'); const caseId = providedCaseId || `PHX-${Date.now()}-${randomSuffix}`; const submittedAt = metadata?.submittedAt || new Date().toISOString(); const sanitizedMetadata = stripPhotoDataUrl({ ...metadata, caseId, submittedAt, }); try { const photoResult = await uploadPhoto(photoFile, caseId); const sidecarResult = await uploadSidecar({ ...sanitizedMetadata, photoFileId: photoResult.fileId || '', photoUrl: photoResult.photoUrl || '', }, caseId); return { success: true, caseId, photoFileId: photoResult.fileId || '', sidecarFileId: sidecarResult.fileId || '', sidecarPayload: sidecarResult.sidecarPayload || sanitizedMetadata, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : String(error), }; } } if (typeof module !== 'undefined' && module.exports) { module.exports = { getBoxStatus, testBoxConnection, uploadPhoto, uploadSidecar, submitToBox, stripPhotoDataUrl, }; } if (typeof window !== 'undefined') { window.getBoxStatus = getBoxStatus; window.testBoxConnection = testBoxConnection; window.submitToBox = submitToBox; window.BoxUpload = { getBoxStatus, testBoxConnection, uploadPhoto, uploadSidecar, submitToBox, stripPhotoDataUrl, }; }