доразметка событий на гпт4.1

This commit is contained in:
kazachilo 2025-04-28 16:07:07 +03:00
parent 181d89e733
commit 3c925708ab
8 changed files with 93 additions and 19 deletions

View File

@ -77,7 +77,7 @@ const AppContent: React.FC = () => {
else if (hasSeenOnboarding && !hasAcceptedTerms && !location.pathname.includes('/onboarding/terms')) {
navigate('/onboarding/terms');
}
}, [navigate, location.pathname]);
}, []);
// Отслеживаем изменение маршрута для аналитики
useEffect(() => {

View File

@ -46,6 +46,7 @@ const BlockRenderer: React.FC<BlockRendererProps> = ({ block, onAction, extraPro
);
return () => URL.revokeObjectURL(tempUrl);
}}
onAction={onAction}
/>;
case 'divider':
return <DividerBlock block={block as DividerBlockType} />;

View File

@ -6,9 +6,10 @@ import { getTranslation } from '../../constants/translations';
interface UploadPhotoBlockProps {
onPhotoSelect?: (file: File) => void;
previewUrl?: string;
onAction?: (actionType: string, actionValue: string, blockId?: string, buttonId?: string) => void;
}
const UploadPhotoBlock: React.FC<UploadPhotoBlockProps> = ({ onPhotoSelect, previewUrl }) => {
const UploadPhotoBlock: React.FC<UploadPhotoBlockProps> = ({ onPhotoSelect, previewUrl, onAction }) => {
const navigate = useNavigate();
const fileInputRef = useRef<HTMLInputElement>(null);
const [isDragging, setIsDragging] = useState(false);
@ -19,6 +20,11 @@ const UploadPhotoBlock: React.FC<UploadPhotoBlockProps> = ({ onPhotoSelect, prev
localStorage.removeItem('stickerPreviewUrl');
localStorage.removeItem('stickerImageData');
// Отправляем событие аналитики, если передан onAction
if (typeof onAction === 'function') {
onAction('uploadPhoto', '', undefined, undefined);
}
onPhotoSelect?.(file);
navigate('/crop-photo', { state: { file } });
}

View File

@ -8,6 +8,9 @@ import { getCurrentUserId } from '../../constants/user';
interface GenerationButtonProps {
onStartGeneration: () => void;
isGenerating: boolean;
presetName?: string;
memeId?: string;
emotionType?: string;
}
/**
@ -15,7 +18,10 @@ interface GenerationButtonProps {
*/
const GenerationButton: React.FC<GenerationButtonProps> = ({
onStartGeneration,
isGenerating
isGenerating,
presetName,
memeId,
emotionType
}) => {
// Находим блок кнопки генерации в конфигурации
const generateButton = homeScreenConfig.homeScreen.blocks.find(block => block.type === 'generateButton');
@ -28,11 +34,20 @@ const GenerationButton: React.FC<GenerationButtonProps> = ({
const handleAction = (actionType: string, actionValue: string) => {
if (actionType === 'function' && actionValue === 'startGeneration' && !isGenerating) {
// Отслеживаем событие нажатия на кнопку генерации
// Аналитика: пресет или мем
if (emotionType === 'memes' && memeId) {
customAnalyticsService.trackEvent({
telegram_id: getCurrentUserId(),
event_category: 'generation',
event_name: 'generate_button_click'
event_category: 'generation_meme',
event_name: memeId
});
} else if (presetName) {
customAnalyticsService.trackEvent({
telegram_id: getCurrentUserId(),
event_category: 'generation_preset',
event_name: presetName
});
}
onStartGeneration();
}

View File

@ -37,6 +37,17 @@ const PresetSelector: React.FC<PresetSelectorProps> = ({
// Обработчик выбора пресета
const handleAction = (actionType: string, actionValue: string, blockId?: string, buttonId?: string) => {
if (actionType === 'selectPreset') {
// Отправляем событие выбора пресета
import('../../services/customAnalyticsService').then(({ default: customAnalyticsService }) => {
import('../../constants/user').then(({ getCurrentUserId }) => {
customAnalyticsService.trackEvent({
telegram_id: getCurrentUserId(),
event_category: 'generation',
event_name: 'preset_select',
unit: actionValue
});
});
});
onPresetSelect(actionValue, buttonId);
} else if (actionType === 'function' && actionValue === 'toggleInput') {
onToggleInput();

View File

@ -1,10 +1,12 @@
import React, { useCallback } from 'react';
import React, { useCallback, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import TokenPacksModal from './TokenPacksModal';
import { paymentService } from '../../services/paymentService';
import { tokenPacks } from '../../constants/tokenPacks';
import { useBalance } from '../../contexts/BalanceContext';
import { updateBalanceWithRetries } from '../../utils/balanceUtils';
import customAnalyticsService from '../../services/customAnalyticsService';
import { getCurrentUserId } from '../../constants/user';
interface TokenPacksModalContainerProps {
isVisible: boolean;
@ -24,6 +26,7 @@ const TokenPacksModalContainer: React.FC<TokenPacksModalContainerProps> = ({
}) => {
const navigate = useNavigate();
const { updateBalance } = useBalance();
const attemptedRef = useRef(false);
/**
* Обработчик покупки пакета токенов
@ -32,6 +35,14 @@ const TokenPacksModalContainer: React.FC<TokenPacksModalContainerProps> = ({
const pack = tokenPacks.find(p => p.id === packId);
if (!pack) return;
// Аналитика: попытка оплаты
customAnalyticsService.trackEvent({
telegram_id: getCurrentUserId(),
event_category: 'payment',
event_name: 'purchase_attempt'
});
attemptedRef.current = true;
onClose();
paymentService.showBuyTokensPopup(pack, async (userData) => {
@ -45,18 +56,34 @@ const TokenPacksModalContainer: React.FC<TokenPacksModalContainerProps> = ({
});
}, [onClose, updateBalance, onSuccess]);
/**
* Обработчик отмены/закрытия модалки
*/
const handleClose = useCallback(() => {
if (!attemptedRef.current) {
// Аналитика: отмена оплаты
customAnalyticsService.trackEvent({
telegram_id: getCurrentUserId(),
event_category: 'payment',
event_name: 'purchase_cancel'
});
}
onClose();
attemptedRef.current = false;
}, [onClose]);
/**
* Обработчик нажатия на кнопку "Показать все пакеты"
*/
const handleShowAllPacks = useCallback(() => {
onClose();
handleClose();
navigate('/profile');
}, [onClose, navigate]);
}, [handleClose, navigate]);
return (
<TokenPacksModal
isVisible={isVisible}
onClose={onClose}
onClose={handleClose}
onShowAllPacks={handleShowAllPacks}
missingTokens={missingTokens}
onBuyPack={handleBuyPack}

View File

@ -265,6 +265,17 @@ const CropPhoto: React.FC = () => {
// Убираем префикс data:image/jpeg;base64, оставляем только данные
const imageData = previewUrl.split(',')[1];
// Отправляем событие применения обрезки
import('../services/customAnalyticsService').then(({ default: customAnalyticsService }) => {
import('../constants/user').then(({ getCurrentUserId }) => {
customAnalyticsService.trackEvent({
telegram_id: getCurrentUserId(),
event_category: 'photo',
event_name: 'crop_photo_apply'
});
});
});
// Сохраняем данные в localStorage для навигации между страницами
localStorage.setItem('stickerPreviewUrl', previewUrl);
localStorage.setItem('stickerImageData', imageData);

View File

@ -252,6 +252,9 @@ const Home: React.FC = () => {
<GenerationButton
onStartGeneration={startGeneration}
isGenerating={isGenerating}
presetName={selectedPresetId}
memeId={selectedMemeId}
emotionType={selectedEmotionType}
/>
</div>
</div>