Commit Graph

319 Commits

Author SHA1 Message Date
Fringg
39bdf8b5c3 fix: CopiedToast not visible due to CSS transform context
Use createPortal to render toast at document.body level,
escaping framer-motion's transform on the tab content wrapper.
Remove unused useRef import and shareToastTapCopy i18n key.
2026-03-10 07:39:04 +03:00
Fringg
0322974ebd fix: replace orphaned shareModal i18n keys in GiftResult
GiftResult.tsx referenced gift.shareModalCopied and shareModalCopyAll
which were removed with the modal. Use common.copied and add new
gift.copyMessage key instead.
2026-03-10 07:30:17 +03:00
Fringg
9fbfcf21ff refactor: replace share modal with auto-copy toast
Remove the full-screen ShareModal dialog that appeared when sharing a
gift code. Replace with a bottom toast that automatically copies the
share message to clipboard on button press and slides up from the
bottom. The toast auto-dismisses after 5 seconds and can be tapped
to copy again.
2026-03-10 07:27:39 +03:00
Fringg
7549ae70eb feat: show localized error for self-activation attempt 2026-03-10 06:45:14 +03:00
Fringg
51ec799c0c feat: split my gifts into Active/Activated/Received sections
Sent gifts are now sorted into "Active gifts" (awaiting activation)
and "Activated" (already used). Received gifts remain separate.
2026-03-10 06:39:50 +03:00
Fringg
1bafcca1ef fix: gift UI improvements — declension, GB display, share modal, deep links
- Fix Russian device count declension (_one/_few/_many)
- Show traffic GB and tariff description in buy tab
- Replace copy/share buttons with share modal (bot + cabinet links)
- GiftResult: code-only success state with formatted share message
- Support ?tab=activate&code=TOKEN for auto-activation via cabinet link
- Add is_code_only + purchase_token to API types
2026-03-10 06:03:28 +03:00
Fringg
af3e535c69 feat: gift subscription redesign — code-only purchase + 3-tab UI
- Remove recipient input from buy flow (code-only gifts)
- 3-tab UI: Buy, Activate, My Gifts with animations
- After purchase, switch to My Gifts tab to show gift code
- Gift code display with copy/share buttons
- Activate tab: enter gift code to activate subscription
- My Gifts tab: sent/received gifts with status badges
- Fix: use navigator.language instead of hardcoded ru-RU for dates
- Fix: spread array before sort to prevent React Query cache mutation
- Fix: ARIA tab linkage with proper id/aria-labelledby
- Fix: guard VITE_BOT_USERNAME against undefined in share URLs
- Fix: wrap clipboard/share fallbacks in try/catch
- Add error state to MyGiftsTabContent
2026-03-10 05:37:57 +03:00
Fringg
ea06ad1d8f fix: show fallback when tariff has no available periods for renewal
When all periods are removed from a tariff, users saw an empty
purchase form with no way to renew. Now shows a message explaining
the situation and a button to choose a different tariff.
2026-03-10 01:27:48 +03:00
Fringg
638844ef47 feat: add open_in setting for custom buttons (external browser / Telegram miniapp) 2026-03-09 23:33:05 +03:00
Fringg
082471bf92 feat: add button reordering within rows and replace modal with inline add panel
- Add up/down arrow buttons to reorder buttons within rows (builtin + custom)
- Replace AddButtonDialog modal (bg-black/50 overlay) with inline expandable panel
- Add moveUp/moveDown i18n keys for all locales (en/ru/zh/fa)
- Add aria-labels for accessibility on reorder buttons
2026-03-09 23:26:16 +03:00
Fringg
23aa86f1a8 feat: add menu editor tab with drag-and-drop rows, custom URL buttons, and button configuration
- Add menuLayout.ts API client with normalizeConfig and type definitions
- Add MenuEditorTab.tsx with DnD rows, button CRUD, style/emoji/label editors
- Replace ButtonsTab with MenuEditorTab on admin settings page
- Add menu editor translations for ru, en, zh, fa locales
- Loading/error states, useMemo optimizations, proper ref patterns
2026-03-09 23:07:38 +03:00
Fringg
78fda22679 fix: add missing nameRequired i18n key for promo group form validation 2026-03-09 22:16:37 +03:00
Fringg
9c7ab4b789 fix: admin promo groups - add default toggle, fix threshold reset to 0
- Added is_default toggle to promo group create/edit form
- Send 0 instead of null when clearing auto-assign threshold
- Added isDefault i18n keys for ru, en, zh, fa
2026-03-09 22:08:43 +03:00
Fringg
9542607832 feat: add gift subscription toggle to admin branding settings
Add CABINET_GIFT_ENABLED toggle in Admin Settings > Branding > Interface Options,
alongside existing fullscreen and email auth toggles. Includes updateGiftEnabled
API method and i18n keys for all 4 locales (ru/en/zh/fa).
2026-03-09 20:56:42 +03:00
Fringg
6ea1de2e8a fix: harden gift subscription frontend after multi-agent review
- Handle expired status in GiftResult (stop polling + show FailedState)
- Add PollErrorState for balance mode poll errors (softer UX)
- Remove non-null assertions in handleSubmit (explicit narrowing)
- Wrap gift routes in ErrorBoundary
- Add pollErrorTitle/pollErrorDesc i18n keys to all 4 locales
2026-03-09 20:34:41 +03:00
Fringg
7890d480e0 feat: add gift navigation, routes, and i18n translations 2026-03-09 19:04:50 +03:00
Fringg
b59122818c feat: add dedicated TopUpResult page for payment return flow
Replace toast-based payment return with animated result page showing
pending/success/failed/timeout states. Extract shared Spinner,
AnimatedCheckmark and AnimatedCrossmark components. Add sessionStorage
persistence with validation and TTL for cross-redirect payment data.
Unify ProtectedRoute with withLayout prop, add aria-live accessibility.
2026-03-09 03:58:56 +03:00
Fringg
7940410d7d feat: support disabled daily subscription status in cabinet UI
- Show SubscriptionCardExpired for disabled daily subscriptions
- Use togglePause() API for resume instead of renewSubscription()
- Add "Suspended" status badge and balance query invalidation
- Add dashboard.suspended and subscription.pause.suspended translations (ru, en, zh, fa)
2026-03-08 21:36:10 +03:00
c0mrade
71a0111a04 revert: remove device manager redesign, restore original device UI 2026-03-08 01:00:21 +03:00
c0mrade
edb7ef0488 feat: unified device manager with dot-based selector
Replace separate buy/reduce device sections with a single DeviceManager component featuring a dot-step selector for intuitive device limit adjustment.
2026-03-08 00:17:04 +03:00
Fringg
eed077b019 feat: add gift purchase UI states for telegram recipients
- Add recipient_in_bot and bot_link fields to PurchaseStatus API type
- Show bot link instruction when gift recipient is not in bot
- Show "gift sent via Telegram" message when recipient is in bot
- Fix duplicate text rendering in GiftPendingActivationState
- Handle recipientInBot=null edge case safely
- Add gift notification translations for ru, en, zh, fa locales
2026-03-07 20:33:55 +03:00
Fringg
0ce74ea5fb fix: rename duplicate 'purchases' i18n key to 'purchaseCount'
The admin.landings namespace had two 'purchases' keys at the same level:
a string for purchase count label and an object for purchases section.
JSON last-key-wins caused the string to be overwritten by the object,
producing "returned an object instead of string" error on landings list.
2026-03-07 13:22:08 +03:00
Fringg
887b13dec2 feat: add purchases list with pagination to landing stats page
Add card-based purchase list below charts with:
- Status filter dropdown (all/pending/paid/delivered/etc)
- Paginated card list with contact, gift recipient, tariff, price
- Status badges, responsive mobile/desktop layout
- Translations for ru/en
2026-03-07 09:50:03 +03:00
Fringg
30190199ed feat: add landing page statistics page with recharts
Add AdminLandingStats page with:
- Summary cards (purchases, revenue, gifts, conversion)
- AreaChart with dual Y-axis (daily purchases + revenue)
- BarChart (tariff distribution)
- PieChart donut (gift vs regular breakdown)
- Responsive layout for desktop and mobile
- Stats button on landing cards list

