mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
feat: migrate Telegram Login Widget to v23 with admin-configurable settings
- Upgrade telegram-widget.js from v22 to v23 (TelegramLoginButton + ConnectedAccounts) - TelegramLoginButton fetches widget config from API instead of hardcoded values - Add TelegramWidgetConfig type and API method with fallback to env defaults - Remove botUsername prop — now sourced from backend API - Add useEffect cleanup to prevent orphaned iframes on unmount - Add TELEGRAM_WIDGET category to admin interface settings menu - Add i18n translations for widget settings (ru, en, zh, fa)
This commit is contained in:
@@ -23,6 +23,14 @@ export interface EmailAuthEnabled {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface TelegramWidgetConfig {
|
||||
bot_username: string;
|
||||
size: 'large' | 'medium' | 'small';
|
||||
radius: number;
|
||||
userpic: boolean;
|
||||
request_access: boolean;
|
||||
}
|
||||
|
||||
export interface AnalyticsCounters {
|
||||
yandex_metrika_id: string;
|
||||
google_ads_id: string;
|
||||
@@ -251,6 +259,24 @@ export const brandingApi = {
|
||||
}
|
||||
},
|
||||
|
||||
// Get Telegram widget config (public, no auth required)
|
||||
getTelegramWidgetConfig: async (): Promise<TelegramWidgetConfig> => {
|
||||
try {
|
||||
const response = await apiClient.get<TelegramWidgetConfig>(
|
||||
'/cabinet/branding/telegram-widget',
|
||||
);
|
||||
return response.data;
|
||||
} catch {
|
||||
return {
|
||||
bot_username: import.meta.env.VITE_TELEGRAM_BOT_USERNAME || '',
|
||||
size: 'large',
|
||||
radius: 8,
|
||||
userpic: true,
|
||||
request_access: true,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// Update analytics counters (admin only)
|
||||
updateAnalyticsCounters: async (data: Partial<AnalyticsCounters>): Promise<AnalyticsCounters> => {
|
||||
const response = await apiClient.patch<AnalyticsCounters>('/cabinet/branding/analytics', data);
|
||||
|
||||
@@ -1,42 +1,58 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { brandingApi, type TelegramWidgetConfig } from '../api/branding';
|
||||
|
||||
interface TelegramLoginButtonProps {
|
||||
botUsername: string;
|
||||
referralCode?: string;
|
||||
}
|
||||
|
||||
export default function TelegramLoginButton({
|
||||
botUsername,
|
||||
referralCode,
|
||||
}: TelegramLoginButtonProps) {
|
||||
export default function TelegramLoginButton({ referralCode }: TelegramLoginButtonProps) {
|
||||
const { t } = useTranslation();
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { data: widgetConfig } = useQuery<TelegramWidgetConfig>({
|
||||
queryKey: ['telegram-widget-config'],
|
||||
queryFn: brandingApi.getTelegramWidgetConfig,
|
||||
staleTime: 60000,
|
||||
});
|
||||
|
||||
const botUsername =
|
||||
widgetConfig?.bot_username || import.meta.env.VITE_TELEGRAM_BOT_USERNAME || '';
|
||||
|
||||
// Load widget script
|
||||
useEffect(() => {
|
||||
if (!containerRef.current || !botUsername) return;
|
||||
if (!containerRef.current || !botUsername || !widgetConfig) return;
|
||||
|
||||
// Clear previous widget using safe DOM API
|
||||
while (containerRef.current.firstChild) {
|
||||
containerRef.current.removeChild(containerRef.current.firstChild);
|
||||
const container = containerRef.current;
|
||||
|
||||
// Clear previous widget
|
||||
while (container.firstChild) {
|
||||
container.removeChild(container.firstChild);
|
||||
}
|
||||
|
||||
// Get current URL for redirect
|
||||
const redirectUrl = `${window.location.origin}/auth/telegram/callback`;
|
||||
|
||||
// Create script element for Telegram Login Widget
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://telegram.org/js/telegram-widget.js?22';
|
||||
script.src = 'https://telegram.org/js/telegram-widget.js?23';
|
||||
script.setAttribute('data-telegram-login', botUsername);
|
||||
script.setAttribute('data-size', 'large');
|
||||
script.setAttribute('data-radius', '8');
|
||||
script.setAttribute('data-size', widgetConfig.size);
|
||||
script.setAttribute('data-radius', String(widgetConfig.radius));
|
||||
script.setAttribute('data-userpic', String(widgetConfig.userpic));
|
||||
script.setAttribute('data-auth-url', redirectUrl);
|
||||
if (widgetConfig.request_access) {
|
||||
script.setAttribute('data-request-access', 'write');
|
||||
}
|
||||
script.async = true;
|
||||
|
||||
containerRef.current.appendChild(script);
|
||||
}, [botUsername]);
|
||||
container.appendChild(script);
|
||||
|
||||
return () => {
|
||||
while (container.firstChild) {
|
||||
container.removeChild(container.firstChild);
|
||||
}
|
||||
};
|
||||
}, [botUsername, widgetConfig]);
|
||||
|
||||
if (!botUsername || botUsername === 'your_bot') {
|
||||
return (
|
||||
@@ -48,10 +64,8 @@ export default function TelegramLoginButton({
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
{/* Telegram Widget will be inserted here */}
|
||||
<div ref={containerRef} className="flex justify-center" />
|
||||
|
||||
{/* Fallback link for mobile */}
|
||||
<div className="text-center">
|
||||
<p className="mb-2 text-xs text-gray-500">{t('auth.orOpenInApp')}</p>
|
||||
<a
|
||||
|
||||
@@ -67,6 +67,7 @@ export const MENU_SECTIONS: MenuSection[] = [
|
||||
'INTERFACE_SUBSCRIPTION',
|
||||
'CONNECT_BUTTON',
|
||||
'MINIAPP',
|
||||
'TELEGRAM_WIDGET',
|
||||
'HAPP',
|
||||
'SKIP',
|
||||
'ADDITIONAL',
|
||||
|
||||
@@ -1681,7 +1681,16 @@
|
||||
"projectName": "Project name",
|
||||
"quickPresets": "Quick presets",
|
||||
"resetAllColors": "Reset all colors",
|
||||
"statusColors": "Status colors"
|
||||
"statusColors": "Status colors",
|
||||
"categories": {
|
||||
"TELEGRAM_WIDGET": "Telegram Login Widget"
|
||||
},
|
||||
"settingNames": {
|
||||
"Telegram Widget Size": "Widget Size",
|
||||
"Telegram Widget Radius": "Corner Radius",
|
||||
"Telegram Widget Userpic": "Show User Photo",
|
||||
"Telegram Widget Request Access": "Request Access"
|
||||
}
|
||||
},
|
||||
"theme": {
|
||||
"accentColor": "Accent color",
|
||||
|
||||
@@ -1341,7 +1341,16 @@
|
||||
"projectName": "نام پروژه",
|
||||
"quickPresets": "پیشتنظیمهای سریع",
|
||||
"resetAllColors": "بازنشانی همه رنگها",
|
||||
"statusColors": "رنگهای وضعیت"
|
||||
"statusColors": "رنگهای وضعیت",
|
||||
"categories": {
|
||||
"TELEGRAM_WIDGET": "Telegram Login Widget"
|
||||
},
|
||||
"settingNames": {
|
||||
"Telegram Widget Size": "اندازه ویجت",
|
||||
"Telegram Widget Radius": "شعاع گوشه",
|
||||
"Telegram Widget Userpic": "نمایش تصویر کاربر",
|
||||
"Telegram Widget Request Access": "درخواست دسترسی"
|
||||
}
|
||||
},
|
||||
"buttons": {
|
||||
"color": "رنگ دکمه",
|
||||
|
||||
@@ -1762,6 +1762,10 @@
|
||||
"Subscription Show Devices": "Показывать устройства",
|
||||
"Telegram Stars Enabled": "Stars включены",
|
||||
"Telegram Stars Rate Rub": "Курс Stars (₽)",
|
||||
"Telegram Widget Size": "Размер виджета",
|
||||
"Telegram Widget Radius": "Скругление углов",
|
||||
"Telegram Widget Userpic": "Показывать аватар",
|
||||
"Telegram Widget Request Access": "Запрос доступа",
|
||||
"Tribute Api Key": "API ключ",
|
||||
"Tribute Donate Link": "Ссылка доната",
|
||||
"Tribute Enabled": "Tribute включен",
|
||||
@@ -2164,6 +2168,7 @@
|
||||
"PAL24": "PAL24",
|
||||
"WATA": "Wata",
|
||||
"TELEGRAM": "Telegram",
|
||||
"TELEGRAM_WIDGET": "Telegram Login Widget",
|
||||
"SUBSCRIPTIONS_CORE": "Основные",
|
||||
"SIMPLE_SUBSCRIPTION": "Простая подписка",
|
||||
"PERIODS": "Периоды",
|
||||
|
||||
@@ -1379,7 +1379,16 @@
|
||||
"projectName": "项目名称",
|
||||
"quickPresets": "快速预设",
|
||||
"resetAllColors": "重置所有颜色",
|
||||
"statusColors": "状态颜色"
|
||||
"statusColors": "状态颜色",
|
||||
"categories": {
|
||||
"TELEGRAM_WIDGET": "Telegram Login Widget"
|
||||
},
|
||||
"settingNames": {
|
||||
"Telegram Widget Size": "小部件大小",
|
||||
"Telegram Widget Radius": "圆角半径",
|
||||
"Telegram Widget Userpic": "显示头像",
|
||||
"Telegram Widget Request Access": "请求访问权限"
|
||||
}
|
||||
},
|
||||
"buttons": {
|
||||
"color": "按钮颜色",
|
||||
|
||||
@@ -44,7 +44,7 @@ function TelegramLinkWidget() {
|
||||
const redirectUrl = `${window.location.origin}/auth/link/telegram/callback?csrf_state=${encodeURIComponent(csrfState)}`;
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://telegram.org/js/telegram-widget.js?22';
|
||||
script.src = 'https://telegram.org/js/telegram-widget.js?23';
|
||||
script.setAttribute('data-telegram-login', botUsername);
|
||||
script.setAttribute('data-size', 'small');
|
||||
script.setAttribute('data-radius', '8');
|
||||
|
||||
@@ -485,10 +485,7 @@ export default function Login() {
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<TelegramLoginButton
|
||||
botUsername={botUsername}
|
||||
referralCode={referralCode || undefined}
|
||||
/>
|
||||
<TelegramLoginButton referralCode={referralCode || undefined} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user