Add POI feature and imporve the overall backend implementation
This commit is contained in:
163
frontend/src/services/api/geocodingApi.ts
Normal file
163
frontend/src/services/api/geocodingApi.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* Geocoding API Client
|
||||
*
|
||||
* Provides address search, autocomplete, and geocoding functionality
|
||||
* using the backend Nominatim service.
|
||||
*/
|
||||
|
||||
import { apiClient } from '../../api/client/apiClient';
|
||||
|
||||
const GEOCODING_BASE_URL = '/geocoding';
|
||||
|
||||
export interface AddressResult {
|
||||
display_name: string;
|
||||
lat: number;
|
||||
lon: number;
|
||||
osm_type: string;
|
||||
osm_id: number;
|
||||
place_id: number;
|
||||
type: string;
|
||||
class: string;
|
||||
address: {
|
||||
road?: string;
|
||||
house_number?: string;
|
||||
suburb?: string;
|
||||
city?: string;
|
||||
municipality?: string;
|
||||
state?: string;
|
||||
postcode?: string;
|
||||
country?: string;
|
||||
country_code?: string;
|
||||
};
|
||||
boundingbox: string[];
|
||||
}
|
||||
|
||||
export interface GeocodeResult {
|
||||
display_name: string;
|
||||
lat: number;
|
||||
lon: number;
|
||||
address: {
|
||||
road?: string;
|
||||
house_number?: string;
|
||||
suburb?: string;
|
||||
city?: string;
|
||||
municipality?: string;
|
||||
state?: string;
|
||||
postcode?: string;
|
||||
country?: string;
|
||||
country_code?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CoordinateValidation {
|
||||
valid: boolean;
|
||||
address?: string;
|
||||
}
|
||||
|
||||
export const geocodingApi = {
|
||||
/**
|
||||
* Search for addresses matching query (autocomplete)
|
||||
*
|
||||
* @param query - Search query (minimum 3 characters)
|
||||
* @param countryCode - ISO country code (default: 'es')
|
||||
* @param limit - Maximum number of results (default: 10)
|
||||
*/
|
||||
async searchAddresses(
|
||||
query: string,
|
||||
countryCode: string = 'es',
|
||||
limit: number = 10
|
||||
): Promise<AddressResult[]> {
|
||||
if (!query || query.trim().length < 3) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const response = await apiClient.get<AddressResult[]>(
|
||||
`${GEOCODING_BASE_URL}/search`,
|
||||
{
|
||||
params: {
|
||||
q: query,
|
||||
country_code: countryCode,
|
||||
limit
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Geocode an address to get coordinates
|
||||
*
|
||||
* @param address - Full address string
|
||||
* @param countryCode - ISO country code (default: 'es')
|
||||
*/
|
||||
async geocodeAddress(
|
||||
address: string,
|
||||
countryCode: string = 'es'
|
||||
): Promise<GeocodeResult> {
|
||||
const response = await apiClient.get<GeocodeResult>(
|
||||
`${GEOCODING_BASE_URL}/geocode`,
|
||||
{
|
||||
params: {
|
||||
address,
|
||||
country_code: countryCode
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Reverse geocode coordinates to get address
|
||||
*
|
||||
* @param lat - Latitude
|
||||
* @param lon - Longitude
|
||||
*/
|
||||
async reverseGeocode(
|
||||
lat: number,
|
||||
lon: number
|
||||
): Promise<GeocodeResult> {
|
||||
const response = await apiClient.get<GeocodeResult>(
|
||||
`${GEOCODING_BASE_URL}/reverse`,
|
||||
{
|
||||
params: { lat, lon }
|
||||
}
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate coordinates
|
||||
*
|
||||
* @param lat - Latitude
|
||||
* @param lon - Longitude
|
||||
*/
|
||||
async validateCoordinates(
|
||||
lat: number,
|
||||
lon: number
|
||||
): Promise<CoordinateValidation> {
|
||||
const response = await apiClient.get<CoordinateValidation>(
|
||||
`${GEOCODING_BASE_URL}/validate`,
|
||||
{
|
||||
params: { lat, lon }
|
||||
}
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check geocoding service health
|
||||
*/
|
||||
async checkHealth(): Promise<{
|
||||
status: string;
|
||||
service: string;
|
||||
base_url: string;
|
||||
is_public_api: boolean;
|
||||
}> {
|
||||
const response = await apiClient.get(`${GEOCODING_BASE_URL}/health`);
|
||||
return response;
|
||||
}
|
||||
};
|
||||
109
frontend/src/services/api/poiContextApi.ts
Normal file
109
frontend/src/services/api/poiContextApi.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* POI Context API Client
|
||||
*
|
||||
* API client for POI detection and context management
|
||||
*/
|
||||
|
||||
import { apiClient } from '../../api/client/apiClient';
|
||||
import type {
|
||||
POIDetectionResponse,
|
||||
POIContextResponse,
|
||||
FeatureImportanceResponse,
|
||||
CompetitorAnalysis,
|
||||
POICacheStats
|
||||
} from '@/types/poi';
|
||||
|
||||
const POI_BASE_URL = '/poi-context';
|
||||
|
||||
export const poiContextApi = {
|
||||
/**
|
||||
* Detect POIs for a tenant's bakery location
|
||||
*/
|
||||
async detectPOIs(
|
||||
tenantId: string,
|
||||
latitude: number,
|
||||
longitude: number,
|
||||
forceRefresh: boolean = false
|
||||
): Promise<POIDetectionResponse> {
|
||||
const response = await apiClient.post<POIDetectionResponse>(
|
||||
`${POI_BASE_URL}/${tenantId}/detect`,
|
||||
null,
|
||||
{
|
||||
params: {
|
||||
latitude,
|
||||
longitude,
|
||||
force_refresh: forceRefresh
|
||||
}
|
||||
}
|
||||
);
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get POI context for a tenant
|
||||
*/
|
||||
async getPOIContext(tenantId: string): Promise<POIContextResponse> {
|
||||
const response = await apiClient.get<POIContextResponse>(
|
||||
`${POI_BASE_URL}/${tenantId}`
|
||||
);
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Refresh POI context for a tenant
|
||||
*/
|
||||
async refreshPOIContext(tenantId: string): Promise<POIDetectionResponse> {
|
||||
const response = await apiClient.post<POIDetectionResponse>(
|
||||
`${POI_BASE_URL}/${tenantId}/refresh`
|
||||
);
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete POI context for a tenant
|
||||
*/
|
||||
async deletePOIContext(tenantId: string): Promise<void> {
|
||||
await apiClient.delete(`${POI_BASE_URL}/${tenantId}`);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get feature importance summary
|
||||
*/
|
||||
async getFeatureImportance(tenantId: string): Promise<FeatureImportanceResponse> {
|
||||
const response = await apiClient.get<FeatureImportanceResponse>(
|
||||
`${POI_BASE_URL}/${tenantId}/feature-importance`
|
||||
);
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get competitor analysis
|
||||
*/
|
||||
async getCompetitorAnalysis(tenantId: string): Promise<{
|
||||
tenant_id: string;
|
||||
location: { latitude: number; longitude: number };
|
||||
competitor_analysis: CompetitorAnalysis;
|
||||
insights: string[];
|
||||
}> {
|
||||
const response = await apiClient.get(
|
||||
`${POI_BASE_URL}/${tenantId}/competitor-analysis`
|
||||
);
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check POI service health
|
||||
*/
|
||||
async checkHealth(): Promise<{ status: string; overpass_api: any }> {
|
||||
const response = await apiClient.get(`${POI_BASE_URL}/health`);
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get cache statistics
|
||||
*/
|
||||
async getCacheStats(): Promise<{ status: string; cache_stats: POICacheStats }> {
|
||||
const response = await apiClient.get(`${POI_BASE_URL}/cache/stats`);
|
||||
return response;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user