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
Production moved from on-prem VM 249 (10.22.68.249) to OVH VPS (57.128.200.27, inpi-vps-waw01). Updated ALL documentation, slash commands, memory files, architecture docs, and deploy procedures. Added |local_time Jinja filter (UTC→Europe/Warsaw) and converted 155 .strftime() calls across 71 templates so timestamps display in Polish timezone regardless of server timezone. Also includes: created_by_id tracking, abort import fix, ICS calendar fix for missing end times, Pros Poland data cleanup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
390 lines
12 KiB
HTML
390 lines
12 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Pokrycie Social Media - Raporty - Norda Biznes Partner{% 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(180px, 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, #dbeafe 0%, #bfdbfe 100%);
|
|
border-color: #3b82f6;
|
|
}
|
|
|
|
.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);
|
|
}
|
|
|
|
.section-title {
|
|
font-size: var(--font-size-xl);
|
|
font-weight: 600;
|
|
color: var(--text-primary);
|
|
margin-bottom: var(--spacing-lg);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-sm);
|
|
}
|
|
|
|
.platforms-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
gap: var(--spacing-md);
|
|
margin-bottom: var(--spacing-2xl);
|
|
}
|
|
|
|
.platform-card {
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-lg);
|
|
padding: var(--spacing-lg);
|
|
text-align: center;
|
|
}
|
|
|
|
.platform-icon {
|
|
font-size: 2rem;
|
|
margin-bottom: var(--spacing-sm);
|
|
}
|
|
|
|
.platform-name {
|
|
font-weight: 600;
|
|
color: var(--text-primary);
|
|
margin-bottom: var(--spacing-xs);
|
|
text-transform: capitalize;
|
|
}
|
|
|
|
.platform-count {
|
|
font-size: var(--font-size-2xl);
|
|
font-weight: 700;
|
|
color: var(--primary);
|
|
}
|
|
|
|
.platform-percent {
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.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 th.platform-col {
|
|
text-align: center;
|
|
width: 50px;
|
|
}
|
|
|
|
.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;
|
|
}
|
|
|
|
.check-icon {
|
|
display: inline-flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 24px;
|
|
height: 24px;
|
|
border-radius: 50%;
|
|
font-size: var(--font-size-sm);
|
|
}
|
|
|
|
.check-icon.has {
|
|
background: #dcfce7;
|
|
color: #16a34a;
|
|
}
|
|
|
|
.check-icon.missing {
|
|
background: #fee2e2;
|
|
color: #dc2626;
|
|
}
|
|
|
|
.platform-cell {
|
|
text-align: center;
|
|
}
|
|
|
|
.total-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: 30px;
|
|
text-align: center;
|
|
}
|
|
|
|
.total-badge.high {
|
|
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
|
}
|
|
|
|
.total-badge.medium {
|
|
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
|
|
}
|
|
|
|
.total-badge.low {
|
|
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
|
|
}
|
|
|
|
.total-badge.none {
|
|
background: var(--secondary);
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.data-table-container {
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.data-table {
|
|
min-width: 700px;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container">
|
|
<div class="report-header">
|
|
<a href="{{ url_for('reports.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>📱</span> Pokrycie Social Media</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|local_time('%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_companies }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="stats-grid">
|
|
<div class="stat-card highlight">
|
|
<div class="stat-icon">✅</div>
|
|
<div class="stat-value">{{ stats.with_social }}</div>
|
|
<div class="stat-label">Firmy z Social Media</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-icon">❌</div>
|
|
<div class="stat-value">{{ stats.without_social }}</div>
|
|
<div class="stat-label">Bez Social Media</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-icon">📈</div>
|
|
<div class="stat-value">{{ stats.coverage_percent }}%</div>
|
|
<div class="stat-label">Pokrycie</div>
|
|
</div>
|
|
</div>
|
|
|
|
<h2 class="section-title">📊 Statystyki platform</h2>
|
|
<div class="platforms-grid">
|
|
{% for platform in platforms %}
|
|
<div class="platform-card">
|
|
<div class="platform-icon">
|
|
{% if platform == 'facebook' %}📘
|
|
{% elif platform == 'instagram' %}📷
|
|
{% elif platform == 'linkedin' %}💼
|
|
{% elif platform == 'youtube' %}📺
|
|
{% elif platform == 'tiktok' %}🎵
|
|
{% elif platform == 'twitter' %}🐦
|
|
{% endif %}
|
|
</div>
|
|
<div class="platform-name">{{ platform }}</div>
|
|
<div class="platform-count">{{ platform_stats[platform].count }}</div>
|
|
<div class="platform-percent">{{ platform_stats[platform].percent }}%</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
|
|
<h2 class="section-title">📋 Szczegółowa tabela</h2>
|
|
<div class="data-table-container">
|
|
<table class="data-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Firma</th>
|
|
<th class="platform-col" title="Facebook">FB</th>
|
|
<th class="platform-col" title="Instagram">IG</th>
|
|
<th class="platform-col" title="LinkedIn">LI</th>
|
|
<th class="platform-col" title="YouTube">YT</th>
|
|
<th class="platform-col" title="TikTok">TT</th>
|
|
<th class="platform-col" title="Twitter/X">X</th>
|
|
<th>Razem</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for company in companies %}
|
|
{% set profile_count = company.social_media_profiles|length %}
|
|
<tr>
|
|
<td>
|
|
<a href="{{ url_for('company_detail', company_id=company.id) }}" class="company-link">
|
|
{{ company.name }}
|
|
</a>
|
|
</td>
|
|
{% for platform in platforms %}
|
|
<td class="platform-cell">
|
|
{% set has_platform = company.social_media_profiles|selectattr('platform', 'equalto', platform)|list|length > 0 %}
|
|
{% if has_platform %}
|
|
<span class="check-icon has">✓</span>
|
|
{% else %}
|
|
<span class="check-icon missing">✗</span>
|
|
{% endif %}
|
|
</td>
|
|
{% endfor %}
|
|
<td>
|
|
{% if profile_count >= 4 %}
|
|
<span class="total-badge high">{{ profile_count }}</span>
|
|
{% elif profile_count >= 2 %}
|
|
<span class="total-badge medium">{{ profile_count }}</span>
|
|
{% elif profile_count == 1 %}
|
|
<span class="total-badge low">{{ profile_count }}</span>
|
|
{% else %}
|
|
<span class="total-badge none">0</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|