3.1 KiB
3.1 KiB
Task 7: Implement Epic/Story/Task Forms
Task ID: TASK-007 | Story: STORY-002 | Sprint: Sprint 1 Estimated Hours: 5h | Assignee: Frontend Developer 2 | Priority: P0 | Status: Not Started
Task Description
Build React forms for creating/editing Epic/Story/Task with validation, parent selection, and error handling.
Implementation
Example: EpicForm.tsx
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { useCreateEpic, useUpdateEpic } from '../hooks/useEpics';
const epicSchema = z.object({
title: z.string().min(3, 'Title must be at least 3 characters'),
description: z.string().optional(),
projectId: z.string().uuid('Invalid project ID'),
priority: z.enum(['Low', 'Medium', 'High', 'Critical']),
status: z.enum(['Backlog', 'Todo', 'InProgress', 'Done'])
});
type EpicFormData = z.infer<typeof epicSchema>;
export const EpicForm: React.FC<{ epic?: Epic, onSuccess: () => void }> = ({ epic, onSuccess }) => {
const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm<EpicFormData>({
resolver: zodResolver(epicSchema),
defaultValues: epic || {}
});
const createEpic = useCreateEpic();
const updateEpic = useUpdateEpic();
const onSubmit = async (data: EpicFormData) => {
try {
if (epic) {
await updateEpic.mutateAsync({ id: epic.id, dto: data });
} else {
await createEpic.mutateAsync(data);
}
onSuccess();
} catch (error) {
console.error('Form submission error:', error);
}
};
return (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<div>
<label htmlFor="title">Title *</label>
<input id="title" {...register('title')} className="form-input" />
{errors.title && <span className="text-red-500">{errors.title.message}</span>}
</div>
<div>
<label htmlFor="description">Description</label>
<textarea id="description" {...register('description')} className="form-textarea" />
</div>
<div>
<label htmlFor="priority">Priority *</label>
<select id="priority" {...register('priority')} className="form-select">
<option value="Low">Low</option>
<option value="Medium">Medium</option>
<option value="High">High</option>
<option value="Critical">Critical</option>
</select>
</div>
<button type="submit" disabled={isSubmitting} className="btn-primary">
{isSubmitting ? 'Saving...' : (epic ? 'Update Epic' : 'Create Epic')}
</button>
</form>
);
};
Acceptance Criteria
- EpicForm component with validation
- StoryForm with parent epic selection dropdown
- TaskForm with parent story selection dropdown
- Zod schemas for all forms
- Loading states during submission
- Error messages displayed
Deliverables
- EpicForm.tsx
- StoryForm.tsx (with parent epic selector)
- TaskForm.tsx (with parent story selector)
- Validation schemas
- Unit tests (15+ tests)
Status: Not Started | Created: 2025-11-04