import React, { useState, useEffect, useCallback } from 'react' import { useAuth } from './auth/AuthContext' import TaskDetail from './TaskDetail' import LoadingError from './LoadingError' import Toast from './Toast' import './WishlistDetail.css' import './TaskList.css' const API_URL = '/api/wishlist' function WishlistDetail({ wishlistId, onNavigate, onRefresh }) { const { authFetch } = useAuth() const [wishlistItem, setWishlistItem] = useState(null) const [loading, setLoading] = useState(true) const [loadingWishlist, setLoadingWishlist] = useState(true) const [error, setError] = useState(null) const [isCompleting, setIsCompleting] = useState(false) const [isDeleting, setIsDeleting] = useState(false) const [toastMessage, setToastMessage] = useState(null) const [selectedTaskForDetail, setSelectedTaskForDetail] = useState(null) const fetchWishlistDetail = useCallback(async () => { try { setLoadingWishlist(true) setLoading(true) setError(null) const response = await authFetch(`${API_URL}/${wishlistId}`) if (!response.ok) { throw new Error('Ошибка загрузки желания') } const data = await response.json() setWishlistItem(data) } catch (err) { setError(err.message) console.error('Error fetching wishlist detail:', err) } finally { setLoading(false) setLoadingWishlist(false) } }, [wishlistId, authFetch]) useEffect(() => { if (wishlistId) { fetchWishlistDetail() } else { setWishlistItem(null) setLoading(true) setLoadingWishlist(true) setError(null) } }, [wishlistId, fetchWishlistDetail]) const handleEdit = () => { onNavigate?.('wishlist-form', { wishlistId: wishlistId }) } const handleComplete = async () => { if (!wishlistItem || !wishlistItem.unlocked) return setIsCompleting(true) try { const response = await authFetch(`${API_URL}/${wishlistId}/complete`, { method: 'POST', }) if (!response.ok) { throw new Error('Ошибка при завершении') } if (onRefresh) { onRefresh() } if (onNavigate) { onNavigate('wishlist') } } catch (err) { console.error('Error completing wishlist:', err) setToastMessage({ text: err.message || 'Ошибка при завершении', type: 'error' }) } finally { setIsCompleting(false) } } const handleUncomplete = async () => { if (!wishlistItem || !wishlistItem.completed) return setIsCompleting(true) try { const response = await authFetch(`${API_URL}/${wishlistId}/uncomplete`, { method: 'POST', }) if (!response.ok) { throw new Error('Ошибка при отмене завершения') } if (onRefresh) { onRefresh() } fetchWishlistDetail() } catch (err) { console.error('Error uncompleting wishlist:', err) setToastMessage({ text: err.message || 'Ошибка при отмене завершения', type: 'error' }) } finally { setIsCompleting(false) } } const handleDelete = async () => { if (!wishlistItem) return if (!window.confirm('Вы уверены, что хотите удалить это желание?')) { return } setIsDeleting(true) try { const response = await authFetch(`${API_URL}/${wishlistId}`, { method: 'DELETE', }) if (!response.ok) { throw new Error('Ошибка при удалении') } if (onRefresh) { onRefresh() } if (onNavigate) { onNavigate('wishlist') } } catch (err) { console.error('Error deleting wishlist:', err) setToastMessage({ text: err.message || 'Ошибка при удалении', type: 'error' }) } finally { setIsDeleting(false) } } const handleCreateTask = () => { if (!wishlistItem || !wishlistItem.unlocked || wishlistItem.completed) return onNavigate?.('task-form', { wishlistId: wishlistId }) } const handleTaskCheckmarkClick = (e) => { e.stopPropagation() if (wishlistItem?.linked_task) { setSelectedTaskForDetail(wishlistItem.linked_task.id) } } const handleTaskItemClick = () => { if (wishlistItem?.linked_task) { onNavigate?.('task-form', { taskId: wishlistItem.linked_task.id }) } } const handleCloseDetail = () => { setSelectedTaskForDetail(null) } const handleTaskCompleted = () => { setToastMessage({ text: 'Задача выполнена', type: 'success' }) // После выполнения задачи желание тоже завершается, перенаправляем на список if (onRefresh) { onRefresh() } if (onNavigate) { onNavigate('wishlist') } } const handleUnlinkTask = async (e) => { e.stopPropagation() if (!wishlistItem?.linked_task) return try { // Загружаем текущую задачу const taskResponse = await authFetch(`/api/tasks/${wishlistItem.linked_task.id}`) if (!taskResponse.ok) { throw new Error('Ошибка при загрузке задачи') } const taskData = await taskResponse.json() const task = taskData.task // Формируем payload для обновления задачи const payload = { name: task.name, reward_message: task.reward_message || null, progression_base: task.progression_base || null, repetition_period: task.repetition_period || null, repetition_date: task.repetition_date || null, wishlist_id: null, // Отвязываем от желания rewards: (task.rewards || []).map(r => ({ position: r.position, project_name: r.project_name, value: r.value, use_progression: r.use_progression || false })), subtasks: (task.subtasks || []).map(st => ({ id: st.id, name: st.name || null, reward_message: st.reward_message || null, rewards: (st.rewards || []).map(r => ({ position: r.position, project_name: r.project_name, value: r.value, use_progression: r.use_progression || false })) })) } // Обновляем задачу, отвязывая от желания const updateResponse = await authFetch(`/api/tasks/${wishlistItem.linked_task.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(payload), }) if (!updateResponse.ok) { const errorData = await updateResponse.json().catch(() => ({})) throw new Error(errorData.message || errorData.error || 'Ошибка при отвязке задачи') } setToastMessage({ text: 'Задача отвязана от желания', type: 'success' }) // Обновляем данные желания fetchWishlistDetail() if (onRefresh) { onRefresh() } } catch (err) { console.error('Error unlinking task:', err) setToastMessage({ text: err.message || 'Ошибка при отвязке задачи', type: 'error' }) } } const formatPrice = (price) => { return new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB', minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(price) } const renderUnlockConditions = () => { if (!wishlistItem || !wishlistItem.unlock_conditions || wishlistItem.unlock_conditions.length === 0) { return null } return (