import React, { useEffect, useState, useRef } from 'react'; import styles from './Gallery.module.css'; import apiService from '../services/api'; import { GeneratedImage, PendingTask } from '../types/api'; import ImageViewer from '../components/shared/ImageViewer'; const GalleryScreen: React.FC = () => { const [images, setImages] = useState([]); const [pendingTasks, setPendingTasks] = useState([]); const [loading, setLoading] = useState(true); const [loadingPendingTasks, setLoadingPendingTasks] = useState(true); const [error, setError] = useState(null); const [selectedImage, setSelectedImage] = useState(null); const [refreshing, setRefreshing] = useState(false); const [pullDistance, setPullDistance] = useState(0); const containerRef = useRef(null); const startY = useRef(null); const threshold = 80; // Порог для активации обновления // Функция для расчета времени ожидания const getEstimatedWaitTime = (queuePosition: number | null): string => { if (queuePosition === null) return 'Генерация началась'; const seconds = apiService.calculateEstimatedWaitTime(queuePosition); if (seconds < 60) return `${seconds} сек`; return `${Math.floor(seconds / 60)} мин ${seconds % 60} сек`; }; // Функция для обновления всех данных const refreshAll = async () => { setRefreshing(true); try { // Загружаем изображения const fetchedImages = await apiService.getGeneratedImages(); setImages(fetchedImages); // Загружаем задачи в очереди const fetchedPendingTasks = await apiService.getUserPendingTasks(); setPendingTasks(fetchedPendingTasks); setError(null); } catch (err) { setError('Не удалось обновить данные'); console.error(err); } finally { // Задержка для лучшего UX, чтобы пользователь видел, что происходит обновление setTimeout(() => { setRefreshing(false); }, 500); } }; // Обработчики для pull-to-refresh const handleTouchStart = (e: React.TouchEvent) => { if (containerRef.current && containerRef.current.scrollTop === 0) { startY.current = e.touches[0].clientY; } }; const handleTouchMove = (e: React.TouchEvent) => { if (!startY.current) return; // Только если контейнер в верхней позиции if (containerRef.current && containerRef.current.scrollTop === 0) { const currentY = e.touches[0].clientY; const diff = currentY - startY.current; // Применяем сопротивление - чем дальше тянем, тем сложнее if (diff > 0) { const resistance = 0.4; const distance = Math.min(diff * resistance, threshold * 1.5); setPullDistance(distance); } } }; const handleTouchEnd = async () => { // Если достигли порога, запускаем обновление if (pullDistance >= threshold) { setRefreshing(true); // Сбрасываем расстояние вытягивания setPullDistance(0); // Обновляем данные await refreshAll(); } else { // Анимированно возвращаем к исходному состоянию setPullDistance(0); } startY.current = null; }; // Загрузка данных при монтировании компонента useEffect(() => { const fetchData = async () => { try { setLoading(true); setLoadingPendingTasks(true); // Загружаем изображения const fetchedImages = await apiService.getGeneratedImages(); setImages(fetchedImages); // Загружаем задачи в очереди const fetchedPendingTasks = await apiService.getUserPendingTasks(); setPendingTasks(fetchedPendingTasks); setError(null); } catch (err) { setError('Не удалось загрузить данные'); console.error(err); } finally { setLoading(false); setLoadingPendingTasks(false); } }; fetchData(); }, []); // Отслеживание задач в очереди useEffect(() => { // Если в очереди нет задач, не запускаем интервал if (pendingTasks.length === 0) return; console.log('Запускаем отслеживание задач в очереди:', pendingTasks); // Запускаем интервал только если есть задачи в очереди const intervalId = setInterval(async () => { try { // Сохраняем предыдущий список задач для сравнения const previousTasks = [...pendingTasks]; // Получаем обновленный список задач const fetchedPendingTasks = await apiService.getUserPendingTasks(); console.log('Обновленные задачи в очереди:', fetchedPendingTasks); // Обновляем список задач setPendingTasks(fetchedPendingTasks); // Проверяем, исчезла ли задача из очереди if (previousTasks.length > fetchedPendingTasks.length) { console.log('Задача исчезла из очереди, обновляем галерею'); const fetchedImages = await apiService.getGeneratedImages(); setImages(fetchedImages); } // Если все задачи завершены, очищаем интервал if (fetchedPendingTasks.length === 0) { console.log('Все задачи завершены, останавливаем отслеживание'); clearInterval(intervalId); } } catch (err) { console.error('Ошибка при обновлении статуса задач:', err); } }, 15000); // Обновляем каждые 15 секунд // Очищаем интервал при размонтировании компонента return () => clearInterval(intervalId); }, [pendingTasks.length]); // Зависимость от количества задач return (
{refreshing && Обновление...}

Галерея стикеров

{loading && (
Загрузка изображений...
)} {error && (
{error}
)} {!loading && !error && images.length === 0 && pendingTasks.length === 0 && (
У вас пока нет сгенерированных стикеров
)} {!loading && !loadingPendingTasks && pendingTasks.length > 0 && (

В процессе генерации

{pendingTasks.map((task) => (

{task.status === 'PENDING' ? `В очереди: ${task.queue_position}` : 'Генерация...'}

Осталось: {getEstimatedWaitTime(task.queue_position)}

))}
)} {!loading && !error && images.length > 0 && (
{images.map((image, index) => (
image.url && setSelectedImage(image.url)} > {`Стикер
))}
)}
{/* Полноэкранный просмотр */} {selectedImage && ( setSelectedImage(null)} /> )}
); }; export default GalleryScreen;