Commit Graph

1222 Commits

Author SHA1 Message Date
Fringg
dfa7a09a7c fix: add unmount safety guard to OIDC callback handler
Prevent stale navigate('/') and setState calls after unmount
using mountedRef pattern.
2026-03-07 03:27:14 +03:00
Fringg
b335d666c2 fix: OIDC login UX improvements from review
- Add loading state on button click (not just after callback)
- Add onerror handler for script load failure
- Disable button until OIDC script is loaded
2026-03-07 03:18:49 +03:00
Fringg
45e68ffac2 fix: safe error handling and numeric client_id in OIDC login
- Replace unsafe `as` cast with runtime type guard
- Pass client_id as Number() per Telegram OIDC spec
- Update TypeScript type to string | number
2026-03-07 03:04:46 +03:00
Fringg
5c11f1251a fix: address code review findings for TelegramLoginButton
- Replace useCallback with ref pattern to prevent stale closures and
  unnecessary Telegram.Login.init() re-calls
- Make isOIDC a proper boolean with Boolean() wrapper
- Clear previous error on successful login attempt
- Remove hardcoded fallback string from t() call
2026-03-07 02:51:18 +03:00
Fringg
c221c6e8bf feat: add i18n translations and admin category for Telegram OIDC 2026-03-07 02:40:04 +03:00
Fringg
91f0e9e2fc feat: TelegramLoginButton with OIDC popup + legacy widget fallback
- Add oidc_enabled/oidc_client_id to TelegramWidgetConfig interface and fallback
- Add loginTelegramOIDC API method for id_token auth
- Add loginWithTelegramOIDC to auth store
- Rewrite TelegramLoginButton: OIDC popup when enabled, legacy widget otherwise
- Extend Window.Telegram type with Login SDK in vite-env.d.ts
2026-03-07 02:37:12 +03:00
Fringg
2c65ca8a7f 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)
2026-03-07 01:48:18 +03:00
Fringg
83fbd0e445 fix: auto-select single sub-option and remove unused return_url field
- Auto-select sub-option even when only 1 exists (backend needs suffix)
- Remove return_url from public LandingPaymentMethod (backend doesn't send it)
- Add else branch in auto-select for defensive null reset
2026-03-07 00:01:47 +03:00
Fringg
58e93cd2b7 feat: add payment sub-option selection on quick purchase page
Show sub-options (e.g. СБП, Карта) as selectable buttons when a
payment method has multiple enabled variants. Send suffixed
payment_method ID to backend for correct provider routing.
Split LandingPaymentMethod into public and admin types.
2026-03-06 23:53:31 +03:00
Fringg
d0be127d30 feat: add sub-options UI for landing payment methods + extract components
Add interactive sub-option toggles (Card/SBP/Crypto) to the landing editor
payment method configuration. Extract SortableFeatureItem and
SortableSelectedMethodCard into dedicated component files to reduce
AdminLandingEditor from ~1160 to ~860 lines.
2026-03-06 23:30:53 +03:00
Fringg
b9f1f59e3c fix: show total purchase count instead of paid on admin landings 2026-03-06 22:16:41 +03:00
Fringg
d228d997d8 feat: guest purchase cabinet credentials UI
- CabinetCredentialsState with copyable email/password fields
- Auto-login via JWT token with checkAdminStatus
- /auto-login route with ErrorBoundary and no-referrer meta
- Narrowed contact_type to 'email' | 'telegram' | null
- Disabled button styling for PendingActivation go-to-cabinet
- i18n: added landing.copy key to all 4 locales
2026-03-06 21:59:59 +03:00
Fringg
b852e1e4cd feat: guest purchase activation UI & landing editor improvements
- Add PendingActivationState component with activate button
- Add double-click ref guard on activation handler
- Add activatePurchase API function
- Update PurchaseStatus type with new fields
- Show gift message and recipient contact in success state
- Add pending activation i18n translations (ru, en, zh, fa)
- Improve AdminLandingEditor with allowed_periods support
2026-03-06 19:56:38 +03:00
Fringg
9bd58cb914 fix: handle Pydantic validation errors in notify + nullify empty optional fields
- getApiErrorMessage now formats Pydantic [{loc, msg}] arrays as readable strings
- LandingPaymentMethod description/icon_url nullable
- Send null instead of empty string for optional payment method fields
2026-03-06 18:03:27 +03:00
Fringg
6755c1dc45 fix: landing list crash — title is now LocaleDict, not string
- Update LandingListItem.title type to LocaleDict
- Add resolveLocaleDisplay() helper for extracting display string
- Use resolveLocaleDisplay() in landing list and delete confirm
2026-03-06 17:00:05 +03:00
Fringg
6a92814ce2 fix: admin landing editor — tariff period mapping and cleanup
- Use data.id instead of positional index for tariffPeriodsMap
- Clean up allowedPeriods when tariff is unchecked
- Filter out empty period arrays and orphaned tariff keys on submit
2026-03-06 16:55:13 +03:00
Fringg
ab13616b0f feat: мультиязычные лендинги + переключатель языка + исправления по ревью
Мультиязычность:
- LanguageSwitcher на публичной странице покупки
- Вкладки локалей в админ-редакторе (ru/en/zh/fa)
- LocaleTabs и LocalizedInput компоненты
- Типы: LocaleDict, AdminLandingFeature, toLocaleDict хелпер
- ?lang= параметр при запросе конфига лендинга

Исправления по ревью:
- contentIndicators включает все локализуемые поля
- LocaleTabs вынесен над секциями аккордеона
- text-left → text-start для RTL
- nonEmptyDict: защита от undefined
- featureIds/methodIds обёрнуты в useMemo
- toggleSection/updateFeature* обёрнуты в useCallback
- formatPrice вынесен в shared utils/format.ts
- RTL через LOCALE_META.rtl вместо хардкода
- Переводы zh/fa для валидации и landing
- Variable shadowing: t → tariff
2026-03-06 16:11:58 +03:00
Fringg
e01c9f5143 fix: админ-редактор — системные методы оплаты, реальные периоды тарифов, фильтрация на публичной странице
- Способы оплаты: загрузка из системного API вместо ручного ввода, toggleable чекбоксы
- Периоды тарифов: загрузка из period_prices через useQueries вместо произвольного ввода
- Публичная страница: глобальный список периодов, скрытие тарифов без цены для выбранного периода
- Локализация: добавлены ключи для 4 языков (ru/en/zh/fa)
2026-03-06 07:33:19 +03:00
Fringg
3cea48235f fix: безопасность и UX лендингов — 16 исправлений
- CRITICAL: усиленная CSS-санитизация (escape-последовательности, at-rules)
- CRITICAL: очистка setTimeout при unmount
- HIGH: useMutation для создания покупки (вместо ручного fetch)
- HIGH: DOMPurify + rel="noopener noreferrer" на ссылках
- HIGH: ErrorBoundary для публичных страниц покупки
- MEDIUM: стабильные UUID для DnD элементов
- MEDIUM: race condition в delete timeout
- MEDIUM: клиентская валидация формы лендинга
- MEDIUM: staleTime для админ-запросов
- MEDIUM: общая утилита getApiErrorMessage
- MEDIUM: уведомление о таймауте поллинга
- LOW: ARIA роли для radio-карточек и форм
- LOW: дедупликация иконок в LandingIcons.tsx
- LOW: cn() вместо template literals
2026-03-06 07:23:11 +03:00
Fringg
8b5d777f0a feat: публичные лендинг-страницы для быстрой покупки VPN-подписок
- QuickPurchase: публичная страница покупки с выбором тарифа/периода/оплаты
- PurchaseSuccess: статус покупки с поллингом и копированием ссылки
- AdminLandings: управление лендингами (создание, сортировка, удаление)
- AdminLandingEditor: полнофункциональный редактор лендинга
- API-клиент landings.ts для всех эндпоинтов
- Роутинг /buy/:slug и /buy/success/:token
- Локализация ru/en/zh/fa для всех текстов лендинга
- Санитизация HTML/CSS, rate limit защита, DOMPurify
2026-03-06 07:02:21 +03:00
Egor
52248e7715 Merge pull request #250 from BEDOLAGA-DEV/release-please--branches--main--components--cabinet-frontend
chore(main): release 1.24.0
2026-03-05 11:35:39 +03:00
github-actions[bot]
6841738c29 chore(main): release 1.24.0 2026-03-05 08:32:54 +00:00
Egor
53db628052 Merge pull request #249 from BEDOLAGA-DEV/dev
Dev
2026-03-05 11:32:16 +03:00
Fringg
e278fec506 feat: кликабельные имена пользователей в последних платежах
Имена в блоке "Последние платежи" теперь ведут на профиль
пользователя /admin/users/:id (десктоп и мобильная версия).
2026-03-05 11:16:55 +03:00
Fringg
86f75f25a7 fix: заменить Tailwind green/emerald классы на success из темы
Замена green-*/emerald-* на success-* в 8 файлах:
AdminPolicyEdit, AdminBroadcastDetail, AdminAuditLog, ButtonsTab,
VerifyEmail, BackgroundEditor, AdminPolicies, AdminUpdates
2026-03-05 10:56:59 +03:00
Fringg
d526d095de fix: заменить хардкодный зелёный (#3EDBB0) на акцентный цвет из темы
Все вхождения #3EDBB0, #2BC49A и rgba(62,219,176,...) заменены на
CSS-переменные --color-accent-400/500 из системы тем.

Затронутые компоненты:
- TrialOfferCard: кнопка, бордер, свечение, иконка
- Subscription: лейблы, иконки, кнопки паузы/копирования
- SubscriptionCardActive: бордер карточки, бейдж статуса
- SubscriptionPurchase: градиент триал-блока
- PurchaseCTAButton: градиент кнопки, иконка
- TrafficProgressBar: цвета прогресс-бара
- StatsGrid: убрана зависимость от useTrafficZone, используется accent напрямую
- trafficZone.ts: добавлены mainVar/mainVarRaw для CSS-переменных
- tailwind.config.js: trialGlow keyframes на accent цвет
2026-03-05 10:56:45 +03:00
Fringg
262303d623 feat: add sales_stats RBAC permission section to frontend
- Update route guard and menu item to use sales_stats:read
- Add sales_stats:read to marketer preset
- Add i18n translations for sales_stats section (ru, en, fa, zh)
2026-03-05 05:46:07 +03:00
Fringg
2fc0759f89 feat: account merge flow — merge redirect, error handling, server-complete linking
- Добавлен merge_required + merge_token redirect в OAuthCallback и LinkTelegramCallback
- Server-complete OAuth linking для Mini App (внешний браузер)
- getErrorDetail: единый экстрактор ошибок из axios response
- LinkTelegramCallback: типизированный catch с getErrorDetail
- Удалён мёртвый экспорт getAndClearOAuthState
- CSRF валидация для Telegram и OAuth linking flows
- Типы ServerCompleteResponse, LinkCallbackResponse
2026-03-05 05:25:50 +03:00
Fringg
0d99ea0069 refactor: review round 2 — remove dead code, fix type safety, improve UX
- Remove LinkOAuthCallback.tsx (dead code) and its route from App.tsx
- Move LINK_OAUTH_* constants to OAuthCallback.tsx
- Replace local ServerLinkResult with LinkCallbackResponse from types
- Move merge navigate() from render body to useEffect
- Track errorMode to show correct CTA (Return to Telegram vs Back to Login)
- Remove non-null assertions with proper narrowing
- Extract getErrorDetail helper for error casting
- Add smart polling success detection (stop + toast when linked count increases)
2026-03-05 03:10:22 +03:00
Fringg
da1926f0e1 fix: review findings — polling fallback, sessionStorage cleanup, UX
- Add 5s polling for 90s after opening external browser link (Mini App)
- Show info toast "Continue in browser" when opening external OAuth
- Fix premature sessionStorage cleanup: peek-then-clear pattern
- Use useIsTelegram() hook instead of direct isInTelegramWebApp()
- Add continueInBrowser i18n key (ru, en, zh, fa)
2026-03-05 02:33:33 +03:00
Fringg
7c30a1eab6 feat: open OAuth linking in external browser from Telegram Mini App
- Rewrite OAuthCallback.tsx to handle 3 modes: login, link-browser,
  and link-server (external browser without JWT)
- Add linkServerComplete API method (no JWT, auth via state token)
- Update ConnectedAccounts to use platform.openLink() in Mini App
- Add server-complete endpoint to AUTH_ENDPOINTS (skip Bearer token)
- Enable refetchOnWindowFocus for linked-providers query
- Add returnToTelegram/openTelegram i18n keys (ru, en, zh, fa)
2026-03-05 02:24:28 +03:00
Fringg
9b4a8512c2 fix: remove unused linkTelegramWidget i18n key from all locales 2026-03-04 17:21:16 +03:00
Fringg
a6fabb1d9d feat: add Telegram account linking UI with CSRF protection
- TelegramLinkWidget component with Login Widget for browser users
- One-click initData linking for Mini App users
- LinkTelegramCallback page with CSRF state validation
- URL credential clearing via history.replaceState
- Merge flow support with replace navigation
- i18n keys for all 4 locales (ru, en, zh, fa)
2026-03-04 17:03:48 +03:00
Fringg
584f00297b fix: add Referrer-Policy to prevent merge token leakage via Referer header 2026-03-04 16:14:51 +03:00
Fringg
8ad0500cc8 fix: double-click guard on link, wall-clock timer, blur cleanup
- Add linkingProvider state to prevent double-click on Link button
- Use wall-clock based countdown timer to prevent drift
- Clean up onBlur setTimeout ref on unmount
2026-03-04 16:05:24 +03:00
Fringg
fba4481799 fix: move useState before useMutation for consistent hook ordering 2026-03-04 15:57:04 +03:00
Fringg
71198ab18a refactor: extract shared ProviderIcon, fix canUnlink hiding all buttons
- Extract TelegramIcon + EmailIcon to shared ProviderIcon component
- Remove duplicated icons from ConnectedAccounts and MergeAccounts
- Remove isPending from canUnlink (buttons already have disabled prop)
- Add onSettled to reset confirmingUnlink state after mutation
2026-03-04 15:46:53 +03:00
Fringg
3418ba9b8d fix: prevent onBlur race cancelling unlink confirmation
Add 150ms delay before resetting confirmation state so the click
event fires before blur resets it.
2026-03-04 15:35:45 +03:00
Fringg
d0c01a0e5c fix: replace window.confirm with inline confirmation for unlink
window.confirm() is silently suppressed in Telegram Mini Apps and iOS
WebView, making unlink completely non-functional on mobile. Replaced
with two-click inline confirmation: first click shows destructive
"Confirm disconnect?" button, second click executes unlink. Button
resets on blur.
2026-03-04 15:30:00 +03:00
Fringg
e447e993cb fix: accessibility, query cache clear, post-merge navigation
- Add aria-hidden="true" to all decorative SVGs (TelegramIcon, EmailIcon
  in MergeAccounts + ConnectedAccounts, all 4 OAuthProviderIcon SVGs)
- Add role="radiogroup" with aria-label to subscription choice container
- Clear react-query cache after merge to prevent stale data
- Wrap checkAdminStatus() in try-catch to prevent throw after token set
- Navigate to /profile/accounts after merge instead of /
- Import useQueryClient for cache management
2026-03-04 15:02:08 +03:00
Fringg
579f47e563 fix(merge): accessibility, token guard, state cleanup
- Add role="radio" + aria-checked to subscription radio buttons
- Add aria-hidden="true" to decorative SVG icons
- Treat success=true with null tokens as error (show error toast)
- Guard auto-select useEffect from overwriting user's manual choice
- Clear sessionStorage on OAuth state validation failure
2026-03-04 08:12:18 +03:00
Fringg
aa26059e00 fix: second round review fixes for merge UI
- Fix false success toast when response.success is false (CRITICAL)
- Remove mergeToken! non-null assertion in queryFn
- Add early return for missing mergeToken param
- Zero-pad minutes in formatCountdown (MM:SS format)
- Clamp negative seconds in formatCountdown
- Block all unlink buttons while any unlink mutation is pending
- Clear OAuth state only after validation succeeds (not before)
- Split getAndClearLinkOAuthState into read + clear functions
2026-03-04 07:56:19 +03:00
Fringg
58cf1e3b50 fix: harden merge UI and improve error handling
- MergeAccounts: guard mutationFn against null token/userId
- MergeAccounts: call checkAdminStatus after successful merge
- MergeAccounts: add fallback when success but tokens null
- MergeAccounts: fix ErrorState showing "expired" for all errors
- MergeAccounts: fix formatCountdown dead ternary and hardcoded English
- MergeAccounts: add staleTime/refetchOnWindowFocus to preview query
- MergeAccounts: remove manual useCallback (React Compiler handles it)
- LinkOAuthCallback: add toast feedback on all error/success paths
- ConnectedAccounts: use invalidateQueries instead of refetch
- ConnectedAccounts: add error state rendering
- ConnectedAccounts/LinkOAuthCallback: share sessionStorage key constants
- i18n: add missing profile.accounts.linking key to zh and fa locales
2026-03-04 07:47:36 +03:00
Fringg
93f97d45be feat: account linking and merge UI for cabinet
Add Connected Accounts page (link/unlink OAuth providers), Link OAuth
Callback handler, and Merge Accounts page with subscription comparison
and user choice. Includes API methods, TypeScript types, routes in
App.tsx, navigation from Profile, and i18n for all 4 locales (ru, en,
zh, fa). Merge page works without JWT auth (validated by merge token).
2026-03-04 07:25:45 +03:00
Egor
126443f194 Merge pull request #247 from BEDOLAGA-DEV/release-please--branches--main--components--cabinet-frontend
chore(main): release 1.23.1
2026-03-04 06:15:08 +03:00
github-actions[bot]
7e190543dd chore(main): release 1.23.1 2026-03-04 03:14:28 +00:00
Egor
4359202f76 Merge pull request #246 from BEDOLAGA-DEV/dev
Dev
2026-03-04 06:14:06 +03:00
Fringg
8157ca5f02 fix: ordered list numbering in Info page shows correct sequence
Each numbered rule (1, 2, 3...) was rendered as separate <ol> elements
all starting from 1. Added start attribute to preserve original numbering
and allowed it through DOMPurify sanitization.
2026-03-04 04:49:40 +03:00
Fringg
a3ddddfa8c fix: replace hardcoded green with theme-aware accent color
Normal traffic zone now uses configurable accent palette instead of
hardcoded success/green. Added useTrafficZone hook that resolves
mainHex dynamically from theme colors. Replaced emerald/teal classes
with success palette in SuccessNotificationModal. Fixed hardcoded
green hex values in Subscription and SubscriptionPurchase pages.
2026-03-04 02:50:28 +03:00
Egor
f74a67037b Merge pull request #244 from BEDOLAGA-DEV/release-please--branches--main--components--cabinet-frontend
chore(main): release 1.23.0
2026-03-02 22:27:47 +03:00