Files
controller-v2/client/src/pages/SelectPage.tsx
T

124 lines
3.7 KiB
TypeScript
Raw Normal View History

/* ============================================================
SELECT PAGE — Universal full-screen option picker
Design: iOS Settings style selection list
Usage: Navigate to /select with state object
State params:
title - Page title shown in header
options - Array of option strings
selected - Currently selected index (number)
back - Route to navigate back to after selection
key - Identifier for which setting this controls
============================================================ */
import { useLocation } from "wouter";
import { ChevronLeft, Check } from "lucide-react";
import { useDevice } from "@/contexts/DeviceContext";
import { useEffect, useState } from "react";
/* ── Key → API field mapping ── */
const KEY_TO_SETTING: Record<string, string> = {
effect_value: "effect_value",
crossfeed_value: "crossfeed_value",
language: "language",
analogGain: "analogGain",
soundStep: "soundStep",
xlr: "xlr",
dacGain: "dacGain",
dacImpedance: "dacImpedance",
vu: "vu",
input: "input",
output: "output",
screenLight: "screenLight",
screenOff: "screenOff",
buttonLight: "buttonLight",
autoHome: "autoHome",
sleep: "sleep",
headphone: "peqSelect",
};
// Global state for select page (to avoid URL params)
export let selectPageState: {
title: string;
options: string[];
selected: number;
back: string;
key: string;
} | null = null;
// Helper function to set select page state
export function navigateToSelect(title: string, options: string[], selected: number, back: string, key: string) {
selectPageState = { title, options, selected, back, key };
}
export default function SelectPage() {
const [, setLocation] = useLocation();
const { updateSetting } = useDevice();
const [state, setState] = useState<{
title: string;
options: string[];
selected: number;
back: string;
key: string;
} | null>(selectPageState);
// Clear state when component unmounts
useEffect(() => {
return () => {
selectPageState = null;
};
}, []);
if (!state) {
return null;
}
const { title, options, selected: selectedIdx, back, key } = state;
const handleSelect = (idx: number) => {
// Apply setting if key maps to an API field
const apiField = KEY_TO_SETTING[key];
if (apiField) {
updateSetting({ [apiField]: idx } as Parameters<typeof updateSetting>[0]);
}
// Navigate back
setLocation(back);
};
return (
<div className="min-h-screen bg-black">
{/* ── Header ── */}
<div className="page-header">
<button
onClick={() => setLocation(back)}
className="mr-4 text-white/60 active:text-white transition-colors">
<ChevronLeft size={24} />
</button>
<h1 className="flex-1 text-center text-[17px] font-semibold text-white">{title}</h1>
<div className="w-8" />
</div>
{/* ── Options list ── */}
<div className="px-4 pt-4 pb-24">
<div className="ios-list-group">
{options.map((opt, idx) => {
const isSelected = idx === selectedIdx;
return (
<button
key={idx}
className="ios-list-row w-full text-left active:bg-white/5 transition-colors"
onClick={() => handleSelect(idx)}>
<span className={`flex-1 text-[16px] ${isSelected ? "text-white font-medium" : "text-white/75"}`}>
{opt}
</span>
{isSelected && (
<Check size={18} style={{ color: "#00FFF6" }} />
)}
</button>
);
})}
</div>
</div>
</div>
);
}