StickerAI-Front/src/screens/StickerPacks.tsx

359 lines
13 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import styles from './StickerPacks.module.css';
import { stickerService } from '../services/stickerService';
import { getCurrentUserId } from '../constants/user';
import NotificationModal from '../components/shared/NotificationModal';
import customAnalyticsService from '../services/customAnalyticsService';
import { getTranslation } from '../constants/translations';
// Функция для удаления дописанной части из названия стикерпака
const cleanPackTitle = (title: string): string => {
// Ищем часть "| by @username" и удаляем её
const parts = title.split(' | by @');
return parts[0]; // Возвращаем только первую часть (оригинальное название)
};
interface StickerPack {
name: string;
title: string;
thumbnail_url?: string | null;
share_url?: string;
stickers: Array<{
id?: number;
file_id: string;
emoji: string;
position: number;
file_url?: string | null;
}>;
}
const StickerPacks: React.FC = () => {
const navigate = useNavigate();
const [stickerPacks, setStickerPacks] = useState<StickerPack[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [selectedPack, setSelectedPack] = useState<StickerPack | null>(null);
const [packToDelete, setPackToDelete] = useState<string | null>(null);
const [isDeleting, setIsDeleting] = useState(false);
const [stickerToDelete, setStickerToDelete] = useState<string | null>(null);
const [isDeletingSticker, setIsDeletingSticker] = useState(false);
useEffect(() => {
const fetchStickerPacks = async () => {
try {
setLoading(true);
const stickerSets = await stickerService.getUserStickerPacks(getCurrentUserId().toString());
// Для каждого стикерпака получаем детальную информацию, обрабатывая ошибки отдельно
const packsDetails: StickerPack[] = [];
for (const stickerSet of stickerSets) {
try {
const packDetails = await stickerService.getStickerPack(stickerSet.set_name);
packsDetails.push(packDetails);
} catch (packError) {
console.warn(`Не удалось загрузить стикерпак ${stickerSet.set_name}:`, packError);
// Продолжаем загрузку других стикерпаков
}
}
setStickerPacks(packsDetails);
setError(null);
} catch (err) {
console.error('Ошибка при загрузке стикерпаков:', err);
setError(getTranslation('stickerpacks_error'));
} finally {
setLoading(false);
}
};
fetchStickerPacks();
}, []);
const handleCreateStickerPack = () => {
// Отслеживаем событие нажатия на кнопку "Создать стикерпак"
customAnalyticsService.trackEvent({
telegram_id: getCurrentUserId(),
event_category: 'sticker_packs',
event_name: 'create_sticker_pack_click',
unit: 'from_sticker_packs'
});
navigate('/create-sticker-pack');
};
const handleSelectPack = (pack: StickerPack) => {
setSelectedPack(pack);
};
const handleCloseDetails = () => {
setSelectedPack(null);
};
const handleDeletePack = (packName: string) => {
setPackToDelete(packName);
};
const handleConfirmDelete = async () => {
if (packToDelete) {
try {
setIsDeleting(true);
await stickerService.deleteStickerPack(packToDelete);
// Отслеживаем событие удаления стикерпака
customAnalyticsService.trackEvent({
telegram_id: getCurrentUserId(),
event_category: 'sticker_packs',
event_name: 'sticker_pack_deleted',
unit: packToDelete
});
setStickerPacks(prevPacks => prevPacks.filter(pack => pack.name !== packToDelete));
setSelectedPack(null);
setIsDeleting(false);
setPackToDelete(null);
} catch (err) {
console.error('Ошибка при удалении стикерпака:', err);
alert(getTranslation('stickerpacks_delete_pack_error'));
setIsDeleting(false);
}
}
};
const handleOpenInTelegram = () => {
if (selectedPack && selectedPack.share_url) {
window.open(selectedPack.share_url, '_blank');
}
};
const handleDeleteSticker = (fileId: string) => {
if (!fileId) {
alert(getTranslation('stickerpacks_sticker_id_error'));
return;
}
setStickerToDelete(fileId);
};
const handleConfirmDeleteSticker = async () => {
if (stickerToDelete) {
try {
setIsDeletingSticker(true);
await stickerService.deleteStickerByFileId(stickerToDelete);
// Обновляем список стикеров в выбранном стикерпаке
if (selectedPack) {
const updatedPack = await stickerService.getStickerPack(selectedPack.name);
setSelectedPack(updatedPack);
// Также обновляем стикерпак в общем списке
setStickerPacks(prevPacks =>
prevPacks.map(pack =>
pack.name === selectedPack.name ? updatedPack : pack
)
);
}
setIsDeletingSticker(false);
setStickerToDelete(null);
} catch (err) {
console.error('Ошибка при удалении стикера:', err);
alert(getTranslation('stickerpacks_delete_sticker_error'));
setIsDeletingSticker(false);
}
}
};
return (
<div className={styles.container}>
<div className={styles.header}>
<h1 className={styles.title}>
{getTranslation('stickerpacks_title')}
</h1>
<p className={styles.subtitle}>
{getTranslation('stickerpacks_subtitle')}
</p>
</div>
{loading && (
<div className={styles.placeholder}>
<p>{getTranslation('stickerpacks_loading')}</p>
</div>
)}
{error && (
<div className={styles.error}>
<p>{getTranslation('stickerpacks_error')}</p>
<button
className={styles.retryButton}
onClick={() => window.location.reload()}
>
{getTranslation('stickerpacks_retry_button')}
</button>
</div>
)}
{!loading && !error && stickerPacks.length === 0 && (
<div className={styles.placeholder}>
<span className={styles.placeholderIcon}>📦</span>
<p className={styles.placeholderText}>
{getTranslation('stickerpacks_empty')}
</p>
<button
className={styles.createButton}
onClick={handleCreateStickerPack}
>
{getTranslation('stickerpacks_create_button')}
</button>
</div>
)}
{!loading && !error && stickerPacks.length > 0 && !selectedPack && (
<>
<div className={styles.packsList}>
{stickerPacks.map((pack, index) => (
<div
key={index}
className={styles.packItem}
onClick={() => handleSelectPack(pack)}
>
<div className={styles.packHeader}>
<h3 className={styles.packTitle}>
{getTranslation('stickerpacks_pack_title_prefix')}: <span className={styles.packTitleName}>{cleanPackTitle(pack.title)}</span>
</h3>
<p className={styles.packStats}>
{getTranslation('stickerpacks_pack_stats', pack.stickers ? pack.stickers.length : 0)}
</p>
</div>
<div className={styles.packStickers}>
{pack.stickers && pack.stickers.map((sticker, idx) => (
<div key={idx} className={styles.stickerPreview}>
{sticker.file_url ? (
<img
src={sticker.file_url}
alt={getTranslation('stickerpacks_sticker_alt', idx + 1)}
className={styles.stickerImage}
/>
) : (
<div className={styles.stickerPlaceholder}>🖼</div>
)}
</div>
))}
</div>
{/* Кнопка удаления стикерпака */}
<button
className={styles.deleteButton}
onClick={(e) => {
e.stopPropagation(); // Предотвращаем всплытие события
handleDeletePack(pack.name);
}}
>
{getTranslation('stickerpacks_delete_button')}
</button>
</div>
))}
</div>
<button
className={styles.createButtonFixed}
onClick={handleCreateStickerPack}
>
{getTranslation('stickerpacks_create_button')}
</button>
</>
)}
{selectedPack && (
<div className={styles.packDetails}>
<div className={styles.detailsHeader}>
<button
className={styles.backButton}
onClick={handleCloseDetails}
>
{getTranslation('stickerpacks_back_button')}
</button>
<h2 className={styles.detailsTitle}>{cleanPackTitle(selectedPack.title)}</h2>
</div>
{/* Перемещенный блок с кнопками */}
<div className={styles.detailsActions}>
<button
className={styles.addStickerButton}
onClick={() => navigate(`/add-sticker/${selectedPack.name}`)}
>
{getTranslation('stickerpacks_add_sticker_button')}
</button>
<button
className={styles.openInTelegramButton}
onClick={handleOpenInTelegram}
>
{getTranslation('stickerpacks_open_telegram_button')}
</button>
</div>
<div className={styles.stickersList}>
{selectedPack.stickers && selectedPack.stickers.map((sticker, index) => (
<div key={index} className={styles.stickerItem}>
{sticker.file_url ? (
<img
src={sticker.file_url}
alt={getTranslation('stickerpacks_sticker_alt', index + 1)}
className={styles.stickerImage}
/>
) : (
<div className={styles.stickerImagePlaceholder}>🖼</div>
)}
<div className={styles.stickerEmoji}>{sticker.emoji}</div>
{/* Кнопка удаления стикера */}
<button
className={styles.deleteStickerButton}
onClick={(e) => {
e.stopPropagation(); // Предотвращаем всплытие события
handleDeleteSticker(sticker.file_id);
}}
>
</button>
</div>
))}
</div>
</div>
)}
{/* Модальное окно подтверждения удаления стикерпака */}
<NotificationModal
isVisible={!!packToDelete}
title={getTranslation('stickerpacks_delete_pack_title')}
message={getTranslation('stickerpacks_delete_pack_message')}
isLoading={isDeleting}
showGalleryButton={true}
galleryButtonText={getTranslation('stickerpacks_cancel_button')}
continueButtonText={getTranslation('stickerpacks_confirm_delete_button')}
onContinueClick={handleConfirmDelete}
onGalleryClick={() => setPackToDelete(null)}
isPrimaryGalleryButton={false}
/>
{/* Модальное окно подтверждения удаления стикера */}
<NotificationModal
isVisible={!!stickerToDelete}
title={getTranslation('stickerpacks_delete_sticker_title')}
message={getTranslation('stickerpacks_delete_sticker_message')}
isLoading={isDeletingSticker}
showGalleryButton={true}
galleryButtonText={getTranslation('stickerpacks_cancel_button')}
continueButtonText={getTranslation('stickerpacks_confirm_delete_button')}
onContinueClick={handleConfirmDeleteSticker}
onGalleryClick={() => setStickerToDelete(null)}
isPrimaryGalleryButton={false}
/>
</div>
);
};
export default StickerPacks;