feat(frontend): Implement Story detail page - Sprint 4 Story 1
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>
This commit is contained in:
53
app/(dashboard)/stories/[id]/error.tsx
Normal file
53
app/(dashboard)/stories/[id]/error.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
'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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user