85 lines
2.9 KiB
TypeScript
85 lines
2.9 KiB
TypeScript
import { Button, Container, Flex, Text } from "@radix-ui/themes"
|
|
import { createFileRoute } from "@tanstack/react-router"
|
|
import { Console, Effect, Schema } from "effect"
|
|
import { Component, Form, MutationForm, View } from "effect-view"
|
|
import { TextFieldFormInputView } from "@/lib/form/TextFieldFormInputView"
|
|
import { runtime } from "@/runtime"
|
|
|
|
|
|
const RegisterSchema = Schema.Struct({
|
|
email: Schema.String.check(
|
|
Schema.isPattern(/^[^\s@]+@[^\s@]+\.[^\s@]+$/, {
|
|
message: "Enter a valid email address",
|
|
}),
|
|
),
|
|
password: Schema.String.check(
|
|
Schema.isMinLength(5, {
|
|
message: "Password must be at least 5 characters long",
|
|
}),
|
|
),
|
|
})
|
|
|
|
const RegisterRouteComponent = Component.make("RegisterRouteView")(function*() {
|
|
yield* Component.useOnMount(() => Effect.gen(function*() {
|
|
yield* Effect.addFinalizer(() => Console.log("Form route unmounted"))
|
|
yield* Console.log("Form route mounted")
|
|
}))
|
|
|
|
const [form, emailField, passwordField] = yield* Component.useOnMount(() => Effect.gen(function*() {
|
|
const form = yield* MutationForm.make({
|
|
schema: RegisterSchema,
|
|
initialEncodedValue: { email: "", password: "" },
|
|
f: ([value]) => Effect.log(`Registered ${value.email}`),
|
|
}).pipe(
|
|
MutationForm.run,
|
|
)
|
|
|
|
const emailField = Form.focusObjectOn(form, "email")
|
|
const passwordField = Form.focusObjectOn(form, "password")
|
|
|
|
return [form, emailField, passwordField] as const
|
|
}))
|
|
|
|
const [canCommit, isCommitting] = yield* View.useAll([
|
|
form.canCommit,
|
|
form.isCommitting,
|
|
])
|
|
|
|
const TextFieldFormInput = yield* TextFieldFormInputView.use
|
|
const runPromise = yield* Component.useRunPromise()
|
|
|
|
|
|
return (
|
|
<Container width="300">
|
|
<form onSubmit={event => {
|
|
event.preventDefault()
|
|
void runPromise(form.submit)
|
|
}}>
|
|
<Flex direction="column" gap="2">
|
|
<TextFieldFormInput
|
|
form={emailField}
|
|
placeholder="Email"
|
|
debounce="250 millis"
|
|
/>
|
|
<TextFieldFormInput
|
|
form={passwordField}
|
|
placeholder="Password"
|
|
type="password"
|
|
debounce="250 millis"
|
|
/>
|
|
<Button disabled={!canCommit || isCommitting}>
|
|
{isCommitting ? "Submitting…" : "Submit"}
|
|
</Button>
|
|
</Flex>
|
|
</form>
|
|
<Text size="2">A MutationForm validates local input, then submits it.</Text>
|
|
</Container>
|
|
)
|
|
}).pipe(
|
|
Component.withContext(runtime.context),
|
|
)
|
|
|
|
export const Route = createFileRoute("/form")({
|
|
component: RegisterRouteComponent,
|
|
})
|