feat: use tasks/supports/meetings endpoints instead of issues
This commit is contained in:
@@ -1,15 +1,32 @@
|
|||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import { useParams, useNavigate } from 'react-router-dom'
|
import { useParams, useNavigate } from 'react-router-dom'
|
||||||
import api from '@/services/api'
|
import api from '@/services/api'
|
||||||
import type { Milestone, MilestoneProgress, MilestoneItems, Issue } from '@/types'
|
import type { Milestone, MilestoneProgress, Issue } from '@/types'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
|
interface Task {
|
||||||
|
id: number
|
||||||
|
title: string
|
||||||
|
description?: string
|
||||||
|
status: string
|
||||||
|
task_code?: string
|
||||||
|
task_status?: string
|
||||||
|
estimated_effort?: number
|
||||||
|
estimated_working_time?: string
|
||||||
|
started_on?: string
|
||||||
|
finished_on?: string
|
||||||
|
assignee_id?: number
|
||||||
|
created_at: string
|
||||||
|
}
|
||||||
|
|
||||||
export default function MilestoneDetailPage() {
|
export default function MilestoneDetailPage() {
|
||||||
const { id } = useParams()
|
const { id } = useParams()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const [milestone, setMilestone] = useState<Milestone | null>(null)
|
const [milestone, setMilestone] = useState<Milestone | null>(null)
|
||||||
const [progress, setProgress] = useState<MilestoneProgress | null>(null)
|
const [progress, setProgress] = useState<MilestoneProgress | null>(null)
|
||||||
const [items, setItems] = useState<MilestoneItems | null>(null)
|
const [tasks, setTasks] = useState<Task[]>([])
|
||||||
|
const [supports, setSupports] = useState<Issue[]>([])
|
||||||
|
const [meetings, setMeetings] = useState<Issue[]>([])
|
||||||
const [activeTab, setActiveTab] = useState<'tasks' | 'supports' | 'meetings'>('tasks')
|
const [activeTab, setActiveTab] = useState<'tasks' | 'supports' | 'meetings'>('tasks')
|
||||||
const [showCreateTask, setShowCreateTask] = useState(false)
|
const [showCreateTask, setShowCreateTask] = useState(false)
|
||||||
const [showCreateSupport, setShowCreateSupport] = useState(false)
|
const [showCreateSupport, setShowCreateSupport] = useState(false)
|
||||||
@@ -18,44 +35,56 @@ export default function MilestoneDetailPage() {
|
|||||||
const [newDesc, setNewDesc] = useState('')
|
const [newDesc, setNewDesc] = useState('')
|
||||||
const [newEffort, setNewEffort] = useState(5)
|
const [newEffort, setNewEffort] = useState(5)
|
||||||
const [newTime, setNewTime] = useState('09:00')
|
const [newTime, setNewTime] = useState('09:00')
|
||||||
|
const [projectCode, setProjectCode] = useState('')
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api.get<Milestone>(`/milestones/${id}`).then(({ data }) => setMilestone(data))
|
api.get<Milestone>(`/milestones/${id}`).then(({ data }) => {
|
||||||
|
setMilestone(data)
|
||||||
|
// Get project_code from project
|
||||||
|
if (data.project_id) {
|
||||||
|
api.get(`/projects/${data.project_id}`).then(({ data: proj }) => {
|
||||||
|
setProjectCode(proj.project_code || '')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
api.get<MilestoneProgress>(`/milestones/${id}/progress`).then(({ data }) => setProgress(data)).catch(() => {})
|
api.get<MilestoneProgress>(`/milestones/${id}/progress`).then(({ data }) => setProgress(data)).catch(() => {})
|
||||||
api.get<MilestoneItems>(`/milestones/${id}/items`).then(({ data }) => setItems(data)).catch(() => {})
|
|
||||||
}, [id])
|
}, [id])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!projectCode || !id) return
|
||||||
|
api.get<Task[]>(`/tasks/${projectCode}/${id}`).then(({ data }) => setTasks(data)).catch(() => {})
|
||||||
|
api.get<Issue[]>(`/supports/${projectCode}/${id}`).then(({ data }) => setSupports(data)).catch(() => {})
|
||||||
|
api.get<Issue[]>(`/meetings/${projectCode}/${id}`).then(({ data }) => setMeetings(data)).catch(() => {})
|
||||||
|
}, [projectCode, id])
|
||||||
|
|
||||||
const createItem = async (type: 'tasks' | 'supports' | 'meetings') => {
|
const createItem = async (type: 'tasks' | 'supports' | 'meetings') => {
|
||||||
if (!newTitle.trim()) return
|
if (!newTitle.trim() || !projectCode) return
|
||||||
const payload: any = {
|
const payload: any = {
|
||||||
title: newTitle,
|
title: newTitle,
|
||||||
description: newDesc || null,
|
description: newDesc || null,
|
||||||
status: 'open',
|
|
||||||
priority: 'medium'
|
|
||||||
}
|
}
|
||||||
if (type === 'tasks') {
|
if (type === 'tasks') {
|
||||||
payload.estimated_effort = newEffort
|
payload.estimated_effort = newEffort
|
||||||
payload.estimated_working_time = newTime
|
payload.estimated_working_time = newTime
|
||||||
}
|
}
|
||||||
await api.post(`/milestones/${id}/${type}`, payload)
|
await api.post(`/${type}/${projectCode}/${id}`, payload)
|
||||||
setNewTitle('')
|
setNewTitle('')
|
||||||
setNewDesc('')
|
setNewDesc('')
|
||||||
setShowCreateTask(false)
|
setShowCreateTask(false)
|
||||||
setShowCreateSupport(false)
|
setShowCreateSupport(false)
|
||||||
setShowCreateMeeting(false)
|
setShowCreateMeeting(false)
|
||||||
api.get<MilestoneItems>(`/milestones/${id}/items`).then(({ data }) => setItems(data))
|
// Refresh
|
||||||
|
api.get<Task[]>(`/tasks/${projectCode}/${id}`).then(({ data }) => setTasks(data))
|
||||||
|
api.get<Issue[]>(`/supports/${projectCode}/${id}`).then(({ data }) => setSupports(data))
|
||||||
|
api.get<Issue[]>(`/meetings/${projectCode}/${id}`).then(({ data }) => setMeetings(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
const isProgressing = milestone?.status === 'progressing'
|
const isProgressing = milestone?.status === 'progressing'
|
||||||
|
|
||||||
if (!milestone) return <div className="loading">Loading...</div>
|
if (!milestone) return <div className="loading">Loading...</div>
|
||||||
|
|
||||||
const tasks = items?.tasks || []
|
const renderTaskRow = (t: Task) => (
|
||||||
const supports = items?.supports || []
|
<tr key={t.id} className="clickable" onClick={() => navigate(`/tasks/${projectCode}/${id}/${t.id}`)}>
|
||||||
const meetings = items?.meetings || []
|
|
||||||
|
|
||||||
const renderTaskRow = (t: any) => (
|
|
||||||
<tr key={t.id} className="clickable" onClick={() => navigate(`/issues/${t.id}`)}>
|
|
||||||
<td>{t.task_code || t.id}</td>
|
<td>{t.task_code || t.id}</td>
|
||||||
<td className="issue-title">{t.title}</td>
|
<td className="issue-title">{t.title}</td>
|
||||||
<td><span className={`badge status-${t.task_status || t.status}`}>{t.task_status || t.status}</span></td>
|
<td><span className={`badge status-${t.task_status || t.status}`}>{t.task_status || t.status}</span></td>
|
||||||
@@ -175,8 +204,8 @@ export default function MilestoneDetailPage() {
|
|||||||
<table>
|
<table>
|
||||||
<thead><tr><th>#</th><th>Title</th><th>Status</th><th>Priority</th></tr></thead>
|
<thead><tr><th>#</th><th>Title</th><th>Status</th><th>Priority</th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{supports.map((i: any) => (
|
{supports.map((i) => (
|
||||||
<tr key={i.id} className="clickable" onClick={() => navigate(`/issues/${i.id}`)}>
|
<tr key={i.id} className="clickable" onClick={() => navigate(`/supports/${projectCode}/${id}/${i.id}`)}>
|
||||||
<td>{i.id}</td>
|
<td>{i.id}</td>
|
||||||
<td className="issue-title">{i.title}</td>
|
<td className="issue-title">{i.title}</td>
|
||||||
<td><span className={`badge status-${i.status}`}>{i.status}</span></td>
|
<td><span className={`badge status-${i.status}`}>{i.status}</span></td>
|
||||||
@@ -192,8 +221,8 @@ export default function MilestoneDetailPage() {
|
|||||||
<table>
|
<table>
|
||||||
<thead><tr><th>#</th><th>Title</th><th>Status</th><th>Priority</th></tr></thead>
|
<thead><tr><th>#</th><th>Title</th><th>Status</th><th>Priority</th></tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{meetings.map((i: any) => (
|
{meetings.map((i) => (
|
||||||
<tr key={i.id} className="clickable" onClick={() => navigate(`/issues/${i.id}`)}>
|
<tr key={i.id} className="clickable" onClick={() => navigate(`/meetings/${projectCode}/${id}/${i.id}`)}>
|
||||||
<td>{i.id}</td>
|
<td>{i.id}</td>
|
||||||
<td className="issue-title">{i.title}</td>
|
<td className="issue-title">{i.title}</td>
|
||||||
<td><span className={`badge status-${i.status}`}>{i.status}</span></td>
|
<td><span className={`badge status-${i.status}`}>{i.status}</span></td>
|
||||||
|
|||||||
Reference in New Issue
Block a user