TreeTrack / static /js /modules /api-client.js
RoyAalekh's picture
chore: remove Granim and telemetry UI from frontend; switch Leaflet CSS to prefetch; git rm static/telemetry.html
c3aaa58
raw
history blame
5.62 kB
/**
* API Client Module
* Handles all API communication with authentication
*/
export class ApiClient {
constructor(authManager) {
this.authManager = authManager;
}
async authenticatedFetch(url, options = {}) {
const headers = {
...this.authManager.getAuthHeaders(),
...options.headers
};
const response = await fetch(url, {
...options,
headers
});
if (response.status === 401) {
// Token expired or invalid
this.authManager.clearAuthData();
window.location.href = '/login';
return null;
}
return response;
}
async loadFormOptions() {
try {
const [utilityResponse, phenologyResponse, categoriesResponse] = await Promise.all([
this.authenticatedFetch('/api/utilities'),
this.authenticatedFetch('/api/phenology-stages'),
this.authenticatedFetch('/api/photo-categories')
]);
if (!utilityResponse || !phenologyResponse || !categoriesResponse) {
throw new Error('Failed to load form options');
}
const [utilityData, phenologyData, categoriesData] = await Promise.all([
utilityResponse.json(),
phenologyResponse.json(),
categoriesResponse.json()
]);
return {
utilities: utilityData.utilities,
phenologyStages: phenologyData.stages,
photoCategories: categoriesData.categories
};
} catch (error) {
console.error('Error loading form options:', error);
throw error;
}
}
async saveTree(treeData) {
const response = await this.authenticatedFetch('/api/trees', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(treeData)
});
if (!response) return null;
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || 'Unknown error');
}
return await response.json();
}
async updateTree(treeId, treeData) {
const response = await this.authenticatedFetch(`/api/trees/${treeId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(treeData)
});
if (!response) return null;
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || 'Unknown error');
}
return await response.json();
}
async deleteTree(treeId) {
const response = await this.authenticatedFetch(`/api/trees/${treeId}`, {
method: 'DELETE'
});
if (!response) return null;
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || 'Unknown error');
}
return true;
}
async loadTrees(limit = 20) {
const response = await this.authenticatedFetch(`/api/trees?limit=${limit}`);
if (!response) return [];
if (!response.ok) {
throw new Error('Failed to load trees');
}
return await response.json();
}
async loadTree(treeId) {
const response = await this.authenticatedFetch(`/api/trees/${treeId}`);
if (!response) return null;
if (!response.ok) {
throw new Error('Failed to fetch tree data');
}
return await response.json();
}
async loadTreeCodes() {
const response = await this.authenticatedFetch('/api/tree-codes');
if (!response) return [];
if (!response.ok) {
throw new Error('Failed to load tree codes');
}
const data = await response.json();
return data.tree_codes || [];
}
async searchTreeSuggestions(query, limit = 10) {
const response = await this.authenticatedFetch(
`/api/tree-suggestions?query=${encodeURIComponent(query)}&limit=${limit}`
);
if (!response) return [];
if (!response.ok) {
throw new Error('Failed to search tree suggestions');
}
const data = await response.json();
return data.suggestions || [];
}
async uploadFile(file, type, category = null) {
const formData = new FormData();
formData.append('file', file);
if (category) {
formData.append('category', category);
}
const endpoint = type === 'image' ? '/api/upload/image' : '/api/upload/audio';
let resJson = null;
try {
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.authManager.authToken}`
},
body: formData
});
if (!response.ok) {
// Avoid noisy telemetry; just throw error
throw new Error('Upload failed');
}
resJson = await response.json();
return resJson;
} catch (e) {
// Network or other errors
throw e;
}
}
}