import { createMemo, createSignal, For, Show } from "solid-js";
import { useServerTodos } from "~/lib/todos";
import {
createClientEventLog,
createEventComputed,
createEventProjection,
} from "../../socket/events";
import { createSocketMemo } from "../../socket/lib/shared";
import { CompleteIcon, IncompleteIcon } from "./icons";
export type TodosFilter = "all" | "active" | "completed" | undefined;
export type Todo = {
id: number;
title: string;
completed: boolean;
};
export function TodoApp(props: { filter: TodosFilter; listId?: string }) {
const filter = () => props.filter;
const [editingTodoId, setEditingId] = createSignal();
const setEditing = ({
id,
pending,
}: {
id?: number;
pending?: () => boolean;
}) => {
if (!pending || !pending()) setEditingId(id);
};
let inputRef!: HTMLInputElement;
const serverTodos = useServerTodos(createSocketMemo(() => props.listId));
const { events, appendEvent } = createClientEventLog(serverTodos);
const todos = createEventProjection(
events,
(acc, e) => {
if (e.type === "todo-added") {
acc.push({ id: e.id, title: e.title, completed: false });
}
if (e.type === "todo-toggled") {
const todo = acc.find((t) => t.id === e.id);
if (todo) todo.completed = !todo.completed;
}
if (e.type === "todo-deleted") {
const index = acc.findIndex((note) => note.id === e.id);
if (index !== -1) acc.splice(index, 1);
}
if (e.type === "todo-edited") {
const todo = acc.find((t) => t.id === e.id);
if (todo) todo.title = e.title;
}
return acc;
},
[] as Todo[]
);
const filteredTodos = createMemo(() => {
if (filter() === "active") return todos.filter((t) => !t.completed);
if (filter() === "completed") return todos.filter((t) => t.completed);
return todos;
});
const remainingTodos = createEventProjection(
events,
(acc, e) => {
if (e.type === "todo-added") {
acc.push(e.id);
}
if (e.type === "todo-toggled") {
acc.includes(e.id) ? acc.splice(acc.indexOf(e.id), 1) : acc.push(e.id);
}
if (e.type === "todo-deleted") {
acc.includes(e.id) && acc.splice(acc.indexOf(e.id), 1);
}
return acc;
},
[] as number[]
);
const totalCount = createEventComputed(
events,
(acc, e) => {
if (e.type === "todo-added") {
acc++;
}
if (e.type === "todo-deleted") {
acc--;
}
return acc;
},
0
);
const toggleAll = (completed: boolean) =>
Promise.all(
todos
.filter((t) => t.completed !== completed)
.map((t) => appendEvent({ type: "todo-toggled", id: t.id }))
);
const clearCompleted = () =>
Promise.all(
todos
.filter((t) => t.completed)
.map((t) => appendEvent({ type: "todo-deleted", id: t.id }))
);
return (
<>
todos