Spaces:
Running
Running
/** | |
* TreeTrack Enhanced Application - Modular Architecture | |
* Professional Field Research Tool with Authentication | |
*/ | |
// Import all modules | |
import { AuthManager } from './modules/auth-manager.js'; | |
import { ApiClient } from './modules/api-client.js'; | |
import { UIManager } from './modules/ui-manager.js'; | |
import { FormManager } from './modules/form-manager.js'; | |
import { AutoCompleteManager } from './modules/autocomplete-manager.js'; | |
import { MediaManager } from './modules/media-manager.js'; | |
export class TreeTrackApp { | |
constructor() { | |
// Initialize core managers | |
this.authManager = new AuthManager(); | |
this.apiClient = new ApiClient(this.authManager); | |
this.uiManager = new UIManager(this.authManager); | |
this.formManager = new FormManager(this.apiClient, this.uiManager); | |
this.autoCompleteManager = new AutoCompleteManager(this.apiClient, this.uiManager); | |
this.mediaManager = new MediaManager(this.formManager, this.uiManager); | |
this.init(); | |
} | |
async init() { | |
try { | |
// Check authentication first | |
if (!await this.authManager.checkAuthentication()) { | |
window.location.href = '/login'; | |
return; | |
} | |
// Initialize all managers | |
await this.initializeManagers(); | |
// Setup event listeners | |
this.setupEventListeners(); | |
// Load initial data | |
await this.loadInitialData(); | |
} catch (error) { | |
console.error('Error initializing TreeTrack app:', error); | |
this.uiManager.showMessage('Error initializing application: ' + error.message, 'error'); | |
} | |
} | |
async initializeManagers() { | |
// Initialize UI first | |
this.uiManager.initialize(); | |
// Initialize form components | |
await this.formManager.initialize(); | |
// Initialize media handling | |
this.mediaManager.initialize(); | |
// Initialize autocomplete (with delay to ensure DOM is ready) | |
setTimeout(async () => { | |
await this.autoCompleteManager.initialize(); | |
}, 100); | |
} | |
setupEventListeners() { | |
// Form submission | |
const form = document.getElementById('treeForm'); | |
if (form) { | |
form.addEventListener('submit', (e) => this.handleFormSubmit(e)); | |
} | |
// Reset form | |
const resetBtn = document.getElementById('resetForm'); | |
if (resetBtn) { | |
resetBtn.addEventListener('click', () => this.handleFormReset()); | |
} | |
// GPS location | |
const locationBtn = document.getElementById('getLocation'); | |
if (locationBtn) { | |
locationBtn.addEventListener('click', () => this.mediaManager.getCurrentLocation()); | |
} | |
// Logout functionality | |
const logoutBtn = document.getElementById('logoutBtn'); | |
if (logoutBtn) { | |
logoutBtn.addEventListener('click', () => this.authManager.logout()); | |
} | |
// Tree actions (edit/delete) | |
document.addEventListener('click', (e) => { | |
if (e.target.matches('.edit-tree')) { | |
const treeId = e.target.dataset.treeId; | |
if (treeId) { | |
this.handleEditTree(parseInt(treeId)); | |
} | |
} | |
if (e.target.matches('.delete-tree')) { | |
const treeId = e.target.dataset.treeId; | |
if (treeId) { | |
this.handleDeleteTree(parseInt(treeId)); | |
} | |
} | |
if (e.target.matches('#cancelEdit')) { | |
this.handleCancelEdit(); | |
} | |
}); | |
} | |
async loadInitialData() { | |
try { | |
await this.loadTrees(); | |
} catch (error) { | |
console.error('Error loading initial data:', error); | |
} | |
} | |
async handleFormSubmit(e) { | |
e.preventDefault(); | |
try { | |
// Clear any previous field errors | |
this.uiManager.clearFieldErrors(); | |
// Validate form | |
this.formManager.validateForm(); | |
// Get form data | |
const treeData = this.formManager.getFormData(); | |
// Save or update tree | |
let result; | |
if (this.formManager.isInEditMode()) { | |
result = await this.apiClient.updateTree(this.formManager.getCurrentEditId(), treeData); | |
this.uiManager.showMessage(`Tree #${result.id} updated successfully!`, 'success'); | |
this.handleCancelEdit(); | |
} else { | |
result = await this.apiClient.saveTree(treeData); | |
this.uiManager.showMessage( | |
`Tree successfully added! Tree ID: ${result.id}. The form has been cleared for your next entry.`, | |
'success' | |
); | |
this.formManager.resetForm(true); | |
} | |
// Refresh tree list | |
await this.loadTrees(); | |
this.uiManager.scrollToTop(); | |
} catch (error) { | |
console.error('Error submitting form:', error); | |
this.uiManager.showMessage('Error saving tree: ' + error.message, 'error'); | |
this.uiManager.focusFirstError(); | |
} | |
} | |
handleFormReset() { | |
this.formManager.resetForm(); | |
this.uiManager.clearFieldErrors(); | |
} | |
async handleEditTree(treeId) { | |
try { | |
this.uiManager.showLoadingState('message', 'Loading tree data...'); | |
const tree = await this.apiClient.loadTree(treeId); | |
if (!tree) return; | |
this.formManager.populateForm(tree); | |
this.formManager.setEditMode(treeId); | |
this.uiManager.showMessage(`Loaded tree #${treeId} for editing. Make changes and save.`, 'success'); | |
this.uiManager.scrollToTop(); | |
} catch (error) { | |
console.error('Error loading tree for edit:', error); | |
this.uiManager.showMessage('Error loading tree data: ' + error.message, 'error'); | |
} | |
} | |
async handleDeleteTree(treeId) { | |
if (!this.uiManager.confirmDeletion(treeId)) { | |
return; | |
} | |
try { | |
await this.apiClient.deleteTree(treeId); | |
this.uiManager.showMessage(`Tree #${treeId} deleted successfully.`, 'success'); | |
await this.loadTrees(); | |
} catch (error) { | |
console.error('Error deleting tree:', error); | |
this.uiManager.showMessage('Error deleting tree: ' + error.message, 'error'); | |
} | |
} | |
handleCancelEdit() { | |
this.formManager.resetForm(true); | |
this.formManager.exitEditMode(); | |
this.uiManager.clearFieldErrors(); | |
this.uiManager.showMessage('Edit cancelled. Form cleared.', 'success'); | |
} | |
async loadTrees() { | |
try { | |
this.uiManager.showLoadingState('treeList', 'Loading trees...'); | |
const trees = await this.apiClient.loadTrees(); | |
this.uiManager.renderTreeList(trees); | |
} catch (error) { | |
console.error('Error loading trees:', error); | |
this.uiManager.showErrorState('treeList', 'Error loading trees'); | |
} | |
} | |
// Utility methods for external access (maintaining compatibility) | |
showMessage(message, type) { | |
this.uiManager.showMessage(message, type); | |
} | |
// Global functions for backward compatibility (deprecated - use event delegation instead) | |
editTree(treeId) { | |
console.warn('Global editTree function is deprecated. Use data attributes instead.'); | |
this.handleEditTree(treeId); | |
} | |
deleteTree(treeId) { | |
console.warn('Global deleteTree function is deprecated. Use data attributes instead.'); | |
this.handleDeleteTree(treeId); | |
} | |
capturePhoto(category) { | |
console.warn('Global capturePhoto function is deprecated. Use data attributes instead.'); | |
this.mediaManager.capturePhoto(category); | |
} | |
} | |
// Initialize the app when the page loads | |
let app; | |
document.addEventListener('DOMContentLoaded', () => { | |
app = new TreeTrackApp(); | |
}); | |
// Expose app globally for debugging and backward compatibility | |
window.TreeTrackApp = TreeTrackApp; | |
window.app = app; | |