Skip to main content

Overview

The S-Parking dashboard is a modern single-page application built with ES6 modules, leveraging native JavaScript imports for clean dependency management. The architecture follows a modular design with clear separation of concerns across UI, API, map, and utility layers.

Entry Point: main.js

The main.js file serves as the application orchestrator, initializing all modules and managing the global application state.

Module Import Structure

main.js
import { CONFIG } from './config/config.js';
import { monitorAuthState, logoutUser } from './auth/auth.js';
import { fetchParkingStatus, reserveSpot, releaseSpot } from './api/parking.js';
import { fetchZones, manageZone } from './api/zones.js';
import * as MapCore from './map/core.js';
import * as MapMarkers from './map/markers.js';
import * as MapAdmin from './map/admin.js';
import * as MapBuilder from './map/builder.js';
import * as UI_Sidebar from './ui/sidebar.js';
import * as UI_Charts from './ui/charts.js';
The import system uses:
  • Named imports for specific functions (auth, API calls)
  • Namespace imports for feature modules (Map*, UI_*)
  • Relative paths for all local modules
ES6 modules are loaded natively by the browser - no bundler required during development!

State Management

The application uses a centralized state object for reactive data flow:
main.js
const state = {
    currentUser: null,
    spots: [],
    zones: [],
    historyData: null,
    filter: 'all',
    searchQuery: '',
    myReservation: null,
    isFetching: false,
    isAdminMode: false,
    mapReady: false,
    isBuilderMode: false,
    bulkSelection: { enabled: false, zoneId: null, selected: new Set() },
    zonesSearchQuery: '',
    adminDragging: false,
    adminLastInteraction: 0
};

// Global exposure for cross-module access
window.appState = state;

State Properties

Core Data

  • spots: Array of parking spot objects
  • zones: Array of zone configurations
  • historyData: Historical occupancy data with samples and zone breakdowns

UI State

  • filter: Active filter (‘all’, ‘free’, ‘occupied’, ‘reserved’)
  • searchQuery: Current search text
  • myReservation: User’s active reservation

Admin State

  • isAdminMode: Admin toolbar visibility
  • isBuilderMode: Visual builder tool active
  • bulkSelection: Multi-select state for zone operations

Application Lifecycle

The initialization sequence follows a strict order to ensure dependencies are ready:
main.js
document.addEventListener('DOMContentLoaded', async () => {
    // 1. Initialize Chart.js visualizations
    const ctx = document.getElementById('hourly-chart');
    if (ctx) {
        UI_Charts.initChart(ctx);
    }

    // 2. Monitor authentication state
    monitorAuthState((user) => {
        state.currentUser = user;
        updateUserUI(user);
        
        // Show admin toolbar for authorized users
        if (user && user.email === '[email protected]') {
            state.isAdminMode = true;
        }
    });

    // 3. Initialize Google Maps
    await MapCore.initMap('map');
    state.mapReady = true;

    // 4. Parallel data loading
    const [parkingData, zonesData, historyResponse] = await Promise.all([
        fetchParkingStatus(),
        fetchZones(),
        fetchOccupancyHistory(2)
    ]);
    
    state.spots = parkingData || [];
    state.zones = zonesData || [];
    
    // 5. Render initial UI
    MapMarkers.updateClusterView(state.spots, state.zones, handleSpotClick);
    UI_Sidebar.renderSidebar(state.spots, state.zones, state.historyData.zoneData, 
                             state.filter, state.searchQuery, null, handleSpotClick);

    // 6. Start polling loops
    fetchData();
    setInterval(fetchData, pollingInterval);
});
Parallel data loading with Promise.all() reduces initial load time by ~40% compared to sequential requests.

Module Organization

The codebase is organized into logical feature directories:
api/
├── parking.js    # CRUD operations for spots
├── zones.js      # Zone management
└── history.js    # Occupancy history
Handles all backend communication with caching and localStorage fallbacks.

Event Handling Patterns

Global Function Exposure

For functions called from HTML onclick handlers:
main.js
function focusOnSpot(spotId) {
    const spot = window.appState.spots.find(s => s.id === spotId);
    if (!spot) return false;
    
    MapCore.mapState.map.panTo({ lat: spot.lat, lng: spot.lng });
    setTimeout(() => MapCore.mapState.map.setZoom(20), 400);
    MapMarkers.highlightSpot(spotId);
    
    return true;
}

// Expose globally BEFORE rendering UI
window.focusOnSpot = focusOnSpot;

Event Delegation

For dynamically rendered content:
sidebar.js
document.addEventListener('DOMContentLoaded', () => {
    document.addEventListener('click', (e) => {
        const card = e.target.closest('.spot-card');
        if (!card) return;
        
        const spotId = card.dataset.spotId;
        if (window.focusOnSpot) {
            window.focusOnSpot(spotId);
        }
    });
});

Admin Mode Features

Admin capabilities are conditionally enabled based on user permissions:
main.js
monitorAuthState((user) => {
    const toolbar = document.getElementById('admin-toolbar');
    if (!toolbar) return;
    
    if (user && user.email === '[email protected]') {
        toolbar.classList.remove('hidden');
        toolbar.classList.add('show');
        state.isAdminMode = true;
    } else {
        toolbar.classList.remove('show');
        toolbar.classList.add('hidden');
        state.isAdminMode = false;
    }
});
Admin features include:
  • Drag-and-drop spot repositioning
  • Visual builder for creating spot grids
  • Bulk zone assignment
  • Spot CRUD operations

Debugging & Development

The logger utility provides structured console output:
logger.js
import { logger } from './utils/logger.js';

logger.debug('✅ Google Maps initialized');
logger.error('❌ Failed to fetch parking data:', error);
Global state inspection:
// In browser console:
window.appState
// Shows current spots, zones, filters, etc.

Map Integration

Learn about Google Maps API setup and custom overlays

Builder Mode

Visual tool for creating parking spot layouts

Performance

Caching strategies and polling control

Build docs developers (and LLMs) love