119 lines
5.2 KiB
TypeScript
119 lines
5.2 KiB
TypeScript
import {ActionDispatch, FormEvent, useState} from 'react';
|
|
import {
|
|
Action,
|
|
actionLoadedMaze,
|
|
actionLoadingFailed,
|
|
actionStartedLoading,
|
|
actionToggledShowSolution
|
|
} from "./state/action.ts";
|
|
import styles from "./input-form.module.scss";
|
|
import "./input-form.scss";
|
|
import {State} from "./state/state.ts";
|
|
import {ValidatingInputNumberField, ValidatingInputRegExpField, ValidatorFunction} from "./validating-input-field.tsx";
|
|
|
|
export default function InputForm({state, dispatch}: {
|
|
state: State,
|
|
dispatch: ActionDispatch<[Action]>
|
|
}) {
|
|
const [width, setWidth] = useState(10);
|
|
const [height, setHeight] = useState(10);
|
|
const [id, setId] = useState<string>();
|
|
const [algorithm, setAlgorithm] = useState('wilson');
|
|
|
|
const handleSubmit = (e: FormEvent) => {
|
|
e.preventDefault();
|
|
dispatch(actionStartedLoading());
|
|
dispatch(actionToggledShowSolution(false));
|
|
const url = `https://manuel.friedli.info/labyrinth/create/json?w=${width}&h=${height}&id=${id || ''}&algorithm=${algorithm}`;
|
|
fetch(url)
|
|
.then(response => response.json())
|
|
.then(result => {
|
|
dispatch(actionLoadedMaze(result));
|
|
})
|
|
.catch(reason => {
|
|
console.error("Failed to fetch maze data.", reason);
|
|
dispatch(actionLoadingFailed(reason));
|
|
});
|
|
};
|
|
const validateSizeInput: ValidatorFunction<string, number> = (value: string) => {
|
|
const numberValue = Number(value);
|
|
if (isNaN(numberValue) || "" === value || (Math.floor(numberValue) !== numberValue)) {
|
|
return {
|
|
valid: false,
|
|
message: "Must be an integer greater than 1."
|
|
};
|
|
}
|
|
if (numberValue < 1) {
|
|
return {
|
|
valid: false,
|
|
message: "Must be greater than 1."
|
|
};
|
|
}
|
|
return {
|
|
valid: true,
|
|
value: numberValue
|
|
};
|
|
};
|
|
return (
|
|
<form onSubmit={handleSubmit}>
|
|
<div className={styles.inputform}>
|
|
<ValidatingInputNumberField id={"width"}
|
|
label={"Width"}
|
|
value={width}
|
|
constraints={{
|
|
min: 2
|
|
}}
|
|
validatorFn={validateSizeInput}
|
|
disabled={state.loading}
|
|
onChange={setWidth}
|
|
/>
|
|
<ValidatingInputNumberField id={"height"}
|
|
label={"Height"}
|
|
value={height}
|
|
constraints={{
|
|
min: 2
|
|
}}
|
|
validatorFn={validateSizeInput}
|
|
disabled={state.loading}
|
|
onChange={setHeight}
|
|
/>
|
|
{/*<ValidatingInputBigIntField id={"id"}*/}
|
|
{/* label={"ID (optional)"}*/}
|
|
{/* value={id}*/}
|
|
{/* validatorFn={validateIdInput}*/}
|
|
{/* disabled={state.loading}*/}
|
|
{/* onChange={setId}*/}
|
|
{/* constraints={{*/}
|
|
{/* min: -9223372036854775808n,*/}
|
|
{/* max: 9223372036854775807n*/}
|
|
{/* }}*/}
|
|
{/*/>*/}
|
|
<ValidatingInputRegExpField id={"id"}
|
|
label={"ID (optional)"}
|
|
value={id}
|
|
disabled={state.loading}
|
|
onChange={setId}
|
|
constraints={[
|
|
/^[0-9a-fA-F]{0,16}$/
|
|
]}
|
|
placeholder={"Hex-Number (without 0x prefix)"}
|
|
/>
|
|
<label htmlFor="algorithm">Algorithm:</label>
|
|
<select id={"algorithm"}
|
|
value={algorithm}
|
|
disabled={state.loading}
|
|
onChange={e => setAlgorithm(e.target.value)}>
|
|
<option value="wilson">Wilson</option>
|
|
<option value="random">Random Depth First</option>
|
|
</select>
|
|
</div>
|
|
<button type={"submit"}
|
|
disabled={state.loading
|
|
|| isNaN(width)
|
|
|| isNaN(height)
|
|
}
|
|
className={styles.submitbutton}>{state.loading ? "Loading ..." : "Create Maze!"}
|
|
</button>
|
|
</form>
|
|
);
|
|
}
|