Includes API types, route, translations (ru/en).
2026-03-07 09:36:20 +03:00
Fringg
46f640a7e0 fix: add pagination to campaigns list
The campaigns page was fetching only the first 50 items with no way
to load more. Switched from useQuery to useInfiniteQuery with a
"Load more" button so all campaigns are accessible.
2026-03-07 07:04:56 +03:00
Fringg
f7afa002f0 feat: add discount UI for landing pages
Add discount configuration in admin editor and countdown timer
display on public purchase page.

- Add discount section to AdminLandingEditor with toggle, percent
  slider, datetime pickers, per-tariff overrides, live preview
- Add DiscountBanner with countdown timer to QuickPurchase page
  using AnimatePresence exit animation and proper interval cleanup
- Add strikethrough prices and discount badges to tariff cards,
  summary card and pay button with null/equality guards
- Add discount translations for ru and en locales
- Fix delete/toggle API return types to match backend contracts
- Fix isoToDatetimeLocal to preserve seconds on re-edit
- Fix preview rounding to match backend integer division
2026-03-07 07:01:46 +03:00
Fringg
40722747e3 feat: add user filter chips and resource types to audit log
- Replace user ID text input with checkbox-style user chips extracted from log entries
- Add sales_stats and landings to resource type filter
- Fix export not respecting status filter
- Remove dead auto-refresh interval code
- Add aria-pressed and focus-visible styles for accessibility
2026-03-07 06:17:25 +03:00
Fringg
5228b2dea6 feat: add landings permission section translations for role editor 2026-03-07 06:04:57 +03:00
Fringg
97959b0132 fix: prevent buyer from activating gift pending subscription
When a gift purchase results in pending_activation (recipient has active
subscription), the buyer was shown an Activate button and could replace
the recipient's subscription without consent.

