лучшения стабильности и исправления: 1) тключение вертикальных свайпов для стабильности WebApp в Telegram; 2) бновление механизма получения ID пользователя; 3) справление проксирования изображений; 4) бновление типов для Telegram WebApp API

This commit is contained in:
kazachilo 2025-03-14 11:04:27 +03:00
parent 5456532ddd
commit 065229cf00
10 changed files with 59 additions and 35 deletions

View File

@ -2,6 +2,7 @@ import React, { lazy, Suspense, useEffect } from 'react';
import { BrowserRouter, Routes, Route, Navigate, Outlet, useNavigate, useLocation } from 'react-router-dom'; import { BrowserRouter, Routes, Route, Navigate, Outlet, useNavigate, useLocation } from 'react-router-dom';
import Layout from './components/layout/Layout'; import Layout from './components/layout/Layout';
import Home from './screens/Home'; import Home from './screens/Home';
import { initializeUserId } from './constants/user';
// Ленивая загрузка компонентов // Ленивая загрузка компонентов
const OnboardingWelcome = lazy(() => import('./screens/onboarding/OnboardingWelcome')); const OnboardingWelcome = lazy(() => import('./screens/onboarding/OnboardingWelcome'));
@ -35,6 +36,14 @@ const AppContent: React.FC = () => {
const location = useLocation(); const location = useLocation();
useEffect(() => { useEffect(() => {
// Инициализируем ID пользователя при запуске приложения
initializeUserId();
// Отключаем вертикальные свайпы для предотвращения случайного сворачивания WebApp
if (window.Telegram?.WebApp?.isVersionAtLeast('6.9')) {
window.Telegram.WebApp.disableVerticalSwipes();
}
// Проверяем, видел ли пользователь онбординг и принял ли условия // Проверяем, видел ли пользователь онбординг и принял ли условия
const hasSeenOnboarding = localStorage.getItem('hasSeenOnboarding') === 'true'; const hasSeenOnboarding = localStorage.getItem('hasSeenOnboarding') === 'true';
const hasAcceptedTerms = localStorage.getItem('hasAcceptedTerms') === 'true'; const hasAcceptedTerms = localStorage.getItem('hasAcceptedTerms') === 'true';

View File

@ -13,7 +13,7 @@
flex-direction: column; flex-direction: column;
justify-content: flex-end; justify-content: flex-end;
transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out;
text-align: left; text-align: center;
background-size: 100% 100%; background-size: 100% 100%;
background-position: center; background-position: center;
will-change: transform, background-position; will-change: transform, background-position;
@ -122,6 +122,7 @@
text-align: center; text-align: center;
gap: var(--spacing-small); gap: var(--spacing-small);
z-index: 1; /* Поверх оверлея */ z-index: 1; /* Поверх оверлея */
width: 100%;
} }
.title { .title {

View File

@ -3,7 +3,10 @@
*/ */
// Единый ID для всех операций с API // Единый ID для всех операций с API
export const DEFAULT_USER_ID = 296487847; const DEFAULT_USER_ID = 296487847;
// Переменная для хранения ID текущего пользователя
let CURRENT_USER_ID: number = DEFAULT_USER_ID;
/** /**
* Проверяет, доступен ли объект Telegram WebApp и данные пользователя * Проверяет, доступен ли объект Telegram WebApp и данные пользователя
@ -15,17 +18,22 @@ export const isTelegramWebAppAvailable = (): boolean => {
}; };
/** /**
* Получает ID пользователя для всех операций с API * Инициализация ID пользователя при старте приложения
* Если доступен Telegram WebApp, возвращает реальный ID пользователя
* В противном случае возвращает тестовый ID
*/ */
export const getUserId = (): number => { export const initializeUserId = (): void => {
if (isTelegramWebAppAvailable() && window.Telegram?.WebApp?.initDataUnsafe?.user?.id) { if (isTelegramWebAppAvailable() && window.Telegram?.WebApp?.initDataUnsafe?.user?.id) {
return window.Telegram.WebApp.initDataUnsafe.user.id; CURRENT_USER_ID = window.Telegram.WebApp.initDataUnsafe.user.id;
} console.log('Инициализирован ID пользователя Telegram:', CURRENT_USER_ID);
// Для локальной разработки используем тестовый ID } else {
console.log('Используется тестовый ID пользователя:', DEFAULT_USER_ID); console.log('Используется тестовый ID пользователя:', DEFAULT_USER_ID);
return DEFAULT_USER_ID; }
};
/**
* Получает текущий ID пользователя
*/
export const getCurrentUserId = (): number => {
return CURRENT_USER_ID;
}; };
/** /**
@ -33,7 +41,7 @@ export const getUserId = (): number => {
* Используется для совместимости с API, требующими строковый ID * Используется для совместимости с API, требующими строковый ID
*/ */
export const getUserIdString = (): string => { export const getUserIdString = (): string => {
return getUserId().toString(); return getCurrentUserId().toString();
}; };
/** /**
@ -46,7 +54,7 @@ export const getUserInfo = () => {
} }
// Тестовые данные для локальной разработки // Тестовые данные для локальной разработки
return { return {
id: DEFAULT_USER_ID, id: CURRENT_USER_ID,
first_name: 'Test', first_name: 'Test',
last_name: 'User', last_name: 'User',
username: 'testuser', username: 'testuser',

View File

@ -4,7 +4,7 @@ import styles from './AddStickerToPackScreen.module.css';
import { stickerService } from '../services/stickerService'; import { stickerService } from '../services/stickerService';
import apiService from '../services/api'; import apiService from '../services/api';
import { GeneratedImage } from '../types/api'; import { GeneratedImage } from '../types/api';
import { getUserIdString } from '../constants/user'; import { getCurrentUserId } from '../constants/user';
const AddStickerToPackScreen: React.FC = () => { const AddStickerToPackScreen: React.FC = () => {
const navigate = useNavigate(); const navigate = useNavigate();
@ -81,7 +81,7 @@ const AddStickerToPackScreen: React.FC = () => {
// Добавляем стикер в стикерпак, используя file_id изображения // Добавляем стикер в стикерпак, используя file_id изображения
await stickerService.addStickerToPack( await stickerService.addStickerToPack(
packName, packName,
getUserIdString(), getCurrentUserId().toString(),
selectedImage.link, selectedImage.link,
emoji, emoji,
packTitle // Передаем заголовок стикерпака packTitle // Передаем заголовок стикерпака

View File

@ -4,7 +4,7 @@ import styles from './CreateStickerPack.module.css';
import { stickerService } from '../services/stickerService'; import { stickerService } from '../services/stickerService';
import apiService from '../services/api'; import apiService from '../services/api';
import { GeneratedImage } from '../types/api'; import { GeneratedImage } from '../types/api';
import { getUserIdString } from '../constants/user'; import { getCurrentUserId } from '../constants/user';
/** /**
* Транслитерирует кириллический текст в латиницу. * Транслитерирует кириллический текст в латиницу.
@ -138,7 +138,7 @@ const CreateStickerPack: React.FC = () => {
// Создаем стикерпак // Создаем стикерпак
await stickerService.createStickerPack( await stickerService.createStickerPack(
title, title,
getUserIdString(), getCurrentUserId().toString(),
fileIds, fileIds,
emojis, emojis,
packName packName

View File

@ -3,6 +3,7 @@ import styles from './Profile.module.css';
import { MOCK_USER } from '../constants/mock'; import { MOCK_USER } from '../constants/mock';
import { stickerService } from '../services/stickerService'; import { stickerService } from '../services/stickerService';
import apiService from '../services/api'; import apiService from '../services/api';
import { getCurrentUserId } from '../constants/user';
const Profile: React.FC = () => { const Profile: React.FC = () => {
const [stickersCount, setStickersCount] = useState<number>(0); const [stickersCount, setStickersCount] = useState<number>(0);
@ -15,7 +16,7 @@ const Profile: React.FC = () => {
setLoading(true); setLoading(true);
// Получаем список стикерпаков // Получаем список стикерпаков
const stickerPacks = await stickerService.getUserStickerPacks(stickerService.getUserId()); const stickerPacks = await stickerService.getUserStickerPacks(getCurrentUserId().toString());
setPacksCount(stickerPacks.length); setPacksCount(stickerPacks.length);
// Получаем список созданных стикеров // Получаем список созданных стикеров

View File

@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import styles from './StickerPacks.module.css'; import styles from './StickerPacks.module.css';
import { stickerService } from '../services/stickerService'; import { stickerService } from '../services/stickerService';
import { getUserIdString } from '../constants/user'; import { getCurrentUserId } from '../constants/user';
// Функция для удаления дописанной части из названия стикерпака // Функция для удаления дописанной части из названия стикерпака
const cleanPackTitle = (title: string): string => { const cleanPackTitle = (title: string): string => {
@ -36,7 +36,7 @@ const StickerPacks: React.FC = () => {
const fetchStickerPacks = async () => { const fetchStickerPacks = async () => {
try { try {
setLoading(true); setLoading(true);
const stickerSets = await stickerService.getUserStickerPacks(getUserIdString()); const stickerSets = await stickerService.getUserStickerPacks(getCurrentUserId().toString());
// Для каждого стикерпака получаем детальную информацию, обрабатывая ошибки отдельно // Для каждого стикерпака получаем детальную информацию, обрабатывая ошибки отдельно
const packsDetails: StickerPack[] = []; const packsDetails: StickerPack[] = [];

View File

@ -2,7 +2,7 @@ import { GenerationResponse, ApiError as ApiErrorType, GeneratedImage, PendingTa
import { baseWorkflow } from '../constants/baseWorkflow'; import { baseWorkflow } from '../constants/baseWorkflow';
import { prompts } from '../assets/prompts'; import { prompts } from '../assets/prompts';
import translateService from './translateService'; import translateService from './translateService';
import { DEFAULT_USER_ID } from '../constants/user'; import { getCurrentUserId, isTelegramWebAppAvailable } from '../constants/user';
const API_BASE_URL = 'https://stickerserver.gymnasticstuff.uk'; const API_BASE_URL = 'https://stickerserver.gymnasticstuff.uk';
@ -50,7 +50,7 @@ class GenerationError extends Error {
const apiService = { const apiService = {
// Получение списка задач пользователя в статусе PENDING // Получение списка задач пользователя в статусе PENDING
async getUserPendingTasks(userId = DEFAULT_USER_ID): Promise<PendingTask[]> { async getUserPendingTasks(userId = getCurrentUserId()): Promise<PendingTask[]> {
try { try {
const response = await fetch(`${API_BASE_URL}/user_pending_tasks/${userId}`, { const response = await fetch(`${API_BASE_URL}/user_pending_tasks/${userId}`, {
method: 'GET', method: 'GET',
@ -98,7 +98,7 @@ const apiService = {
return queuePosition * averageGenerationTime; return queuePosition * averageGenerationTime;
}, },
async getGeneratedImages(userId = DEFAULT_USER_ID): Promise<GeneratedImage[]> { async getGeneratedImages(userId = getCurrentUserId()): Promise<GeneratedImage[]> {
try { try {
const response = await fetch(`${API_BASE_URL}/images_links/${userId}`, { const response = await fetch(`${API_BASE_URL}/images_links/${userId}`, {
method: 'GET', method: 'GET',
@ -176,9 +176,10 @@ const apiService = {
console.log(`Используем тег "${tag}" для стиля "${style || 'chibi'}"`); console.log(`Используем тег "${tag}" для стиля "${style || 'chibi'}"`);
// Создаем тело запроса как строку JSON вручную // Создаем тело запроса как строку JSON вручную
const requestBodyJson = `{"tag":"${tag}","user_id":${DEFAULT_USER_ID},"workflow":${workflowJson}}`; const requestBodyJson = `{"tag":"${tag}","user_id":${getCurrentUserId()},"workflow":${workflowJson}}`;
// Сохраняем JSON для отладки // Сохраняем JSON для отладки только при локальной разработке
if (!isTelegramWebAppAvailable()) {
const blob = new Blob([requestBodyJson], { type: 'application/json' }); const blob = new Blob([requestBodyJson], { type: 'application/json' });
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
const a = document.createElement('a'); const a = document.createElement('a');
@ -188,6 +189,7 @@ const apiService = {
a.click(); a.click();
document.body.removeChild(a); document.body.removeChild(a);
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
}
// Отправляем запрос // Отправляем запрос
const response = await fetch(`${API_BASE_URL}/generate_image`, { const response = await fetch(`${API_BASE_URL}/generate_image`, {

View File

@ -1,4 +1,4 @@
import { getUserIdString } from '../constants/user'; import { getCurrentUserId } from '../constants/user';
import { StickerPack, StickerSetResponse } from '../types/api'; import { StickerPack, StickerSetResponse } from '../types/api';
import { normalizeImageUrl } from './api'; import { normalizeImageUrl } from './api';
@ -12,7 +12,7 @@ export class StickerService {
* Получает ID пользователя для работы со стикерпаками * Получает ID пользователя для работы со стикерпаками
*/ */
getUserId(): string { getUserId(): string {
return getUserIdString(); return getCurrentUserId().toString();
} }
/** /**

View File

@ -22,6 +22,9 @@ interface TelegramWebApp {
openTelegramLink: (url: string) => void; openTelegramLink: (url: string) => void;
openLink: (url: string, options?: any) => void; openLink: (url: string, options?: any) => void;
close: () => void; close: () => void;
disableVerticalSwipes: () => void;
enableVerticalSwipes: () => void;
isVersionAtLeast: (version: string) => boolean;
// Другие методы и свойства Telegram Web App API // Другие методы и свойства Telegram Web App API
} }