/
PashigorevAY
/
TestFastAPI
Обзор
Документация
Войти
/
PashigorevAY
/
TestFastAPI
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
frontend/src/components/TaskEditor.tsx
167 строк
5 KB
Pashigorev
Initial commit
05 июл 2026, 21:43
05 июл 2026, 21:43
19770a6
Код
Авторство
О чём код?
import { useState, useEffect } from 'react'; import { Task } from '../types'; import { api } from '../api'; import { PersonSelect } from './PersonSelect'; import { MultiplePersonSelect } from './MultiplePersonSelect'; interface TaskEditorProps { catalogName: string; taskId: string; onBack: () => void; } const FIELD_LABELS: Record<string, string> = { project: 'Проект', title: 'Название', description: 'Описание', assignee: 'Исполнитель', responsibles: 'Ответственные', due_date: 'Дедлайн', labels: 'Метки', assignee_to_epic_reporter: 'Исполнитель, создатель эпика', }; export function TaskEditor({ catalogName, taskId, onBack }: TaskEditorProps) { const [task, setTask] = useState<Task | null>(null); const [originalTask, setOriginalTask] = useState<Task | null>(null); const [labelsInput, setLabelsInput] = useState(''); const hasChanges = task && originalTask && JSON.stringify(task) !== JSON.stringify(originalTask); useEffect(() => { loadTask(); }, [catalogName, taskId]); async function loadTask() { const data = await api.getTask(catalogName, taskId); setTask(data); setOriginalTask(JSON.parse(JSON.stringify(data))); setLabelsInput(data.labels.join(', ')); } async function handleSave() { if (!task) return; await api.saveTask(catalogName, taskId, task); setOriginalTask(JSON.parse(JSON.stringify(task))); } function updateTask<K extends keyof Task>(field: K, value: Task[K]) { if (!task) return; setTask({ ...task, [field]: value }); } function handleLabelsChange(value: string) { setLabelsInput(value); const labels = value.split(',').map((s) => s.trim()).filter((s) => s); updateTask('labels', labels); } if (!task) return <div style={{ padding: '20px' }}>Загрузка...</div>; return ( <div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}> <div style={{ marginBottom: '20px', display: 'flex', gap: '10px', alignItems: 'center' }}> <button onClick={onBack} style={{ backgroundColor: '#e0e0e0' }}>← Назад</button> <h2 style={{ flex: 1 }}>Редактирование задачи: {task.id}</h2> <button onClick={handleSave} disabled={!hasChanges} style={{ backgroundColor: hasChanges ? '#2196F3' : '#e0e0e0', color: 'white' }} > Сохранить </button> </div> <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}> <div> <label style={{ display: 'block', marginBottom: '4px' }}> {FIELD_LABELS.project} </label> <input type="text" value={task.project} onChange={(e) => updateTask('project', e.target.value)} style={{ width: '100%', padding: '8px' }} /> </div> <div> <label style={{ display: 'block', marginBottom: '4px' }}> {FIELD_LABELS.title} </label> <input type="text" value={task.title} onChange={(e) => updateTask('title', e.target.value)} style={{ width: '100%', padding: '8px' }} /> </div> <div> <label style={{ display: 'block', marginBottom: '4px' }}> {FIELD_LABELS.description} </label> <textarea value={task.description} onChange={(e) => updateTask('description', e.target.value)} rows={6} style={{ width: '100%', padding: '8px' }} /> </div> <div> <PersonSelect label={FIELD_LABELS.assignee} value={task.assignee} onChange={(val) => updateTask('assignee', val)} /> </div> <div> <MultiplePersonSelect label={FIELD_LABELS.responsibles} value={task.responsibles} onChange={(val) => updateTask('responsibles', val)} /> </div> <div> <label style={{ display: 'block', marginBottom: '4px' }}> {FIELD_LABELS.due_date} </label> <input type="date" value={task.due_date} onChange={(e) => updateTask('due_date', e.target.value)} style={{ width: '100%', padding: '8px' }} /> </div> <div> <label style={{ display: 'block', marginBottom: '4px' }}> {FIELD_LABELS.labels} (разделяйте запятой) </label> <input type="text" value={labelsInput} onChange={(e) => handleLabelsChange(e.target.value)} placeholder="метка1, метка2" style={{ width: '100%', padding: '8px' }} /> </div> <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}> <input type="checkbox" checked={task.assignee_to_epic_reporter} onChange={(e) => updateTask('assignee_to_epic_reporter', e.target.checked)} id="assignee_to_epic_reporter" /> <label htmlFor="assignee_to_epic_reporter" style={{ margin: 0 }}> {FIELD_LABELS.assignee_to_epic_reporter} </label> </div> </div> </div> ); }