обавлена серия запросов на обновление баланса после генерации
This commit is contained in:
parent
83f4ccc7d0
commit
861670e481
@ -4,6 +4,7 @@ import Layout from './components/layout/Layout';
|
||||
import Home from './screens/Home';
|
||||
import { initializeUserId } from './constants/user';
|
||||
import { trackScreenView } from './services/analyticsService';
|
||||
import { BalanceProvider } from './contexts/BalanceContext';
|
||||
|
||||
// Ленивая загрузка компонентов
|
||||
const OnboardingWelcome = lazy(() => import('./screens/onboarding/OnboardingWelcome'));
|
||||
@ -147,7 +148,9 @@ const AppContent: React.FC = () => {
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<AppContent />
|
||||
<BalanceProvider>
|
||||
<AppContent />
|
||||
</BalanceProvider>
|
||||
</BrowserRouter>
|
||||
);
|
||||
};
|
||||
|
||||
@ -7,15 +7,16 @@ import TokenPacksModal from '../tokens/TokenPacksModal';
|
||||
import { paymentService } from '../../services/paymentService';
|
||||
import { tokenPacks } from '../../constants/tokenPacks';
|
||||
import NotificationModal from '../shared/NotificationModal';
|
||||
import { useBalance } from '../../contexts/BalanceContext';
|
||||
import styles from './Header.module.css';
|
||||
|
||||
const Header: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { balance, updateBalance } = useBalance(); // Используем контекст баланса
|
||||
const [user, setUser] = useState({
|
||||
telegramId: 0,
|
||||
username: '',
|
||||
avatarUrl: '',
|
||||
balance: 0
|
||||
avatarUrl: ''
|
||||
});
|
||||
const [showTokensModal, setShowTokensModal] = useState(false);
|
||||
const [lastPurchasedPack, setLastPurchasedPack] = useState<any>(null);
|
||||
@ -27,34 +28,21 @@ const Header: React.FC = () => {
|
||||
// Получаем информацию о пользователе
|
||||
const userInfo = getUserInfo();
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
// Получаем баланс пользователя
|
||||
const balance = await apiService.getBalance(getCurrentUserId());
|
||||
|
||||
// Если есть данные из Telegram, обновляем состояние
|
||||
if (isTelegramWebAppAvailable()) {
|
||||
setUser({
|
||||
telegramId: userInfo.id,
|
||||
username: userInfo.first_name + (userInfo.last_name ? ` ${userInfo.last_name}` : ''),
|
||||
avatarUrl: userInfo.photo_url || '/ava.jpg', // Используем фото из Telegram или дефолтное
|
||||
balance: balance
|
||||
});
|
||||
} else {
|
||||
// Для локальной разработки
|
||||
setUser({
|
||||
telegramId: 12345678,
|
||||
username: "TestUser",
|
||||
avatarUrl: "/ava.jpg",
|
||||
balance: balance
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching user data:', error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchData();
|
||||
// Если есть данные из Telegram, обновляем состояние
|
||||
if (isTelegramWebAppAvailable()) {
|
||||
setUser({
|
||||
telegramId: userInfo.id,
|
||||
username: userInfo.first_name + (userInfo.last_name ? ` ${userInfo.last_name}` : ''),
|
||||
avatarUrl: userInfo.photo_url || '/ava.jpg' // Используем фото из Telegram или дефолтное
|
||||
});
|
||||
} else {
|
||||
// Для локальной разработки
|
||||
setUser({
|
||||
telegramId: 12345678,
|
||||
username: "TestUser",
|
||||
avatarUrl: "/ava.jpg"
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@ -89,7 +77,7 @@ const Header: React.FC = () => {
|
||||
<img src={images.tokenIcon} alt="Токены" className={styles.tokenImage} />
|
||||
</span>
|
||||
<span className={styles.balanceValue}>
|
||||
{user.balance}
|
||||
{balance}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
@ -110,13 +98,8 @@ const Header: React.FC = () => {
|
||||
|
||||
paymentService.showBuyTokensPopup(pack, async (userData) => {
|
||||
if (userData) {
|
||||
// Обновляем данные на основе полученной информации
|
||||
if (userData.balance !== undefined) {
|
||||
setUser(prev => ({
|
||||
...prev,
|
||||
balance: userData.balance
|
||||
}));
|
||||
}
|
||||
// Обновляем баланс через контекст
|
||||
updateBalance();
|
||||
|
||||
// Показываем модальное окно с информацией об успешной оплате
|
||||
setNotificationTitle('Оплата успешна!');
|
||||
@ -128,11 +111,8 @@ const Header: React.FC = () => {
|
||||
// Получаем баланс пользователя
|
||||
const balance = await apiService.getBalance(getCurrentUserId());
|
||||
|
||||
// Обновляем баланс пользователя
|
||||
setUser(prev => ({
|
||||
...prev,
|
||||
balance: balance
|
||||
}));
|
||||
// Обновляем баланс через контекст
|
||||
updateBalance();
|
||||
|
||||
// Показываем модальное окно с информацией об успешной оплате
|
||||
setNotificationTitle('Оплата успешна!');
|
||||
|
||||
56
src/contexts/BalanceContext.tsx
Normal file
56
src/contexts/BalanceContext.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import React, { createContext, useState, useEffect, useContext, useCallback } from 'react';
|
||||
import apiService from '../services/api';
|
||||
import { getCurrentUserId } from '../constants/user';
|
||||
|
||||
interface BalanceContextType {
|
||||
balance: number;
|
||||
updateBalance: () => Promise<void>;
|
||||
}
|
||||
|
||||
const BalanceContext = createContext<BalanceContextType | undefined>(undefined);
|
||||
|
||||
export const BalanceProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const [balance, setBalance] = useState<number>(0);
|
||||
|
||||
// Функция для обновления баланса
|
||||
const updateBalance = useCallback(async () => {
|
||||
try {
|
||||
console.log('Обновление баланса...');
|
||||
const newBalance = await apiService.getBalance(getCurrentUserId());
|
||||
console.log(`Текущий баланс: ${newBalance}`);
|
||||
setBalance(newBalance);
|
||||
} catch (error) {
|
||||
console.error('Ошибка при обновлении баланса:', error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Инициализация баланса при монтировании компонента
|
||||
useEffect(() => {
|
||||
updateBalance();
|
||||
}, [updateBalance]);
|
||||
|
||||
// Настройка периодического обновления баланса каждые 45 секунд
|
||||
useEffect(() => {
|
||||
const intervalId = setInterval(() => {
|
||||
updateBalance();
|
||||
}, 45000); // 45 секунд
|
||||
|
||||
// Очистка интервала при размонтировании компонента
|
||||
return () => clearInterval(intervalId);
|
||||
}, [updateBalance]);
|
||||
|
||||
return (
|
||||
<BalanceContext.Provider value={{ balance, updateBalance }}>
|
||||
{children}
|
||||
</BalanceContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
// Хук для использования контекста баланса
|
||||
export const useBalance = (): BalanceContextType => {
|
||||
const context = useContext(BalanceContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useBalance must be used within a BalanceProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@ -11,6 +11,7 @@ import TokenPacksModal from '../components/tokens/TokenPacksModal';
|
||||
import { paymentService } from '../services/paymentService';
|
||||
import { tokenPacks } from '../constants/tokenPacks';
|
||||
import { getCurrentUserId } from '../constants/user';
|
||||
import { useBalance } from '../contexts/BalanceContext';
|
||||
|
||||
// Интерфейс для хранения данных о последней генерации
|
||||
interface LastGenerationData {
|
||||
@ -23,6 +24,7 @@ interface LastGenerationData {
|
||||
const Home: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const feedbackHandlerRef = useRef<FeedbackHandlerRef>(null);
|
||||
const { updateBalance } = useBalance(); // Используем контекст баланса
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [previewUrl, setPreviewUrl] = useState<string | undefined>(() => {
|
||||
@ -191,6 +193,30 @@ const Home: React.FC = () => {
|
||||
customPrompt: userPrompt
|
||||
});
|
||||
|
||||
// Функция для выполнения серии запросов на обновление баланса
|
||||
const updateBalanceWithRetries = () => {
|
||||
// Функция для выполнения одной попытки обновления баланса
|
||||
const fetchBalance = async (attempt: number) => {
|
||||
try {
|
||||
console.log(`Попытка ${attempt}/5 обновления баланса после генерации...`);
|
||||
await updateBalance();
|
||||
} catch (error) {
|
||||
console.error(`Ошибка при обновлении баланса (попытка ${attempt}/5):`, error);
|
||||
}
|
||||
};
|
||||
|
||||
// Выполняем первую попытку сразу
|
||||
fetchBalance(1);
|
||||
|
||||
// Выполняем остальные попытки с интервалом в 1 секунду
|
||||
for (let i = 2; i <= 5; i++) {
|
||||
setTimeout(() => fetchBalance(i), (i - 1) * 1000);
|
||||
}
|
||||
};
|
||||
|
||||
// Запускаем серию запросов на обновление баланса
|
||||
updateBalanceWithRetries();
|
||||
|
||||
// Проверяем, была ли ошибка перевода
|
||||
if (response.translationFailed) {
|
||||
setNotificationTitle('Недопустимый промпт');
|
||||
@ -385,7 +411,30 @@ const Home: React.FC = () => {
|
||||
|
||||
paymentService.showBuyTokensPopup(pack, async (userData) => {
|
||||
if (userData) {
|
||||
// Обновляем данные на основе полученной информации
|
||||
// Функция для выполнения серии запросов на обновление баланса
|
||||
const updateBalanceWithRetries = () => {
|
||||
// Функция для выполнения одной попытки обновления баланса
|
||||
const fetchBalance = async (attempt: number) => {
|
||||
try {
|
||||
console.log(`Попытка ${attempt}/5 обновления баланса после пополнения...`);
|
||||
await updateBalance();
|
||||
} catch (error) {
|
||||
console.error(`Ошибка при обновлении баланса (попытка ${attempt}/5):`, error);
|
||||
}
|
||||
};
|
||||
|
||||
// Выполняем первую попытку сразу
|
||||
fetchBalance(1);
|
||||
|
||||
// Выполняем остальные попытки с интервалом в 1 секунду
|
||||
for (let i = 2; i <= 5; i++) {
|
||||
setTimeout(() => fetchBalance(i), (i - 1) * 1000);
|
||||
}
|
||||
};
|
||||
|
||||
// Запускаем серию запросов на обновление баланса
|
||||
updateBalanceWithRetries();
|
||||
|
||||
// Показываем модальное окно с информацией об успешной оплате
|
||||
setNotificationTitle('Оплата успешна!');
|
||||
setNotificationMessage(`Вы успешно приобрели ${pack.tokens + pack.bonusTokens} токенов.`);
|
||||
@ -400,6 +449,30 @@ const Home: React.FC = () => {
|
||||
// Получаем баланс пользователя
|
||||
const balance = await apiService.getBalance(getCurrentUserId());
|
||||
|
||||
// Функция для выполнения серии запросов на обновление баланса
|
||||
const updateBalanceWithRetries = () => {
|
||||
// Функция для выполнения одной попытки обновления баланса
|
||||
const fetchBalance = async (attempt: number) => {
|
||||
try {
|
||||
console.log(`Попытка ${attempt}/5 обновления баланса после пополнения...`);
|
||||
await updateBalance();
|
||||
} catch (error) {
|
||||
console.error(`Ошибка при обновлении баланса (попытка ${attempt}/5):`, error);
|
||||
}
|
||||
};
|
||||
|
||||
// Выполняем первую попытку сразу
|
||||
fetchBalance(1);
|
||||
|
||||
// Выполняем остальные попытки с интервалом в 1 секунду
|
||||
for (let i = 2; i <= 5; i++) {
|
||||
setTimeout(() => fetchBalance(i), (i - 1) * 1000);
|
||||
}
|
||||
};
|
||||
|
||||
// Запускаем серию запросов на обновление баланса
|
||||
updateBalanceWithRetries();
|
||||
|
||||
// Показываем модальное окно с информацией об успешной оплате
|
||||
setNotificationTitle('Оплата успешна!');
|
||||
setNotificationMessage(`Вы успешно приобрели ${pack.tokens + pack.bonusTokens} токенов. Ваш текущий баланс: ${balance} токенов.`);
|
||||
|
||||
@ -24,25 +24,32 @@ export const paymentService = {
|
||||
// Открываем встроенный платеж Telegram без предварительного подтверждения
|
||||
webApp.openInvoice(invoiceLink, async (status: 'paid' | 'cancelled' | 'failed' | 'pending') => {
|
||||
if (status === 'paid') {
|
||||
// Добавляем задержку перед запросом данных пользователя,
|
||||
// чтобы дать серверу время на обработку транзакции и обновление баланса
|
||||
setTimeout(async () => {
|
||||
// Функция для выполнения одной попытки получения данных пользователя
|
||||
const fetchUserData = async (attempt: number) => {
|
||||
try {
|
||||
// Получаем обновленную информацию о пользователе
|
||||
console.log(`Попытка ${attempt}/5 получения данных пользователя...`);
|
||||
const userData = await apiService.getUserInfo(userId);
|
||||
|
||||
if (onSuccess) {
|
||||
onSuccess(userData);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка при получении данных пользователя:', error);
|
||||
console.error(`Ошибка при получении данных пользователя (попытка ${attempt}/5):`, error);
|
||||
|
||||
// Даже если не удалось получить данные, вызываем onSuccess
|
||||
if (onSuccess) {
|
||||
// Если это последняя попытка и произошла ошибка, вызываем onSuccess без параметров
|
||||
if (attempt === 5 && onSuccess) {
|
||||
onSuccess();
|
||||
}
|
||||
}
|
||||
}, 1000); // Задержка в 1 секунду
|
||||
};
|
||||
|
||||
// Выполняем первую попытку сразу
|
||||
fetchUserData(1);
|
||||
|
||||
// Выполняем остальные попытки с интервалом в 1 секунду
|
||||
for (let i = 2; i <= 5; i++) {
|
||||
setTimeout(() => fetchUserData(i), (i - 1) * 1000);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user