import * as Domain from "@/domain" import { Box, Button, Callout, Flex, IconButton, Text, TextArea } from "@radix-ui/themes" import { GetRandomValues, makeUuid4 } from "@typed/id" import { Chunk, Effect, Match, Option, ParseResult, Ref, Runtime, Schema, SubscriptionRef } from "effect" import { Component, Memoized } from "effect-fc" import { Hooks } from "effect-fc/hooks" import { SubscriptionSubRef } from "effect-fc/types" import { FaArrowDown, FaArrowUp } from "react-icons/fa" import { FaDeleteLeft } from "react-icons/fa6" import { TodosState } from "./TodosState.service" const makeTodo = makeUuid4.pipe( Effect.map(id => Domain.Todo.Todo.make({ id, content: "", completedAt: Option.none(), })), Effect.provide(GetRandomValues.CryptoRandom), ) export type TodoProps = ( | { readonly _tag: "new", readonly index?: never } | { readonly _tag: "edit", readonly index: number } ) export class Todo extends Component.make(Effect.fnUntraced(function* Todo(props: TodoProps) { const runtime = yield* Effect.runtime() const state = yield* TodosState const [ref, contentRef] = yield* Hooks.useMemo(() => Match.value(props).pipe( Match.tag("new", () => Effect.andThen(makeTodo, SubscriptionRef.make)), Match.tag("edit", ({ index }) => Effect.succeed(SubscriptionSubRef.makeFromChunkRef(state.ref, index))), Match.exhaustive, Effect.map(ref => [ ref, SubscriptionSubRef.makeFromPath(ref, ["content"]), ] as const), ), [props._tag, props.index]) const [size] = yield* Hooks.useSubscribeRefs(state.sizeRef) const contentInput = yield* Hooks.useInput({ ref: contentRef, schema: Schema.Any }) return ( {Option.isSome(contentInput.error) && {ParseResult.ArrayFormatter.formatErrorSync(contentInput.error.value).map(e => <> • {e.message}
)}
}