From fc503a384778d38436f0a6bb2e0b216e64b6d220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Sun, 17 Aug 2025 21:35:08 +0200 Subject: [PATCH] Todo work --- packages/example/src/todo/Todo.tsx | 116 +++++++++++++++-------------- 1 file changed, 61 insertions(+), 55 deletions(-) diff --git a/packages/example/src/todo/Todo.tsx b/packages/example/src/todo/Todo.tsx index 8281053..2322c98 100644 --- a/packages/example/src/todo/Todo.tsx +++ b/packages/example/src/todo/Todo.tsx @@ -1,5 +1,6 @@ import * as Domain from "@/domain" import { TextAreaInput } from "@/lib/TextAreaInput" +import { TextFieldInput } from "@/lib/TextFieldInput" import { Box, Button, Flex, IconButton } from "@radix-ui/themes" import { GetRandomValues, makeUuid4 } from "@typed/id" import { Chunk, Effect, Match, Option, Ref, Runtime, Schema, SubscriptionRef } from "effect" @@ -12,6 +13,7 @@ import { TodosState } from "./TodosState.service" const StringTextAreaInput = TextAreaInput(Schema.String) +const OptionalDateInput = TextFieldInput({ optional: true, schema: Schema.DateTimeUtc }) const makeTodo = makeUuid4.pipe( Effect.map(id => Domain.Todo.Todo.make({ @@ -32,7 +34,7 @@ export class Todo extends Component.makeUntraced(function* Todo(props: TodoProps const runtime = yield* Effect.runtime() const state = yield* TodosState - const [ref, contentRef] = yield* Hooks.useMemo(() => Match.value(props).pipe( + const [ref, contentRef, completedAtRef] = 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, @@ -40,75 +42,79 @@ export class Todo extends Component.makeUntraced(function* Todo(props: TodoProps Effect.map(ref => [ ref, SubscriptionSubRef.makeFromPath(ref, ["content"]), + SubscriptionSubRef.makeFromPath(ref, ["completedAt"]), ] as const), ), [props._tag, props.index]) const [size] = yield* Hooks.useSubscribeRefs(state.sizeRef) const StringTextAreaInputFC = yield* StringTextAreaInput + const OptionalDateInputFC = yield* OptionalDateInput return ( - - - + + + - - {props._tag === "edit" && - - Runtime.runSync(runtime)( - SubscriptionRef.updateEffect(state.ref, todos => Effect.gen(function*() { - if (props.index <= 0) return yield* Option.none() - return todos.pipe( - Chunk.replace(props.index, yield* Chunk.get(todos, props.index - 1)), - Chunk.replace(props.index - 1, yield* ref), - ) - })) - )} - > - - + + - = size - 1} - onClick={() => Runtime.runSync(runtime)( - SubscriptionRef.updateEffect(state.ref, todos => Effect.gen(function*() { - if (props.index >= size - 1) return yield* Option.none() - return todos.pipe( - Chunk.replace(props.index, yield* Chunk.get(todos, props.index + 1)), - Chunk.replace(props.index + 1, yield* ref), - ) - })) - )} - > - - - - Runtime.runSync(runtime)( - Ref.update(state.ref, Chunk.remove(props.index)) - )} - > - - + {props._tag === "new" && + + } - } - + + - {props._tag === "new" && - - + + + + = size - 1} + onClick={() => Runtime.runSync(runtime)( + SubscriptionRef.updateEffect(state.ref, todos => Effect.gen(function*() { + if (props.index >= size - 1) return yield* Option.none() + return todos.pipe( + Chunk.replace(props.index, yield* Chunk.get(todos, props.index + 1)), + Chunk.replace(props.index + 1, yield* ref), + ) + })) + )} + > + + + + Runtime.runSync(runtime)( + Ref.update(state.ref, Chunk.remove(props.index)) + )} + > + + }