fix: align task pages with backend task api
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import api from '@/services/api'
|
||||
import type { Project } from '@/types'
|
||||
import type { Project, Milestone } from '@/types'
|
||||
|
||||
const TASK_TYPES = [
|
||||
{ value: 'story', label: 'Story', subtypes: ['feature', 'improvement', 'refactor'] },
|
||||
@@ -11,38 +11,56 @@ const TASK_TYPES = [
|
||||
{ value: 'maintenance', label: 'Maintenance', subtypes: ['deploy', 'release'] },
|
||||
{ value: 'research', label: 'Research', subtypes: [] },
|
||||
{ value: 'review', label: 'Review', subtypes: ['code_review', 'decision_review', 'function_review'] },
|
||||
{ value: 'support', label: 'Support', subtypes: ['access', 'information'] },
|
||||
{ value: 'meeting', label: 'Meeting', subtypes: ['conference', 'handover', 'recap'] },
|
||||
{ value: 'resolution', label: 'Resolution', subtypes: [] },
|
||||
]
|
||||
|
||||
export default function CreateTaskPage() {
|
||||
const navigate = useNavigate()
|
||||
const [projects, setProjects] = useState<Project[]>([])
|
||||
const [milestones, setMilestones] = useState<Milestone[]>([])
|
||||
const [form, setForm] = useState({
|
||||
title: '', description: '', project_id: 0, issue_type: 'task',
|
||||
issue_subtype: '', priority: 'medium', tags: '', reporter_id: 1,
|
||||
title: '', description: '', project_id: 0, milestone_id: 0, task_type: 'task',
|
||||
task_subtype: '', priority: 'medium', tags: '', reporter_id: 1,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
api.get<Project[]>('/projects').then(({ data }) => {
|
||||
setProjects(data)
|
||||
if (data.length) setForm((f) => ({ ...f, project_id: data[0].id }))
|
||||
if (data.length) {
|
||||
setForm((f) => ({ ...f, project_id: data[0].id }))
|
||||
// Load milestones for the first project
|
||||
api.get<Milestone[]>(`/milestones?project_id=${data[0].id}`).then(({ data: ms }) => {
|
||||
setMilestones(ms)
|
||||
if (ms.length) setForm((f) => ({ ...f, milestone_id: ms[0].id }))
|
||||
})
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
const currentType = TASK_TYPES.find(t => t.value === form.issue_type) || TASK_TYPES[2]
|
||||
const handleProjectChange = (projectId: number) => {
|
||||
setForm(f => ({ ...f, project_id: projectId, milestone_id: 0 }))
|
||||
api.get<Milestone[]>(`/milestones?project_id=${projectId}`).then(({ data: ms }) => {
|
||||
setMilestones(ms)
|
||||
if (ms.length) setForm((f) => ({ ...f, milestone_id: ms[0].id }))
|
||||
})
|
||||
}
|
||||
|
||||
const currentType = TASK_TYPES.find(t => t.value === form.task_type) || TASK_TYPES[2]
|
||||
const subtypes = currentType.subtypes || []
|
||||
|
||||
const handleTypeChange = (newType: string) => {
|
||||
setForm(f => ({ ...f, issue_type: newType, issue_subtype: '' }))
|
||||
setForm(f => ({ ...f, task_type: newType, task_subtype: '' }))
|
||||
}
|
||||
|
||||
const submit = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
if (!form.milestone_id) {
|
||||
alert('Please select a milestone')
|
||||
return
|
||||
}
|
||||
const payload: any = { ...form, tags: form.tags || null }
|
||||
if (!form.issue_subtype) delete payload.issue_subtype
|
||||
await api.post('/issues', payload)
|
||||
if (!form.task_subtype) delete payload.task_subtype
|
||||
await api.post('/tasks', payload)
|
||||
navigate('/tasks')
|
||||
}
|
||||
|
||||
@@ -50,21 +68,27 @@ export default function CreateTaskPage() {
|
||||
<div className="create-task">
|
||||
<h2>Create Task</h2>
|
||||
<form onSubmit={submit}>
|
||||
<label>Title <input required value={form.title} onChange={(e) => setForm({ ...form, title: e.target.value })} /></label>
|
||||
<label>Description <textarea value={form.description} onChange={(e) => setForm({ ...form, description: e.target.value })} /></label>
|
||||
<label>Title <input data-testid="task-title-input" required value={form.title} onChange={(e) => setForm({ ...form, title: e.target.value })} /></label>
|
||||
<label>Description <textarea data-testid="task-description-input" value={form.description} onChange={(e) => setForm({ ...form, description: e.target.value })} /></label>
|
||||
<label>Projects
|
||||
<select value={form.project_id} onChange={(e) => setForm({ ...form, project_id: Number(e.target.value) })}>
|
||||
<select data-testid="project-select" value={form.project_id} onChange={(e) => handleProjectChange(Number(e.target.value))}>
|
||||
{projects.map((p) => <option key={p.id} value={p.id}>{p.name}</option>)}
|
||||
</select>
|
||||
</label>
|
||||
<label>Milestone
|
||||
<select data-testid="milestone-select" value={form.milestone_id} onChange={(e) => setForm({ ...form, milestone_id: Number(e.target.value) })}>
|
||||
{milestones.length === 0 && <option value={0}>No milestones available</option>}
|
||||
{milestones.map((m) => <option key={m.id} value={m.id}>{m.title}</option>)}
|
||||
</select>
|
||||
</label>
|
||||
<label>Type
|
||||
<select value={form.issue_type} onChange={(e) => handleTypeChange(e.target.value)}>
|
||||
<select data-testid="task-type-select" value={form.task_type} onChange={(e) => handleTypeChange(e.target.value)}>
|
||||
{TASK_TYPES.map((t) => <option key={t.value} value={t.value}>{t.label}</option>)}
|
||||
</select>
|
||||
</label>
|
||||
{subtypes.length > 0 && (
|
||||
<label>Subtype
|
||||
<select value={form.issue_subtype} onChange={(e) => setForm({ ...form, issue_subtype: e.target.value })}>
|
||||
<select value={form.task_subtype} onChange={(e) => setForm({ ...form, task_subtype: e.target.value })}>
|
||||
<option value="">Select subtype</option>
|
||||
{subtypes.map((s) => <option key={s} value={s}>{s.replace('_', ' ')}</option>)}
|
||||
</select>
|
||||
@@ -79,7 +103,7 @@ export default function CreateTaskPage() {
|
||||
</select>
|
||||
</label>
|
||||
<label>Tags <input value={form.tags} onChange={(e) => setForm({ ...form, tags: e.target.value })} placeholder="Comma separated" /></label>
|
||||
<button type="submit" className="btn-primary">Create</button>
|
||||
<button data-testid="create-task-button" type="submit" className="btn-primary">Create</button>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user