class GeneticAlgorithmManager { constructor() { this.apiBaseUrl = '/api/genetic'; this.setupEventListeners(); } setupEventListeners() { // Initialize any UI elements if needed document.addEventListener('DOMContentLoaded', () => { this.initializeUI(); }); } initializeUI() { // Set up event listeners for genetic algorithm buttons const optimizeBtn = document.getElementById('optimize-assignments-btn'); const previewBtn = document.getElementById('preview-optimization-btn'); const applyBtn = document.getElementById('apply-optimization-btn'); if (optimizeBtn) { optimizeBtn.addEventListener('click', () => this.handleOptimizeReservations()); } if (previewBtn) { previewBtn.addEventListener('click', () => this.handlePreviewOptimization()); } if (applyBtn) { applyBtn.addEventListener('click', () => this.handleApplyOptimization()); } } async optimizeReservations(commissionIds, startDate = null, endDate = null) { try { const requestBody = { commission_ids: commissionIds }; if (startDate) { requestBody.start_date = startDate; } if (endDate) { requestBody.end_date = endDate; } const response = await fetch(`${this.apiBaseUrl}/optimize`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': this.getCSRFToken() }, body: JSON.stringify(requestBody) }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || 'Optimization failed'); } return await response.json(); } catch (error) { console.error('Error optimizing reservations:', error); throw error; } } async previewOptimization(commissionIds) { try { const response = await fetch(`${this.apiBaseUrl}/preview-optimization`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': this.getCSRFToken() }, body: JSON.stringify({ commission_ids: commissionIds, dry_run: true }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || 'Preview failed'); } return await response.json(); } catch (error) { console.error('Error previewing optimization:', error); throw error; } } async applyOptimization(reservations) { try { const response = await fetch(`${this.apiBaseUrl}/apply-optimization`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': this.getCSRFToken() }, body: JSON.stringify({ reservations: reservations }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || 'Failed to apply optimization'); } return await response.json(); } catch (error) { console.error('Error applying optimization:', error); throw error; } } async getAlgorithmStatus() { try { const response = await fetch(`${this.apiBaseUrl}/algorithm-status`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': this.getCSRFToken() } }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || 'Failed to get algorithm status'); } return await response.json(); } catch (error) { console.error('Error getting algorithm status:', error); throw error; } } async handleOptimizeReservations() { try { // Get selected commissions from UI const commissionIds = this.getSelectedCommissionIds(); if (commissionIds.length === 0) { this.showAlert('Please select at least one commission to optimize.', 'warning'); return; } this.showLoading(true); const result = await this.optimizeReservations(commissionIds); if (result.success) { this.displayOptimizationResults(result.data); this.showAlert('Optimization completed successfully!', 'success'); } else { this.showAlert('Optimization failed: ' + (result.error || 'Unknown error'), 'danger'); } } catch (error) { this.showAlert('Error during optimization: ' + error.message, 'danger'); } finally { this.showLoading(false); } } async handlePreviewOptimization() { try { const commissionIds = this.getSelectedCommissionIds(); if (commissionIds.length === 0) { this.showAlert('Please select at least one commission to preview.', 'warning'); return; } this.showLoading(true); const result = await this.previewOptimization(commissionIds); if (result.success) { this.displayPreviewResults(result.data); this.showAlert('Preview generated successfully!', 'success'); } else { this.showAlert('Preview failed: ' + (result.error || 'Unknown error'), 'danger'); } } catch (error) { this.showAlert('Error during preview: ' + error.message, 'danger'); } finally { this.showLoading(false); } } async handleApplyOptimization() { try { const pendingReservations = this.getPendingReservations(); if (!pendingReservations || pendingReservations.length === 0) { this.showAlert('No pending reservations to apply.', 'warning'); return; } if (!confirm('Are you sure you want to apply these reservations? This will create actual reservation records.')) { return; } this.showLoading(true); const result = await this.applyOptimization(pendingReservations); if (result.success) { this.showAlert(`Successfully applied ${result.data.applied_count} reservations!`, 'success'); this.clearPendingReservations(); // Redirect to reservations page window.location.href = '/schedule'; } else { this.showAlert('Failed to apply reservations: ' + (result.error || 'Unknown error'), 'danger'); } } catch (error) { this.showAlert('Error applying reservations: ' + error.message, 'danger'); } finally { this.showLoading(false); } } getSelectedCommissionIds() { const checkboxes = document.querySelectorAll('input[name="commission_ids"]:checked'); return Array.from(checkboxes).map(cb => parseInt(cb.value)); } getPendingReservations() { // Try to get from localStorage or a hidden form field const stored = localStorage.getItem('pending_optimizations'); return stored ? JSON.parse(stored) : null; } storePendingReservations(reservations) { localStorage.setItem('pending_optimizations', JSON.stringify(reservations)); } clearPendingReservations() { localStorage.removeItem('pending_optimizations'); } displayOptimizationResults(data) { // Store the results for potential application this.storePendingReservations(data.reservations); // Create results display const resultsContainer = document.getElementById('optimization-results'); if (!resultsContainer) return; const scorePercentage = (data.fitness_score * 100).toFixed(1); resultsContainer.innerHTML = `
Reservations Assigned
Fitness Score
Total Requests
| Code | Name | Students |
|---|
| # | Purpose | Classroom | Start Time | End Time | Attendees |
|---|