Унификация отображения ошибок: LoadingError для загрузки, Toast для действий
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 34s

This commit is contained in:
poignatov
2026-01-11 15:51:28 +03:00
parent 8023fb9108
commit 932dba8682
17 changed files with 284 additions and 91 deletions

View File

@@ -20,6 +20,8 @@ import {
import { CSS } from '@dnd-kit/utilities'
import { getAllProjectsSorted, getProjectColor } from '../utils/projectUtils'
import { useAuth } from './auth/AuthContext'
import LoadingError from './LoadingError'
import Toast from './Toast'
import './Integrations.css'
// API endpoints (используем относительные пути, проксирование настроено в nginx/vite)
@@ -29,20 +31,20 @@ const PROJECT_MOVE_API_URL = '/project/move'
const PROJECT_CREATE_API_URL = '/project/create'
// Компонент экрана добавления проекта
function AddProjectScreen({ onClose, onSuccess }) {
function AddProjectScreen({ onClose, onSuccess, onError }) {
const { authFetch } = useAuth()
const [projectName, setProjectName] = useState('')
const [isSubmitting, setIsSubmitting] = useState(false)
const [error, setError] = useState(null)
const [validationError, setValidationError] = useState(null)
const handleSubmit = async () => {
if (!projectName.trim()) {
setError('Введите название проекта')
setValidationError('Введите название проекта')
return
}
setIsSubmitting(true)
setError(null)
setValidationError(null)
try {
const response = await authFetch(PROJECT_CREATE_API_URL, {
@@ -61,7 +63,9 @@ function AddProjectScreen({ onClose, onSuccess }) {
onSuccess()
} catch (err) {
console.error('Ошибка создания проекта:', err)
setError(err.message || 'Ошибка при создании проекта')
if (onError) {
onError(err.message || 'Ошибка при создании проекта')
}
} finally {
setIsSubmitting(false)
}
@@ -126,10 +130,10 @@ function AddProjectScreen({ onClose, onSuccess }) {
}
// Компонент экрана переноса проекта
function MoveProjectScreen({ project, allProjects, onClose, onSuccess }) {
function MoveProjectScreen({ project, allProjects, onClose, onSuccess, onError }) {
const [newProjectName, setNewProjectName] = useState('')
const [isSubmitting, setIsSubmitting] = useState(false)
const [error, setError] = useState(null)
const [validationError, setValidationError] = useState(null)
const handleProjectClick = (projectName) => {
setNewProjectName(projectName)
@@ -137,12 +141,12 @@ function MoveProjectScreen({ project, allProjects, onClose, onSuccess }) {
const handleSubmit = async () => {
if (!newProjectName.trim()) {
setError('Введите название проекта')
setValidationError('Введите название проекта')
return
}
setIsSubmitting(true)
setError(null)
setValidationError(null)
try {
const projectId = project.id ?? project.name
@@ -163,7 +167,9 @@ function MoveProjectScreen({ project, allProjects, onClose, onSuccess }) {
onSuccess()
} catch (err) {
console.error('Ошибка переноса проекта:', err)
setError(err.message || 'Ошибка при переносе проекта')
if (onError) {
onError(err.message || 'Ошибка при переносе проекта')
}
} finally {
setIsSubmitting(false)
}
@@ -210,8 +216,8 @@ function MoveProjectScreen({ project, allProjects, onClose, onSuccess }) {
placeholder="Введите новое название проекта"
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
/>
{error && (
<div className="mt-2 text-sm text-red-600">{error}</div>
{validationError && (
<div className="mt-2 text-sm text-red-600">{validationError}</div>
)}
</div>
@@ -375,6 +381,7 @@ function ProjectPriorityManager({ allProjectsData, currentWeekData, shouldLoad,
const [projectsLoading, setProjectsLoading] = useState(false)
const [projectsError, setProjectsError] = useState(null)
const [hasDataCache, setHasDataCache] = useState(false) // Отслеживаем наличие кеша
const [toastMessage, setToastMessage] = useState(null)
// Уведомляем родительский компонент об изменении состояния загрузки
useEffect(() => {
@@ -848,7 +855,7 @@ function ProjectPriorityManager({ allProjectsData, currentWeekData, shouldLoad,
fetchProjects()
} catch (error) {
console.error('Ошибка удаления проекта:', error)
setProjectsError(error.message || 'Ошибка удаления проекта')
setToastMessage({ text: error.message || 'Ошибка удаления проекта', type: 'error' })
}
}
@@ -876,18 +883,7 @@ function ProjectPriorityManager({ allProjectsData, currentWeekData, shouldLoad,
</button>
)}
{projectsError && (!maxPriority.length && !mediumPriority.length && !lowPriority.length) && (
<div className="mb-4 rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-700 shadow-sm flex-shrink-0">
<div className="font-semibold">Не удалось загрузить проекты</div>
<div className="mt-2 flex flex-wrap items-center justify-between gap-3">
<span className="text-red-600">{projectsError}</span>
<button
onClick={() => fetchProjects()}
className="rounded-md bg-red-600 px-3 py-1 text-white shadow hover:bg-red-700 transition"
>
Повторить
</button>
</div>
</div>
<LoadingError onRetry={fetchProjects} />
)}
{projectsLoading && (!maxPriority.length && !mediumPriority.length && !lowPriority.length) ? (
@@ -1013,6 +1009,9 @@ function ProjectPriorityManager({ allProjectsData, currentWeekData, shouldLoad,
setSelectedProject(null)
fetchProjects()
}}
onError={(errorMessage) => {
setToastMessage({ text: errorMessage, type: 'error' })
}}
/>
)}
@@ -1024,6 +1023,17 @@ function ProjectPriorityManager({ allProjectsData, currentWeekData, shouldLoad,
setShowAddScreen(false)
fetchProjects()
}}
onError={(errorMessage) => {
setToastMessage({ text: errorMessage, type: 'error' })
}}
/>
)}
{toastMessage && (
<Toast
message={toastMessage.text}
type={toastMessage.type}
onClose={() => setToastMessage(null)}
/>
)}
</div>