fix: adapt referral network for Telegram MiniApp safe areas

- Extract useHeaderHeight() hook — single source of truth for header
  height across AppShell, ReferralNetwork, and TicketNotificationBell
- Portal top offset now computed dynamically from TG safe area insets
  instead of hardcoded top-16 (fixes overlap with TG header bar)
- Two-row mobile layout: title + selector on separate rows so dropdown
  gets full width on small screens
- Add MOBILE_HEADER_HEIGHT_PX and DESKTOP_HEADER_HEIGHT_PX to constants
- Fix TicketNotificationBell using hardcoded 45px for all platforms
This commit is contained in:
Fringg
2026-03-20 04:23:45 +03:00
parent 2780898d1c
commit 33486a09d0
5 changed files with 47 additions and 26 deletions

View File

@@ -6,7 +6,7 @@ import { ticketNotificationsApi } from '../api/ticketNotifications';
import { useAuthStore } from '../store/auth';
import { useToast } from './Toast';
import { useWebSocket, WSMessage } from '../hooks/useWebSocket';
import { useTelegramSDK } from '../hooks/useTelegramSDK';
import { useHeaderHeight } from '../hooks/useHeaderHeight';
import type { TicketNotification } from '../types';
const BellIcon = () => (
@@ -37,12 +37,7 @@ export default function TicketNotificationBell({ isAdmin = false }: TicketNotifi
const { showToast } = useToast();
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
const { isFullscreen, safeAreaInset, contentSafeAreaInset } = useTelegramSDK();
// Calculate dropdown top position (account for fullscreen safe area + TG buttons)
const dropdownTop = isFullscreen
? Math.max(safeAreaInset.top, contentSafeAreaInset.top) + 45 + 64 // safe area + TG buttons + header
: 64; // default header height
const { mobile: dropdownTop } = useHeaderHeight();
// Show toast for WebSocket notification
const showWSNotificationToast = useCallback(
@@ -259,10 +254,8 @@ export default function TicketNotificationBell({ isAdmin = false }: TicketNotifi
{/* Dropdown */}
{isOpen && (
<div
className={`fixed left-4 right-4 z-50 mt-0 w-auto animate-scale-in overflow-hidden rounded-2xl border border-dark-700/50 bg-dark-900/95 shadow-2xl shadow-black/30 backdrop-blur-xl sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:mt-2 sm:w-96 ${
!isFullscreen ? 'top-16' : ''
}`}
style={isFullscreen ? { top: `${dropdownTop}px` } : undefined}
className="fixed left-4 right-4 z-50 mt-0 w-auto animate-scale-in overflow-hidden rounded-2xl border border-dark-700/50 bg-dark-900/95 shadow-2xl shadow-black/30 backdrop-blur-xl sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:mt-2 sm:w-96"
style={{ top: dropdownTop }}
>
{/* Header */}
<div className="flex items-center justify-between border-b border-dark-700/50 bg-dark-800/30 px-4 py-3">