diff --git a/ui/social-bot/src/components/StatusHeader.jsx b/ui/social-bot/src/components/StatusHeader.jsx
new file mode 100644
index 0000000..28ace18
--- /dev/null
+++ b/ui/social-bot/src/components/StatusHeader.jsx
@@ -0,0 +1,260 @@
+/**
+ * StatusHeader.jsx — Persistent status bar with robot health indicators
+ *
+ * Features:
+ * - Battery percentage and status indicator
+ * - WiFi signal strength (RSSI)
+ * - Motor status (running/stopped/error)
+ * - Emergency state indicator (active/clear)
+ * - System uptime
+ * - Current operational mode (idle/navigation/social/docking)
+ * - Real-time updates from ROS topics
+ * - Always visible at top of dashboard
+ */
+
+import { useEffect, useState } from 'react';
+
+function StatusHeader({ subscribe }) {
+ const [batteryPercent, setBatteryPercent] = useState(null);
+ const [batteryVoltage, setBatteryVoltage] = useState(null);
+ const [wifiRssi, setWifiRssi] = useState(null);
+ const [wifiQuality, setWifiQuality] = useState('unknown');
+ const [motorStatus, setMotorStatus] = useState('idle');
+ const [motorCurrent, setMotorCurrent] = useState(null);
+ const [emergencyActive, setEmergencyActive] = useState(false);
+ const [uptime, setUptime] = useState(0);
+ const [currentMode, setCurrentMode] = useState('idle');
+ const [connected, setConnected] = useState(true);
+
+ // Battery subscriber
+ useEffect(() => {
+ const unsubBattery = subscribe(
+ '/saltybot/battery',
+ 'sensor_msgs/BatteryState',
+ (msg) => {
+ try {
+ setBatteryPercent(Math.round(msg.percentage * 100));
+ setBatteryVoltage(msg.voltage?.toFixed(1));
+ } catch (e) {
+ console.error('Error parsing battery data:', e);
+ }
+ }
+ );
+ return unsubBattery;
+ }, [subscribe]);
+
+ // WiFi RSSI subscriber
+ useEffect(() => {
+ const unsubWifi = subscribe(
+ '/saltybot/wifi_rssi',
+ 'std_msgs/Float32',
+ (msg) => {
+ try {
+ const rssi = Math.round(msg.data);
+ setWifiRssi(rssi);
+
+ if (rssi > -50) setWifiQuality('excellent');
+ else if (rssi > -60) setWifiQuality('good');
+ else if (rssi > -70) setWifiQuality('fair');
+ else if (rssi > -80) setWifiQuality('weak');
+ else setWifiQuality('poor');
+ } catch (e) {
+ console.error('Error parsing WiFi data:', e);
+ }
+ }
+ );
+ return unsubWifi;
+ }, [subscribe]);
+
+ // Motor status subscriber
+ useEffect(() => {
+ const unsubMotor = subscribe(
+ '/saltybot/motor_status',
+ 'std_msgs/String',
+ (msg) => {
+ try {
+ const status = msg.data?.toLowerCase() || 'unknown';
+ setMotorStatus(status);
+ } catch (e) {
+ console.error('Error parsing motor status:', e);
+ }
+ }
+ );
+ return unsubMotor;
+ }, [subscribe]);
+
+ // Motor current subscriber
+ useEffect(() => {
+ const unsubCurrent = subscribe(
+ '/saltybot/motor_current',
+ 'std_msgs/Float32',
+ (msg) => {
+ try {
+ setMotorCurrent(Math.round(msg.data * 100) / 100);
+ } catch (e) {
+ console.error('Error parsing motor current:', e);
+ }
+ }
+ );
+ return unsubCurrent;
+ }, [subscribe]);
+
+ // Emergency subscriber
+ useEffect(() => {
+ const unsubEmergency = subscribe(
+ '/saltybot/emergency',
+ 'std_msgs/Bool',
+ (msg) => {
+ try {
+ setEmergencyActive(msg.data === true);
+ } catch (e) {
+ console.error('Error parsing emergency status:', e);
+ }
+ }
+ );
+ return unsubEmergency;
+ }, [subscribe]);
+
+ // Uptime tracking
+ useEffect(() => {
+ const startTime = Date.now();
+ const interval = setInterval(() => {
+ const elapsed = Math.floor((Date.now() - startTime) / 1000);
+ const hours = Math.floor(elapsed / 3600);
+ const minutes = Math.floor((elapsed % 3600) / 60);
+ setUptime(`${hours}h ${minutes}m`);
+ }, 1000);
+
+ return () => clearInterval(interval);
+ }, []);
+
+ // Current mode subscriber
+ useEffect(() => {
+ const unsubMode = subscribe(
+ '/saltybot/current_mode',
+ 'std_msgs/String',
+ (msg) => {
+ try {
+ const mode = msg.data?.toLowerCase() || 'idle';
+ setCurrentMode(mode);
+ } catch (e) {
+ console.error('Error parsing mode:', e);
+ }
+ }
+ );
+ return unsubMode;
+ }, [subscribe]);
+
+ // Connection status
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ setConnected(batteryPercent !== null);
+ }, 2000);
+ return () => clearTimeout(timer);
+ }, [batteryPercent]);
+
+ const getBatteryColor = () => {
+ if (batteryPercent === null) return 'text-gray-600';
+ if (batteryPercent > 60) return 'text-green-400';
+ if (batteryPercent > 30) return 'text-amber-400';
+ return 'text-red-400';
+ };
+
+ const getWifiColor = () => {
+ if (wifiRssi === null) return 'text-gray-600';
+ if (wifiQuality === 'excellent' || wifiQuality === 'good') return 'text-green-400';
+ if (wifiQuality === 'fair') return 'text-amber-400';
+ return 'text-red-400';
+ };
+
+ const getMotorColor = () => {
+ if (motorStatus === 'running') return 'text-green-400';
+ if (motorStatus === 'idle') return 'text-gray-500';
+ return 'text-red-400';
+ };
+
+ const getModeColor = () => {
+ switch (currentMode) {
+ case 'navigation':
+ return 'text-cyan-400';
+ case 'social':
+ return 'text-purple-400';
+ case 'docking':
+ return 'text-blue-400';
+ default:
+ return 'text-gray-500';
+ }
+ };
+
+ return (
+
+ {/* Connection status */}
+
+
+
+ {connected ? 'CONNECTED' : 'DISCONNECTED'}
+
+
+
+ {/* Battery */}
+
+ 🔋
+
+ {batteryPercent !== null ? `${batteryPercent}%` : '—'}
+
+ {batteryVoltage && (
+ {batteryVoltage}V
+ )}
+
+
+ {/* WiFi */}
+
+ 📡
+
+ {wifiRssi !== null ? `${wifiRssi}dBm` : '—'}
+
+ {wifiQuality}
+
+
+ {/* Motors */}
+
+ ⚙️
+
+ {motorStatus}
+
+ {motorCurrent !== null && (
+ {motorCurrent}A
+ )}
+
+
+ {/* Emergency */}
+
+
+ {emergencyActive ? '🚨 EMERGENCY' : '✓ Safe'}
+
+
+
+ {/* Uptime */}
+
+ ⏱️
+ {uptime}
+
+
+ {/* Current Mode */}
+
+ Mode:
+
+ {currentMode}
+
+
+
+ );
+}
+
+export { StatusHeader };