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>
1379 lines
58 KiB
HTML
1379 lines
58 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}{{ company.name }} - Panel Admin{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
.detail-header {
|
|
margin-bottom: var(--spacing-xl);
|
|
}
|
|
|
|
.breadcrumb {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-xs);
|
|
margin-bottom: var(--spacing-sm);
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.breadcrumb a {
|
|
color: var(--primary);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.breadcrumb a:hover { text-decoration: underline; }
|
|
|
|
.breadcrumb svg {
|
|
width: 14px;
|
|
height: 14px;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.header-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
gap: var(--spacing-md);
|
|
}
|
|
|
|
.header-row h1 {
|
|
font-size: var(--font-size-3xl);
|
|
color: var(--text-primary);
|
|
margin: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-sm);
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.header-actions {
|
|
display: flex;
|
|
gap: var(--spacing-sm);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.btn-link {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: var(--spacing-xs);
|
|
padding: var(--spacing-sm) var(--spacing-lg);
|
|
border-radius: var(--radius);
|
|
font-size: var(--font-size-sm);
|
|
font-weight: 500;
|
|
text-decoration: none;
|
|
transition: var(--transition);
|
|
border: 1px solid var(--border);
|
|
background: var(--surface);
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.btn-link:hover { background: var(--background); }
|
|
.btn-link svg { width: 16px; height: 16px; }
|
|
|
|
.badge {
|
|
display: inline-block;
|
|
padding: 2px 8px;
|
|
border-radius: 4px;
|
|
font-size: 0.75rem;
|
|
font-weight: 500;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.badge-active { background: #D1FAE5; color: #065F46; }
|
|
.badge-pending { background: #FEF3C7; color: #92400E; }
|
|
.badge-inactive { background: #E5E7EB; color: #374151; }
|
|
.badge-archived { background: #FEE2E2; color: #991B1B; }
|
|
|
|
.stats-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
gap: var(--spacing-lg);
|
|
margin-bottom: var(--spacing-xl);
|
|
}
|
|
|
|
.stat-card {
|
|
background: var(--surface);
|
|
padding: var(--spacing-lg);
|
|
border-radius: var(--radius-lg);
|
|
box-shadow: var(--shadow);
|
|
text-align: center;
|
|
}
|
|
|
|
.stat-value {
|
|
font-size: var(--font-size-3xl);
|
|
font-weight: 700;
|
|
color: var(--primary);
|
|
}
|
|
|
|
.stat-label {
|
|
color: var(--text-secondary);
|
|
font-size: var(--font-size-sm);
|
|
margin-top: var(--spacing-xs);
|
|
}
|
|
|
|
.progress-bar-wrap {
|
|
width: 100%;
|
|
height: 8px;
|
|
background: var(--border);
|
|
border-radius: 4px;
|
|
margin-top: var(--spacing-sm);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.progress-bar-fill {
|
|
height: 100%;
|
|
border-radius: 4px;
|
|
transition: width 0.3s ease;
|
|
}
|
|
|
|
.section {
|
|
background: var(--surface);
|
|
padding: var(--spacing-xl);
|
|
border-radius: var(--radius-lg);
|
|
box-shadow: var(--shadow);
|
|
margin-bottom: var(--spacing-xl);
|
|
}
|
|
|
|
.section h2 {
|
|
font-size: var(--font-size-xl);
|
|
margin-bottom: var(--spacing-lg);
|
|
color: var(--text-primary);
|
|
border-bottom: 2px solid var(--border);
|
|
padding-bottom: var(--spacing-sm);
|
|
}
|
|
|
|
.info-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: var(--spacing-xl);
|
|
}
|
|
|
|
.info-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-md);
|
|
margin-bottom: var(--spacing-lg);
|
|
}
|
|
|
|
.logo-box {
|
|
width: 80px;
|
|
height: 80px;
|
|
border-radius: var(--radius-lg);
|
|
overflow: hidden;
|
|
flex-shrink: 0;
|
|
background: var(--background);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border: 1px solid var(--border);
|
|
}
|
|
|
|
.logo-box.dark-bg {
|
|
background: #1a1a2e;
|
|
border-color: #2d2d44;
|
|
}
|
|
|
|
.logo-box img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: contain;
|
|
}
|
|
|
|
.logo-box svg {
|
|
width: 32px;
|
|
height: 32px;
|
|
color: var(--text-secondary);
|
|
opacity: 0.4;
|
|
}
|
|
|
|
.info-field {
|
|
margin-bottom: var(--spacing-md);
|
|
}
|
|
|
|
.info-label {
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-secondary);
|
|
margin-bottom: 2px;
|
|
}
|
|
|
|
.info-value {
|
|
color: var(--text-primary);
|
|
word-break: break-word;
|
|
}
|
|
|
|
.info-value a {
|
|
color: var(--primary);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.info-value a:hover { text-decoration: underline; }
|
|
|
|
.info-empty { color: var(--text-secondary); opacity: 0.5; }
|
|
|
|
/* Workflow section */
|
|
.master-btn-wrap {
|
|
margin-bottom: var(--spacing-lg);
|
|
display: flex;
|
|
gap: var(--spacing-md);
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.btn-master {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: var(--spacing-sm);
|
|
padding: var(--spacing-md) var(--spacing-xl);
|
|
background: linear-gradient(135deg, var(--primary), var(--primary-light));
|
|
color: white;
|
|
border: none;
|
|
border-radius: var(--radius-lg);
|
|
font-size: var(--font-size-lg);
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: var(--transition);
|
|
box-shadow: var(--shadow-md);
|
|
}
|
|
|
|
.btn-master.btn-refresh {
|
|
background: linear-gradient(135deg, var(--warning, #f59e0b), #fbbf24);
|
|
font-size: var(--font-size-base);
|
|
}
|
|
|
|
.btn-master:hover { opacity: 0.9; box-shadow: var(--shadow-lg); }
|
|
.btn-master:disabled { opacity: 0.6; cursor: not-allowed; }
|
|
.btn-master svg { width: 22px; height: 22px; }
|
|
|
|
.actions-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
gap: var(--spacing-lg);
|
|
}
|
|
|
|
.action-card {
|
|
background: var(--surface);
|
|
padding: var(--spacing-lg);
|
|
border-radius: var(--radius-lg);
|
|
box-shadow: var(--shadow);
|
|
border-left: 4px solid var(--border);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--spacing-sm);
|
|
}
|
|
|
|
.action-card.done { border-left-color: var(--success); }
|
|
|
|
.action-card-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-sm);
|
|
}
|
|
|
|
.step-number {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 24px;
|
|
height: 24px;
|
|
border-radius: 50%;
|
|
background: var(--primary);
|
|
color: #fff;
|
|
font-size: 13px;
|
|
font-weight: 700;
|
|
flex-shrink: 0;
|
|
line-height: 1;
|
|
}
|
|
|
|
.action-card.done .step-number {
|
|
background: var(--success);
|
|
}
|
|
|
|
.action-card-header svg {
|
|
width: 20px;
|
|
height: 20px;
|
|
color: var(--primary);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.action-card-header h3 {
|
|
font-size: var(--font-size-base);
|
|
color: var(--text-primary);
|
|
margin: 0;
|
|
}
|
|
|
|
.action-status {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-xs);
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.status-dot {
|
|
width: 10px;
|
|
height: 10px;
|
|
border-radius: 50%;
|
|
display: inline-block;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.status-dot.green { background: var(--success); }
|
|
.status-dot.gray { background: var(--border); }
|
|
|
|
.action-score {
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.btn-action {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: var(--spacing-xs);
|
|
padding: var(--spacing-sm) var(--spacing-md);
|
|
background: var(--primary);
|
|
color: white;
|
|
border: none;
|
|
border-radius: var(--radius);
|
|
font-size: var(--font-size-sm);
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: var(--transition);
|
|
margin-top: auto;
|
|
}
|
|
|
|
.btn-action:hover { opacity: 0.9; }
|
|
.btn-action:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
.btn-action svg { width: 16px; height: 16px; }
|
|
|
|
.spinner {
|
|
display: inline-block;
|
|
width: 14px;
|
|
height: 14px;
|
|
border: 2px solid rgba(255,255,255,0.3);
|
|
border-top-color: white;
|
|
border-radius: 50%;
|
|
animation: spin 0.6s linear infinite;
|
|
}
|
|
|
|
@keyframes spin {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
/* Logo candidates gallery */
|
|
.logo-candidates {
|
|
margin-top: var(--spacing-sm);
|
|
padding-top: var(--spacing-sm);
|
|
border-top: 1px solid var(--border);
|
|
}
|
|
|
|
.logo-candidates-label {
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-secondary);
|
|
margin-bottom: var(--spacing-sm);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.logo-candidates-grid {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--spacing-sm);
|
|
}
|
|
|
|
.logo-candidate {
|
|
position: relative;
|
|
width: 80px;
|
|
height: 80px;
|
|
border: 2px solid var(--border);
|
|
border-radius: var(--radius);
|
|
overflow: hidden;
|
|
cursor: pointer;
|
|
transition: var(--transition);
|
|
background: #f8f8f8;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.logo-candidate:hover { border-color: var(--primary); transform: scale(1.05); }
|
|
.logo-candidate.recommended { border-color: var(--success); border-width: 3px; }
|
|
|
|
.logo-candidate img {
|
|
max-width: 100%;
|
|
max-height: 100%;
|
|
object-fit: contain;
|
|
}
|
|
|
|
.logo-candidate-badge {
|
|
position: absolute;
|
|
top: 2px;
|
|
right: 2px;
|
|
background: var(--success);
|
|
color: white;
|
|
font-size: 9px;
|
|
padding: 1px 4px;
|
|
border-radius: 3px;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.logo-candidate-info {
|
|
font-size: 10px;
|
|
color: var(--text-secondary);
|
|
text-align: center;
|
|
margin-top: 2px;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
max-width: 80px;
|
|
}
|
|
|
|
.logo-candidate-wrapper {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
.logo-cancel-btn {
|
|
margin-top: var(--spacing-sm);
|
|
padding: var(--spacing-xs) var(--spacing-sm);
|
|
background: none;
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-secondary);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.logo-cancel-btn:hover { background: var(--surface); }
|
|
|
|
/* Completeness checklist */
|
|
.checklist-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: var(--spacing-xs) var(--spacing-xl);
|
|
}
|
|
|
|
.checklist-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-sm);
|
|
padding: var(--spacing-sm) 0;
|
|
border-bottom: 1px solid var(--border);
|
|
font-size: var(--font-size-sm);
|
|
}
|
|
|
|
.checklist-item svg {
|
|
width: 18px;
|
|
height: 18px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.check-ok { color: var(--success); }
|
|
.check-missing { color: var(--error); }
|
|
|
|
.hint-apply-btn {
|
|
padding: 1px 8px;
|
|
font-size: var(--font-size-xs);
|
|
background: var(--primary);
|
|
color: white;
|
|
border: none;
|
|
border-radius: var(--radius);
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
}
|
|
.hint-apply-btn:hover { opacity: 0.9; }
|
|
|
|
/* Toast */
|
|
.toast-container {
|
|
position: fixed;
|
|
top: 20px;
|
|
right: 20px;
|
|
z-index: 2000;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10px;
|
|
}
|
|
|
|
.toast {
|
|
background: var(--surface);
|
|
padding: var(--spacing-md) var(--spacing-lg);
|
|
border-radius: var(--radius-lg);
|
|
box-shadow: var(--shadow-lg);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-sm);
|
|
min-width: 280px;
|
|
max-width: 400px;
|
|
animation: slideIn 0.3s ease;
|
|
border-left: 4px solid var(--primary);
|
|
}
|
|
|
|
.toast.success { border-left-color: var(--success); }
|
|
.toast.error { border-left-color: var(--error); }
|
|
.toast-message { flex: 1; color: var(--text-primary); }
|
|
|
|
.toast-close {
|
|
background: none;
|
|
border: none;
|
|
color: var(--text-secondary);
|
|
cursor: pointer;
|
|
padding: 4px;
|
|
}
|
|
|
|
@keyframes slideIn {
|
|
from { transform: translateX(100%); opacity: 0; }
|
|
to { transform: translateX(0); opacity: 1; }
|
|
}
|
|
|
|
@keyframes slideOut {
|
|
from { transform: translateX(0); opacity: 1; }
|
|
to { transform: translateX(100%); opacity: 0; }
|
|
}
|
|
|
|
/* Preview section */
|
|
.preview-section {
|
|
border-top: 2px solid var(--border);
|
|
padding-top: var(--spacing-lg);
|
|
margin-top: var(--spacing-lg);
|
|
}
|
|
.preview-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
cursor: pointer;
|
|
padding: var(--spacing-sm) 0;
|
|
user-select: none;
|
|
}
|
|
.preview-header h2 { margin: 0; }
|
|
.preview-toggle {
|
|
transition: transform 0.2s;
|
|
color: var(--text-secondary);
|
|
}
|
|
.preview-toggle.collapsed { transform: rotate(-90deg); }
|
|
.preview-body { overflow: hidden; }
|
|
.preview-body.collapsed { display: none; }
|
|
.preview-block { margin-bottom: var(--spacing-xl); }
|
|
.preview-block h3 {
|
|
font-size: var(--font-size-base);
|
|
color: var(--text-secondary);
|
|
margin-bottom: var(--spacing-md);
|
|
font-weight: 600;
|
|
}
|
|
.preview-grid-3 {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
gap: var(--spacing-md);
|
|
}
|
|
.preview-grid-4 {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
gap: var(--spacing-md);
|
|
}
|
|
.preview-card {
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-lg);
|
|
padding: var(--spacing-lg);
|
|
text-align: center;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: var(--spacing-sm);
|
|
}
|
|
.preview-card a {
|
|
color: var(--text-secondary);
|
|
font-size: var(--font-size-sm);
|
|
text-decoration: none;
|
|
}
|
|
.preview-card a:hover { text-decoration: underline; }
|
|
.preview-score-circle {
|
|
width: 48px;
|
|
height: 48px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 18px;
|
|
font-weight: 700;
|
|
}
|
|
.preview-social-icon {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
.preview-label {
|
|
font-size: var(--font-size-sm);
|
|
color: var(--text-secondary);
|
|
}
|
|
.preview-value {
|
|
font-size: 24px;
|
|
font-weight: 700;
|
|
}
|
|
.preview-badge {
|
|
font-size: 11px;
|
|
padding: 2px 8px;
|
|
border-radius: 12px;
|
|
}
|
|
.preview-empty {
|
|
color: var(--text-secondary);
|
|
font-style: italic;
|
|
padding: var(--spacing-lg);
|
|
text-align: center;
|
|
border: 1px dashed var(--border);
|
|
border-radius: var(--radius-lg);
|
|
}
|
|
@media (max-width: 768px) {
|
|
.header-row { flex-direction: column; }
|
|
.info-grid { grid-template-columns: 1fr; }
|
|
.actions-grid { grid-template-columns: 1fr; }
|
|
.checklist-grid { grid-template-columns: 1fr; }
|
|
.header-actions { width: 100%; justify-content: flex-end; }
|
|
.preview-grid-3 { grid-template-columns: 1fr; }
|
|
.preview-grid-4 { grid-template-columns: repeat(2, 1fr); }
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container">
|
|
<!-- 1. Header -->
|
|
<div class="detail-header">
|
|
<div class="breadcrumb">
|
|
<a href="{{ url_for('admin.admin_companies') }}">Firmy</a>
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
|
|
<span>{{ company.name }}</span>
|
|
</div>
|
|
<div class="header-row">
|
|
<h1>
|
|
{{ company.name }}
|
|
<span class="badge badge-{{ company.status or 'pending' }}">{{ company.status or 'pending' }}</span>
|
|
</h1>
|
|
<div class="header-actions">
|
|
<a href="/company/{{ company.id }}" target="_blank" class="btn-link" style="color: #059669;">
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/></svg>
|
|
Profil publiczny
|
|
</a>
|
|
<a href="{{ url_for('admin.company_settings', company_id=company.id) }}" class="btn-link">
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.11 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><circle cx="12" cy="12" r="3"/></svg>
|
|
Ustawienia
|
|
</a>
|
|
<a href="{{ url_for('admin.admin_companies') }}" class="btn-link">
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>
|
|
Lista firm
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 2. Stats -->
|
|
<div class="stats-grid">
|
|
<div class="stat-card">
|
|
<div class="stat-value" style="color: {% if completeness.score < 30 %}var(--error){% elif completeness.score < 70 %}var(--warning){% else %}var(--success){% endif %};">{{ completeness.score }}%</div>
|
|
<div class="stat-label">Kompletność</div>
|
|
<div class="progress-bar-wrap">
|
|
<div class="progress-bar-fill" style="width: {{ completeness.score }}%; background: {% if completeness.score < 30 %}var(--error){% elif completeness.score < 70 %}var(--warning){% else %}var(--success){% endif %};"></div>
|
|
</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-value">{{ users|length }}</div>
|
|
<div class="stat-label">Użytkownicy</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-value" style="font-size: var(--font-size-xl);">{{ company.created_at|local_time('%d.%m.%Y') if company.created_at else '---' }}</div>
|
|
<div class="stat-label">Utworzono</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 3. Company info -->
|
|
<div class="section">
|
|
<h2>Dane firmy</h2>
|
|
<div class="info-header">
|
|
<div class="logo-box {{ 'dark-bg' if company.logo_dark_bg else '' }}">
|
|
{% if enrichment.logo.path %}
|
|
<img src="{{ enrichment.logo.path }}" alt="Logo {{ company.name }}">
|
|
{% else %}
|
|
<svg fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path d="M6.827 6.175A2.31 2.31 0 015.186 7.23c-.38.054-.757.112-1.134.175C2.999 7.58 2.25 8.507 2.25 9.574V18a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9.574c0-1.067-.75-1.994-1.802-2.169a47.865 47.865 0 00-1.134-.175 2.31 2.31 0 01-1.64-1.055l-.822-1.316a2.192 2.192 0 00-1.736-1.039 48.774 48.774 0 00-5.232 0 2.192 2.192 0 00-1.736 1.039l-.821 1.316z"/><path d="M16.5 12.75a4.5 4.5 0 11-9 0 4.5 4.5 0 019 0z"/></svg>
|
|
{% endif %}
|
|
</div>
|
|
<div>
|
|
<h3 style="margin: 0; color: var(--text-primary);">{{ company.name }}</h3>
|
|
{% if company.legal_name and company.legal_name != company.name %}
|
|
<div style="font-size: var(--font-size-sm); color: var(--text-secondary);">{{ company.legal_name }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="info-grid">
|
|
<div>
|
|
<div class="info-field">
|
|
<div class="info-label">NIP</div>
|
|
<div class="info-value">{% if company.nip %}<span style="font-family: monospace;">{{ company.nip }}</span>{% else %}<span class="info-empty">—</span>{% endif %}</div>
|
|
</div>
|
|
<div class="info-field">
|
|
<div class="info-label">KRS</div>
|
|
<div class="info-value">{% if company.krs %}<span style="font-family: monospace;">{{ company.krs }}</span>{% else %}<span class="info-empty">—</span>{% endif %}</div>
|
|
</div>
|
|
<div class="info-field">
|
|
<div class="info-label">REGON</div>
|
|
<div class="info-value">{% if company.regon %}<span style="font-family: monospace;">{{ company.regon }}</span>{% else %}<span class="info-empty">—</span>{% endif %}</div>
|
|
</div>
|
|
<div class="info-field">
|
|
<div class="info-label">Forma prawna</div>
|
|
<div class="info-value">{{ company.legal_form or '' }}{%- if not company.legal_form %}<span class="info-empty">—</span>{% endif %}</div>
|
|
</div>
|
|
<div class="info-field">
|
|
<div class="info-label">PKD</div>
|
|
<div class="info-value">{% if company.pkd_code %}{{ company.pkd_code }}{% if company.pkd_description %} — {{ company.pkd_description }}{% endif %}{% else %}<span class="info-empty">—</span>{% endif %}</div>
|
|
</div>
|
|
<div class="info-field">
|
|
<div class="info-label">Właściciel</div>
|
|
<div class="info-value">{% if company.owner_first_name or company.owner_last_name %}{{ company.owner_first_name or '' }} {{ company.owner_last_name or '' }}{% else %}<span class="info-empty">—</span>{% endif %}</div>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="info-field">
|
|
<div class="info-label">Adres</div>
|
|
<div class="info-value">
|
|
{% if company.address_street or company.address_city %}
|
|
{{ company.address_street or '' }}{% if company.address_street and company.address_city %}, {% endif %}
|
|
{{ company.address_postal or '' }} {{ company.address_city or '' }}
|
|
{% else %}
|
|
<span class="info-empty">—</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="info-field">
|
|
<div class="info-label">Email</div>
|
|
<div class="info-value">{% if company.email %}<a href="mailto:{{ company.email }}">{{ company.email }}</a>{% else %}<span class="info-empty">—</span>{% endif %}</div>
|
|
</div>
|
|
<div class="info-field">
|
|
<div class="info-label">Telefon</div>
|
|
<div class="info-value">{{ company.phone or '' }}{%- if not company.phone %}<span class="info-empty">—</span>{% endif %}</div>
|
|
</div>
|
|
<div class="info-field">
|
|
<div class="info-label">Strona WWW</div>
|
|
<div class="info-value">{% if company.website %}<a href="{{ company.website }}" target="_blank" rel="noopener">{{ company.website }}</a>{% else %}<span class="info-empty">—</span>{% endif %}</div>
|
|
</div>
|
|
<div class="info-field">
|
|
<div class="info-label">Kategoria</div>
|
|
<div class="info-value">{{ company.category.name if company.category else '' }}{%- if not company.category %}<span class="info-empty">—</span>{% endif %}</div>
|
|
</div>
|
|
<div class="info-field">
|
|
<div class="info-label">Opis</div>
|
|
<div class="info-value">{% if company.description_short %}{{ company.description_short[:200] }}{% if company.description_short|length > 200 %}...{% endif %}{% else %}<span class="info-empty">—</span>{% endif %}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% if company.admin_notes %}
|
|
<div style="margin-top: var(--spacing-lg); padding-top: var(--spacing-md); border-top: 1px solid var(--border);">
|
|
<div class="info-label" style="color: var(--warning); font-weight: 600;">Notatki administracyjne</div>
|
|
<div class="info-value" style="white-space: pre-line;">{{ company.admin_notes }}</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- 4. Workflow -->
|
|
<div class="section">
|
|
<h2>Workflow uzbrajania firmy</h2>
|
|
|
|
<div class="master-btn-wrap">
|
|
<button id="btn-arm" class="btn-master" onclick="armCompany(false)">
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M13 10V3L4 14h7v7l9-11h-7z"/></svg>
|
|
Uzbrój firmę
|
|
</button>
|
|
<button id="btn-refresh" class="btn-master btn-refresh" onclick="armCompany(true)">
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
|
|
Zaktualizuj dane
|
|
</button>
|
|
</div>
|
|
|
|
<div class="actions-grid">
|
|
<!-- 1. Registry -->
|
|
<div class="action-card {{ 'done' if enrichment.registry.done else '' }}">
|
|
<div class="action-card-header">
|
|
<span class="step-number">1</span>
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path 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>
|
|
<h3>Dane urzędowe</h3>
|
|
</div>
|
|
<div class="action-status">
|
|
{% if enrichment.registry.done %}
|
|
<span class="status-dot green"></span>
|
|
Wykonano{% if enrichment.registry.date %} {{ enrichment.registry.date|local_time('%d.%m.%Y') }}{% endif %}
|
|
{% else %}
|
|
<span class="status-dot gray"></span>
|
|
Nie wykonano
|
|
{% endif %}
|
|
</div>
|
|
{% if enrichment.registry.stale %}
|
|
<div style="background: #fef9c3; color: #854d0e; padding: 6px 10px; border-radius: var(--radius); font-size: var(--font-size-xs); margin-top: var(--spacing-xs);">
|
|
Dane z rejestru pobrane ponad 6 mcy temu — odśwież
|
|
</div>
|
|
{% endif %}
|
|
{% if enrichment.registry.source %}
|
|
<div class="action-score">Źródło: {{ enrichment.registry.source }}</div>
|
|
{% endif %}
|
|
<button id="btn-registry" class="btn-action" onclick="fetchRegistry()" {{ 'disabled' if not company.nip }}>
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/></svg>
|
|
Pobierz dane
|
|
</button>
|
|
</div>
|
|
|
|
<!-- 2. SEO -->
|
|
<div class="action-card {{ 'done' if enrichment.seo.done else '' }}">
|
|
<div class="action-card-header">
|
|
<span class="step-number">2</span>
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/></svg>
|
|
<h3>Audyt SEO</h3>
|
|
</div>
|
|
<div class="action-status">
|
|
{% if enrichment.seo.done %}
|
|
<span class="status-dot green"></span>
|
|
Wykonano{% if enrichment.seo.date %} {{ enrichment.seo.date|local_time('%d.%m.%Y') }}{% endif %}
|
|
{% else %}
|
|
<span class="status-dot gray"></span>
|
|
Nie wykonano
|
|
{% endif %}
|
|
</div>
|
|
{% if enrichment.seo.score is not none and enrichment.seo.score is defined %}
|
|
<div class="action-score">Wynik: {{ enrichment.seo.score }}/100</div>
|
|
{% endif %}
|
|
<button id="btn-seo" class="btn-action" onclick="runSeoAudit()" {{ 'disabled' if not company.website }}>
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/><path d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
|
Uruchom audyt
|
|
</button>
|
|
</div>
|
|
|
|
<!-- 3. Social Media -->
|
|
<div class="action-card {{ 'done' if enrichment.social.done else '' }}">
|
|
<div class="action-card-header">
|
|
<span class="step-number">3</span>
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
|
|
<h3>Audyt Social Media</h3>
|
|
</div>
|
|
<div class="action-status">
|
|
{% if enrichment.social.done %}
|
|
<span class="status-dot green"></span>
|
|
Wykonano ({{ enrichment.social.count }} profili)
|
|
{% else %}
|
|
<span class="status-dot gray"></span>
|
|
Nie wykonano
|
|
{% endif %}
|
|
</div>
|
|
<button id="btn-social" class="btn-action" onclick="runSocialAudit()">
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/><path d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
|
Uruchom audyt
|
|
</button>
|
|
</div>
|
|
|
|
<!-- 4. GBP -->
|
|
<div class="action-card {{ 'done' if enrichment.gbp.done else '' }}">
|
|
<div class="action-card-header">
|
|
<span class="step-number">4</span>
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"/><path d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
|
|
<h3>Audyt GBP</h3>
|
|
</div>
|
|
<div class="action-status">
|
|
{% if enrichment.gbp.done %}
|
|
<span class="status-dot green"></span>
|
|
Wykonano{% if enrichment.gbp.date %} {{ enrichment.gbp.date|local_time('%d.%m.%Y') }}{% endif %}
|
|
{% else %}
|
|
<span class="status-dot gray"></span>
|
|
Nie wykonano
|
|
{% endif %}
|
|
</div>
|
|
{% if enrichment.gbp.score is not none and enrichment.gbp.score is defined %}
|
|
<div class="action-score">Wynik: {{ enrichment.gbp.score }}/100</div>
|
|
{% endif %}
|
|
<button id="btn-gbp" class="btn-action" onclick="runGbpAudit()">
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"/><path d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
|
Uruchom audyt
|
|
</button>
|
|
</div>
|
|
|
|
<!-- 5. Logo -->
|
|
<div class="action-card {{ 'done' if enrichment.logo.done else '' }}">
|
|
<div class="action-card-header">
|
|
<span class="step-number">5</span>
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/></svg>
|
|
<h3>Logo firmy</h3>
|
|
</div>
|
|
<div class="action-status">
|
|
{% if enrichment.logo.done %}
|
|
<span class="status-dot green"></span>
|
|
Pobrano
|
|
{% else %}
|
|
<span class="status-dot gray"></span>
|
|
Nie pobrano
|
|
{% endif %}
|
|
</div>
|
|
<button id="btn-logo" class="btn-action" onclick="fetchLogo()" {{ 'disabled' if not company.website }}>
|
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/></svg>
|
|
Szukaj logo
|
|
</button>
|
|
<div id="logo-candidates" class="logo-candidates" style="display:none;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 5. Preview: what the user sees -->
|
|
<div class="section preview-section">
|
|
<div class="preview-header" onclick="togglePreview()">
|
|
<h2>Podgląd profilu użytkownika</h2>
|
|
<svg class="preview-toggle" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><polyline points="6 9 12 15 18 9"/></svg>
|
|
</div>
|
|
<div class="preview-body" id="previewBody">
|
|
|
|
{# Social Media #}
|
|
<div class="preview-block">
|
|
<h3>Social Media</h3>
|
|
{% if social_accounts and social_accounts|length > 0 %}
|
|
<div class="preview-grid-3">
|
|
{% for sm in social_accounts %}
|
|
{% set colors = {'facebook': '#1877F2', 'instagram': '#E4405F', 'linkedin': '#0A66C2', 'youtube': '#FF0000', 'twitter': '#000000', 'tiktok': '#000000'} %}
|
|
{% set color = colors.get(sm.platform, '#6b7280') %}
|
|
<div class="preview-card" style="border-color: {{ color }}30;">
|
|
<div class="preview-social-icon" style="background: {{ color }}15;">
|
|
{% if sm.platform == 'facebook' %}
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="{{ color }}"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>
|
|
{% elif sm.platform == 'instagram' %}
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="{{ color }}"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg>
|
|
{% elif sm.platform == 'linkedin' %}
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="{{ color }}"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>
|
|
{% elif sm.platform == 'youtube' %}
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="{{ color }}"><path d="M23.498 6.186a3.016 3.016 0 00-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 00.502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 002.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 002.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/></svg>
|
|
{% elif sm.platform == 'tiktok' %}
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="{{ color }}"><path d="M12.525.02c1.31-.02 2.61-.01 3.91-.02.08 1.53.63 3.09 1.75 4.17 1.12 1.11 2.7 1.62 4.24 1.79v4.03c-1.44-.05-2.89-.35-4.2-.97-.57-.26-1.1-.59-1.62-.93-.01 2.92.01 5.84-.02 8.75-.08 1.4-.54 2.79-1.35 3.94-1.31 1.92-3.58 3.17-5.91 3.21-1.43.08-2.86-.31-4.08-1.03-2.02-1.19-3.44-3.37-3.65-5.71-.02-.5-.03-1-.01-1.49.18-1.9 1.12-3.72 2.58-4.96 1.66-1.44 3.98-2.13 6.15-1.72.02 1.48-.04 2.96-.04 4.44-.99-.32-2.15-.23-3.02.37-.63.41-1.11 1.04-1.36 1.75-.21.51-.15 1.07-.14 1.61.24 1.64 1.82 3.02 3.5 2.87 1.12-.01 2.19-.66 2.77-1.61.19-.33.4-.67.41-1.06.1-1.79.06-3.57.07-5.36.01-4.03-.01-8.05.02-12.07z"/></svg>
|
|
{% else %}
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="{{ color }}"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
|
|
{% endif %}
|
|
</div>
|
|
<div style="font-weight: 600; text-transform: capitalize;">{{ sm.platform }}</div>
|
|
{% if sm.followers_count %}
|
|
<div class="preview-label">{{ sm.followers_count }} obserwujących</div>
|
|
{% elif sm.page_name %}
|
|
<div class="preview-label">{{ sm.page_name|truncate(25) }}</div>
|
|
{% endif %}
|
|
{% if sm.check_status == 'needs_verification' %}
|
|
<span class="preview-badge" style="background: #fef3c7; color: #92400e;">Do weryfikacji</span>
|
|
{% elif sm.is_valid %}
|
|
<span class="preview-badge" style="background: #dcfce7; color: #166534;">Zweryfikowany</span>
|
|
{% endif %}
|
|
{% if sm.url %}
|
|
<a href="{{ sm.url }}" target="_blank">Zobacz profil</a>
|
|
{% endif %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<div class="preview-empty">Brak profili social media. Uruchom audyt powyżej.</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{# SEO PageSpeed #}
|
|
<div class="preview-block">
|
|
<h3>SEO — PageSpeed</h3>
|
|
{% if seo_analysis and seo_analysis.seo_audited_at %}
|
|
<div class="preview-grid-4">
|
|
{% set scores = [
|
|
('SEO', seo_analysis.pagespeed_seo_score),
|
|
('Wydajność', seo_analysis.pagespeed_performance_score),
|
|
('Dostępność', seo_analysis.pagespeed_accessibility_score),
|
|
('Best Practices', seo_analysis.pagespeed_best_practices_score)
|
|
] %}
|
|
{% for label, score in scores %}
|
|
<div class="preview-card">
|
|
{% if score is not none %}
|
|
{% if score >= 90 %}
|
|
{% set sc = '#166534' %}{% set bg = '#dcfce7' %}{% set bc = '#86efac' %}
|
|
{% elif score >= 50 %}
|
|
{% set sc = '#92400e' %}{% set bg = '#fef3c7' %}{% set bc = '#fcd34d' %}
|
|
{% else %}
|
|
{% set sc = '#991b1b' %}{% set bg = '#fee2e2' %}{% set bc = '#fca5a5' %}
|
|
{% endif %}
|
|
<div class="preview-score-circle" style="background: {{ bg }}; color: {{ sc }}; border: 2px solid {{ bc }};">
|
|
{{ score }}
|
|
</div>
|
|
{% else %}
|
|
<div class="preview-score-circle" style="background: #f3f4f6; color: #9ca3af; border: 2px solid #e5e7eb;">
|
|
—
|
|
</div>
|
|
{% endif %}
|
|
<div class="preview-label">{{ label }}</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<div class="preview-empty">Brak audytu SEO. Uruchom audyt powyżej.</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{# GBP #}
|
|
<div class="preview-block">
|
|
<h3>Google Business Profile</h3>
|
|
{% if gbp_audit and gbp_audit.completeness_score is not none %}
|
|
<div class="preview-grid-4">
|
|
{# Reviews #}
|
|
<div class="preview-card">
|
|
<div class="preview-value" style="color: #d97706;">{{ gbp_audit.review_count or 0 }}</div>
|
|
<div class="preview-label">Opinii</div>
|
|
</div>
|
|
{# Rating #}
|
|
<div class="preview-card">
|
|
{% set rating = gbp_audit.average_rating or 0 %}
|
|
{% if rating >= 4.5 %}{% set rc = '#166534' %}
|
|
{% elif rating >= 3.5 %}{% set rc = '#d97706' %}
|
|
{% else %}{% set rc = '#991b1b' %}{% endif %}
|
|
<div class="preview-value" style="color: {{ rc }};">{{ '%.1f'|format(rating) }}</div>
|
|
<div class="preview-label">Średnia ocen</div>
|
|
</div>
|
|
{# Photos #}
|
|
<div class="preview-card">
|
|
<div class="preview-value" style="color: #2563eb;">{{ gbp_audit.photo_count or 0 }}</div>
|
|
<div class="preview-label">Zdjęć</div>
|
|
</div>
|
|
{# Completeness #}
|
|
<div class="preview-card">
|
|
{% set cs = gbp_audit.completeness_score %}
|
|
{% if cs >= 90 %}{% set cc = '#166534' %}
|
|
{% elif cs >= 50 %}{% set cc = '#d97706' %}
|
|
{% else %}{% set cc = '#991b1b' %}{% endif %}
|
|
<div class="preview-value" style="color: {{ cc }};">{{ cs }}%</div>
|
|
<div class="preview-label">Kompletność</div>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div class="preview-empty">Brak audytu GBP. Uruchom audyt powyżej.</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 6. Completeness checklist -->
|
|
<div class="section">
|
|
<h2>Lista kompletności ({{ completeness.filled }}/{{ completeness.total }})</h2>
|
|
<div class="checklist-grid">
|
|
{% for field_name, is_filled in completeness.fields.items() %}
|
|
<div class="checklist-item">
|
|
{% if is_filled %}
|
|
<svg class="check-ok" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
|
<span>{{ field_name }}</span>
|
|
{% else %}
|
|
<svg class="check-missing" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
|
<span>{{ field_name }}</span>
|
|
{% if hints and hints.get(field_name) %}
|
|
<div class="hint-badge" style="margin-left: auto; display: flex; align-items: center; gap: 4px;">
|
|
<span style="font-size: var(--font-size-xs); color: var(--primary);">
|
|
{{ hints[field_name].source }}{% if hints[field_name].value %}: {{ hints[field_name].value[:40] }}{% endif %}
|
|
</span>
|
|
{% if hints[field_name].get('google_name') %}
|
|
<span style="font-size: var(--font-size-xs); color: #d97706;" title="Nazwa profilu Google nie zgadza się z nazwą firmy — zweryfikuj!">
|
|
(profil: {{ hints[field_name].google_name[:30] }})
|
|
</span>
|
|
{% endif %}
|
|
{% if hints[field_name].action == 'apply' and hints[field_name].value %}
|
|
<button onclick="applyHint({{ company.id }}, '{{ field_name }}', '{{ hints[field_name].value|e }}')"
|
|
class="hint-apply-btn" title="Uzupełnij to pole">Uzupełnij</button>
|
|
{% elif hints[field_name].action == 'fetch_registry' %}
|
|
<button onclick="window.location.href='#enrichment'" class="hint-apply-btn" title="Pobierz z rejestru">Pobierz</button>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Toast Container -->
|
|
<div id="toastContainer" class="toast-container"></div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
var csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
|
|
|
// Preview section toggle
|
|
function togglePreview() {
|
|
var body = document.getElementById('previewBody');
|
|
var toggle = document.querySelector('.preview-toggle');
|
|
body.classList.toggle('collapsed');
|
|
toggle.classList.toggle('collapsed');
|
|
}
|
|
|
|
function showToast(message, type) {
|
|
var container = document.getElementById('toastContainer');
|
|
var toast = document.createElement('div');
|
|
toast.className = 'toast ' + (type || 'success');
|
|
toast.innerHTML = '<span class="toast-message">' + message + '</span>' +
|
|
'<button class="toast-close" onclick="this.parentElement.remove()">' +
|
|
'<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M6 18L18 6M6 6l12 12"/></svg>' +
|
|
'</button>';
|
|
container.appendChild(toast);
|
|
setTimeout(function() {
|
|
toast.style.animation = 'slideOut 0.3s ease forwards';
|
|
setTimeout(function() { toast.remove(); }, 300);
|
|
}, 5000);
|
|
}
|
|
|
|
function applyHint(companyId, fieldName, value) {
|
|
if (!confirm('Uzupełnić pole "' + fieldName + '" wartością: ' + value + '?')) return;
|
|
|
|
fetch('/api/company/' + companyId + '/apply-hint', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': csrfToken
|
|
},
|
|
body: JSON.stringify({field: fieldName, value: value})
|
|
})
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(data) {
|
|
if (data.success) {
|
|
showToast('Pole "' + fieldName + '" uzupełnione', 'success');
|
|
setTimeout(function() { location.reload(); }, 1000);
|
|
} else {
|
|
showToast('Błąd: ' + data.error, 'error');
|
|
}
|
|
})
|
|
.catch(function(err) { showToast('Błąd: ' + err.message, 'error'); });
|
|
}
|
|
|
|
var _skipReload = false;
|
|
|
|
function runEnrichAction(btn, url, body) {
|
|
var original = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<span class="spinner"></span> Pobieram...';
|
|
return fetch(url, {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json', 'X-CSRFToken': csrfToken},
|
|
body: JSON.stringify(body || {})
|
|
})
|
|
.then(function(resp) { return resp.json(); })
|
|
.then(function(data) {
|
|
if (data.success) {
|
|
showToast(data.message || 'Gotowe!', 'success');
|
|
btn.innerHTML = '<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" style="width:16px;height:16px"><path d="M5 13l4 4L19 7"/></svg> Gotowe';
|
|
if (!_skipReload) {
|
|
setTimeout(function() { location.reload(); }, 1500);
|
|
}
|
|
return true;
|
|
} else {
|
|
showToast(data.error || 'Wystąpił błąd', 'error');
|
|
btn.innerHTML = original;
|
|
btn.disabled = false;
|
|
return false;
|
|
}
|
|
})
|
|
.catch(function() {
|
|
showToast('Błąd połączenia z serwerem', 'error');
|
|
btn.innerHTML = original;
|
|
btn.disabled = false;
|
|
return false;
|
|
});
|
|
}
|
|
|
|
function fetchRegistry() {
|
|
var btn = document.getElementById('btn-registry');
|
|
return runEnrichAction(btn, '/api/company/{{ company.id }}/enrich-registry', {});
|
|
}
|
|
|
|
|
|
function fetchLogo() {
|
|
var btn = document.getElementById('btn-logo');
|
|
var original = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<span class="spinner"></span> Szukam...';
|
|
|
|
return fetch('/api/company/{{ company.id }}/fetch-logo', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json', 'X-CSRFToken': csrfToken},
|
|
body: JSON.stringify({action: 'fetch'})
|
|
})
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(data) {
|
|
btn.innerHTML = original;
|
|
btn.disabled = false;
|
|
|
|
if (!data.success || !data.candidates || data.candidates.length === 0) {
|
|
showToast(data.message || 'Nie znaleziono logo', 'error');
|
|
return false;
|
|
}
|
|
|
|
var container = document.getElementById('logo-candidates');
|
|
var html = '<div class="logo-candidates-label">Wybierz logo (' + data.candidates.length + ' kandydatów):</div>';
|
|
html += '<div class="logo-candidates-grid">';
|
|
data.candidates.forEach(function(c) {
|
|
var imgUrl = '/static/img/companies/' + c.filename + '?t=' + Date.now();
|
|
var rec = (c.index === data.recommended_index) ? ' recommended' : '';
|
|
html += '<div class="logo-candidate-wrapper">';
|
|
html += '<div class="logo-candidate' + rec + '" onclick="confirmLogo(' + c.index + ')" title="' + c.label + ' (' + c.width + 'x' + c.height + ')">';
|
|
if (c.index === data.recommended_index) {
|
|
html += '<span class="logo-candidate-badge">OK</span>';
|
|
}
|
|
html += '<img src="' + imgUrl + '" alt="Kandydat ' + (c.index + 1) + '">';
|
|
html += '</div>';
|
|
html += '<div class="logo-candidate-info">' + c.label + '</div>';
|
|
html += '</div>';
|
|
});
|
|
html += '</div>';
|
|
html += '<button class="logo-cancel-btn" onclick="cancelLogo()">Anuluj</button>';
|
|
|
|
container.innerHTML = html;
|
|
container.style.display = 'block';
|
|
showToast('Znaleziono ' + data.candidates.length + ' kandydatów — wybierz logo', 'success');
|
|
return true;
|
|
})
|
|
.catch(function() {
|
|
showToast('Błąd połączenia z serwerem', 'error');
|
|
btn.innerHTML = original;
|
|
btn.disabled = false;
|
|
return false;
|
|
});
|
|
}
|
|
|
|
function confirmLogo(index) {
|
|
var container = document.getElementById('logo-candidates');
|
|
container.innerHTML = '<span class="spinner"></span> Zapisuję...';
|
|
|
|
fetch('/api/company/{{ company.id }}/fetch-logo', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json', 'X-CSRFToken': csrfToken},
|
|
body: JSON.stringify({action: 'confirm', index: index})
|
|
})
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(data) {
|
|
if (data.success) {
|
|
showToast('Logo zapisane!', 'success');
|
|
setTimeout(function() { location.reload(); }, 1000);
|
|
} else {
|
|
showToast(data.message || 'Błąd zapisu', 'error');
|
|
container.style.display = 'none';
|
|
}
|
|
})
|
|
.catch(function() {
|
|
showToast('Błąd połączenia', 'error');
|
|
container.style.display = 'none';
|
|
});
|
|
}
|
|
|
|
function cancelLogo() {
|
|
fetch('/api/company/{{ company.id }}/fetch-logo', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json', 'X-CSRFToken': csrfToken},
|
|
body: JSON.stringify({action: 'cancel'})
|
|
});
|
|
document.getElementById('logo-candidates').style.display = 'none';
|
|
showToast('Anulowano', 'info');
|
|
}
|
|
|
|
function runSeoAudit() {
|
|
var btn = document.getElementById('btn-seo');
|
|
return runEnrichAction(btn, '/api/seo/audit', {company_id: {{ company.id }}});
|
|
}
|
|
|
|
function runSocialAudit() {
|
|
var btn = document.getElementById('btn-social');
|
|
return runEnrichAction(btn, '/api/social/audit', {company_id: {{ company.id }}});
|
|
}
|
|
|
|
function runGbpAudit() {
|
|
var btn = document.getElementById('btn-gbp');
|
|
return runEnrichAction(btn, '/api/gbp/audit', {company_id: {{ company.id }}, fetch_google: true});
|
|
}
|
|
|
|
function fetchLogoAuto() {
|
|
/* Wersja logo dla trybu automatycznego — wybiera rekomendowanego kandydata */
|
|
var btn = document.getElementById('btn-logo');
|
|
var original = btn.innerHTML;
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<span class="spinner"></span> Szukam logo...';
|
|
|
|
return fetch('/api/company/{{ company.id }}/fetch-logo', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json', 'X-CSRFToken': csrfToken},
|
|
body: JSON.stringify({action: 'fetch'})
|
|
})
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(data) {
|
|
if (!data.success || !data.candidates || data.candidates.length === 0) {
|
|
btn.innerHTML = original;
|
|
btn.disabled = false;
|
|
showToast('Logo: brak kandydatów', 'warning');
|
|
return false;
|
|
}
|
|
var pick = (data.recommended_index !== null && data.recommended_index !== undefined)
|
|
? data.recommended_index : 0;
|
|
btn.innerHTML = '<span class="spinner"></span> Zapisuję logo...';
|
|
return fetch('/api/company/{{ company.id }}/fetch-logo', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json', 'X-CSRFToken': csrfToken},
|
|
body: JSON.stringify({action: 'confirm', index: pick})
|
|
})
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(res) {
|
|
btn.innerHTML = original;
|
|
btn.disabled = false;
|
|
if (res.success) {
|
|
showToast('Logo zapisane automatycznie (kandydat #' + (pick + 1) + ')', 'success');
|
|
}
|
|
return res.success;
|
|
});
|
|
})
|
|
.catch(function() {
|
|
btn.innerHTML = original;
|
|
btn.disabled = false;
|
|
return false;
|
|
});
|
|
}
|
|
|
|
function armCompany(forceAll) {
|
|
_skipReload = true;
|
|
var isRefresh = !!forceAll;
|
|
var masterBtn = document.getElementById(isRefresh ? 'btn-refresh' : 'btn-arm');
|
|
var otherBtn = document.getElementById(isRefresh ? 'btn-arm' : 'btn-refresh');
|
|
masterBtn.disabled = true;
|
|
otherBtn.disabled = true;
|
|
masterBtn.innerHTML = '<span class="spinner"></span> ' + (isRefresh ? 'Aktualizuję...' : 'Uzbrajam firmę...');
|
|
|
|
var steps = [
|
|
{id: 'btn-registry', fn: fetchRegistry, skip: forceAll ? false : {{ 'true' if enrichment.registry.done else 'false' }}, requires: {{ 'true' if company.nip else 'false' }} },
|
|
{id: 'btn-seo', fn: runSeoAudit, skip: forceAll ? false : {{ 'true' if enrichment.seo.done else 'false' }}, requires: {{ 'true' if company.website else 'false' }} },
|
|
{id: 'btn-social', fn: runSocialAudit, skip: forceAll ? false : {{ 'true' if enrichment.social.done else 'false' }}, requires: true },
|
|
{id: 'btn-gbp', fn: runGbpAudit, skip: forceAll ? false : {{ 'true' if enrichment.gbp.done else 'false' }}, requires: true },
|
|
{id: 'btn-logo', fn: fetchLogoAuto, skip: forceAll ? false : {{ 'true' if enrichment.logo.done else 'false' }}, requires: {{ 'true' if company.website else 'false' }} }
|
|
];
|
|
|
|
var pending = steps.filter(function(s) { return !s.skip && s.requires; });
|
|
|
|
if (pending.length === 0) {
|
|
showToast('Wszystkie kroki zostały już wykonane!', 'success');
|
|
masterBtn.disabled = false;
|
|
otherBtn.disabled = false;
|
|
masterBtn.innerHTML = isRefresh
|
|
? '<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" style="width:22px;height:22px"><path d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg> Zaktualizuj dane'
|
|
: '<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" style="width:22px;height:22px"><path d="M13 10V3L4 14h7v7l9-11h-7z"/></svg> Uzbrój firmę';
|
|
_skipReload = false;
|
|
return;
|
|
}
|
|
|
|
var idx = 0;
|
|
var label = isRefresh ? 'Aktualizuję' : 'Uzbrajam';
|
|
function runNext() {
|
|
if (idx >= pending.length) {
|
|
showToast(label + ' zakończone! Odświeżam stronę...', 'success');
|
|
setTimeout(function() { location.reload(); }, 2000);
|
|
return;
|
|
}
|
|
var step = pending[idx];
|
|
idx++;
|
|
masterBtn.innerHTML = '<span class="spinner"></span> Krok ' + idx + '/' + pending.length + '...';
|
|
step.fn().then(function() {
|
|
runNext();
|
|
});
|
|
}
|
|
runNext();
|
|
}
|
|
{% endblock %}
|