nordabiz/templates/user_profile.html
Maciej Pienczyn 51bd9f25dc
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
feat: company dropdown on user profile for multi-company users
- "Profil firmy" button becomes a dropdown listing all companies
- Subtitle under name shows all companies separated by dots
- Single-company users see no changes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:25:29 +02:00

347 lines
13 KiB
HTML

{% extends "base.html" %}
{% block title %}{{ profile_user.name or 'Użytkownik' }} - Norda Biznes Partner{% endblock %}
{% block extra_css %}
<style>
.profile-header {
background: white;
padding: var(--spacing-2xl);
border-radius: var(--radius-xl);
box-shadow: var(--shadow-lg);
margin-bottom: var(--spacing-xl);
}
.profile-avatar {
width: 120px;
height: 120px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 48px;
color: white;
font-weight: 600;
margin-bottom: var(--spacing-lg);
overflow: hidden;
}
.profile-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.profile-name {
font-size: var(--font-size-3xl);
color: var(--text-primary);
margin-bottom: var(--spacing-sm);
}
.profile-subtitle {
font-size: var(--font-size-lg);
color: var(--text-secondary);
margin-bottom: var(--spacing-lg);
}
.profile-section {
background: white;
padding: var(--spacing-xl);
border-radius: var(--radius-xl);
box-shadow: var(--shadow);
margin-bottom: var(--spacing-xl);
}
.section-title {
font-size: var(--font-size-xl);
color: var(--text-primary);
margin-bottom: var(--spacing-lg);
padding-bottom: var(--spacing-md);
border-bottom: 2px solid var(--border);
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.section-title svg {
width: 22px;
height: 22px;
color: var(--primary);
}
.contact-actions {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-sm);
margin-top: var(--spacing-lg);
}
.contact-btn {
display: inline-flex;
align-items: center;
gap: var(--spacing-xs);
padding: var(--spacing-sm) var(--spacing-lg);
border-radius: var(--radius);
text-decoration: none;
font-weight: 500;
font-size: var(--font-size-sm);
transition: var(--transition);
}
.contact-btn.primary {
background: var(--primary);
color: white;
}
.contact-btn.primary:hover {
background: #1d4ed8;
}
.contact-btn.secondary {
background: var(--background);
color: var(--text-primary);
border: 1px solid var(--border);
}
.contact-btn.secondary:hover {
border-color: var(--primary);
color: var(--primary);
}
.contact-btn svg {
width: 16px;
height: 16px;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: var(--spacing-md);
margin-bottom: var(--spacing-lg);
}
.stat-card {
background: var(--background);
border-radius: var(--radius-lg);
padding: var(--spacing-lg);
text-align: center;
}
.stat-card .stat-value {
font-size: var(--font-size-2xl);
font-weight: 700;
color: var(--primary);
}
.stat-card .stat-label {
font-size: var(--font-size-sm);
color: var(--text-secondary);
margin-top: var(--spacing-xs);
}
.event-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--spacing-sm) var(--spacing-md);
background: var(--background);
border-radius: var(--radius);
margin-bottom: var(--spacing-xs);
text-decoration: none;
color: var(--text-primary);
transition: var(--transition);
}
.event-item:hover {
background: #e0e7ff;
}
.event-item .event-date {
font-size: var(--font-size-sm);
color: var(--text-secondary);
white-space: nowrap;
}
.company-badge {
display: inline-flex;
align-items: center;
gap: var(--spacing-xs);
padding: var(--spacing-xs) var(--spacing-md);
background: #fee2e2;
color: #991b1b;
border-radius: var(--radius);
font-weight: 500;
font-size: var(--font-size-sm);
text-decoration: none;
transition: var(--transition);
}
.company-badge:hover {
background: #fecaca;
}
.company-badge svg {
width: 14px;
height: 14px;
}
.back-link {
display: inline-flex;
align-items: center;
gap: var(--spacing-xs);
color: var(--text-secondary);
text-decoration: none;
margin-bottom: var(--spacing-lg);
}
.back-link:hover {
color: var(--primary);
}
</style>
{% endblock %}
{% block content %}
<a href="#" onclick="history.back(); return false;" class="back-link">
<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="M10 19l-7-7m0 0l7-7m-7 7h18"/>
</svg>
Wstecz
</a>
<div class="profile-header">
<div class="profile-avatar">
{% if profile_user.avatar_path %}
<img src="{{ url_for('static', filename=profile_user.avatar_path) }}" alt="{{ profile_user.name }}">
{% else %}
{{ (profile_user.name or profile_user.email)[0].upper() }}{{ (profile_user.name or '').split()[-1][0].upper() if (profile_user.name or '').split()|length > 1 else '' }}
{% endif %}
</div>
<h1 class="profile-name">
{{ profile_user.name or 'Użytkownik' }}
{% if profile_user.chamber_role in ('prezes', 'wiceprezes') %}
<span style="display:inline-block;background:{{ '#fef3c7' if profile_user.chamber_role == 'prezes' else '#dbeafe' }};color:{{ '#92400e' if profile_user.chamber_role == 'prezes' else '#1d4ed8' }};font-size:12px;padding:3px 10px;border-radius:20px;font-weight:600;vertical-align:middle;margin-left:8px;">{{ profile_user.chamber_role_label }}</span>
{% endif %}
{% if profile_user.chamber_role in ('komisja_rewizyjna', 'sad_kolezenski') %}
<span style="display:inline-block;background:{{ '#f3e8ff' if profile_user.chamber_role == 'komisja_rewizyjna' else '#f3f4f6' }};color:{{ '#6b21a8' if profile_user.chamber_role == 'komisja_rewizyjna' else '#4b5563' }};font-size:12px;padding:3px 10px;border-radius:20px;font-weight:600;vertical-align:middle;margin-left:8px;">{{ profile_user.chamber_role_label }}</span>
{% endif %}
{% if profile_user.is_rada_member %}
<span style="display:inline-block;background:#ecfdf5;color:#065f46;font-size:12px;padding:3px 10px;border-radius:20px;font-weight:600;vertical-align:middle;margin-left:8px;">Rada Izby</span>
{% endif %}
</h1>
<p class="profile-subtitle">
{% if user_companies and user_companies|length > 1 %}
{{ user_companies|map(attribute='company')|selectattr('name')|map(attribute='name')|join(' · ') }}
{% elif profile_user.company %}
{{ profile_user.company.name }}
{% else %}
Członek portalu Norda Biznes
{% endif %}
{% if last_active_label %}
<span style="display:inline-block;margin-left:12px;padding:2px 10px;background:#ecfdf5;color:#166534;border-radius:12px;font-size:var(--font-size-sm);">{{ last_active_label }}</span>
{% endif %}
</p>
{% if current_user.is_authenticated and current_user.id != profile_user.id %}
<div class="contact-actions">
<a href="{{ url_for('messages.messages_new', to=profile_user.id) }}" class="contact-btn primary">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path 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>
Wyślij wiadomość prywatną na portalu
</a>
{% if user_companies and user_companies|length > 1 %}
<div style="position:relative;display:inline-block;">
<button class="contact-btn secondary" onclick="this.nextElementSibling.style.display = this.nextElementSibling.style.display === 'block' ? 'none' : 'block';" type="button">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path d="M19 21V5a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v5m-4 0h4"/>
</svg>
Profil firmy ▾
</button>
<div style="display:none;position:absolute;top:100%;left:0;margin-top:4px;background:var(--bg-primary);border:1px solid var(--border);border-radius:var(--radius);box-shadow:0 4px 12px rgba(0,0,0,0.15);min-width:220px;z-index:100;overflow:hidden;">
{% for uc in user_companies %}
{% if uc.company %}
<a href="{{ url_for('company_detail_by_slug', slug=uc.company.slug) }}" style="display:block;padding:10px 14px;color:var(--text-primary);text-decoration:none;font-size:14px;border-bottom:1px solid var(--border-light);">
{{ uc.company.name }}
</a>
{% endif %}
{% endfor %}
</div>
</div>
{% elif profile_user.company %}
<a href="{{ url_for('company_detail_by_slug', slug=profile_user.company.slug) }}" class="contact-btn secondary">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path d="M19 21V5a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v5m-4 0h4"/>
</svg>
Profil firmy
</a>
{% endif %}
</div>
{% endif %}
</div>
{% if attended_events or forum_topics_count > 0 or forum_replies_count > 0 %}
<div class="profile-section">
<h2 class="section-title">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path d="M13 10V3L4 14h7v7l9-11h-7z"/>
</svg>
Aktywność na portalu
</h2>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-value">{{ forum_topics_count }}</div>
<div class="stat-label">temat{{ 'ów' if forum_topics_count != 1 else '' }} na forum</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ forum_replies_count }}</div>
<div class="stat-label">odpowiedzi</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ attended_events|length }}</div>
<div class="stat-label">wydarzeń</div>
</div>
</div>
{% if attended_events %}
<div style="font-weight: 600; font-size: var(--font-size-sm); color: var(--text-secondary); margin-bottom: var(--spacing-sm);">Zapisany na wydarzenia:</div>
{% for event in attended_events %}
<a href="{{ url_for('calendar.calendar_event', event_id=event.id) }}" class="event-item">
<span>
<svg width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" style="vertical-align:-2px;margin-right:4px;">
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/>
</svg>
{{ event.title }}
</span>
<span class="event-date">{{ event.event_date.strftime('%d.%m.%Y') }}</span>
</a>
{% endfor %}
{% endif %}
</div>
{% endif %}
{% if user_companies %}
<div class="profile-section">
<h2 class="section-title">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path d="M19 21V5a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v5m-4 0h4"/>
</svg>
Powiązane firmy
</h2>
<div style="display:flex;flex-wrap:wrap;gap:var(--spacing-sm);">
{% for uc in user_companies %}
{% if uc.company %}
<a href="{{ url_for('company_detail_by_slug', slug=uc.company.slug) }}" class="company-badge">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path d="M19 21V5a2 2 0 0 0-2-2H7a2 2 0 0 0-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v5m-4 0h4"/>
</svg>
{{ uc.company.name }} ({{ uc.role.value if uc.role else 'członek' }})
</a>
{% endif %}
{% endfor %}
</div>
</div>
{% endif %}
{% endblock %}