import api from '../api'; import type { ApiRequestOptions } from '../hooks/useApi'; // ============================================================================ // TYPES & INTERFACES // ============================================================================ export interface AddressSuggestion { label: string; value: string; coordinates?: { x: number; y: number; }; } /** Real Estate Project (Projekt). Backend-driven CRUD uses instanceId. */ export interface RealEstateProject { id: string; label: string; statusProzess?: string; mandateId?: string; featureInstanceId?: string; perimeter?: any; parzellen?: RealEstateParcel[]; sysCreatedAt?: number; sysModifiedAt?: number; [key: string]: any; } /** Real Estate Parcel (Parzelle). */ export interface RealEstateParcel { id: string; label?: string; mandateId?: string; featureInstanceId?: string; strasseNr?: string; plz?: string; perimeter?: any; bauzone?: string; sysCreatedAt?: number; sysModifiedAt?: number; [key: string]: any; } export interface PaginationParams { page?: number; pageSize?: number; sort?: Array<{ field: string; direction: 'asc' | 'desc' }>; filters?: Record; search?: string; } export interface PaginatedResponse { items: T[]; pagination?: { currentPage: number; pageSize: number; totalItems: number; totalPages: number; sort?: Array<{ field: string; direction: string }>; filters?: Record; }; } export type ApiRequestFunction = (options: ApiRequestOptions) => Promise; // ============================================================================ // HELPER FUNCTIONS (instanceId-based CRUD) // ============================================================================ function _getRealEstateBaseUrl(instanceId: string): string { return `/api/realestate/${instanceId}`; } function _buildPaginationParams(params?: PaginationParams): Record { if (!params) return {}; const paginationObj: Record = {}; if (params.page !== undefined) paginationObj.page = params.page; if (params.pageSize !== undefined) paginationObj.pageSize = params.pageSize; if (params.sort) paginationObj.sort = params.sort; if (params.filters) paginationObj.filters = params.filters; if (params.search) paginationObj.search = params.search; if (Object.keys(paginationObj).length === 0) return {}; return { pagination: JSON.stringify(paginationObj) } as Record; } // ============================================================================ // PROJECTS CRUD (instanceId-based) // ============================================================================ export async function fetchProjects( request: ApiRequestFunction, instanceId: string, params?: PaginationParams ): Promise> { return await request({ url: `${_getRealEstateBaseUrl(instanceId)}/projects`, method: 'get', params: _buildPaginationParams(params) }); } export async function fetchProjectById( request: ApiRequestFunction, instanceId: string, id: string ): Promise { try { return await request({ url: `${_getRealEstateBaseUrl(instanceId)}/projects/${id}`, method: 'get' }); } catch { return null; } } export async function createProject( request: ApiRequestFunction, instanceId: string, data: Partial ): Promise { return await request({ url: `${_getRealEstateBaseUrl(instanceId)}/projects`, method: 'post', data }); } export async function updateProject( request: ApiRequestFunction, instanceId: string, id: string, data: Partial ): Promise { return await request({ url: `${_getRealEstateBaseUrl(instanceId)}/projects/${id}`, method: 'put', data }); } export async function deleteProject( request: ApiRequestFunction, instanceId: string, id: string ): Promise { await request({ url: `${_getRealEstateBaseUrl(instanceId)}/projects/${id}`, method: 'delete' }); } // ============================================================================ // PARCELS CRUD (instanceId-based) // ============================================================================ export async function fetchParcels( request: ApiRequestFunction, instanceId: string, params?: PaginationParams ): Promise> { return await request({ url: `${_getRealEstateBaseUrl(instanceId)}/parcels`, method: 'get', params: _buildPaginationParams(params) }); } export async function fetchParcelById( request: ApiRequestFunction, instanceId: string, id: string ): Promise { try { return await request({ url: `${_getRealEstateBaseUrl(instanceId)}/parcels/${id}`, method: 'get' }); } catch { return null; } } export async function createParcel( request: ApiRequestFunction, instanceId: string, data: Partial ): Promise { return await request({ url: `${_getRealEstateBaseUrl(instanceId)}/parcels`, method: 'post', data }); } export async function updateParcel( request: ApiRequestFunction, instanceId: string, id: string, data: Partial ): Promise { return await request({ url: `${_getRealEstateBaseUrl(instanceId)}/parcels/${id}`, method: 'put', data }); } export async function deleteParcel( request: ApiRequestFunction, instanceId: string, id: string ): Promise { await request({ url: `${_getRealEstateBaseUrl(instanceId)}/parcels/${id}`, method: 'delete' }); } // ============================================================================ // ADDRESS AUTOCOMPLETE (legacy, no instanceId) // ============================================================================ /** * Get address autocomplete suggestions for Swiss addresses * Endpoint: GET /api/realestate/address/autocomplete * * @param query - Search text (minimum 2 characters) * @param limit - Maximum number of results (default: 10, max: 20) * @returns Array of address suggestions */ export async function autocompleteAddress( query: string, limit: number = 10 ): Promise { if (query.length < 2) { return []; } try { const trimmedQuery = query.trim(); const requestParams = { query: trimmedQuery, limit: Math.min(Math.max(limit, 1), 20) // Clamp between 1 and 20 }; if (import.meta.env.DEV) { console.log('🔍 [AddressAutocomplete] Requesting suggestions:', { query: trimmedQuery, limit: requestParams.limit, url: '/api/realestate/address/autocomplete' }); } const response = await api.get('/api/realestate/address/autocomplete', { params: requestParams }); const results = response.data || []; if (import.meta.env.DEV) { console.log('✅ [AddressAutocomplete] Received suggestions:', { count: results.length, results: results.slice(0, 3) // Log first 3 for debugging }); } return results; } catch (error: any) { // Detailed error logging const errorDetails: any = { message: error?.message || 'Unknown error', query: query.trim(), limit: limit }; if (error?.response) { // HTTP error response errorDetails.status = error.response.status; errorDetails.statusText = error.response.statusText; errorDetails.data = error.response.data; errorDetails.headers = error.response.headers; console.error('❌ [AddressAutocomplete] API Error Response:', { status: errorDetails.status, statusText: errorDetails.statusText, detail: errorDetails.data?.detail || errorDetails.data, url: error.config?.url, method: error.config?.method }); } else if (error?.request) { // Request made but no response received errorDetails.requestError = true; console.error('❌ [AddressAutocomplete] Network Error - No response received:', { message: error.message, url: error.config?.url }); } else { // Error setting up request console.error('❌ [AddressAutocomplete] Request Setup Error:', errorDetails); } // Log full error in dev mode if (import.meta.env.DEV) { console.error('❌ [AddressAutocomplete] Full error object:', error); } // Return empty array on error to allow graceful degradation return []; } }