Унификация отображения ошибок: LoadingError для загрузки, Toast для действий
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 34s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 34s
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user