Commit Graph

367 Commits

Author SHA1 Message Date
Fringg
d89c534c0b fix: rewrite BackgroundBoxes from 225 DOM divs to single canvas element
Root cause: 225 individually animated DOM elements forced Chrome's
compositor to create separate paint regions per element. Any hover
state change on page content triggered re-compositing of all 225
regions, causing visible flickering on all pages.

Canvas fix: single <canvas> element renders the entire grid effect
via requestAnimationFrame. Canvas content is pixel-based and cannot
be affected by DOM hover state changes on other elements.

Additional fixes:
- Fix z-index collision: portal z-index -1 → -2 (was same as body::before noise)
- Replace all transition-all with specific properties on .btn, .btn-icon,
  .input, .nav-item, .bottom-nav-item, checkbox
- Remove backdrop-blur-sm from desktop .bento-card and .card
  (forced Chrome to re-sample animated background pixels on every hover)
2026-02-27 08:46:22 +03:00
Fringg
fe32322c32 perf: remove permanent GPU layer promotion from cards to fix flickering
Remove translateZ(0) from base states of .bento-card, .card, .glass
and their light theme variants. Remove transform-gpu from Card.tsx.
Change bentoFadeIn animation to end with transform:none instead of
translateY(0). GPU promotion now only occurs during hover/active
interactions, preventing Chrome from creating excessive compositing
layers that cause flickering with animated backgrounds.
2026-02-27 08:27:07 +03:00
Fringg
7f17d95ed6 fix: replace framer-motion with CSS keyframes in boxes background
The boxes background was creating 225 motion.div elements, each running
independent opacity animations via framer-motion JS on the main thread.
This blocked hover transitions on cards, causing visible flickering.

CSS @keyframes run on the compositor thread and have zero main-thread
cost, eliminating the interference with user interactions.
2026-02-27 08:18:24 +03:00
Fringg
12c97a2c5e fix: render animated background via portal at z-index:-1 to stop implicit compositing
Previous isolation:isolate fix didn't work because:
- position:fixed elements still see through isolation boundary
- backdrop-filter samples all rendered content regardless of stacking context
- The real issue: animated background at z-index:0 with will-change:transform
  forces Chrome to implicitly composite EVERY overlapping element

Fix: render BackgroundRenderer via createPortal on document.body with
z-index:-1, placing it below the root stacking context. This eliminates
implicit compositing entirely.

Also:
- Remove backdrop-blur-xl from desktop header (was resampling bg 60fps)
- Remove will-change:opacity from card ::after pseudo-element
- Replace transition-all with transition-colors on header buttons
2026-02-27 08:14:20 +03:00
Fringg
04eacf6421 fix: isolate content layer from animated background to eliminate flickering
Root cause: backdrop-filter on header/nav resamples the animated
background 60fps, causing GPU compositing flicker (Chromium bug).

- Add isolation: isolate wrapper in AppShell to prevent backdrop-filter
  from seeing through to the animated background layer
- Add will-change: transform + translateZ(0) to BackgroundRenderer
  for stable GPU layer
- Replace contain: layout style with contain: content on main
- Replace transition-all with specific properties in Card component
2026-02-27 07:52:45 +03:00
Fringg
d8cf4301ca fix: resolve hover flickering caused by GPU layer destruction
- Preserve translateZ(0) on all hover/active transforms to prevent
  GPU compositing layer teardown/recreation cycle
- Lower body::before noise texture z-index to -1
- Add will-change: opacity to card spotlight pseudo-element
- Include backdrop-blur-linear in mobile performance override
- Replace transition-all with specific properties in BentoCard
2026-02-27 07:41:27 +03:00
Fringg
bdc201b5ea fix: eliminate hover flickering across all pages
- Extract CountdownTimer into React.memo component to isolate 1s
  interval re-renders from the full Subscription page
