import { withBerthQueue } from '~/server/utils/operation-lock'; import { getNocoDbConfiguration } from '~/server/utils/nocodb'; import { requireAuth } from '~/server/utils/auth'; import { BerthStatus, BerthArea, SidePontoon, MooringType, CleatType, CleatCapacity, BollardType, BollardCapacity, Access } from '~/utils/types'; export default defineEventHandler(async (event) => { console.log('[update-berth] Request received'); // Check authentication (x-tag header OR Keycloak session) await requireAuth(event); try { const body = await readBody(event); const { berthId, updates } = body; console.log('[update-berth] Request body:', { berthId, updates }); if (!berthId || !updates) { throw createError({ statusCode: 400, statusMessage: "berthId and updates object are required" }); } // Validate enum fields const validEnumFields: Record = { 'Status': Object.values(BerthStatus), 'Area': Object.values(BerthArea), 'Side Pontoon': Object.values(SidePontoon), 'Mooring Type': Object.values(MooringType), 'Cleat Type': Object.values(CleatType), 'Cleat Capacity': Object.values(CleatCapacity), 'Bollard Type': Object.values(BollardType), 'Bollard Capacity': Object.values(BollardCapacity), 'Access': Object.values(Access) }; // Validate enum values for (const [field, value] of Object.entries(updates)) { if (validEnumFields[field] && value !== null && value !== undefined) { if (!validEnumFields[field].includes(value as string)) { throw createError({ statusCode: 400, statusMessage: `Invalid value for ${field}: ${value}. Must be one of: ${validEnumFields[field].join(', ')}` }); } } } // Handle measurement conversions // If metric values are being updated, convert them to imperial for storage const measurementFields = ['Nominal Boat Size', 'Water Depth', 'Length', 'Width', 'Depth']; const processedUpdates = { ...updates }; for (const field of measurementFields) { if (processedUpdates[field] !== undefined) { const value = processedUpdates[field]; if (typeof value === 'string') { // Parse user input and convert metric to imperial if needed const cleanInput = value.replace(/[^\d.]/g, ''); const numericValue = parseFloat(cleanInput); if (!isNaN(numericValue)) { const isMetric = value.toLowerCase().includes('m') && !value.toLowerCase().includes('ft'); if (isMetric) { // Convert metric to imperial for NocoDB storage const imperial = numericValue / 0.3048; processedUpdates[field] = parseFloat(imperial.toFixed(2)); console.log(`[update-berth] Converted ${field} from ${numericValue}m to ${processedUpdates[field]}ft`); } else { // Assume imperial, store as is processedUpdates[field] = numericValue; } } } } } // Use queuing system to handle concurrent updates return await withBerthQueue(berthId, async () => { const config = getNocoDbConfiguration(); const berthsTableId = "mczgos9hr3oa9qc"; const url = `${config.url}/api/v2/tables/${berthsTableId}/records/${berthId}`; console.log('[update-berth] URL:', url); console.log('[update-berth] Processed updates:', processedUpdates); const result = await $fetch(url, { method: 'PATCH', headers: { "xc-token": config.token, }, body: processedUpdates, }); console.log('[update-berth] Successfully updated berth:', berthId); return result; }); } catch (error) { console.error('[update-berth] Error occurred:', error); console.error('[update-berth] Error details:', error instanceof Error ? error.message : 'Unknown error'); throw error; } });