- Add GiftPendingActivationState component showing "Gift sent" message
- Use ?activate=1 URL hint from recipient email to distinguish viewer
- Buyer sees success message, recipient sees activate button
- Add giftPendingActivationDesc translations (ru, en, zh, fa)
2026-03-07 06:00:17 +03:00
Fringg
bc45294487 feat: add external squad selection to tariff admin form
- Add ExternalSquadInfo type and getAvailableExternalSquads API method
- Add external_squad_uuid field to TariffDetail, TariffCreateRequest, TariffUpdateRequest
- Add radio-button external squad picker in Servers tab of tariff create/edit
- Add translations for external squad UI in all 4 locales (en, ru, zh, fa)
2026-03-07 05:44:29 +03:00
Fringg
6d5c6fb9b3 fix: mobile layout and period label translations for quick purchase landing
- Add i18n period labels (ru/en/zh/fa) instead of backend English-only labels
- Period tabs wrap on mobile instead of horizontal scroll
- Prevent horizontal overflow shifting the layout
2026-03-07 04:04:39 +03:00
Fringg
c221c6e8bf feat: add i18n translations and admin category for Telegram OIDC 2026-03-07 02:40:04 +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
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
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
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
firewookie
00a013f02b - Интеграция рекурентов от Юкассы
- Багфикс личного кабинета
2026-03-06 09:47:58 +05: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
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
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
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
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
Fringg
f012710df0 feat: add daily deposits by payment method chart
Add MultiSeriesAreaChart showing daily deposit amounts per payment
method with human-readable labels and currency formatting. Memoize
all derived data before early returns for React Compiler compat.
2026-03-02 22:08:16 +03:00