- Add box-shadow transition to .hover-border-gradient (was instant)
- Remove conflicting p-[1.5px] from PurchaseCTAButton (CSS border
  already handles 1.5px)
- Replace transition-all with specific properties on bento-card-hover,
  bento-card-glow, device dots, toggle switches, progress bars
- Reduce translateY hover from -4px to -2px to prevent cursor
  losing hover target during fast vertical mouse movement
2026-02-27 07:02:59 +03:00
Fringg
126f9ab9b9 refactor: extract purchase/renewal flow to separate page
Move ~1900 lines of purchase/renewal logic from Subscription.tsx into
a new SubscriptionPurchase.tsx page at /subscription/purchase.

- Create SubscriptionPurchase.tsx with tariffs grid, classic mode wizard,
  switch preview modal, and promo handling
- Create PurchaseCTAButton.tsx with animated gradient border, state-aware
  colors and context-aware text
- Create subscriptionHelpers.ts with shared utilities
- Add CopyIcon to shared icons module
- Register /subscription/purchase route with lazy loading
- Update SubscriptionCardExpired and PromoOffersSection navigators
- Add CTA translation keys to ru.json and en.json
- Remove all scrollToExtend references
2026-02-27 06:47:30 +03:00
Fringg
f4d7a2cc8d fix: subscription UI improvements - expired card, duplicate badges, live countdown
- SubscriptionCardExpired: use trialTitle for expired trials, remove traffic/devices grid, show only expiry date
- Subscription page: remove duplicate trial badge from zone indicator, fix expired trial badge showing "Пробный период" instead of "Истекла"
- Subscription page: replace static days counter with live HH:MM:SS countdown timer, merge "Действует до" into countdown block
- Subscription page: remove duplicate traffic percentage block
- Handle expired state in countdown (show "Истекла" in red instead of 00:00:00)
- Use live countdown.days for urgency threshold instead of stale server value
2026-02-27 06:04:06 +03:00
Fringg
27f85a1db1 fix: add subscription tab to desktop nav, fix device dots overflow, show available referral balance
- Add Subscription tab to desktop header navigation (was only in mobile)
- Fix device dots overflow for large limits (>10) by using progress bar
- Show available referral balance on dashboard instead of total earnings
- Add available_balance and withdrawn fields to ReferralInfo type
2026-02-27 04:53:37 +03:00
Fringg
4d14e3e806 feat: add fullscreen QR code for subscription connection
- New ConnectionQR page with fullscreen QR display (no modal)
- QR button in InstallationGuide header next to platform selector
- Respects hideLink setting: shows URL below QR only when visible
- i18n translations for ru, en, zh, fa
2026-02-27 03:14:15 +03:00
Fringg
7e89ccea5c fix: stop beams background from causing UI flickering in browser
Remove opacity from beamDash keyframes — opacity on SVG paths triggers
full-page repaints. Animate only stroke-dashoffset (compositor-friendly).
Reduce animated paths from 50 to 17 (every 3rd). Isolate container with
contain:strict + will-change:transform for own compositor layer.
2026-02-25 13:27:14 +03:00
Fringg
d019953693 perf: throttle theme color picker, rewrite beams with CSS animation
ThemeTab: throttle applyThemeColors via requestAnimationFrame (1x/frame),
debounce queryClient.setQueryData 150ms. Fixes browser lag when dragging
color sliders (~60 calls/sec × 50+ CSS var writes).

