All files PairingForm.tsx

100% Statements 16/16
100% Branches 11/11
100% Functions 5/5
100% Lines 15/15

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                10x 428x 428x 428x   428x   428x 202x 202x     428x   15x 14x         428x 15x 15x     428x                                                                                                      
import { useState, useEffect } from "react";
import { useStores } from "~/hooks/useStores";
import { CodeInput } from "./CodeInput";
import { IoLogInOutline } from "react-icons/io5";
import { TbLockPassword } from "react-icons/tb";
import { useMutation } from "@tanstack/react-query";
import { Logo } from "./Logo";
 
export const PairingForm = () => {
	const { hub } = useStores();
	const [code, setCode] = useState<string[]>(["", "", "", ""]);
	const [isInputValid, setIsInputValid] = useState<boolean>(true);
 
	const token = code.join("");
 
	useEffect(() => {
		const inputRegex = /^[A-Za-z0-9]{4}$/;
		setIsInputValid(token.length === 4 ? inputRegex.test(token) : true);
	}, [token]);
 
	const { mutate, isError, isPending, error } = useMutation({
		mutationFn: async (pairingCode: string) => {
			await new Promise((resolve) => setTimeout(resolve, 1000));
			return hub.service.pair(pairingCode);
		},
		mutationKey: ["PAIR_HUB"],
	});
 
	const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
		e.preventDefault();
		mutate(token);
	};
 
	return (
		<form
			className="max-w-md md:min-w-md bg-base-100 border border-base-300 p-8 rounded-4xl shadow-sm"
			onSubmit={handleSubmit}
			aria-labelledby="form-title"
		>
			<Logo />
			<fieldset className="fieldset flex flex-col items-stretch gap-4 mt-6">
				<legend
					id="form-title"
					className="fieldset-legend md:text-xl text-lg flex items-center gap-2 mb-4"
				>
					<TbLockPassword aria-hidden="true" />
					<span>Sign in to control devices</span>
				</legend>
 
				{isError && (
					<p className="text-error text-base" role="alert">
						{error.message}
					</p>
				)}
 
				<label
					htmlFor="access-code"
					className="fieldset-label text-xl text-base-content"
				>
					Access Code
				</label>
 
				{isPending ? (
					<p className="text-accent text-xl font-medium flex gap-2">
						<span className="loading loading-spinner loading-lg"></span>{" "}
						One moment
					</p>
				) : (
					<CodeInput onCodeChange={setCode} />
				)}
 
				<button
					type="submit"
					className="btn btn-primary btn-xl w-full mt-4 py-7"
					disabled={token.length !== 4 || !isInputValid || isPending}
					aria-disabled={token.length !== 4 || !isInputValid}
				>
					<IoLogInOutline aria-hidden="true" />
					<span>Connect Hub</span>
				</button>
			</fieldset>
		</form>
	);
};