Created comprehensive Story and Task files for Sprint 4 frontend implementation: Story 1: Story Detail Page Foundation (P0 Critical - 3 days) - 6 tasks: route creation, header, sidebar, data loading, Edit/Delete, responsive design - Fixes critical 404 error when clicking Story cards - Two-column layout consistent with Epic detail page Story 2: Task Management in Story Detail (P0 Critical - 2 days) - 6 tasks: API verification, hooks, TaskList, TaskCard, TaskForm, integration - Complete Task CRUD with checkbox status toggle - Filters, sorting, and optimistic UI updates Story 3: Enhanced Story Form (P1 High - 2 days) - 6 tasks: acceptance criteria, assignee selector, tags, story points, integration - Aligns with UX design specification - Backward compatible with existing Stories Story 4: Quick Add Story Workflow (P1 High - 2 days) - 5 tasks: inline form, keyboard shortcuts, batch creation, navigation - Rapid Story creation with minimal fields - Keyboard shortcut (Cmd/Ctrl + N) Story 5: Story Card Component (P2 Medium - 1 day) - 4 tasks: component variants, visual states, Task count, optimization - Reusable component with list/kanban/compact variants - React.memo optimization Story 6: Kanban Story Creation Enhancement (P2 Optional - 2 days) - 4 tasks: Epic card enhancement, inline form, animation, real-time updates - Contextual Story creation from Kanban - Stretch goal - implement only if ahead of schedule Total: 6 Stories, 31 Tasks, 12 days estimated Priority breakdown: P0 (2), P1 (2), P2 (2 optional) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
6.6 KiB
6.6 KiB
task_id, story_id, sprint_id, status, type, assignee, created_date, estimated_hours
| task_id | story_id | sprint_id | status | type | assignee | created_date | estimated_hours |
|---|---|---|---|---|---|---|---|
| sprint_4_story_1_task_2 | sprint_4_story_1 | sprint_4 | not_started | frontend | Frontend Developer 1 | 2025-11-05 | 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
- Create
components/projects/story-header.tsx - Display Story title (32px, bold)
- Add back button (navigates to parent Epic)
- Display status badge with color coding
- Display priority badge with color coding
- Add Edit button (opens Story form dialog)
- Add Delete button (opens confirmation dialog)
- Implement responsive layout for mobile
- 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
// 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 (
<div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
<div className="flex items-start gap-4">
{/* Back Button */}
<Button
variant="ghost"
size="icon"
onClick={handleBack}
aria-label="Back to Epic"
>
<ArrowLeft className="h-5 w-5" />
</Button>
{/* Title and Badges */}
<div className="flex-1">
<h1 className="text-3xl font-bold tracking-tight mb-2 line-clamp-2">
{story.title}
</h1>
<div className="flex items-center gap-2 flex-wrap">
{/* Status Badge */}
<Badge variant={getStatusVariant(story.status)}>
{story.status}
</Badge>
{/* Priority Badge */}
<Badge variant={getPriorityVariant(story.priority)}>
{story.priority}
</Badge>
</div>
</div>
</div>
{/* Action Buttons */}
<div className="flex items-center gap-2">
<Button
variant="outline"
size="sm"
onClick={onEdit}
aria-label="Edit Story"
>
<Edit className="h-4 w-4 mr-2" />
Edit
</Button>
<Button
variant="destructive"
size="sm"
onClick={onDelete}
aria-label="Delete Story"
>
<Trash2 className="h-4 w-4 mr-2" />
Delete
</Button>
</div>
</div>
);
}
// 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:
// app/(dashboard)/stories/[id]/page.tsx
import { StoryHeader } from '@/components/projects/story-header';
// Inside component
<StoryHeader
story={story}
onEdit={() => 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:
- View Story detail page
- Verify title displays correctly
- Click back button → Navigates to Epic detail
- Press ESC key → Navigates to Epic detail
- Verify status badge color matches status value
- Verify priority badge color matches priority value
- Click Edit button → Triggers onEdit callback
- Click Delete button → Triggers onDelete callback
- Test on mobile → Buttons stack vertically
Unit Test:
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(<StoryHeader story={mockStory} onEdit={jest.fn()} onDelete={jest.fn()} />);
expect(screen.getByText('Test Story')).toBeInTheDocument();
});
it('calls onEdit when edit button clicked', () => {
const onEdit = jest.fn();
render(<StoryHeader story={mockStory} onEdit={onEdit} onDelete={jest.fn()} />);
fireEvent.click(screen.getByLabelText('Edit Story'));
expect(onEdit).toHaveBeenCalled();
});
it('calls onDelete when delete button clicked', () => {
const onDelete = jest.fn();
render(<StoryHeader story={mockStory} onEdit={jest.fn()} onDelete={onDelete} />);
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.