BackgroundBeams: replace 20 framer-motion linearGradient JS loops with
pure CSS stroke-dashoffset animation on all 50 original Aceternity paths.
Single shared gradient, GPU-composited keyframes, zero per-frame JS.
2026-02-25 13:21:22 +03:00
Fringg
a725265026 feat: add Freekassa SBP and card payment method icons and labels
Add icons, admin labels, and i18n descriptions for freekassa_sbp
and freekassa_card payment methods in the cabinet frontend.
2026-02-25 12:32:07 +03:00
Fringg
21fc75a17d refactor: simplify dashboard stats grid to 2 cards
Remove Subscription and Earnings cards from StatsGrid.
Merge earnings display into Referrals card as subtitle.
Remove subscription-status onboarding step (target removed).
2026-02-25 12:04:35 +03:00
Fringg
70e1ed60bd feat: add animated gradient border to Connect Device buttons
Pure CSS conic-gradient animation with @property --border-angle,
dynamic accent color from traffic zone, light theme + reduced motion support.
2026-02-25 11:18:39 +03:00
Fringg
f474067efb feat: adapt dashboard and subscription page for light theme
- Add glassTheme utility with theme-aware color tokens
- Replace hardcoded rgba(255,255,255,...) with dynamic values
- Replace text-white with text-dark-50 for auto theme remapping
- Restyle subscription page block to match dashboard glassmorphic design
- Light mode: white semi-opaque cards with subtle shadows
- Dark mode: unchanged visual appearance
2026-02-25 11:00:14 +03:00
Fringg
a819f309c8 fix: show actual connected devices count instead of device limit 2026-02-25 10:30:37 +03:00
Fringg
bef5102a71 fix: remove duplicate tariff info line, make tariff card clickable 2026-02-25 10:27:44 +03:00
Fringg
6b688ad451 refactor: rewrite dashboard components to match prototype design
- Rewrite TrafficProgressBar with multi-segment gradient fill, flex-based
  zone tints, shimmer + highlight overlays, radial glow at fill edge
- Rewrite SubscriptionCardActive with zone header, big percentage on right,
  connect device card with device dots, tariff/days-left two-column row,
  sparkline placeholder, traffic refresh controls
- Rewrite SubscriptionCardExpired with red glow, grid pattern, gradient
  renew button, outline tariffs button
- Rewrite TrialOfferCard with animated glow background, grid pattern,
  icon glow animation, price tag with old price, gradient CTA buttons
- Rewrite StatsGrid with 2x2 card layout, icon+label+chevron header,
  big value numbers, zone-colored balance/earnings cards
- Update Sparkline with color prop and last-point dot indicator
- Update useAnimatedNumber to use easeOutExpo matching prototype
- Add formatTraffic utility for MB/GB/TB unit formatting
- Add mainHex to trafficZone for inline style support
- Update animations to match prototype timing
- Add new i18n keys for redesigned components
2026-02-25 10:22:50 +03:00
Fringg
909374d369 feat: add dashboard sub-components for subscription cards and stats grid
SubscriptionCardActive with animated zone dot, traffic bar, connect button.
SubscriptionCardExpired with red theme and renewal actions.
TrialOfferCard with stats grid and free/paid activation.
StatsGrid 2x2 with font-display values and font-mono labels.
2026-02-25 10:07:57 +03:00
Fringg
eb1f788033 feat: add TrafficProgressBar and Sparkline components
TrafficProgressBar with zone tints, shimmer animation, glow dot,
threshold markers, scale labels, unlimited/compact modes, and full
ARIA support. Sparkline SVG component ready for daily usage data.
2026-02-25 10:07:49 +03:00
Fringg
d8b83ccdb8 fix: rewrite gradient border with @property CSS angle animation
Pure CSS approach: @property --border-angle + conic-gradient on border-box.
No extra elements, no overflow issues, no JS animation.
Smooth rotation via CSS Houdini custom property animation.
2026-02-25 08:48:48 +03:00
Fringg
e95db23573 fix: rewrite HoverBorderGradient with CSS rotate instead of framer-motion
Replace framer-motion gradient interpolation (buggy in TG WebView) with
pure CSS conic-gradient + transform:rotate() keyframe animation.
Transform animations are GPU-accelerated and reliable everywhere.
2026-02-25 08:44:42 +03:00
Fringg
4332c2bd25 fix: improve HoverBorderGradient visibility with accent colors and darker bg
- Use accent CSS vars for gradient (matches app theme dynamically)
- Increase gradient spot size for visible animation
- Darker inner bg (dark-900) for better contrast
- Increase blur to 3px for glow effect
2026-02-25 08:41:18 +03:00
Fringg
3fb9606fd0 feat: add HoverBorderGradient effect to key action buttons
Apply animated gradient border effect (Aceternity UI) to:
- Dashboard "Connect Devices" button
- Dashboard "Activate Trial" buttons (free and paid variants)
- Subscription page "Connect Devices" button
2026-02-25 08:37:28 +03:00
Fringg
44d88f7653 perf: prefetch background chunk on page load from localStorage cache
- Add prefetchBackground() to registry — triggers dynamic import
  without creating React component
