112 lines
4.1 KiB
JavaScript
112 lines
4.1 KiB
JavaScript
|
import React, {useState} from 'react';
|
||
|
import ValidatingInputNumberField from "./ValidatingInputNumberField";
|
||
|
|
||
|
export default function InputForm({handleResult}) {
|
||
|
const [width, setWidth] = useState(2);
|
||
|
const [height, setHeight] = useState(2);
|
||
|
const [id, setId] = useState(null);
|
||
|
const [status, setStatus] = useState("typing"); // "typing", "submitting"
|
||
|
|
||
|
if (status === "submitted") {
|
||
|
return <span/>;
|
||
|
}
|
||
|
const callAPI = () => {
|
||
|
let url = "https://manuel.friedli.info/labyrinth/create/json?w=" + width +
|
||
|
"&h=" + height;
|
||
|
if (!!id) {
|
||
|
url += "&id=" + id;
|
||
|
}
|
||
|
fetch(url)
|
||
|
.then(response => response.json())
|
||
|
.then(result => {
|
||
|
handleResult(result);
|
||
|
// FIXME doesn't update the contents of the text input field.
|
||
|
setId(_ => result.id);
|
||
|
})
|
||
|
.catch(reason => {
|
||
|
console.error("Failed to fetch maze data.", reason);
|
||
|
// FIXME alert is not user friendly
|
||
|
alert("Failed to fetch maze data: " + reason);
|
||
|
})
|
||
|
.finally(() => {
|
||
|
setStatus("typing");
|
||
|
});
|
||
|
};
|
||
|
const handleSubmit = (e) => {
|
||
|
e.preventDefault();
|
||
|
setStatus("submitting");
|
||
|
callAPI();
|
||
|
};
|
||
|
const validateWidthHeightInput = value => {
|
||
|
if (isNaN(value) || "" === value || (Math.floor(value) !== Number(value))) {
|
||
|
return {
|
||
|
valid: false,
|
||
|
message: "Must be an integer greater than 1.",
|
||
|
value
|
||
|
};
|
||
|
}
|
||
|
if (value < 1) {
|
||
|
return {
|
||
|
valid: false,
|
||
|
message: "Must be greater than 1.",
|
||
|
value
|
||
|
};
|
||
|
}
|
||
|
return {
|
||
|
valid: true,
|
||
|
value
|
||
|
};
|
||
|
};
|
||
|
const validateIdInput = value => {
|
||
|
// FIXME doesn't handle strings with characters correctly (e.g. "asdf" yields an empty value, due to "type=number").
|
||
|
if (isNaN(value) || ("" !== value && ((Math.floor(value) !== Number(value))))) {
|
||
|
return {
|
||
|
valid: false,
|
||
|
message: "Must be empty or an integer",
|
||
|
value
|
||
|
};
|
||
|
}
|
||
|
return {
|
||
|
valid: true,
|
||
|
value
|
||
|
}
|
||
|
};
|
||
|
return (
|
||
|
<form onSubmit={handleSubmit}>
|
||
|
<ValidatingInputNumberField id={"width"}
|
||
|
label={"Width"}
|
||
|
defaultValue={width}
|
||
|
constraints={{
|
||
|
min: 2
|
||
|
}}
|
||
|
validatorFn={validateWidthHeightInput}
|
||
|
disabled={status === "submitting"}
|
||
|
onChange={setWidth}
|
||
|
/><br/>
|
||
|
<ValidatingInputNumberField id={"height"}
|
||
|
label={"Height"}
|
||
|
defaultValue={height}
|
||
|
constraints={{
|
||
|
min: 2
|
||
|
}}
|
||
|
validatorFn={validateWidthHeightInput}
|
||
|
disabled={status === "submitting"}
|
||
|
onChange={setHeight}
|
||
|
/><br/>
|
||
|
<ValidatingInputNumberField id={"id"}
|
||
|
label={"ID (optional)"}
|
||
|
defaultValue={id}
|
||
|
validatorFn={validateIdInput}
|
||
|
disabled={status === "submitting"}
|
||
|
onChange={setId}
|
||
|
/><br/>
|
||
|
<button type={"submit"}
|
||
|
disabled={status === "submitting"
|
||
|
|| isNaN(width)
|
||
|
|| isNaN(height)
|
||
|
}>GO!
|
||
|
</button>
|
||
|
</form>
|
||
|
);
|
||
|
}
|