Working field
All checks were successful
Lint / lint (push) Successful in 12s

This commit is contained in:
Julien Valverdé
2025-09-30 15:54:59 +02:00
parent 47e21f6340
commit 040e671fd3
3 changed files with 53 additions and 38 deletions

View File

@@ -0,0 +1,40 @@
import { Callout, Flex, TextField } from "@radix-ui/themes"
import { Array, Option } from "effect"
import { Component, Form } from "effect-fc"
import { useSubscribables } from "effect-fc/hooks"
export interface TextFieldFormInputProps
extends TextField.RootProps, Form.useInput.Options {
readonly field: Form.FormField<any, string>
}
export class TextFieldFormInput extends Component.makeUntraced("TextFieldFormInput")(function*(props: TextFieldFormInputProps) {
const { value, setValue } = yield* Form.useInput(props.field, props)
const [issues, isValidating, isSubmitting] = yield* useSubscribables(
props.field.issuesSubscribable,
props.field.isValidatingSubscribable,
props.field.isSubmittingSubscribable,
)
return (
<Flex direction="column" gap="1">
<TextField.Root
value={value}
onChange={e => setValue(e.target.value)}
disabled={isSubmitting}
{...props}
/>
{Option.match(Array.head(issues), {
onSome: issue => (
<Callout.Root>
<Callout.Text>{issue.message}</Callout.Text>
</Callout.Root>
),
onNone: () => <></>,
})}
</Flex>
)
}) {}

View File

@@ -1,7 +1,8 @@
import { TextFieldFormInput } from "@/lib/form/TextFieldFormInput"
import { runtime } from "@/runtime"
import { Button, Callout, Container, Flex, TextField } from "@radix-ui/themes"
import { Button, Container, Flex } from "@radix-ui/themes"
import { createFileRoute } from "@tanstack/react-router"
import { Array, Effect, Option, Schema } from "effect"
import { Effect, Schema } from "effect"
import { Component, Form } from "effect-fc"
import { useContext, useSubscribables } from "effect-fc/hooks"
@@ -34,14 +35,11 @@ class RegisterForm extends Effect.Service<RegisterForm>()("RegisterForm", {
class RegisterPage extends Component.makeUntraced("RegisterPage")(function*() {
const form = yield* RegisterForm
const emailField = Form.useField(form, ["email"])
const passwordField = Form.useField(form, ["password"])
const emailInput = yield* Form.useInput(emailField, { debounce: "200 millis" })
const passwordInput = yield* Form.useInput(passwordField, { debounce: "200 millis" })
const submit = yield* Form.useSubmit(form)
const [canSubmit] = yield* useSubscribables(form.canSubmitSubscribable)
const TextFieldFormInputFC = yield* TextFieldFormInput
return (
<Container>
<form onSubmit={e => {
@@ -49,36 +47,16 @@ class RegisterPage extends Component.makeUntraced("RegisterPage")(function*() {
void submit()
}}>
<Flex direction="column" gap="2">
<TextField.Root
value={emailInput.value}
onChange={e => emailInput.setValue(e.target.value)}
<TextFieldFormInputFC
field={Form.useField(form, ["email"])}
debounce="500 millis"
/>
{Option.match(Array.head(emailInput.issues), {
onSome: issue => (
<Callout.Root>
<Callout.Text>{issue.message}</Callout.Text>
</Callout.Root>
),
onNone: () => <></>,
})}
<TextField.Root
value={passwordInput.value}
onChange={e => passwordInput.setValue(e.target.value)}
<TextFieldFormInputFC
field={Form.useField(form, ["password"])}
debounce="500 millis"
/>
{Option.match(Array.head(passwordInput.issues), {
onSome: issue => (
<Callout.Root>
<Callout.Text>{issue.message}</Callout.Text>
</Callout.Root>
),
onNone: () => <></>,
})}
<Button disabled={!canSubmit}>Submit</Button>
</Flex>
</form>