- Call prefetch at module init in BackgroundRenderer using cached
  config from localStorage, before React renders
- Background JS chunk starts downloading immediately instead of
  waiting for Suspense to trigger lazy() import
2026-02-25 08:14:13 +03:00
Fringg
65afb29274 fix: boxes background not covering viewport
- Use 300% oversized CSS grid container instead of fixed-size flex cells
- Grid with 1fr units auto-fills the container, skew+scale covers viewport
- Simplified to flat cell array, removed SVG crosses for cleaner look
2026-02-25 07:57:56 +03:00
Fringg
f16f96e442 fix: boxes background not covering full screen
- Use original Aceternity positioning: translate(-40%,-60%) with
  -top-1/4 left-1/4 to cover viewport after skew transform
- Switch from CSS grid to flex layout matching original structure
- Add cross (+) SVG markers at grid intersections
- Use pastel color palette from original, animate opacity per cell
- Increase default rows to 20 for better coverage
2026-02-25 07:53:30 +03:00
Fringg
94ddf319bd fix: animation config not updating for users after admin change
- Remove refetchOnWindowFocus: false — allow refetch on miniapp return
- Add initialDataUpdatedAt: 0 — treat localStorage cache as stale,
  refetch immediately instead of serving cached data for 60s
- Lower staleTime to 30s
2026-02-25 07:48:49 +03:00
Fringg
79ff7412cb fix: remove gemini-effect and noise backgrounds, fix aurora animation
- Delete google-gemini-effect.tsx and noise-background.tsx
- Remove from types, registry, and backend whitelist
- Rewrite aurora: use animate-aurora directly on element instead of
  invisible pseudo-element with mix-blend-difference
2026-02-25 07:43:41 +03:00
Fringg
de97a030d2 fix: rewrite 5 broken background components from Aceternity sources
- Aurora: remove invert filter (broken on dark bg), use dark gradient directly
- Beams: use animated linearGradient positions instead of pathLength animation
- Beams Collision: add collision detection, explosion particles, AnimatePresence
- Gemini Effect: rewrite as SVG motion.path with animated pathLength (was canvas)
- Noise: change mixBlendMode from overlay to screen (overlay invisible on dark bg)
2026-02-25 07:31:16 +03:00
Fringg
1a702a68b9 feat: replace animated backgrounds with Aceternity UI system
- Add 16 animated background components (aurora, sparkles, vortex, shooting-stars,
  beams, beams-collision, gradient-animation, wavy, lines, boxes, meteors, grid,
  dots, spotlight, noise, ripple, gemini-effect)
