FEAT: Refactor berth API functions to use dedicated utility methods for fetching and updating berths, and add connection test for NocoDB
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import type { Interest, Berth } from "@/utils/types";
|
||||
|
||||
export interface PageInfo {
|
||||
pageSize: number;
|
||||
totalRows: number;
|
||||
@@ -11,8 +13,14 @@ export interface InterestsResponse {
|
||||
PageInfo: PageInfo;
|
||||
}
|
||||
|
||||
export interface BerthsResponse {
|
||||
list: Berth[];
|
||||
PageInfo: PageInfo;
|
||||
}
|
||||
|
||||
export enum Table {
|
||||
Interest = "mbs9hjauug4eseo",
|
||||
Berth = "mczgos9hr3oa9qc",
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -414,3 +422,146 @@ export const getInterestByFieldAsync = async (fieldName: string, value: any): Pr
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// Berth functions
|
||||
export const getBerths = async () => {
|
||||
console.log('[nocodb.getBerths] Fetching berths from NocoDB...');
|
||||
|
||||
const result = await $fetch<BerthsResponse>(createTableUrl(Table.Berth), {
|
||||
headers: {
|
||||
"xc-token": getNocoDbConfiguration().token,
|
||||
},
|
||||
params: {
|
||||
limit: 1000,
|
||||
// Include interested parties (expand the linked field)
|
||||
fields: '*,Interested Parties.Id,Interested Parties.Full Name,Interested Parties.Sales Process Level,Interested Parties.EOI Status,Interested Parties.Contract Status'
|
||||
},
|
||||
});
|
||||
|
||||
console.log('[nocodb.getBerths] Successfully fetched berths, count:', result.list?.length || 0);
|
||||
|
||||
// Sort berths by letter zone and then by number using Mooring Number
|
||||
if (result.list && Array.isArray(result.list)) {
|
||||
result.list.sort((a, b) => {
|
||||
const berthA = a['Mooring Number'] || '';
|
||||
const berthB = b['Mooring Number'] || '';
|
||||
|
||||
// Extract letter and number parts
|
||||
const matchA = berthA.match(/^([A-Za-z]+)(\d+)$/);
|
||||
const matchB = berthB.match(/^([A-Za-z]+)(\d+)$/);
|
||||
|
||||
if (matchA && matchB) {
|
||||
const [, letterA, numberA] = matchA;
|
||||
const [, letterB, numberB] = matchB;
|
||||
|
||||
// First sort by letter zone
|
||||
const letterCompare = letterA.localeCompare(letterB);
|
||||
if (letterCompare !== 0) {
|
||||
return letterCompare;
|
||||
}
|
||||
|
||||
// Then sort by number within the same letter zone
|
||||
return parseInt(numberA) - parseInt(numberB);
|
||||
}
|
||||
|
||||
// Fallback to string comparison if pattern doesn't match
|
||||
return berthA.localeCompare(berthB);
|
||||
});
|
||||
|
||||
console.log('[nocodb.getBerths] Berths sorted by zone and number');
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const getBerthById = async (id: string) => {
|
||||
console.log('[nocodb.getBerthById] Fetching berth ID:', id);
|
||||
|
||||
const result = await $fetch<Berth>(`${createTableUrl(Table.Berth)}/${id}`, {
|
||||
headers: {
|
||||
"xc-token": getNocoDbConfiguration().token,
|
||||
},
|
||||
params: {
|
||||
// Include interested parties (expand the linked field)
|
||||
fields: '*,Interested Parties.Id,Interested Parties.Full Name,Interested Parties.Sales Process Level,Interested Parties.EOI Status,Interested Parties.Contract Status'
|
||||
}
|
||||
});
|
||||
|
||||
console.log('[nocodb.getBerthById] Successfully fetched berth:', result.Id);
|
||||
return result;
|
||||
};
|
||||
|
||||
export const updateBerth = async (id: string, data: Partial<Berth>): Promise<Berth> => {
|
||||
console.log('[nocodb.updateBerth] Updating berth:', id);
|
||||
console.log('[nocodb.updateBerth] Data fields:', Object.keys(data));
|
||||
|
||||
// Create a clean data object that matches the Berth schema
|
||||
const cleanData: Record<string, any> = {};
|
||||
|
||||
// Only include fields that are part of the Berth schema
|
||||
const allowedFields = [
|
||||
"Mooring Number",
|
||||
"Area",
|
||||
"Status",
|
||||
"Nominal Boat Size",
|
||||
"Water Depth",
|
||||
"Length",
|
||||
"Width",
|
||||
"Depth",
|
||||
"Side Pontoon",
|
||||
"Power Capacity",
|
||||
"Voltage",
|
||||
"Mooring Type",
|
||||
"Access",
|
||||
"Cleat Type",
|
||||
"Cleat Capacity",
|
||||
"Bollard Type",
|
||||
"Bollard Capacity",
|
||||
"Price",
|
||||
"Bow Facing"
|
||||
];
|
||||
|
||||
// Filter the data to only include allowed fields
|
||||
for (const field of allowedFields) {
|
||||
if (field in data) {
|
||||
const value = (data as any)[field];
|
||||
|
||||
// Handle clearing fields - NocoDB requires null for clearing, not undefined
|
||||
if (value === undefined) {
|
||||
cleanData[field] = null;
|
||||
console.log(`[nocodb.updateBerth] Converting undefined to null for field: ${field}`);
|
||||
} else {
|
||||
cleanData[field] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[nocodb.updateBerth] Clean data fields:', Object.keys(cleanData));
|
||||
|
||||
// PATCH requires ID in the body (not in URL)
|
||||
// Ensure ID is an integer
|
||||
cleanData.Id = parseInt(id);
|
||||
|
||||
const url = createTableUrl(Table.Berth);
|
||||
console.log('[nocodb.updateBerth] URL:', url);
|
||||
|
||||
try {
|
||||
console.log('[nocodb.updateBerth] Sending PATCH request');
|
||||
|
||||
const result = await $fetch<Berth>(url, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"xc-token": getNocoDbConfiguration().token,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: cleanData
|
||||
});
|
||||
|
||||
console.log('[nocodb.updateBerth] Update successful for ID:', id);
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
console.error('[nocodb.updateBerth] Update failed:', error);
|
||||
console.error('[nocodb.updateBerth] Error details:', error instanceof Error ? error.message : 'Unknown error');
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user