Skip to main content

Overview

The Zones API provides functions to fetch, create, update, and delete parking zones. It includes intelligent caching (5-minute TTL) and localStorage fallback for offline operation.

Import

import { 
  fetchZones, 
  manageZone, 
  invalidateZonesCache 
} from './js/api/zones.js';

Caching Behavior

The Zones API implements a two-layer caching strategy:
  • Memory Cache: Stores zones in memory with 5-minute TTL
  • localStorage Cache: Persistent fallback storage when API is unavailable

Cache Keys

STORAGE_KEY_ZONES
string
default:"'sparking_zones_local'"
localStorage key for cached zones data
STORAGE_KEY_ZONES_SYNC
string
default:"'sparking_zones_synced_at'"
localStorage key for last sync timestamp (ISO 8601 format)

Cache Duration

The cache TTL is configurable via CONFIG.PERFORMANCE.CACHE_ZONES (default: 300000ms = 5 minutes).

fetchZones

Retrieves all parking zones with intelligent caching.

Function Signature

async function fetchZones(): Promise<Array<Zone>>

Returns

zones
array
Array of zone objects
id
string
Unique zone identifier (e.g., “zone_vip”, “zone_general”)
name
string
Display name of the zone
order
number
Sort order for display (lower numbers appear first)
desc
string
Zone description
color
string
Color identifier for UI rendering (e.g., “blue”, “red”, “green”)
created_at
string
Creation timestamp (ISO 8601)
updated_at
string
Last update timestamp (ISO 8601)
_local
boolean
Flag indicating zone exists only in localStorage (not synced to server)

Cache Behavior

  1. Memory cache hit: Returns cached data if less than 5 minutes old
  2. API call: Fetches from CONFIG.GET_ZONES_URL and updates both memory and localStorage
  3. Fallback: Returns localStorage data if API fails
  4. Empty array: Returns [] if both API and localStorage are unavailable

Usage Example

import { fetchZones } from './js/api/zones.js';

try {
  const zones = await fetchZones();
  console.log(`Loaded ${zones.length} zones`);
  
  // Sort by display order
  const sortedZones = zones.sort((a, b) => a.order - b.order);
  
  // Render zone selector
  sortedZones.forEach(zone => {
    console.log(`${zone.name} (${zone.color})`);
  });
} catch (error) {
  console.error('Failed to load zones:', error);
}

manageZone

Unified function to create, update, or delete zones.

Function Signature

async function manageZone(
  action: 'create' | 'update' | 'delete',
  zoneData: ZoneData
): Promise<ManageZoneResponse>

Parameters

action
string
required
Operation to perform: 'create', 'update', or 'delete'
zoneData
object
required
Zone data object with fields depending on action

Zone Data Fields

zoneData.id
string
Zone ID (required for update and delete)
zoneData.name
string
Zone display name (required for create, optional for update)
zoneData.order
number
Sort order (default: 999)
zoneData.desc
string
Zone description
zoneData.color
string
Color identifier (default: “blue”)

Returns

response
object
Operation result object
success
boolean
Whether the operation succeeded
zone
object
Created or updated zone object (for create/update actions)
_local
boolean
If true, change was saved only to localStorage (offline mode)

Behavior

  • Invalidates zones cache immediately
  • Sends POST request to CONFIG.MANAGE_ZONES_URL
  • On API failure, saves changes locally with _local: true flag
  • After success, refreshes localStorage with latest data

Usage Examples

Create Zone

import { manageZone } from './js/api/zones.js';

const result = await manageZone('create', {
  name: 'VIP Section',
  order: 1,
  desc: 'Premium parking area near main entrance',
  color: 'gold'
});

if (result.success) {
  console.log('Zone created:', result.zone);
  if (result._local) {
    console.warn('Zone saved locally - will sync when online');
  }
}

Update Zone

import { manageZone } from './js/api/zones.js';

// Update zone name and description
const result = await manageZone('update', {
  id: 'zone_vip',
  name: 'Executive Parking',
  desc: 'Reserved for executives and guests'
});

if (result.success) {
  console.log('Zone updated:', result.zone);
}

Delete Zone

import { manageZone } from './js/api/zones.js';

const result = await manageZone('delete', {
  id: 'zone_old'
});

if (result.success) {
  console.log('Zone deleted');
}

Complete Workflow Example

import { fetchZones, manageZone, invalidateZonesCache } from './js/api/zones.js';

// Load existing zones
const zones = await fetchZones();
console.log(`Current zones: ${zones.length}`);

// Create new zone
const newZone = await manageZone('create', {
  name: 'Visitor Parking',
  order: 10,
  color: 'blue'
});

if (newZone.success) {
  // Update the zone's description
  await manageZone('update', {
    id: newZone.zone.id,
    desc: 'Short-term parking for visitors'
  });
  
  // Force cache refresh
  invalidateZonesCache();
  
  // Reload zones
  const updatedZones = await fetchZones();
  console.log(`Updated zones: ${updatedZones.length}`);
}

invalidateZonesCache

Manually invalidates the memory cache to force a fresh API call.

Function Signature

function invalidateZonesCache(): void

Usage Example

import { invalidateZonesCache, fetchZones } from './js/api/zones.js';

// After external update
invalidateZonesCache();
const freshZones = await fetchZones();

Helper Functions

Convenience Wrappers

You can create convenience wrappers for cleaner code:
import { manageZone } from './js/api/zones.js';

// Create zone helper
export async function createZone(name, order, desc, color = 'blue') {
  return await manageZone('create', { name, order, desc, color });
}

// Update zone helper
export async function updateZone(id, updates) {
  return await manageZone('update', { id, ...updates });
}

// Delete zone helper
export async function deleteZone(id) {
  return await manageZone('delete', { id });
}

// Usage
const result = await createZone('Guest Parking', 5, 'Visitor area');

Error Handling

All operations can fail. Recommended error handling:
import { fetchZones, manageZone } from './js/api/zones.js';

// Wrap in try-catch
try {
  const zones = await fetchZones();
  
  await manageZone('create', {
    name: 'New Zone',
    order: 20
  });
} catch (error) {
  console.error('Zone operation failed:', error.message);
  // Show error to user
}

// Check result status
const result = await manageZone('update', { id: 'zone_1', name: 'Updated' });
if (!result || !result.success) {
  console.error('Update failed');
}

Offline Support

The Zones API includes full offline support:

Read Operations

  • Falls back to localStorage if API is unavailable
  • Returns empty array if no cached data exists

Write Operations

  • Saves changes locally with _local: true flag
  • Changes persist until next successful API sync

Detecting Offline Changes

import { fetchZones } from './js/api/zones.js';

const zones = await fetchZones();
const localZones = zones.filter(z => z._local);

if (localZones.length > 0) {
  console.warn(`${localZones.length} zones not synced to server`);
  // Show sync indicator in UI
}

Integration with Parking API

Zones and parking spots are linked via zone_id:
import { fetchZones } from './js/api/zones.js';
import { fetchParkingStatus } from './js/api/parking.js';

const [zones, spots] = await Promise.all([
  fetchZones(),
  fetchParkingStatus()
]);

// Group spots by zone
const spotsByZone = {};
zones.forEach(zone => {
  spotsByZone[zone.id] = spots.filter(s => s.zone_id === zone.id);
});

// Display zone statistics
zones.forEach(zone => {
  const zoneSpots = spotsByZone[zone.id] || [];
  const available = zoneSpots.filter(s => s.status === 1).length;
  console.log(`${zone.name}: ${available}/${zoneSpots.length} available`);
});

Build docs developers (and LLMs) love