- Add full admin BackgroundEditor with live preview, type gallery, per-type settings
- Add BackgroundRenderer with lazy loading, localStorage cache, mobile reduction
- Add input sanitization (sanitizeColor, clampNumber) across all components
- Add translations for en, ru, zh, fa locales
- Remove old Aurora (WebGL/OGL) and AnimatedBackground (CSS wave-blob)
- Remove ogl dependency, add simplex-noise
2026-02-25 07:12:59 +03:00
Fringg
874ee2682e feat: add RBAC permission system to admin cabinet frontend
- Permission store (Zustand) with wildcard matching and role level checks
- PermissionRoute guard for route-level access control
- PermissionGate component for element-level visibility
- Admin Roles page: CRUD, permission editor, role assignment
- Admin Policies page: ABAC policy management (time/IP conditions)
- Admin Audit Log page: filterable log viewer with CSV export
- AdminPanel sidebar navigation gated by permissions
- 4 locale files updated (en, ru, zh, fa) with RBAC translations
- API client module for all RBAC endpoints
2026-02-25 03:02:52 +03:00
Fringg
5a55892145 feat: add channel edit in admin, hide subscribed channels in blocking screen
- Admin panel: added Edit button on channel cards with inline edit form
  (title, link, sort order) using existing PATCH API
- Subscription screen: filter out already-subscribed channels so users
  only see what they still need to subscribe to
- Updated channelIdHint to remove @username reference (numeric only)
- Added i18n keys: edit, editing, form.save (en/ru/fa/zh)
2026-02-24 03:12:12 +03:00
Fringg
a767fe96d3 feat: add multi-channel subscription blocking UI and admin management
- Channel subscription blocking screen with per-channel status display
- Safe URL handling with protocol validation (no open redirect)
- Race-condition-safe subscription check with useRef guard
- Admin channel management page with create, toggle, delete
- Error handlers on all admin mutations with haptic feedback
- Proper type guard for channel subscription error detection
- Accessibility: aria-labels on icon-only buttons
- Localization: en, ru, zh, fa translations
2026-02-24 02:51:03 +03:00
Fringg
03ad255bf1 perf: add Zustand selectors to prevent cascading re-renders
Replace all bare useAuthStore(), useBlockingStore(), and
useSuccessNotification() calls with individual field selectors.
This prevents components from re-rendering when unrelated store
fields change.

- 21 useAuthStore usages across 20 files: individual selectors
  for 1-2 fields, useShallow for 3+ fields
- 5 useBlockingStore usages: individual selectors
- 2 useSuccessNotification usages: individual selectors
2026-02-23 17:15:30 +03:00
Fringg
860493058a perf: fix GPU-heavy CSS patterns
- Remove mix-blend-mode: overlay from body::before noise texture
  (was forcing fullscreen GPU compositing on every paint)
- Disable noise texture on mobile via display:none media query
- Replace backdrop-filter animation in backdropFadeIn/Out keyframes
  with opacity-only animation (backdrop-filter transition is expensive)
- Replace toast progress bar width animation with scaleX (GPU-composited)
- Remove redundant will-change: transform from .glass and .wave-blob
2026-02-23 17:14:57 +03:00
Fringg
9a84e13e6c perf: fix critical WebGL GPU resource leaks in Aurora
- Fix isWebglAvailable() leaking a full WebGL context on every check
  by replacing OGL Renderer with raw canvas.getContext() + loseContext()
- Add visibilitychange listener to fully stop rAF loop when tab hidden
  and restart on visibility restore (was running 24/7 in background)
- Properly destroy WebGL context on unmount via WEBGL_lose_context
  extension and gl.deleteProgram() (was only nulling JS refs)
