Source: components/system_settings/index.js

import NumericSlider from "../../components/numeric_slider";
import {useState, useEffect} from "preact/hooks";
import {
	updateDeviceSettings,
	getDeviceSettings} from "../../utils/api";
import {useConnectivity} from "../../context/online_context";
import useInterval from "../../utils/use_interval";
import SimpleChooser from '../../components/single_chooser';
import { LabelSpinner } from '../../components/spinner';
import RANGE_CONSTANTS from '../../utils/constants';
import style from './style.css';

/**
 * @brief Generates a UI element for changing NanoLux device system settings.
 */
const SystemControls = () => {

	// Checks if the web app is connected to the device.
	const { isConnected } = useConnectivity();

	// Flag representing if initial data has been obtained from
	// the device.
	const [loading, setLoading] = useState(true);

	// Flag that tells the object to update the NanoLux device with new data.
	const [updated, setUpdated] = useState(false);

	// System settings data structure
	const [data, setData] = useState({
		length: 60,
		loop: 40,
		debug: 0
	});

	/**
	 * @brief Manages initial querying of the data from the NanoLux device.
	 * 		  Sets the loading flag to false when done.
	 */
	useEffect(() => {
		if (isConnected) {
			getDeviceSettings()
				.then(data => setData(data))
				.then(setLoading(false));
		}  
	}, [isConnected])

	
	/**
	 * @brief Updates the pattern on the Nanolux device 
	 * if it is connected and has modified data,
	 * then flags the data structure.
	 */
	useInterval(() => {
		if (isConnected && updated) {
			updateDeviceSettings(data);
			setUpdated(false);
		}
	}, 100);

	/**
	 * @brief Updates a parameter in the subpattern data structure with a new value.
	 * @param ref The string reference to update in the data structure
	 * @param value The new value to update the data structure with
	 */
	const update = (ref, value) => {
		if(!loading){		
			setData((oldData) => {
				let newData = Object.assign({}, oldData);
				newData[ref] = value;
				return newData;
			})
		}
		setUpdated(true);
	}

	/**
	 * @brief Generates the UI element for adjusting system settings.
	 */
	return (
		(!loading ? 
			<div>
				<NumericSlider
					className={style.settings_control}
					label="LED Strip Length"
					min={RANGE_CONSTANTS.LENGTH_MIN}
					max={RANGE_CONSTANTS.LENGTH_MAX}
					initial={data.length}
					structure_ref="length"
					update={update}
				/>
				<br/>
				<NumericSlider
					className={style.settings_control}
					label="LED Update Time (ms)"
					min={RANGE_CONSTANTS.LOOP_MIN}
					max={RANGE_CONSTANTS.LOOP_MAX}
					initial={data.loop}
					structure_ref="loop"
					update={update}
				/>
				<br/>
				<SimpleChooser
					className={style.settings_control}
					label="Debug Mode"
					options={[
						{option : "Debug Out", idx : 1},
						{option : "Simulator Out", idx : 2},
					]}
					noSelection={true}
					initial={data.debug}
					structure_ref="debug"
					update={update}	
				/>
				<br/>
			</div> 
		: <LabelSpinner></LabelSpinner>)		
	);
}

export default SystemControls;