nordabiz/templates/reports/membership.html
Maciej Pienczyn 6648cce3f4 fix: Naprawiono błąd 500 w raportach - url_for z company_id
Zmieniono url_for('company_detail', slug=...) na
url_for('company_detail', company_id=...) we wszystkich raportach.

Route company_detail wymaga company_id, nie slug.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 07:28:09 +01:00

325 lines
10 KiB
HTML

{% extends "base.html" %}
{% block title %}Staż członkostwa - Raporty - Norda Biznes Hub{% endblock %}
{% block extra_css %}
<style>
.report-header {
margin-bottom: var(--spacing-xl);
}
.report-header .back-link {
display: inline-flex;
align-items: center;
gap: var(--spacing-xs);
color: var(--text-secondary);
text-decoration: none;
font-size: var(--font-size-sm);
margin-bottom: var(--spacing-md);
}
.report-header .back-link:hover {
color: var(--primary);
}
.report-header h1 {
font-size: var(--font-size-3xl);
color: var(--text-primary);
display: flex;
align-items: center;
gap: var(--spacing-md);
}
.report-header h1 span {
font-size: 2rem;
}
.report-meta {
background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
border: 1px solid #86efac;
border-radius: var(--radius-lg);
padding: var(--spacing-lg);
margin-bottom: var(--spacing-xl);
}
.report-meta-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: var(--spacing-md);
}
.report-meta-item {
display: flex;
align-items: center;
gap: var(--spacing-sm);
font-size: var(--font-size-sm);
color: #166534;
}
.report-meta-item svg {
width: 16px;
height: 16px;
flex-shrink: 0;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: var(--spacing-lg);
margin-bottom: var(--spacing-xl);
}
.stat-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: var(--spacing-lg);
text-align: center;
}
.stat-card.highlight {
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
border-color: #fbbf24;
}
.stat-icon {
font-size: 1.5rem;
margin-bottom: var(--spacing-sm);
}
.stat-value {
font-size: var(--font-size-2xl);
font-weight: 700;
color: var(--text-primary);
}
.stat-label {
font-size: var(--font-size-sm);
color: var(--text-secondary);
margin-top: var(--spacing-xs);
}
.stat-detail {
font-size: var(--font-size-xs);
color: var(--text-muted, #9ca3af);
margin-top: var(--spacing-xs);
}
.data-table-container {
background: var(--surface);
border-radius: var(--radius-lg);
overflow: hidden;
box-shadow: var(--shadow);
}
.data-table {
width: 100%;
border-collapse: collapse;
}
.data-table th,
.data-table td {
padding: var(--spacing-md);
text-align: left;
border-bottom: 1px solid var(--border);
}
.data-table th {
background: var(--background);
font-weight: 600;
font-size: var(--font-size-sm);
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.data-table tbody tr:hover {
background: var(--background);
}
.data-table tbody tr:last-child td {
border-bottom: none;
}
.company-link {
color: var(--primary);
text-decoration: none;
font-weight: 500;
}
.company-link:hover {
text-decoration: underline;
}
.years-badge {
display: inline-block;
background: var(--primary);
color: white;
padding: var(--spacing-xs) var(--spacing-sm);
border-radius: var(--radius);
font-size: var(--font-size-sm);
font-weight: 500;
min-width: 60px;
text-align: center;
}
.years-badge.veteran {
background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
}
.years-badge.senior {
background: linear-gradient(135deg, #a855f7 0%, #9333ea 100%);
}
.years-badge.regular {
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
}
.years-badge.new {
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
}
.category-badge {
display: inline-block;
background: var(--background);
color: var(--text-secondary);
padding: var(--spacing-xs) var(--spacing-sm);
border-radius: var(--radius);
font-size: var(--font-size-xs);
}
.row-number {
color: var(--text-muted, #9ca3af);
font-size: var(--font-size-sm);
width: 40px;
}
@media (max-width: 768px) {
.data-table-container {
overflow-x: auto;
}
.data-table {
min-width: 600px;
}
}
</style>
{% endblock %}
{% block content %}
<div class="container">
<div class="report-header">
<a href="{{ url_for('reports_index') }}" 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="M15 19l-7-7 7-7"/>
</svg>
Powrót do raportów
</a>
<h1><span>&#x1F3C6;</span> Staż członkostwa w Izbie NORDA</h1>
</div>
<div class="report-meta">
<div class="report-meta-grid">
<div class="report-meta-item">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>
</svg>
<span>Wygenerowano: {{ generated_at.strftime('%d.%m.%Y, %H:%M:%S') }}</span>
</div>
<div class="report-meta-item">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4"/>
</svg>
<span>Źródło: baza danych nordabiznes.pl</span>
</div>
<div class="report-meta-item">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"/>
</svg>
<span>Firm w raporcie: {{ stats.total_with_date }}</span>
</div>
</div>
</div>
<div class="stats-grid">
<div class="stat-card highlight">
<div class="stat-icon">&#x1F451;</div>
<div class="stat-value">{{ stats.oldest.name if stats.oldest else '-' }}</div>
<div class="stat-label">Najstarszy członek</div>
<div class="stat-detail">
{% if stats.oldest %}
od {{ stats.oldest.member_since.strftime('%d.%m.%Y') }} ({{ stats.oldest.membership_years }} lat)
{% endif %}
</div>
</div>
<div class="stat-card">
<div class="stat-icon">&#x1F195;</div>
<div class="stat-value">{{ stats.newest.name if stats.newest else '-' }}</div>
<div class="stat-label">Najnowszy członek</div>
<div class="stat-detail">
{% if stats.newest %}
od {{ stats.newest.member_since.strftime('%d.%m.%Y') }}
{% endif %}
</div>
</div>
<div class="stat-card">
<div class="stat-icon">&#x1F4CA;</div>
<div class="stat-value">{{ "%.1f"|format(stats.avg_years) }} lat</div>
<div class="stat-label">Średni staż</div>
<div class="stat-detail">wszystkich członków</div>
</div>
<div class="stat-card">
<div class="stat-icon">&#x2753;</div>
<div class="stat-value">{{ stats.total_without_date }}</div>
<div class="stat-label">Bez daty</div>
<div class="stat-detail">firmy do uzupełnienia</div>
</div>
</div>
<div class="data-table-container">
<table class="data-table">
<thead>
<tr>
<th>#</th>
<th>Firma</th>
<th>Data przystąpienia</th>
<th>Staż</th>
<th>Kategoria</th>
</tr>
</thead>
<tbody>
{% for company in companies %}
<tr>
<td class="row-number">{{ loop.index }}</td>
<td>
<a href="{{ url_for('company_detail', company_id=company.id) }}" class="company-link">
{{ company.name }}
</a>
</td>
<td>{{ company.member_since.strftime('%d.%m.%Y') }}</td>
<td>
{% if company.membership_years >= 20 %}
<span class="years-badge veteran">{{ company.membership_years }} lat</span>
{% elif company.membership_years >= 10 %}
<span class="years-badge senior">{{ company.membership_years }} lat</span>
{% elif company.membership_years >= 5 %}
<span class="years-badge regular">{{ company.membership_years }} lat</span>
{% else %}
<span class="years-badge new">{{ company.membership_years }} lat</span>
{% endif %}
</td>
<td>
{% if company.category %}
<span class="category-badge">{{ company.category }}</span>
{% else %}
<span class="category-badge">-</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}