Some checks failed
Test examples / Test Examples (20) (push) Has been cancelled
Test examples / Test Examples (22) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Trigger Release / start (push) Has been cancelled
Stale issue handler / stale (push) Has been cancelled
Update Font Data / create-pull-request (push) Has been cancelled
build-and-deploy / deploy-target (push) Has been cancelled
build-and-deploy / build (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / build-wasm (nodejs) (push) Has been cancelled
build-and-deploy / build-wasm (web) (push) Has been cancelled
build-and-deploy / Deploy preview tarball (push) Has been cancelled
build-and-deploy / Potentially publish release (push) Has been cancelled
build-and-deploy / publish-turbopack-npm-packages (push) Has been cancelled
build-and-deploy / Deploy examples (push) Has been cancelled
build-and-deploy / thank you, build (push) Has been cancelled
build-and-deploy / Upload Turbopack Bytesize metrics to Datadog (push) Has been cancelled
Rspack Next.js development integration tests / Rspack integration tests (push) Has been cancelled
Rspack Next.js production integration tests / Rspack integration tests (push) Has been cancelled
Turbopack Next.js development integration tests / Next.js integration tests (push) Has been cancelled
Turbopack Next.js production integration tests / Next.js integration tests (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack development test manifest (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack production test manifest (push) Has been cancelled
Upload bundler test manifests to areweturboyet.com / Upload test results (push) Has been cancelled
Update React / create-pull-request (push) Has been cancelled
test-e2e-project-reset-cron / reset-test-project (push) Has been cancelled
Notify about the top 15 issues/PRs/feature requests (most reacted) in the last 90 days / run (push) Has been cancelled
233 lines
5.5 KiB
TypeScript
233 lines
5.5 KiB
TypeScript
import { useState } from "react";
|
|
import { useRouter } from "next/router";
|
|
import { mutate } from "swr";
|
|
|
|
interface FormData {
|
|
name: string;
|
|
owner_name: string;
|
|
species: string;
|
|
age: number;
|
|
poddy_trained: boolean;
|
|
diet: string[];
|
|
image_url: string;
|
|
likes: string[];
|
|
dislikes: string[];
|
|
}
|
|
|
|
interface Error {
|
|
name?: string;
|
|
owner_name?: string;
|
|
species?: string;
|
|
image_url?: string;
|
|
}
|
|
|
|
type Props = {
|
|
formId: string;
|
|
petForm: FormData;
|
|
forNewPet?: boolean;
|
|
};
|
|
|
|
const Form = ({ formId, petForm, forNewPet = true }: Props) => {
|
|
const router = useRouter();
|
|
const contentType = "application/json";
|
|
const [errors, setErrors] = useState({});
|
|
const [message, setMessage] = useState("");
|
|
|
|
const [form, setForm] = useState({
|
|
name: petForm.name,
|
|
owner_name: petForm.owner_name,
|
|
species: petForm.species,
|
|
age: petForm.age,
|
|
poddy_trained: petForm.poddy_trained,
|
|
diet: petForm.diet,
|
|
image_url: petForm.image_url,
|
|
likes: petForm.likes,
|
|
dislikes: petForm.dislikes,
|
|
});
|
|
|
|
/* The PUT method edits an existing entry in the mongodb database. */
|
|
const putData = async (form: FormData) => {
|
|
const { id } = router.query;
|
|
|
|
try {
|
|
const res = await fetch(`/api/pets/${id}`, {
|
|
method: "PUT",
|
|
headers: {
|
|
Accept: contentType,
|
|
"Content-Type": contentType,
|
|
},
|
|
body: JSON.stringify(form),
|
|
});
|
|
|
|
// Throw error with status code in case Fetch API req failed
|
|
if (!res.ok) {
|
|
throw new Error(res.status.toString());
|
|
}
|
|
|
|
const { data } = await res.json();
|
|
|
|
mutate(`/api/pets/${id}`, data, false); // Update the local data without a revalidation
|
|
router.push("/");
|
|
} catch (error) {
|
|
setMessage("Failed to update pet");
|
|
}
|
|
};
|
|
|
|
/* The POST method adds a new entry in the mongodb database. */
|
|
const postData = async (form: FormData) => {
|
|
try {
|
|
const res = await fetch("/api/pets", {
|
|
method: "POST",
|
|
headers: {
|
|
Accept: contentType,
|
|
"Content-Type": contentType,
|
|
},
|
|
body: JSON.stringify(form),
|
|
});
|
|
|
|
// Throw error with status code in case Fetch API req failed
|
|
if (!res.ok) {
|
|
throw new Error(res.status.toString());
|
|
}
|
|
|
|
router.push("/");
|
|
} catch (error) {
|
|
setMessage("Failed to add pet");
|
|
}
|
|
};
|
|
|
|
const handleChange = (
|
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
|
) => {
|
|
const target = e.target;
|
|
const value =
|
|
target.name === "poddy_trained"
|
|
? (target as HTMLInputElement).checked
|
|
: target.value;
|
|
const name = target.name;
|
|
|
|
setForm({
|
|
...form,
|
|
[name]: value,
|
|
});
|
|
};
|
|
|
|
/* Makes sure pet info is filled for pet name, owner name, species, and image url*/
|
|
const formValidate = () => {
|
|
let err: Error = {};
|
|
if (!form.name) err.name = "Name is required";
|
|
if (!form.owner_name) err.owner_name = "Owner is required";
|
|
if (!form.species) err.species = "Species is required";
|
|
if (!form.image_url) err.image_url = "Image URL is required";
|
|
return err;
|
|
};
|
|
|
|
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
|
e.preventDefault();
|
|
const errs = formValidate();
|
|
|
|
if (Object.keys(errs).length === 0) {
|
|
forNewPet ? postData(form) : putData(form);
|
|
} else {
|
|
setErrors({ errs });
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<form id={formId} onSubmit={handleSubmit}>
|
|
<label htmlFor="name">Name</label>
|
|
<input
|
|
type="text"
|
|
maxLength={20}
|
|
name="name"
|
|
value={form.name}
|
|
onChange={handleChange}
|
|
required
|
|
/>
|
|
|
|
<label htmlFor="owner_name">Owner</label>
|
|
<input
|
|
type="text"
|
|
maxLength={20}
|
|
name="owner_name"
|
|
value={form.owner_name}
|
|
onChange={handleChange}
|
|
required
|
|
/>
|
|
|
|
<label htmlFor="species">Species</label>
|
|
<input
|
|
type="text"
|
|
maxLength={30}
|
|
name="species"
|
|
value={form.species}
|
|
onChange={handleChange}
|
|
required
|
|
/>
|
|
|
|
<label htmlFor="age">Age</label>
|
|
<input
|
|
type="number"
|
|
name="age"
|
|
value={form.age}
|
|
onChange={handleChange}
|
|
/>
|
|
|
|
<label htmlFor="poddy_trained">Potty Trained</label>
|
|
<input
|
|
type="checkbox"
|
|
name="poddy_trained"
|
|
checked={form.poddy_trained}
|
|
onChange={handleChange}
|
|
/>
|
|
|
|
<label htmlFor="diet">Diet</label>
|
|
<textarea
|
|
name="diet"
|
|
maxLength={60}
|
|
value={form.diet}
|
|
onChange={handleChange}
|
|
/>
|
|
|
|
<label htmlFor="image_url">Image URL</label>
|
|
<input
|
|
type="url"
|
|
name="image_url"
|
|
value={form.image_url}
|
|
onChange={handleChange}
|
|
required
|
|
/>
|
|
|
|
<label htmlFor="likes">Likes</label>
|
|
<textarea
|
|
name="likes"
|
|
maxLength={60}
|
|
value={form.likes}
|
|
onChange={handleChange}
|
|
/>
|
|
|
|
<label htmlFor="dislikes">Dislikes</label>
|
|
<textarea
|
|
name="dislikes"
|
|
maxLength={60}
|
|
value={form.dislikes}
|
|
onChange={handleChange}
|
|
/>
|
|
|
|
<button type="submit" className="btn">
|
|
Submit
|
|
</button>
|
|
</form>
|
|
<p>{message}</p>
|
|
<div>
|
|
{Object.keys(errors).map((err, index) => (
|
|
<li key={index}>{err}</li>
|
|
))}
|
|
</div>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default Form;
|