--- task_id: sprint_4_story_1_task_2 story_id: sprint_4_story_1 sprint_id: sprint_4 status: not_started type: frontend assignee: Frontend Developer 1 created_date: 2025-11-05 estimated_hours: 3 --- # Task 2: Implement Story Header Component ## Description Create the Story header component that displays the Story title, status badge, priority badge, and action buttons (Edit, Delete). This header sits at the top of the Story detail page and includes a back button for navigation. ## What to Do 1. Create `components/projects/story-header.tsx` 2. Display Story title (32px, bold) 3. Add back button (navigates to parent Epic) 4. Display status badge with color coding 5. Display priority badge with color coding 6. Add Edit button (opens Story form dialog) 7. Add Delete button (opens confirmation dialog) 8. Implement responsive layout for mobile 9. Add keyboard navigation (ESC key for back) ## Files to Create/Modify - `components/projects/story-header.tsx` (new, ~100-150 lines) - `app/(dashboard)/stories/[id]/page.tsx` (modify, integrate header) ## Implementation Details ```typescript // components/projects/story-header.tsx 'use client'; import { useRouter } from 'next/navigation'; import { ArrowLeft, Edit, Trash2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import type { Story } from '@/types/project'; interface StoryHeaderProps { story: Story; onEdit: () => void; onDelete: () => void; } export function StoryHeader({ story, onEdit, onDelete }: StoryHeaderProps) { const router = useRouter(); const handleBack = () => { router.push(`/epics/${story.epicId}`); }; // Keyboard shortcut: ESC to go back useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') { handleBack(); } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, []); return (
{/* Back Button */} {/* Title and Badges */}

{story.title}

{/* Status Badge */} {story.status} {/* Priority Badge */} {story.priority}
{/* Action Buttons */}
); } // Helper functions for badge variants function getStatusVariant(status: string) { const variants = { Backlog: 'secondary', Todo: 'default', InProgress: 'warning', Done: 'success', }; return variants[status] || 'default'; } function getPriorityVariant(priority: string) { const variants = { Low: 'default', Medium: 'warning', High: 'destructive', Critical: 'destructive', }; return variants[priority] || 'default'; } ``` **Integration in page.tsx**: ```typescript // app/(dashboard)/stories/[id]/page.tsx import { StoryHeader } from '@/components/projects/story-header'; // Inside component setIsEditDialogOpen(true)} onDelete={() => setIsDeleteDialogOpen(true)} /> ``` ## Acceptance Criteria - [ ] Header displays Story title (max 2 lines, ellipsis overflow) - [ ] Back button navigates to parent Epic detail page - [ ] ESC key also navigates back - [ ] Status badge shows correct color (Backlog/Todo/InProgress/Done) - [ ] Priority badge shows correct color (Low/Medium/High/Critical) - [ ] Edit button opens Story form dialog (handler passed from page) - [ ] Delete button opens confirmation dialog (handler passed from page) - [ ] Responsive layout: Stack vertically on mobile - [ ] All buttons have proper ARIA labels - [ ] Keyboard accessible (Tab navigation works) ## Testing **Manual Testing**: 1. View Story detail page 2. Verify title displays correctly 3. Click back button → Navigates to Epic detail 4. Press ESC key → Navigates to Epic detail 5. Verify status badge color matches status value 6. Verify priority badge color matches priority value 7. Click Edit button → Triggers onEdit callback 8. Click Delete button → Triggers onDelete callback 9. Test on mobile → Buttons stack vertically **Unit Test**: ```typescript import { render, screen, fireEvent } from '@testing-library/react'; import { StoryHeader } from './story-header'; describe('StoryHeader', () => { const mockStory = { id: '123', title: 'Test Story', status: 'InProgress', priority: 'High', epicId: 'epic-123', }; it('renders story title', () => { render(); expect(screen.getByText('Test Story')).toBeInTheDocument(); }); it('calls onEdit when edit button clicked', () => { const onEdit = jest.fn(); render(); fireEvent.click(screen.getByLabelText('Edit Story')); expect(onEdit).toHaveBeenCalled(); }); it('calls onDelete when delete button clicked', () => { const onDelete = jest.fn(); render(); fireEvent.click(screen.getByLabelText('Delete Story')); expect(onDelete).toHaveBeenCalled(); }); }); ``` ## Dependencies **Prerequisites**: - Task 1 (page structure must exist) - ✅ shadcn/ui Button, Badge components **Blocks**: - Task 5 (Edit/Delete dialogs need header buttons) ## Estimated Time 3 hours ## Notes Reuse badge color logic from Epic header component if it exists. Keep the component simple and focused - dialogs are handled in Task 5.