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