// Movement Column // Purpose: Assembles the mobile movement column, which is the right column by default. // Scope: Owns movement availability while the in-video DockingHud owns every dock/undock action. import { FaChargingStation } from 'react-icons/fa'; import { useControlActions, useControlSelector } from '../../controls/index.js'; import { useSessionSelector } from '../../context/SessionContext.jsx'; import { useTelemetrySelector } from '../../context/TelemetryContext.jsx'; import { dockTelemetryEqual, selectDockTelemetry } from '../../context/telemetryViews.js'; import useCanControlRover from '../../hooks/useCanControlRover.js'; import { triggerTouchHaptic } from '../../lib/touchHaptics.js'; import ControlPadPanel from './ControlPadPanel.jsx'; function MovementColumnContent({ layout }) { const roverId = useControlSelector((control) => control.state.roverId); const actions = useControlActions(); const dockTelemetry = useTelemetrySelector(roverId, selectDockTelemetry, dockTelemetryEqual); const canControl = useCanControlRover(roverId); const batteryState = useSessionSelector((state) => { const rover = (state.session?.roster || []).find((entry) => String(entry.id) === String(roverId)); return rover?.batteryState || null; }); const batteryUrgent = Boolean(batteryState?.urgentActive); const batteryLow = Boolean(batteryState?.warnActive || batteryUrgent); const docked = Boolean(dockTelemetry?.homeBase); const drivingMode = String(dockTelemetry?.oiModeLabel || '').toLowerCase() === 'full'; const movementDisabled = !roverId || !canControl || docked || dockTelemetry.movementLocked || (!drivingMode && !dockTelemetry.cameraLocked); // Both controls share the same hardware-availability boundary. Dock assist // changes their actions, not who is allowed to command the rover. const dockActionDisabled = movementDisabled; const handleDockAction = () => { if (dockActionDisabled) return; triggerTouchHaptic('button'); // Mobile deliberately enters assist on the first tap. The centered video HUD // provides the resulting instruction, so a confirmation modal would only add // friction between intent and the camera-guided docking task. if (dockTelemetry.cameraLocked) { actions.sendCommand('cancelDocking'); } else { actions.sendCommand('enterDocking'); } }; return (