All files Device.tsx

85.71% Statements 12/14
91.66% Branches 11/12
60% Functions 3/5
85.71% Lines 12/14

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102              33x             470x   470x 470x   470x 63x     470x       470x 470x 470x   470x                                                                                               63x                                            
import { BiHide } from "react-icons/bi";
import { useStores } from "~/hooks/useStores";
import { HubDevice } from "~/types/HubDevice";
import { deviceToIconMap } from "~/utils/deviceToIconMap";
import { getFigure } from "~/utils/getFigure";
import { sanitizeName } from "~/utils/sanitizeName";
 
export const Device = ({
	device,
	controlDevice,
}: {
	device: HubDevice;
	controlDevice: (device: HubDevice) => void;
}) => {
	const { archive } = useStores();
 
	const deviceName = sanitizeName(device.name ?? "");
	const deviceFigure = getFigure(deviceToIconMap(35), deviceName);
 
	const handleToggle = (device: HubDevice) => {
		controlDevice(device);
	};
 
	const handleArchive = (deviceId: number) => {
		archive.add(deviceId);
	};
 
	const deviceId = `device-${device.connectedDeviceId}`;
	const toggleId = `toggle-${device.connectedDeviceId}`;
	const hideButtonId = `hide-${device.connectedDeviceId}`;
 
	return (
		<div
			key={device.connectedDeviceId}
			className="flex flex-col items-center justify-center text-base-content border-1 border-base-300 py-2 px-4 rounded-3xl"
			aria-labelledby={deviceId}
		>
			<div className="flex justify-between w-[100%]">
				<div className="flex gap-2 items-center justify-center">
					<div
						aria-hidden="true"
						role="img"
						aria-label={`${deviceName} device icon - ${
							device.isActive ? "active" : "inactive"
						}`}
					>
						{device.isActive
							? deviceFigure.active
							: deviceFigure.inactive}
					</div>
					<span id={deviceId} className="font-semibold min-w-max">
						{deviceName}
					</span>
				</div>
				<div
					className="flex flex-row items-center justify-center gap-3 p-2"
					role="group"
					aria-label={`Controls for ${deviceName}`}
				>
					<button
						id={hideButtonId}
						onClick={() => handleArchive(device.connectedDeviceId)}
						className="text-error hover:opacity-100 opacity-60 transition-opacity duration-200 cursor-pointer focus:outline-none focus:ring-2 focus:ring-error focus:ring-offset-2 rounded"
						aria-label={`Hide ${deviceName} device`}
						data-cy={`hide-${device.name}`}
						type="button"
					>
						<BiHide size={22} aria-hidden="true" />
					</button>
					<div className="flex flex-col items-center gap-1">
						<label htmlFor={toggleId} className="sr-only">
							{device.isActive
								? `Turn off ${deviceName}`
								: `Turn on ${deviceName}`}
						</label>
						<input
							id={toggleId}
							type="checkbox"
							checked={device.isActive}
							onChange={() => handleToggle(device)}
							className={`toggle ${
								device.isActive
									? "toggle-primary"
									: "toggle-accent"
							} cursor-pointer toggle-lg focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2`}
							aria-describedby={`${toggleId}-status`}
						/>
						<span
							id={`${toggleId}-status`}
							className="sr-only"
							aria-live="polite"
						>
							{deviceName} is currently{" "}
							{device.isActive ? "on" : "off"}
						</span>
					</div>
				</div>
			</div>
		</div>
	);
};