fix: align frontend status types with API string enum serialization
ASP.NET serializes C# enums as strings by default ("Pending", "Active"),
but frontend types used numeric values (0, 1). Changed WorkTaskStatus and
NoteType to string values matching API output.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@ import type { TaskNote } from '../types'
|
|||||||
export function useCreateNote() {
|
export function useCreateNote() {
|
||||||
const qc = useQueryClient()
|
const qc = useQueryClient()
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: ({ taskId, content, type }: { taskId: number; content: string; type: number }) =>
|
mutationFn: ({ taskId, content, type }: { taskId: number; content: string; type: string }) =>
|
||||||
request<TaskNote>({ method: 'POST', url: `/tasks/${taskId}/notes`, data: { content, type } }),
|
request<TaskNote>({ method: 'POST', url: `/tasks/${taskId}/notes`, data: { content, type } }),
|
||||||
onSuccess: () => qc.invalidateQueries({ queryKey: ['tasks'] }),
|
onSuccess: () => qc.invalidateQueries({ queryKey: ['tasks'] }),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -70,11 +70,11 @@ export default function KanbanBoard({ tasks, isLoading, onTaskClick }: KanbanBoa
|
|||||||
if (!task) return
|
if (!task) return
|
||||||
|
|
||||||
// Determine target status from the droppable column ID
|
// Determine target status from the droppable column ID
|
||||||
let targetStatus: number | null = null
|
let targetStatus: string | null = null
|
||||||
const overId = String(over.id)
|
const overId = String(over.id)
|
||||||
|
|
||||||
if (overId.startsWith('column-')) {
|
if (overId.startsWith('column-')) {
|
||||||
targetStatus = Number(overId.replace('column-', ''))
|
targetStatus = overId.replace('column-', '')
|
||||||
} else {
|
} else {
|
||||||
// Dropped over another card - find which column it belongs to
|
// Dropped over another card - find which column it belongs to
|
||||||
const overTaskId = Number(over.id)
|
const overTaskId = Number(over.id)
|
||||||
@@ -136,7 +136,7 @@ export default function KanbanBoard({ tasks, isLoading, onTaskClick }: KanbanBoa
|
|||||||
color={col.color}
|
color={col.color}
|
||||||
tasks={col.tasks}
|
tasks={col.tasks}
|
||||||
onTaskClick={onTaskClick}
|
onTaskClick={onTaskClick}
|
||||||
onAddTask={col.status === 0 ? () => {} : undefined}
|
onAddTask={col.status === WorkTaskStatus.Pending ? () => {} : undefined}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import { useState } from 'react'
|
|||||||
import { useDroppable } from '@dnd-kit/core'
|
import { useDroppable } from '@dnd-kit/core'
|
||||||
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable'
|
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable'
|
||||||
import { Plus } from 'lucide-react'
|
import { Plus } from 'lucide-react'
|
||||||
import type { WorkTask } from '../types/index.ts'
|
import { WorkTaskStatus, type WorkTask } from '../types/index.ts'
|
||||||
import TaskCard from './TaskCard.tsx'
|
import TaskCard from './TaskCard.tsx'
|
||||||
import CreateTaskForm from './CreateTaskForm.tsx'
|
import CreateTaskForm from './CreateTaskForm.tsx'
|
||||||
|
|
||||||
interface KanbanColumnProps {
|
interface KanbanColumnProps {
|
||||||
status: number
|
status: string
|
||||||
label: string
|
label: string
|
||||||
color: string
|
color: string
|
||||||
tasks: WorkTask[]
|
tasks: WorkTask[]
|
||||||
@@ -65,7 +65,7 @@ export default function KanbanColumn({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Add task form / button (Pending column only) */}
|
{/* Add task form / button (Pending column only) */}
|
||||||
{status === 0 && (
|
{status === WorkTaskStatus.Pending && (
|
||||||
<div className="px-3 pb-3">
|
<div className="px-3 pb-3">
|
||||||
{showForm ? (
|
{showForm ? (
|
||||||
<CreateTaskForm onClose={() => setShowForm(false)} />
|
<CreateTaskForm onClose={() => setShowForm(false)} />
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ interface NotesListProps {
|
|||||||
notes: TaskNote[]
|
notes: TaskNote[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const NOTE_TYPE_CONFIG: Record<number, { label: string; color: string }> = {
|
const NOTE_TYPE_CONFIG: Record<string, { label: string; color: string }> = {
|
||||||
[NoteType.PauseNote]: { label: 'Pause', color: '#f59e0b' },
|
[NoteType.PauseNote]: { label: 'Pause', color: '#f59e0b' },
|
||||||
[NoteType.ResumeNote]: { label: 'Resume', color: '#6366f1' },
|
[NoteType.ResumeNote]: { label: 'Resume', color: '#6366f1' },
|
||||||
[NoteType.General]: { label: 'General', color: '#64748b' },
|
[NoteType.General]: { label: 'General', color: '#64748b' },
|
||||||
|
|||||||
@@ -99,12 +99,12 @@ export default function SearchBar({ onSelect }: SearchBarProps) {
|
|||||||
[isOpen, results, selectedIndex, handleSelect]
|
[isOpen, results, selectedIndex, handleSelect]
|
||||||
)
|
)
|
||||||
|
|
||||||
const getStatusLabel = (status: number) => {
|
const getStatusLabel = (status: string) => {
|
||||||
const col = COLUMN_CONFIG.find((c) => c.status === status)
|
const col = COLUMN_CONFIG.find((c) => c.status === status)
|
||||||
return col ? col.label : 'Unknown'
|
return col ? col.label : 'Unknown'
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStatusColor = (status: number) => {
|
const getStatusColor = (status: string) => {
|
||||||
const col = COLUMN_CONFIG.find((c) => c.status === status)
|
const col = COLUMN_CONFIG.find((c) => c.status === status)
|
||||||
return col ? col.color : '#64748b'
|
return col ? col.color : '#64748b'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
export const COLUMN_CONFIG = [
|
export const COLUMN_CONFIG = [
|
||||||
{ status: 0, label: 'Pending', color: '#94a3b8' },
|
{ status: 'Pending' as const, label: 'Pending', color: '#94a3b8' },
|
||||||
{ status: 1, label: 'Active', color: '#06b6d4' },
|
{ status: 'Active' as const, label: 'Active', color: '#06b6d4' },
|
||||||
{ status: 2, label: 'Paused', color: '#f59e0b' },
|
{ status: 'Paused' as const, label: 'Paused', color: '#f59e0b' },
|
||||||
{ status: 3, label: 'Completed', color: '#10b981' },
|
{ status: 'Completed' as const, label: 'Completed', color: '#10b981' },
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
export const CATEGORY_COLORS: Record<string, string> = {
|
export const CATEGORY_COLORS: Record<string, string> = {
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
export const WorkTaskStatus = {
|
export const WorkTaskStatus = {
|
||||||
Pending: 0,
|
Pending: 'Pending',
|
||||||
Active: 1,
|
Active: 'Active',
|
||||||
Paused: 2,
|
Paused: 'Paused',
|
||||||
Completed: 3,
|
Completed: 'Completed',
|
||||||
Abandoned: 4,
|
Abandoned: 'Abandoned',
|
||||||
} as const
|
} as const
|
||||||
export type WorkTaskStatus = (typeof WorkTaskStatus)[keyof typeof WorkTaskStatus]
|
export type WorkTaskStatus = (typeof WorkTaskStatus)[keyof typeof WorkTaskStatus]
|
||||||
|
|
||||||
export const NoteType = {
|
export const NoteType = {
|
||||||
PauseNote: 0,
|
PauseNote: 'PauseNote',
|
||||||
ResumeNote: 1,
|
ResumeNote: 'ResumeNote',
|
||||||
General: 2,
|
General: 'General',
|
||||||
} as const
|
} as const
|
||||||
export type NoteType = (typeof NoteType)[keyof typeof NoteType]
|
export type NoteType = (typeof NoteType)[keyof typeof NoteType]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user