diff options
Diffstat (limited to 'src/pages/logintest')
-rw-r--r-- | src/pages/logintest/Form.tsx | 53 | ||||
-rw-r--r-- | src/pages/logintest/ServerForm.tsx | 67 | ||||
-rw-r--r-- | src/pages/logintest/funcs.ts | 24 | ||||
-rw-r--r-- | src/pages/logintest/index.tsx | 24 |
4 files changed, 168 insertions, 0 deletions
diff --git a/src/pages/logintest/Form.tsx b/src/pages/logintest/Form.tsx new file mode 100644 index 0000000..a593acb --- /dev/null +++ b/src/pages/logintest/Form.tsx @@ -0,0 +1,53 @@ +"use client"; + +import { useFormStatus } from "react-dom"; + +const SubmitButton = () => { + const { pending } = useFormStatus(); + return ( + <> + <button + disabled={pending} + type="submit" + className="hover:bg-slate-50 w-fit rounded-lg bg-white p-2" + > + {pending ? "Pending..." : "Submit"} + </button> + </> + ); +}; + +export const Form = ({ + message, + greet, +}: { + message: Promise<string>; + greet: (formData: FormData) => Promise<void>; +}) => ( + <div style={{ border: "3px blue dashed", margin: "1em", padding: "1em" }}> + <p>{message}</p> + <form action={greet}> + <div className="flex flex-col gap-1 text-left"> + <div> + Name:{" "} + <input + name="name" + required + className="invalid:border-red-500 rounded-sm border px-2 py-1" + /> + </div> + <div> + Email:{" "} + <input + type="email" + name="email" + required + className="invalid:border-red-500 rounded-sm border px-2 py-1" + /> + </div> + <SubmitButton /> + </div> + </form> + <h3>This is a client component.</h3> + </div> +); diff --git a/src/pages/logintest/ServerForm.tsx b/src/pages/logintest/ServerForm.tsx new file mode 100644 index 0000000..8e629b8 --- /dev/null +++ b/src/pages/logintest/ServerForm.tsx @@ -0,0 +1,67 @@ +async function submitUserProfile(formData: FormData) { + "use server"; + const name = formData.get("name"); + const age = formData.get("age"); + const favoriteColor = formData.get("favoriteColor"); + const hobby = formData.get("hobby"); + const isSubscribed = formData.get("newsletter") === "on"; + + console.log({ + name, + age, + favoriteColor, + hobby, + isSubscribed, + }); +} + +export const ServerForm = () => { + return ( + <form action={submitUserProfile} className="space-y-4"> + <div style={{ display: "flex", gap: 4, marginBottom: 4 }}> + <label htmlFor="name">Full Name</label> + <input type="text" name="name" id="name" required /> + </div> + + <div style={{ display: "flex", gap: 4, marginBottom: 4 }}> + <label htmlFor="age">Age</label> + <input type="number" name="age" id="age" min="13" max="120" /> + </div> + + <div style={{ display: "flex", gap: 4, marginBottom: 4 }}> + <label htmlFor="favoriteColor">Favorite Color</label> + <select name="favoriteColor" id="favoriteColor"> + <option value="red">Red</option> + <option value="blue">Blue</option> + <option value="green">Green</option> + <option value="purple">Purple</option> + <option value="yellow">Yellow</option> + </select> + </div> + + <div style={{ display: "flex", gap: 4, marginBottom: 4 }}> + <label htmlFor="hobby">Favorite Hobby</label> + <input + type="text" + name="hobby" + id="hobby" + placeholder="e.g. Reading, Gaming, Cooking" + /> + </div> + + <div style={{ display: "flex", gap: 4, marginBottom: 4 }}> + <label> + <input type="checkbox" name="newsletter" /> + Subscribe to newsletter + </label> + </div> + + <button + type="submit" + className="hover:bg-slate-50 w-fit rounded-lg bg-white p-2" + > + Save Profile + </button> + </form> + ); +}; diff --git a/src/pages/logintest/funcs.ts b/src/pages/logintest/funcs.ts new file mode 100644 index 0000000..4ffd5ef --- /dev/null +++ b/src/pages/logintest/funcs.ts @@ -0,0 +1,24 @@ +import { readFile, writeFile } from "node:fs/promises"; +import { unstable_rerenderRoute } from "waku/router/server"; + +export const getMessage = async () => { + const data = await readFile("./message.txt", "utf8"); + return data; +}; + +export const greet = async (formData: FormData) => { + "use server"; + // simulate a slow server response + await new Promise((resolve) => setTimeout(resolve, 1000)); + const currentData = await getMessage(); + await writeFile( + "./message.txt", + currentData + "\n" + formData.get("name") + " from server!", + ); + unstable_rerenderRoute("/"); +}; + +export const increment = async (count: number) => { + "use server"; + return count + 1; +}; diff --git a/src/pages/logintest/index.tsx b/src/pages/logintest/index.tsx new file mode 100644 index 0000000..df8bc08 --- /dev/null +++ b/src/pages/logintest/index.tsx @@ -0,0 +1,24 @@ +import { Form } from "./Form"; +import { getMessage, greet } from "./funcs"; +import { ServerForm } from "./ServerForm"; + +export default function HomePage() { + return ( + <div className="flex h-full w-full flex-col items-center justify-center gap-8 p-6"> + <div className="bg-slate-100 rounded-md p-4"> + <h2 className="text-2xl">Server Form</h2> + <ServerForm /> + </div> + <div className="bg-slate-100 rounded-md p-4"> + <h2 className="text-2xl">Client Form</h2> + <Form message={getMessage()} greet={greet} /> + </div> + </div> + ); +} + +export const getConfig = async () => { + return { + render: "dynamic", + } as const; +}; |