/
FlysAt
/
DataFoundry
Обзор
Документация
Войти
/
FlysAt
/
DataFoundry
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
frontend/src/components/modals/AddAnnotationModal.tsx
147 строк
5 KB
FlysAt8
LS/ann/valid/review
05 май 2026, 13:30
05 май 2026, 13:30
7dc1605
Код
Авторство
О чём код?
import React, { useState, useEffect } from 'react'; import { X, Plus, Loader2 } from 'lucide-react'; import { useToast } from '../../contexts/ToastContext'; import { useAuth } from '../../contexts/AuthContext'; import { ordersAPI } from '../../api/orders'; interface AddAnnotationModalProps { isOpen: boolean; onClose: () => void; orderId: number; onSuccess: () => void; } export const AddAnnotationModal: React.FC<AddAnnotationModalProps> = ({ isOpen, onClose, orderId, onSuccess, }) => { const [annotationsInput, setAnnotationsInput] = useState(''); const [loading, setLoading] = useState(false); const { showToast } = useToast(); const { token } = useAuth(); useEffect(() => { if (!isOpen) { setAnnotationsInput(''); } }, [isOpen]); if (!isOpen) return null; const handleSubmit = async () => { if (!token) { showToast('Необходимо войти в систему'); return; } const annotationTypes = annotationsInput .split(',') .map(s => s.trim()) .filter(s => s.length > 0); if (annotationTypes.length === 0) { showToast('Введите хотя бы один тип аннотации'); return; } setLoading(true); try { await ordersAPI.addAnnotationTypes(orderId, annotationTypes, token); showToast('Аннотации успешно добавлены'); onSuccess(); onClose(); } catch (error: any) { console.error('Failed to add annotations:', error); showToast(error.message || 'Ошибка добавления аннотаций'); } finally { setLoading(false); } }; return ( <div className="fixed inset-0 z-50"> <div className="absolute inset-0 bg-black/50 backdrop-blur-sm" onClick={onClose}></div> <div className="absolute inset-0 flex items-center justify-center p-4"> <div className="bg-white dark:bg-slate-800 rounded-2xl shadow-2xl w-full max-w-md p-8 relative animate-slide-up"> <button onClick={onClose} disabled={loading} className="absolute top-4 right-4 p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors disabled:opacity-50" > <X className="w-5 h-5" /> </button> <h2 className="text-2xl font-bold mb-2 text-gray-900 dark:text-white"> Добавить аннотации </h2> <p className="text-gray-600 dark:text-gray-400 mb-6"> Введите новые типы аннотаций через запятую </p> <div className="mb-6"> <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"> Типы аннотаций </label> <input type="text" value={annotationsInput} onChange={(e) => setAnnotationsInput(e.target.value)} placeholder="Например: автомобиль, пешеход, светофор" className="w-full px-4 py-3 rounded-xl border border-gray-300 dark:border-gray-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:border-primary-500 focus:ring-2 focus:ring-primary-500/20 transition-all" disabled={loading} /> <p className="text-xs text-gray-500 mt-1"> Разделяйте аннотации запятыми </p> </div> {annotationsInput.trim() && ( <div className="mb-6 flex flex-wrap gap-2"> {annotationsInput.split(',').map((tag, idx) => { const trimmed = tag.trim(); if (!trimmed) return null; return ( <span key={idx} className="px-2 py-1 rounded-lg text-xs font-medium bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300" > {trimmed} </span> ); })} </div> )} <div className="flex gap-3"> <button onClick={handleSubmit} disabled={loading} className="flex-1 py-3 bg-gradient-to-r from-primary-600 to-secondary-600 text-white rounded-xl font-bold hover:from-primary-700 hover:to-secondary-700 transition-all disabled:opacity-50 flex items-center justify-center gap-2" > {loading ? ( <> <Loader2 className="w-5 h-5 animate-spin" /> <span>Добавление...</span> </> ) : ( <> <Plus className="w-5 h-5" /> <span>Добавить</span> </> )} </button> <button onClick={onClose} disabled={loading} className="px-6 py-3 border border-gray-300 dark:border-gray-600 rounded-xl text-gray-700 dark:text-gray-300 font-medium hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors disabled:opacity-50" > Отмена </button> </div> </div> </div> </div> ); };