fix: resolve 3 UX bugs from gitlooper ticket sweep (#45 #47 #48)

- #47: Remove misleading asterisk from Budget (EUR) label in project
  wizard — budget is optional per canGoNext() logic
- #48: Parse Zod validation JSON in wizard submit error handler so users
  see "Responsible person is required" instead of raw JSON array
- #45: Expose isEntriesError from timeline query context; TimelineView
  now renders an explicit error message instead of a silent empty canvas
  when the getEntriesView query fails

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
2026-04-03 11:25:42 +02:00
parent 339ae47540
commit 5a8dc6c166
3 changed files with 30 additions and 4 deletions
@@ -203,6 +203,7 @@ export interface TimelineContextValue {
// ─ Loading
isLoading: boolean;
isInitialLoading: boolean;
isEntriesError: boolean;
totalAllocCount: number;
activeFilterCount: number;
@@ -328,6 +329,7 @@ export function TimelineProvider({
) as {
data: TimelineEntriesView | undefined;
isLoading: boolean;
isError: boolean;
refetch: () => Promise<unknown>;
};
@@ -344,11 +346,12 @@ export function TimelineProvider({
) as {
data: TimelineEntriesView | undefined;
isLoading: boolean;
isError: boolean;
refetch: () => Promise<unknown>;
};
const entriesViewQuery = isSelfServiceTimeline ? selfEntriesViewQuery : staffEntriesViewQuery;
const { data: entriesView, isLoading, refetch: refetchEntriesView } = entriesViewQuery;
const { data: entriesView, isLoading, isError: isEntriesError, refetch: refetchEntriesView } = entriesViewQuery;
const assignments = entriesView?.assignments ?? [];
const demands = entriesView?.demands ?? [];
@@ -774,6 +777,7 @@ export function TimelineProvider({
blinkOverbookedDays,
isLoading,
isInitialLoading,
isEntriesError,
totalAllocCount,
activeFilterCount,
}),
@@ -800,6 +804,7 @@ export function TimelineProvider({
blinkOverbookedDays,
isLoading,
isInitialLoading,
isEntriesError,
totalAllocCount,
activeFilterCount,
],
@@ -332,6 +332,7 @@ function TimelineViewContent({
today,
isLoading,
isInitialLoading,
isEntriesError,
totalAllocCount,
} = ctx;
@@ -708,7 +709,11 @@ function TimelineViewContent({
onScroll={handleContainerScroll}
className="app-surface relative z-0 flex-1 overflow-auto"
>
{isInitialLoading ? (
{isEntriesError ? (
<div className="flex flex-col items-center justify-center gap-3 py-24 text-sm text-red-600 dark:text-red-400">
<span>Failed to load timeline data. Please try refreshing the page.</span>
</div>
) : isInitialLoading ? (
<div className="flex items-center justify-center py-24 text-sm text-gray-500 dark:text-gray-400">
Loading timeline...
</div>