- Reduce target FPS from 20 to 10 (slow gradient, visually identical)
2026-02-23 17:14:47 +03:00
Fringg
2b2ead837c feat: add referral code persistence across all auth methods
Mirrors campaign.ts localStorage pattern to capture ?ref= from URL and pass
referral_code to backend during Telegram Widget, OAuth, email login, and
Mini App authentication. Fixes redirect loop when email auth is disabled.
2026-02-18 23:59:32 +03:00
Fringg
96f9a719fd fix: hide empty blocks in connection installation guide
Filter out blocks with no title, description, or buttons
instead of rendering empty cards/accordions/timeline items.
2026-02-18 09:17:10 +03:00
Fringg
e0dd21fd0b feat: add web campaign links — capture, auth integration, bonus UI
- Add campaign.ts utility (capture from URL, localStorage with TTL, validation)
- Pass campaign_slug in all auth API methods (telegram, widget, email, oauth)
- Consume slug in auth store login methods, set pendingCampaignBonus state
- Add CampaignBonusNotifier component (toast on bonus, mounted in AppShell)
- Show web_link alongside bot deep_link in AdminCampaignStats
- Add CampaignBonusInfo type with union bonus_type
- Fix VerifyEmail: ref guard against StrictMode double-fire, setTimeout cleanup
- Fix AdminCampaignStats: setTimeout refs with cleanup, i18n-aware locale
- Wrap all localStorage access in try/catch (Safari private browsing safety)
- Add campaignBonus translations (ru/en/fa/zh)
2026-02-17 06:44:10 +03:00
Fringg
fc7ee6abfe fix: move cabinet_branding to sessionStorage and add WebGL availability check
- Branding cache moved from localStorage to sessionStorage so it clears
  when the mini-app is closed, preventing stale names after admin updates
- Added initialDataUpdatedAt: 0 to all branding queries so fresh data is
  always fetched on page refresh while showing cached data instantly
- One-time migration moves existing localStorage value to sessionStorage
- Aurora component now checks WebGL availability upfront, skipping all
  hooks and subscriptions when WebGL is not supported
2026-02-16 07:25:06 +03:00
Fringg
54f1483312 fix: prevent button settings cards from overflowing in admin panel
- Add flex-wrap to color picker chips so they wrap on narrow cards
- Add min-w-0/truncate to header text, shrink-0 to badge+toggle group
- Reduce chip padding for better fit in 2-column grid
- Add overflow-hidden to card container as safety net
2026-02-16 02:10:52 +03:00
Fringg
150a1b2dba fix: normalize all API responses, add error handling and reset confirmation
- Extract normalizeConfig() for consistent response normalization
- Add onError handlers to mutations with useNotify
- Add window.confirm before destructive reset action
- Add resetConfirm translation key to all locales
2026-02-13 00:41:00 +03:00
Fringg
1a0a5ff453 feat: add per-button enable/disable toggle and custom labels per locale
- Add Toggle per section card to show/hide button in main menu
- Add collapsible locale label inputs (ru, en, ua, zh, fa) per section
- Normalize server response for backward compatibility with older API
- Update all 4 locale files with new translation keys
2026-02-12 23:42:58 +03:00
Fringg
e586129c37 feat: add 'no color' option for button style customization
Adds a 'default' style option that removes color from buttons, showing
Telegram's native default style. Updates type, UI chip, preview, and
translations for all 4 locales.
2026-02-12 23:25:49 +03:00
Fringg
b2898730b9 feat: add ButtonsTab for per-section button style customization
Visual editor in admin settings for configuring Telegram button colors
and custom emoji IDs per menu section. Includes API client, draft state
management, save/reset, and translations for ru/en/fa/zh locales.
2026-02-12 23:16:08 +03:00
Fringg
dcfd362c43 refactor: replace ChangeEmailModal with inline email change flow in Profile
- Remove modal-based email change (491 lines deleted)
- Add inline step-by-step flow directly in email card (email → code → success)
- Add change email button for unverified emails (typo fix use case)
- Hide change email for OAuth users (google, yandex, discord, vk)
- Auto-focus inputs, Enter submit, animated transitions, 3s auto-close on success
2026-02-11 05:42:47 +03:00
Fringg
23f56afaf7 fix: stretch low-res Aurora canvas to fill viewport
OGL renderer.setSize() sets both the internal buffer and CSS dimensions,
so the 10% resolution canvas was only covering 10% of the screen.
Now explicitly reset canvas.style.width/height to 100% after setSize()
so the small buffer is upscaled by the browser to full viewport.
2026-02-08 17:46:23 +03:00