From 68480c1eb1ccab480f9b4dade280eaa171891f31 Mon Sep 17 00:00:00 2001 From: DeeCee03 Date: Sat, 6 Jun 2026 15:47:54 +0200 Subject: [PATCH] =?UTF-8?q?feat(heute):=20ToDos=20mitten=20am=20Tag=20hinz?= =?UTF-8?q?uf=C3=BCgen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nach dem Lock-in konnte man ToDos nur bearbeiten/abhaken, aber keine neuen anlegen. Neuer Endpoint dayEntry.addTodo hängt ein einzelnes ToDo an den heutigen Tageseintrag an (erlaubt solange der Eintrag vom heutigen Berlin-Tag ist, auch nach der Reflexion). Inline-Feld „Neues ToDo hinzufügen" in der EinstempeltView; aktualisiert Heute + Dashboard-Sichten. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/api/src/routers/day-entry.ts | 40 ++++++++++++++++++++++++ apps/web/src/routes/heute.tsx | 37 ++++++++++++++++++++++ packages/shared/src/schemas/day-entry.ts | 8 +++++ 3 files changed, 85 insertions(+) diff --git a/apps/api/src/routers/day-entry.ts b/apps/api/src/routers/day-entry.ts index ad30b95..0f66062 100644 --- a/apps/api/src/routers/day-entry.ts +++ b/apps/api/src/routers/day-entry.ts @@ -240,6 +240,46 @@ export const dayEntryRouter = router({ return updated; }), + /** + * Einzelnes ToDo mitten am Tag hinzufügen (auch nach der Reflexion möglich, + * solange der Tageseintrag vom heutigen Berlin-Tag ist). + */ + addTodo: protectedProcedure + .input(DayEntrySchemas.addTodoInput) + .mutation(async ({ ctx, input }) => { + const date = todayIso(); + const entry = ( + await ctx.db + .select() + .from(dayEntry) + .where(and(eq(dayEntry.userId, ctx.user.id), eq(dayEntry.date, date))) + .limit(1) + )[0]; + if (!entry) { + throw new TRPCError({ + code: 'BAD_REQUEST', + message: 'Du bist heute noch nicht locked in.', + }); + } + const existing = await ctx.db + .select({ id: todo.id }) + .from(todo) + .where(eq(todo.dayEntryId, entry.id)); + const [created] = await ctx.db + .insert(todo) + .values({ + dayEntryId: entry.id, + userId: ctx.user.id, + date: entry.date, + title: input.title, + order: existing.length, + bezugKind: input.bezugKind ?? null, + bezugId: input.bezugId ?? null, + }) + .returning(); + return created; + }), + /** * Abend-Reflexion. Setzt Ampel + Trend, optional Blocker. */ diff --git a/apps/web/src/routes/heute.tsx b/apps/web/src/routes/heute.tsx index f90a0c2..dd7ea8c 100644 --- a/apps/web/src/routes/heute.tsx +++ b/apps/web/src/routes/heute.tsx @@ -273,6 +273,42 @@ function TodoRow({ ); } +function AddTodoInline() { + const utils = trpc.useUtils(); + const [title, setTitle] = useState(''); + const add = trpc.dayEntry.addTodo.useMutation({ + onSuccess: async () => { + setTitle(''); + await utils.dayEntry.today.invalidate(); + await utils.dayEntry.todayTeam.invalidate(); + await utils.dashboard.overview.invalidate(); + }, + }); + return ( +
{ + e.preventDefault(); + const v = title.trim(); + if (!v) return; + add.mutate({ title: v }); + }} + > + setTitle(e.target.value)} + placeholder="Neues ToDo hinzufügen …" + maxLength={200} + className="flex-1 rounded-[var(--radius-md)] border border-[var(--color-border)] bg-white px-3 py-2 text-sm focus:border-[var(--color-ink)] focus:outline-none" + /> + +
+ ); +} + function EinstempeltView({ todos, entry, @@ -322,6 +358,7 @@ function EinstempeltView({ ))} + diff --git a/packages/shared/src/schemas/day-entry.ts b/packages/shared/src/schemas/day-entry.ts index b5c94cf..cf12d29 100644 --- a/packages/shared/src/schemas/day-entry.ts +++ b/packages/shared/src/schemas/day-entry.ts @@ -57,6 +57,14 @@ export const editTodoTitleInput = z.object({ }); export type EditTodoTitleInput = z.infer; +// Einzelnes ToDo mitten am Tag zum heutigen Tageseintrag hinzufügen. +export const addTodoInput = z.object({ + title: z.string().min(1).max(200), + bezugKind: bezugKindSchema.optional(), + bezugId: z.string().uuid().optional(), +}); +export type AddTodoInput = z.infer; + export const markAbsentInput = z.object({ from: z.string().regex(/^\d{4}-\d{2}-\d{2}$/), to: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),