Deadline nachträglich editierbar, Arbeitsmodus aus UI entfernen
Deadline lässt sich jetzt direkt im Projekt-Header bearbeiten (Inline- Datepicker mit Freitag/Wochenende-Warnung), via project.update. Der Arbeitsmodus (Kanban/Cycle) ist in ebw bedeutungslos und fliegt aus der Projekterstellung und der Header-Zeile raus. DB-Spalte bleibt ungenutzt bestehen (keine destruktive Migration nötig). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
684841ffb4
commit
ba8e524261
4 files changed
+72
-18
No files matched your search
@@ -74,7 +74,6 @@ export const projectRouter = router({
|
||||
logoUrl: input.logoUrl ?? null,
|
||||
kind: input.kind,
|
||||
verantwortlicheUserId: input.verantwortlicheUserId ?? null,
|
||||
arbeitsmodus: input.arbeitsmodus ?? null,
|
||||
outlineSteckbriefUrl: input.outlineSteckbriefUrl,
|
||||
planeProjectUrl: input.planeProjectUrl,
|
||||
risikolisteUrl: input.risikolisteUrl ?? null,
|
||||
|
||||
@@ -192,7 +192,6 @@ function ProjectCreateDialog({
|
||||
}
|
||||
}, [areas, areaId, defaultSlug]);
|
||||
const [kind, setKind] = useState<'kundenprojekt' | 'internes_projekt'>('internes_projekt');
|
||||
const [arbeitsmodus, setArbeitsmodus] = useState<'cycle' | 'kanban'>('kanban');
|
||||
const [steckbrief, setSteckbrief] = useState('');
|
||||
const [plane, setPlane] = useState('');
|
||||
|
||||
@@ -215,7 +214,6 @@ function ProjectCreateDialog({
|
||||
description: description.trim() || undefined,
|
||||
logoUrl: logoUrl ?? undefined,
|
||||
kind,
|
||||
arbeitsmodus,
|
||||
outlineSteckbriefUrl: steckbrief,
|
||||
planeProjectUrl: plane,
|
||||
milestones: [],
|
||||
@@ -280,16 +278,6 @@ function ProjectCreateDialog({
|
||||
<option value="internes_projekt">Internes Projekt</option>
|
||||
</select>
|
||||
</Field>
|
||||
<Field label="Arbeitsmodus">
|
||||
<select
|
||||
value={arbeitsmodus}
|
||||
onChange={(e) => setArbeitsmodus(e.target.value as 'cycle' | 'kanban')}
|
||||
className="w-full rounded-[var(--radius-md)] border border-[var(--color-border)] bg-white px-3 py-2 text-sm"
|
||||
>
|
||||
<option value="kanban">Kanban</option>
|
||||
<option value="cycle">Cycle</option>
|
||||
</select>
|
||||
</Field>
|
||||
<Field label="Outline-Steckbrief-URL">
|
||||
<input
|
||||
required
|
||||
|
||||
@@ -123,10 +123,11 @@ export function ProjektRoute() {
|
||||
<span className="rounded-full bg-black/5 px-2.5 py-1 text-xs">archiviert</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-[var(--color-ink-muted)]">
|
||||
{p.kind === 'kundenprojekt' ? 'Kundenprojekt' : 'Internes Projekt'} ·{' '}
|
||||
{p.arbeitsmodus ?? '—'} · {p.deadline ? `Deadline ${p.deadline}` : 'kein Deadline'}
|
||||
</p>
|
||||
<div className="flex flex-wrap items-center gap-2 text-[var(--color-ink-muted)]">
|
||||
<span>{p.kind === 'kundenprojekt' ? 'Kundenprojekt' : 'Internes Projekt'}</span>
|
||||
<span>·</span>
|
||||
<DeadlineControl projectId={p.id} deadline={p.deadline} />
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<ModusControl projectId={p.id} modus={p.modus as ProjectModus} />
|
||||
</div>
|
||||
@@ -243,6 +244,63 @@ function ModusControl({ projectId, modus }: { projectId: string; modus: ProjectM
|
||||
}
|
||||
|
||||
// --- Ziel & Maxime + SMART-Ziel, Nicht-Ziele, Liefergegenstände, Zieldreieck -
|
||||
function DeadlineControl({ projectId, deadline }: { projectId: string; deadline: string | null }) {
|
||||
const utils = trpc.useUtils();
|
||||
const [editing, setEditing] = useState(false);
|
||||
const [draft, setDraft] = useState(deadline ?? '');
|
||||
const update = trpc.project.update.useMutation({
|
||||
onSuccess: async () => {
|
||||
toast(voice.toast.saved);
|
||||
await utils.project.byId.invalidate({ id: projectId });
|
||||
setEditing(false);
|
||||
},
|
||||
});
|
||||
|
||||
if (editing) {
|
||||
const warnings = dateWarnings(draft || undefined);
|
||||
return (
|
||||
<span className="inline-flex flex-wrap items-center gap-2">
|
||||
<input
|
||||
type="date"
|
||||
value={draft}
|
||||
onChange={(e) => setDraft(e.target.value)}
|
||||
className="rounded-[var(--radius-md)] border border-[var(--color-border)] bg-white px-2 py-1 text-sm text-[var(--color-ink)]"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
disabled={update.isPending}
|
||||
onClick={() => update.mutate({ projectId, deadline: draft || null })}
|
||||
>
|
||||
Speichern
|
||||
</Button>
|
||||
<Button type="button" variant="ghost" size="sm" onClick={() => setEditing(false)}>
|
||||
Abbrechen
|
||||
</Button>
|
||||
{warnings.length > 0 && (
|
||||
<span className="flex items-center gap-1 text-xs text-[var(--color-ampel-amber-fg)]">
|
||||
<AlertTriangle size={12} /> {warnings[0]}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setDraft(deadline ?? '');
|
||||
setEditing(true);
|
||||
}}
|
||||
className="inline-flex items-center gap-1 hover:text-[var(--color-ink)] hover:underline"
|
||||
title="Deadline bearbeiten"
|
||||
>
|
||||
{deadline ? `Deadline ${deadline}` : 'kein Deadline'}
|
||||
<Pencil size={12} />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
function HeaderLogo({
|
||||
projectId,
|
||||
logoUrl,
|
||||
|
||||
@@ -18,7 +18,6 @@ export const createProjectInput = z.object({
|
||||
logoUrl: logoUrlSchema.optional(),
|
||||
kind: z.enum(['kundenprojekt', 'internes_projekt']),
|
||||
verantwortlicheUserId: z.string().uuid().optional(),
|
||||
arbeitsmodus: z.enum(['cycle', 'kanban']).optional(),
|
||||
outlineSteckbriefUrl: z.string().url(),
|
||||
planeProjectUrl: z.string().url(),
|
||||
risikolisteUrl: z.string().url().optional(),
|
||||
@@ -114,6 +113,16 @@ export const updateProjectInput = z.object({
|
||||
liefergegenstaende: z.string().max(2000).nullable().optional(),
|
||||
zieldreieckFlex: zieldreieckFlexSchema.nullable().optional(),
|
||||
logoUrl: logoUrlSchema.nullable().optional(),
|
||||
start: z
|
||||
.string()
|
||||
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
||||
.nullable()
|
||||
.optional(),
|
||||
deadline: z
|
||||
.string()
|
||||
.regex(/^\d{4}-\d{2}-\d{2}$/)
|
||||
.nullable()
|
||||
.optional(),
|
||||
outlineSteckbriefUrl: z.string().url().nullable().optional(),
|
||||
planeProjectUrl: z.string().url().nullable().optional(),
|
||||
risikolisteUrl: z.string().url().nullable().optional(),
|
||||
|
||||
Reference in new issue
Block a user