Move user menu outside header for iOS z-index stacking fix
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions

On iOS, elements inside a stacking context (nav-menu z-index:99) cannot
escape above it regardless of their own z-index. Move overlay and
bottom sheet to body level (after </header>) so they render on top of
everything. Close hamburger menu before opening bottom sheet on mobile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-03-25 15:44:19 +01:00
parent 362f092d5b
commit 2c5aa22ab3

View File

@ -1627,69 +1627,6 @@
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
</svg>
</button>
<div class="user-menu-overlay" id="userMenuOverlay" onclick="closeUserMenu()"></div>
<div class="user-menu" id="userMenu">
<div class="user-menu-handle"></div>
<div class="user-menu-mobile-header">
<span class="user-avatar">{{ current_user.name[:1].upper() }}</span>
<span class="user-menu-mobile-name">{{ current_user.name }}</span>
</div>
<a href="{{ url_for('dashboard') }}" class="user-menu-item">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
</svg>
Mój Panel
</a>
<a href="{{ url_for('messages_inbox') }}" class="user-menu-item user-menu-item-badge">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
</svg>
Wiadomości
<span class="user-menu-badge" id="userMenuUnreadBadge" style="display: none;">0</span>
</a>
<div class="user-menu-divider"></div>
<a href="{{ url_for('konto_dane') }}" class="user-menu-item">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
</svg>
Moje konto
</a>
{% if current_user.company_id and current_user.email == 'maciej.pienczyn@inpi.pl' %}
<a href="{{ url_for('auth.konto_integracje') }}" class="user-menu-item owner-only">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"/>
</svg>
Integracje
</a>
{% endif %}
{% if not current_user.company_id %}
<a href="{{ url_for('membership.apply') }}" class="user-menu-item" style="color: var(--primary);">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"/>
</svg>
Złóż deklarację
</a>
{% elif current_user.company and not current_user.company.nip %}
<a href="{{ url_for('membership.data_request') }}" class="user-menu-item" style="color: var(--warning);">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
</svg>
Uzupełnij dane firmy
</a>
{% endif %}
<a href="{{ url_for('release_notes') }}" class="user-menu-item">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"/>
</svg>
Co nowego
</a>
<a href="{{ url_for('logout') }}" class="user-menu-item user-menu-logout">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"/>
</svg>
Wyloguj
</a>
</div>
</li>
{% else %}
<li><a href="{{ url_for('login') }}" class="btn btn-outline btn-sm">Zaloguj</a></li>
@ -1708,6 +1645,73 @@
</div>
</header>
{% if current_user.is_authenticated %}
<!-- User menu (outside header for proper z-index stacking on iOS) -->
<div class="user-menu-overlay" id="userMenuOverlay" onclick="closeUserMenu()"></div>
<div class="user-menu" id="userMenu">
<div class="user-menu-handle"></div>
<div class="user-menu-mobile-header">
<span class="user-avatar">{{ current_user.name[:1].upper() }}</span>
<span class="user-menu-mobile-name">{{ current_user.name }}</span>
</div>
<a href="{{ url_for('dashboard') }}" class="user-menu-item">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/>
</svg>
Mój Panel
</a>
<a href="{{ url_for('messages_inbox') }}" class="user-menu-item user-menu-item-badge">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
</svg>
Wiadomości
<span class="user-menu-badge" id="userMenuUnreadBadge" style="display: none;">0</span>
</a>
<div class="user-menu-divider"></div>
<a href="{{ url_for('konto_dane') }}" class="user-menu-item">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
</svg>
Moje konto
</a>
{% if current_user.company_id and current_user.email == 'maciej.pienczyn@inpi.pl' %}
<a href="{{ url_for('auth.konto_integracje') }}" class="user-menu-item owner-only">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"/>
</svg>
Integracje
</a>
{% endif %}
{% if not current_user.company_id %}
<a href="{{ url_for('membership.apply') }}" class="user-menu-item" style="color: var(--primary);">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"/>
</svg>
Złóż deklarację
</a>
{% elif current_user.company and not current_user.company.nip %}
<a href="{{ url_for('membership.data_request') }}" class="user-menu-item" style="color: var(--warning);">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
</svg>
Uzupełnij dane firmy
</a>
{% endif %}
<a href="{{ url_for('release_notes') }}" class="user-menu-item">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"/>
</svg>
Co nowego
</a>
<a href="{{ url_for('logout') }}" class="user-menu-item user-menu-logout">
<svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"/>
</svg>
Wyloguj
</a>
</div>
{% endif %}
{% if current_user.is_authenticated and current_user.can_access_admin_panel() %}
<!-- Admin Bar -->
<div class="admin-bar">
@ -2081,18 +2085,23 @@
// User menu toggle
function toggleUserMenu(event) {
event.stopPropagation();
const userDropdown = document.querySelector('.user-dropdown');
const userMenu = document.getElementById('userMenu');
const overlay = document.getElementById('userMenuOverlay');
var userDropdown = document.querySelector('.user-dropdown');
var userMenu = document.getElementById('userMenu');
var overlay = document.getElementById('userMenuOverlay');
// Close notifications if open
const notificationsMenu = document.getElementById('notificationsMenu');
var notificationsMenu = document.getElementById('notificationsMenu');
if (notificationsMenu) notificationsMenu.classList.remove('show');
const isOpen = userMenu.classList.contains('show');
var isOpen = userMenu.classList.contains('show');
if (isOpen) {
closeUserMenu();
} else {
// On mobile: close hamburger first, then show bottom sheet
if (window.innerWidth <= 768) {
var navMenu = document.getElementById('navMenu');
if (navMenu) navMenu.classList.remove('active');
}
userDropdown.classList.add('active');
userMenu.classList.add('show');
if (overlay) overlay.classList.add('show');