feat(web): add saved searches, image lightbox, and web vitals tracking
New features: - Saved searches dashboard page with CRUD hooks and API client - Image lightbox component for property gallery full-screen viewing - Web vitals provider and reporting utilities for performance monitoring - Image blur placeholder generation utility Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
66
apps/web/lib/saved-search-api.ts
Normal file
66
apps/web/lib/saved-search-api.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { apiClient } from './api-client';
|
||||
|
||||
// ─── Interfaces ──────────────────────────────────────────
|
||||
|
||||
export interface SavedSearchFilters {
|
||||
transactionType?: string;
|
||||
propertyType?: string;
|
||||
city?: string;
|
||||
district?: string;
|
||||
priceMin?: string;
|
||||
priceMax?: string;
|
||||
areaMin?: string;
|
||||
areaMax?: string;
|
||||
bedrooms?: string;
|
||||
}
|
||||
|
||||
export interface SavedSearch {
|
||||
id: string;
|
||||
name: string;
|
||||
filters: SavedSearchFilters;
|
||||
alertEnabled: boolean;
|
||||
lastAlertAt: string | null;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface SavedSearchListResult {
|
||||
data: SavedSearch[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
}
|
||||
|
||||
export interface CreateSavedSearchPayload {
|
||||
name: string;
|
||||
filters: SavedSearchFilters;
|
||||
alertEnabled?: boolean;
|
||||
}
|
||||
|
||||
export interface UpdateSavedSearchPayload {
|
||||
name?: string;
|
||||
filters?: SavedSearchFilters;
|
||||
alertEnabled?: boolean;
|
||||
}
|
||||
|
||||
// ─── API Functions ───────────────────────────────────────
|
||||
|
||||
export const savedSearchApi = {
|
||||
list: (params: { page?: number; limit?: number } = {}) => {
|
||||
const query = new URLSearchParams();
|
||||
if (params.page) query.append('page', String(params.page));
|
||||
if (params.limit) query.append('limit', String(params.limit));
|
||||
const qs = query.toString();
|
||||
return apiClient.get<SavedSearchListResult>(`/saved-searches${qs ? `?${qs}` : ''}`);
|
||||
},
|
||||
|
||||
getById: (id: string) => apiClient.get<SavedSearch>(`/saved-searches/${id}`),
|
||||
|
||||
create: (data: CreateSavedSearchPayload) =>
|
||||
apiClient.post<SavedSearch>('/saved-searches', data),
|
||||
|
||||
update: (id: string, data: UpdateSavedSearchPayload) =>
|
||||
apiClient.patch<SavedSearch>(`/saved-searches/${id}`, data),
|
||||
|
||||
delete: (id: string) =>
|
||||
apiClient.delete<{ deleted: boolean }>(`/saved-searches/${id}`),
|
||||
};
|
||||
Reference in New Issue
Block a user