Add complete Story detail page with two-column layout, breadcrumb navigation, and full CRUD operations. Key Features: - Story detail page at /stories/[id] route - Two-column layout (main content + metadata sidebar) - Breadcrumb navigation: Projects > Project > Epics > Epic > Stories > Story - Story header with title, status, priority badges, Edit/Delete actions - Main content area with Story description and Tasks placeholder - Metadata sidebar with: * Status selector (with optimistic updates) * Priority selector * Assignee display * Time tracking (estimated/actual hours) * Created/Updated dates * Parent Epic card (clickable link) - Edit Story dialog (reuses StoryForm component) - Delete Story confirmation dialog - Loading state (skeleton loaders) - Error handling with error.tsx - Responsive design (mobile/tablet/desktop) - Accessibility support (keyboard navigation, ARIA labels) Technical Implementation: - Uses Next.js 13+ App Router with dynamic routes - React Query for data fetching and caching - Optimistic updates for status/priority changes - Proper TypeScript typing throughout - Reuses existing components (StoryForm, shadcn/ui) - 85% code reuse from Epic detail page pattern Bug Fixes: - Fixed TypeScript error in pm.ts (api.post generic type) Files Created: - app/(dashboard)/stories/[id]/page.tsx (478 lines) - app/(dashboard)/stories/[id]/loading.tsx (66 lines) - app/(dashboard)/stories/[id]/error.tsx (53 lines) Files Modified: - lib/api/pm.ts (added generic type to api.post<Epic>) Verification: - Build successful (npm run build) - No TypeScript errors - Route registered: /stories/[id] (Dynamic) Next Steps: - Task management functionality (Sprint 4 Story 2) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
54 lines
1.4 KiB
TypeScript
54 lines
1.4 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect } from 'react';
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from '@/components/ui/card';
|
|
import { AlertCircle } from 'lucide-react';
|
|
|
|
export default function StoryDetailError({
|
|
error,
|
|
reset,
|
|
}: {
|
|
error: Error & { digest?: string };
|
|
reset: () => void;
|
|
}) {
|
|
useEffect(() => {
|
|
// Log the error to an error reporting service
|
|
console.error('Story detail page error:', error);
|
|
}, [error]);
|
|
|
|
return (
|
|
<div className="flex items-center justify-center min-h-[400px] p-4">
|
|
<Card className="w-full max-w-md">
|
|
<CardHeader>
|
|
<div className="flex items-center gap-2">
|
|
<AlertCircle className="h-5 w-5 text-destructive" />
|
|
<CardTitle className="text-destructive">Error Loading Story</CardTitle>
|
|
</div>
|
|
<CardDescription>
|
|
{error.message || 'An unexpected error occurred while loading the story.'}
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="flex flex-col gap-2">
|
|
<Button onClick={() => reset()} className="w-full">
|
|
Try Again
|
|
</Button>
|
|
<Button
|
|
onClick={() => window.history.back()}
|
|
variant="outline"
|
|
className="w-full"
|
|
>
|
|
Go Back
|
|
</Button>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|