// Nickname Form // Purpose: Defines the Nickname Form module and the local helpers/components used in this file. // Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit. import { useEffect, useState } from 'react'; import { useSessionActions } from '../../context/SessionContext.jsx'; import { useSettingsNamespace } from '../../settings/index.js'; import { trackAnalyticsEvent } from '../../analytics/index.js'; export default function NicknameForm({ compact = false }) { const { setNickname } = useSessionActions(); const { value, save } = useSettingsNamespace('profile', { nickname: '' }); const [nicknameInput, setNicknameInput] = useState(value.nickname || ''); const [saving, setSaving] = useState(false); useEffect(() => { setNicknameInput(value.nickname || ''); }, [value.nickname]); async function handleSave(event) { event.preventDefault(); const trimmed = (nicknameInput || '').trim().slice(0, 32); if (!trimmed) return; setSaving(true); try { // Nicknames are identity metadata rather than rover-control permission. // Spectator pages use the same socket action and local profile storage as // the driver UI so chat/user-list labels stay consistent across routes. await setNickname(trimmed); save({ nickname: trimmed }); /* The event records that a nickname was saved, while the shared analytics session reporter owns the actual nickname field. Keeping that split prevents every form call site from needing to know privacy/config rules. */ trackAnalyticsEvent('nickname_set', { length: trimmed.length, }); } catch (err) { alert(err.message); } finally { setSaving(false); } } return (