From 7f9a4506c51001b3cb6ff771ea0dbd0ecf04a63d Mon Sep 17 00:00:00 2001 From: DeeCee03 Date: Sat, 6 Jun 2026 18:56:54 +0200 Subject: [PATCH] =?UTF-8?q?refactor(zeit):=20Pausen=20nicht=20mehr=20buche?= =?UTF-8?q?n=20=E2=80=94=20L=C3=BCcken=20zwischen=20Tasks=20=3D=20Pause?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pause-Feature entfernt: kein Pause-Button, kein break-Buchen mehr. Man bucht nur Tasks; stoppt man eine Task und es läuft keine andere, ist die Lücke automatisch eine Pause — im Kalender/Tagesansicht schlicht leer. Tasks bleiben pausierbar (Stop = Pause, erneut Start = Fortsetzen → mehrere Segmente auf dieselbe Task, Lücke dazwischen leer). Wall-Clock zählt Lücken ohnehin nicht. - time.pause-Endpoint entfernt; 'break' aus der angebotenen Kategorienliste raus (bleibt im Enum für Altdaten). - TimerPill: Pause-Button + Pause-Panel-Grund entfernt; Stop/Start je Task bleibt (= pausieren/fortsetzen). Heute-ToDo-Zeile entsprechend beschriftet. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/api/src/routers/time.ts | 25 -------------- apps/web/src/components/time/TimerPill.tsx | 38 +--------------------- apps/web/src/routes/heute.tsx | 3 +- packages/shared/src/schemas/time-entry.ts | 8 ++--- 4 files changed, 5 insertions(+), 69 deletions(-) diff --git a/apps/api/src/routers/time.ts b/apps/api/src/routers/time.ts index 963076f..4359fe1 100644 --- a/apps/api/src/routers/time.ts +++ b/apps/api/src/routers/time.ts @@ -143,31 +143,6 @@ export const timeRouter = router({ return { stopped }; }), - /** - * Pause: stoppt ALLE laufenden Tasks und startet eine Pause (break). - */ - pause: protectedProcedure - .input(TimeEntrySchemas.pauseInput) - .mutation(async ({ ctx, input }) => { - const now = new Date(); - const dayEntryId = await findCurrentDayEntryId(ctx.db, ctx.user.id); - return ctx.db.transaction(async (tx) => { - await stopAllActive(tx, ctx.user.id, now); - const [brk] = await tx - .insert(timeEntry) - .values({ - userId: ctx.user.id, - dayEntryId, - category: 'break', - description: input.description ?? null, - startedAt: now, - }) - .returning(); - if (!brk) throw new Error('Pause konnte nicht gestartet werden.'); - return brk; - }); - }), - /** * Alle Time-Entries des heutigen Tages plus aktiver. */ diff --git a/apps/web/src/components/time/TimerPill.tsx b/apps/web/src/components/time/TimerPill.tsx index 47e5748..e6007a4 100644 --- a/apps/web/src/components/time/TimerPill.tsx +++ b/apps/web/src/components/time/TimerPill.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef, useState } from 'react'; -import { Play, Square, Plus, Pause } from 'lucide-react'; +import { Play, Square, Plus } from 'lucide-react'; import { clsx } from 'clsx'; import { toast } from 'sonner'; import { trpc } from '../../lib/trpc'; @@ -85,15 +85,6 @@ export function TimerPill() { toast('Timer läuft.'); }, }); - const pauseMutation = trpc.time.pause.useMutation({ - onSuccess: async () => { - await invalidate(); - setPickerOpen(false); - setPanelOpen(false); - toast('Pause läuft.'); - }, - }); - const count = active.length; const longest = count > 0 ? Math.max(...active.map(elapsedOf)) : 0; @@ -130,17 +121,6 @@ export function TimerPill() { )} - - {pickerOpen && ( t.status === 'open')} @@ -174,7 +154,6 @@ function TimersPanel({ onChanged: () => Promise; }) { const stopMutation = trpc.time.stop.useMutation({ onSuccess: onChanged }); - const updateMutation = trpc.time.update.useMutation({ onSuccess: onChanged }); return (

@@ -199,21 +178,6 @@ function TimersPanel({

- {a.category === 'break' && ( - { - const v = e.target.value.trim(); - if ((a.description ?? '') !== v) { - updateMutation.mutate({ id: a.id, description: v || null }); - } - }} - className="mt-1 ml-4 w-[calc(100%-1rem)] rounded-[var(--radius-md)] border border-[var(--color-border)] bg-white px-2 py-1 text-xs" - /> - )} ))} diff --git a/apps/web/src/routes/heute.tsx b/apps/web/src/routes/heute.tsx index 4e709ef..242c30d 100644 --- a/apps/web/src/routes/heute.tsx +++ b/apps/web/src/routes/heute.tsx @@ -238,7 +238,8 @@ function TodoRow({ ? stopMutation.mutate({ id: activeHere.id }) : startMutation.mutate({ todoId: todo.id, category: 'focus' }) } - aria-label={isRunningHere ? 'Timer stoppen' : 'Timer für diesen ToDo starten'} + aria-label={isRunningHere ? 'Task pausieren' : 'Task starten / fortsetzen'} + title={isRunningHere ? 'Pausieren' : 'Starten / fortsetzen'} className={ isRunningHere ? 'inline-flex h-7 items-center gap-1 rounded-full bg-[var(--color-ampel-red-bg)] px-2 text-xs font-medium text-[var(--color-ampel-red-fg)]' diff --git a/packages/shared/src/schemas/time-entry.ts b/packages/shared/src/schemas/time-entry.ts index 4a808cf..6b3c9ae 100644 --- a/packages/shared/src/schemas/time-entry.ts +++ b/packages/shared/src/schemas/time-entry.ts @@ -15,9 +15,10 @@ export const TIME_CATEGORIES: { value: TimeCategory; label: string }[] = [ { value: 'meeting', label: 'Meeting' }, { value: 'admin', label: 'Admin' }, { value: 'learning', label: 'Lernen' }, - { value: 'break', label: 'Pause' }, { value: 'other', label: 'Sonstiges' }, ]; +// 'break' bleibt im Enum (timeCategorySchema) für Altdaten, wird aber nicht mehr +// angeboten — Pausen werden nicht gebucht (Lücken zwischen Tasks = Pause). export const startTimeEntryInput = z.object({ todoId: z.string().uuid().optional(), @@ -36,11 +37,6 @@ export const updateTimeEntryInput = z.object({ }); export type UpdateTimeEntryInput = z.infer; -export const pauseInput = z.object({ - description: z.string().max(200).optional(), -}); -export type PauseInput = z.infer; - export const teamTimelineInput = z.object({ date: z .string()