// Map control buttons and utilities
// This file contains all button controls that are positioned on the top-right corner of the map
import L from "leaflet";
import { applyThemeToButton } from "./theme_utils";
/**
* Creates a standardized button element for map controls
* @param {String} className - CSS class name for the button
* @param {String} svgIcon - SVG icon HTML
* @param {String} title - Button title/tooltip
* @param {String} userTheme - User's theme preference ('dark' or 'light')
* @param {Function} onClickCallback - Callback function to execute when button is clicked
* @returns {HTMLElement} Button element
*/
function createStandardButton(className, svgIcon, title, userTheme, onClickCallback) {
const button = L.DomUtil.create('button', className);
button.innerHTML = svgIcon;
button.title = title;
// Apply standard button styling
applyThemeToButton(button, userTheme);
button.style.width = '48px';
button.style.height = '48px';
button.style.borderRadius = '4px';
button.style.padding = '0';
button.style.display = 'flex';
button.style.alignItems = 'center';
button.style.justifyContent = 'center';
button.style.fontSize = '18px';
button.style.transition = 'all 0.2s ease';
// Disable map interactions when clicking the button
L.DomEvent.disableClickPropagation(button);
// Attach click handler if provided
// Note: Some buttons (like Add Visit) have their handlers attached separately
if (onClickCallback && typeof onClickCallback === 'function') {
L.DomEvent.on(button, 'click', () => {
onClickCallback(button);
});
}
return button;
}
/**
* Creates a "Toggle Panel" button control for the map
* @param {Function} onClickCallback - Callback function to execute when button is clicked
* @param {String} userTheme - User's theme preference ('dark' or 'light')
* @returns {L.Control} Leaflet control instance
*/
export function createTogglePanelControl(onClickCallback, userTheme = 'dark') {
const TogglePanelControl = L.Control.extend({
onAdd: function(map) {
const svgIcon = `
`;
return createStandardButton('toggle-panel-button', svgIcon, 'Toggle Panel', userTheme, onClickCallback);
}
});
return TogglePanelControl;
}
/**
* Creates a "Visits Drawer" button control for the map
* @param {Function} onClickCallback - Callback function to execute when button is clicked
* @param {String} userTheme - User's theme preference ('dark' or 'light')
* @returns {L.Control} Leaflet control instance
*/
export function createVisitsDrawerControl(onClickCallback, userTheme = 'dark') {
const DrawerControl = L.Control.extend({
onAdd: function(map) {
const svgIcon = '';
return createStandardButton('leaflet-control-button drawer-button', svgIcon, 'Toggle Visits Drawer', userTheme, onClickCallback);
}
});
return DrawerControl;
}
/**
* Creates an "Area Selection" button control for the map
* @param {Function} onClickCallback - Callback function to execute when button is clicked
* @param {String} userTheme - User's theme preference ('dark' or 'light')
* @returns {L.Control} Leaflet control instance
*/
export function createAreaSelectionControl(onClickCallback, userTheme = 'dark') {
const SelectionControl = L.Control.extend({
onAdd: function(map) {
const svgIcon = '';
const button = createStandardButton('leaflet-bar leaflet-control leaflet-control-custom', svgIcon, 'Select Area', userTheme, onClickCallback);
button.id = 'selection-tool-button';
return button;
}
});
return SelectionControl;
}
/**
* Creates an "Add Visit" button control for the map
* @param {Function} onClickCallback - Callback function to execute when button is clicked
* @param {String} userTheme - User's theme preference ('dark' or 'light')
* @returns {L.Control} Leaflet control instance
*/
export function createAddVisitControl(onClickCallback, userTheme = 'dark') {
const AddVisitControl = L.Control.extend({
onAdd: function(map) {
const svgIcon = '';
return createStandardButton('leaflet-control-button add-visit-button', svgIcon, 'Add a visit', userTheme, onClickCallback);
}
});
return AddVisitControl;
}
/**
* Adds all top-right corner buttons to the map in the correct order
* Order: 1. Select Area, 2. Add Visit, 3. Open Calendar, 4. Open Drawer
* Note: Layer control is added separately by Leaflet and appears at the top
*
* @param {Object} map - Leaflet map instance
* @param {Object} callbacks - Object containing callback functions for each button
* @param {Function} callbacks.onSelectArea - Callback for select area button
* @param {Function} callbacks.onAddVisit - Callback for add visit button
* @param {Function} callbacks.onToggleCalendar - Callback for toggle calendar/panel button
* @param {Function} callbacks.onToggleDrawer - Callback for toggle drawer button
* @param {String} userTheme - User's theme preference ('dark' or 'light')
* @returns {Object} Object containing references to all created controls
*/
export function addTopRightButtons(map, callbacks, userTheme = 'dark') {
const controls = {};
// 1. Select Area button
if (callbacks.onSelectArea) {
const SelectionControl = createAreaSelectionControl(callbacks.onSelectArea, userTheme);
controls.selectionControl = new SelectionControl({ position: 'topright' });
map.addControl(controls.selectionControl);
}
// 2. Add Visit button
// Note: Button is always created, callback is optional (add_visit_controller attaches its own handler)
const AddVisitControl = createAddVisitControl(callbacks.onAddVisit, userTheme);
controls.addVisitControl = new AddVisitControl({ position: 'topright' });
map.addControl(controls.addVisitControl);
// 3. Open Calendar (Toggle Panel) button
if (callbacks.onToggleCalendar) {
const TogglePanelControl = createTogglePanelControl(callbacks.onToggleCalendar, userTheme);
controls.togglePanelControl = new TogglePanelControl({ position: 'topright' });
map.addControl(controls.togglePanelControl);
}
// 4. Open Drawer button
if (callbacks.onToggleDrawer) {
const DrawerControl = createVisitsDrawerControl(callbacks.onToggleDrawer, userTheme);
controls.drawerControl = new DrawerControl({ position: 'topright' });
map.addControl(controls.drawerControl);
}
return controls;
}
/**
* Updates the Add Visit button to show active state
* @param {HTMLElement} button - The button element to update
*/
export function setAddVisitButtonActive(button) {
if (!button) return;
button.style.backgroundColor = '#dc3545';
button.style.color = 'white';
button.innerHTML = '✕';
}
/**
* Updates the Add Visit button to show inactive/default state
* @param {HTMLElement} button - The button element to update
* @param {String} userTheme - User's theme preference ('dark' or 'light')
*/
export function setAddVisitButtonInactive(button, userTheme = 'dark') {
if (!button) return;
applyThemeToButton(button, userTheme);
button.innerHTML = '';
}