feat(social-audit): Add Social Media audit dashboard
- Create /audit/social/<slug> route with platform presence analysis - Create social_audit.html template with 6 platforms (FB, IG, LinkedIn, YT, X, TikTok) - Add purple "Audyt Social" button on company profile next to GBP and SEO audits - Show score based on platforms count, profile details and recommendations Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c7b57100ad
commit
505800381e
89
app.py
89
app.py
@ -4070,6 +4070,95 @@ def seo_audit_dashboard(slug):
|
||||
db.close()
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SOCIAL MEDIA AUDIT USER-FACING DASHBOARD
|
||||
# ============================================================
|
||||
|
||||
@app.route('/audit/social/<slug>')
|
||||
@login_required
|
||||
def social_audit_dashboard(slug):
|
||||
"""
|
||||
User-facing Social Media audit dashboard for a specific company.
|
||||
|
||||
Displays social media presence audit with:
|
||||
- Overall presence score (platforms found / total platforms)
|
||||
- Platform-by-platform status
|
||||
- Profile validation status
|
||||
- Recommendations for missing platforms
|
||||
|
||||
Access control:
|
||||
- Admins: Can view all companies
|
||||
- Regular users: Can only view their own company
|
||||
|
||||
Args:
|
||||
slug: Company URL slug
|
||||
|
||||
Returns:
|
||||
Rendered social_audit.html template with company and social data
|
||||
"""
|
||||
db = SessionLocal()
|
||||
try:
|
||||
# Find company by slug
|
||||
company = db.query(Company).filter_by(slug=slug, status='active').first()
|
||||
if not company:
|
||||
flash('Firma nie została znaleziona.', 'error')
|
||||
return redirect(url_for('dashboard'))
|
||||
|
||||
# Access control - admin can view all, users only their company
|
||||
if not current_user.is_admin:
|
||||
if current_user.company_id != company.id:
|
||||
flash('Brak uprawnień do wyświetlenia audytu social media tej firmy.', 'error')
|
||||
return redirect(url_for('dashboard'))
|
||||
|
||||
# Get social media profiles for this company
|
||||
social_profiles = db.query(CompanySocialMedia).filter(
|
||||
CompanySocialMedia.company_id == company.id
|
||||
).all()
|
||||
|
||||
# Define all platforms we track
|
||||
all_platforms = ['facebook', 'instagram', 'linkedin', 'youtube', 'twitter', 'tiktok']
|
||||
|
||||
# Build social media data
|
||||
profiles_dict = {}
|
||||
for profile in social_profiles:
|
||||
profiles_dict[profile.platform] = {
|
||||
'url': profile.url,
|
||||
'is_valid': profile.is_valid,
|
||||
'check_status': profile.check_status,
|
||||
'page_name': profile.page_name,
|
||||
'followers_count': profile.followers_count,
|
||||
'verified_at': profile.verified_at,
|
||||
'last_checked_at': profile.last_checked_at
|
||||
}
|
||||
|
||||
# Calculate score (platforms with profiles / total platforms)
|
||||
platforms_with_profiles = len([p for p in all_platforms if p in profiles_dict])
|
||||
total_platforms = len(all_platforms)
|
||||
score = int((platforms_with_profiles / total_platforms) * 100) if total_platforms > 0 else 0
|
||||
|
||||
social_data = {
|
||||
'profiles': profiles_dict,
|
||||
'all_platforms': all_platforms,
|
||||
'platforms_count': platforms_with_profiles,
|
||||
'total_platforms': total_platforms,
|
||||
'score': score
|
||||
}
|
||||
|
||||
# Determine if user can run audit (admin or company owner)
|
||||
can_audit = current_user.is_admin or current_user.company_id == company.id
|
||||
|
||||
logger.info(f"Social Media audit dashboard viewed by {current_user.email} for company: {company.name}")
|
||||
|
||||
return render_template('social_audit.html',
|
||||
company=company,
|
||||
social_data=social_data,
|
||||
can_audit=can_audit
|
||||
)
|
||||
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
# ============================================================
|
||||
# GBP AUDIT USER-FACING DASHBOARD
|
||||
# ============================================================
|
||||
|
||||
@ -289,6 +289,10 @@
|
||||
.contact-bar-item.seo-audit { color: #16a34a; border-color: #16a34a; background: rgba(22, 163, 74, 0.05); }
|
||||
.contact-bar-item.seo-audit:hover { background: #16a34a; color: white; }
|
||||
|
||||
/* Social Media Audit link - styled as action button */
|
||||
.contact-bar-item.social-audit { color: #a855f7; border-color: #a855f7; background: rgba(168, 85, 247, 0.05); }
|
||||
.contact-bar-item.social-audit:hover { background: #a855f7; color: white; }
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.contact-bar {
|
||||
justify-content: center;
|
||||
@ -515,6 +519,18 @@
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{# Social Media Audit link - visible to admins (all profiles) or regular users (own company only) #}
|
||||
{% if current_user.is_authenticated %}
|
||||
{% if current_user.is_admin or (current_user.company_id and current_user.company_id == company.id) %}
|
||||
<a href="{{ url_for('social_audit_dashboard', slug=company.slug) }}" class="contact-bar-item social-audit" title="Audyt Social Media">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M17 8h2a2 2 0 012 2v6a2 2 0 01-2 2h-2v4l-4-4H9a1.994 1.994 0 01-1.414-.586m0 0L11 14h4a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2v4l.586-.586z"/>
|
||||
</svg>
|
||||
<span>Audyt Social</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- O firmie - Single Description (prioritized sources) -->
|
||||
|
||||
668
templates/social_audit.html
Normal file
668
templates/social_audit.html
Normal file
@ -0,0 +1,668 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Audyt Social Media - {{ company.name }} - Norda Biznes Hub{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.audit-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: var(--spacing-xl);
|
||||
flex-wrap: wrap;
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.audit-header-info h1 {
|
||||
font-size: var(--font-size-2xl);
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.audit-header-info p {
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
.data-source-info {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-xs);
|
||||
margin-top: var(--spacing-sm);
|
||||
padding: var(--spacing-xs) var(--spacing-sm);
|
||||
background: rgba(168, 85, 247, 0.1);
|
||||
border-radius: var(--radius);
|
||||
font-size: var(--font-size-sm);
|
||||
color: #a855f7;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: var(--spacing-sm);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Score Section */
|
||||
.score-section {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: var(--spacing-xl);
|
||||
margin-bottom: var(--spacing-xl);
|
||||
background: var(--surface);
|
||||
padding: var(--spacing-xl);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.score-section {
|
||||
grid-template-columns: 1fr;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.score-circle {
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
background: conic-gradient(
|
||||
var(--score-color, var(--secondary)) calc(var(--score-percent, 0) * 3.6deg),
|
||||
#e2e8f0 0deg
|
||||
);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.score-circle::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
border-radius: 50%;
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
.score-value {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.score-value.score-good { color: var(--success); }
|
||||
.score-value.score-medium { color: var(--warning); }
|
||||
.score-value.score-poor { color: var(--error); }
|
||||
|
||||
.score-label {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--text-secondary);
|
||||
margin-top: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.score-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.score-category {
|
||||
font-size: var(--font-size-lg);
|
||||
font-weight: 600;
|
||||
margin-bottom: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.score-category.excellent { color: var(--success); }
|
||||
.score-category.good { color: #22c55e; }
|
||||
.score-category.average { color: var(--warning); }
|
||||
.score-category.poor { color: var(--error); }
|
||||
|
||||
.score-description {
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-size-sm);
|
||||
line-height: 1.6;
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.platforms-summary {
|
||||
display: flex;
|
||||
gap: var(--spacing-lg);
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--text-secondary);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.platforms-summary-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.platforms-summary-item svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.platforms-summary-item.found { color: var(--success); }
|
||||
.platforms-summary-item.missing { color: var(--text-secondary); }
|
||||
|
||||
/* Section Title */
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
font-size: var(--font-size-lg);
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.section-title svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: #a855f7;
|
||||
}
|
||||
|
||||
/* Platforms Grid */
|
||||
.platforms-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: var(--spacing-md);
|
||||
margin-bottom: var(--spacing-xl);
|
||||
}
|
||||
|
||||
.platform-card {
|
||||
background: var(--surface);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--spacing-lg);
|
||||
box-shadow: var(--shadow);
|
||||
border-left: 4px solid;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.platform-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
.platform-card.found {
|
||||
border-left-color: var(--success);
|
||||
}
|
||||
|
||||
.platform-card.missing {
|
||||
border-left-color: var(--text-tertiary);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.platform-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.platform-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: var(--radius);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.platform-icon.facebook { background: #1877f2; color: white; }
|
||||
.platform-icon.instagram { background: linear-gradient(45deg, #f09433, #e6683c, #dc2743, #cc2366, #bc1888); color: white; }
|
||||
.platform-icon.linkedin { background: #0a66c2; color: white; }
|
||||
.platform-icon.youtube { background: #ff0000; color: white; }
|
||||
.platform-icon.twitter { background: #000000; color: white; }
|
||||
.platform-icon.tiktok { background: #000000; color: white; }
|
||||
|
||||
.platform-name {
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-base);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.platform-status {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-xs);
|
||||
font-size: var(--font-size-sm);
|
||||
padding: 2px 8px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.platform-status.active {
|
||||
background: rgba(34, 197, 94, 0.1);
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.platform-status.inactive {
|
||||
background: rgba(107, 114, 128, 0.1);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.platform-details {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.platform-url {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-xs);
|
||||
margin-bottom: var(--spacing-xs);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.platform-url a {
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.platform-url a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.platform-meta {
|
||||
display: flex;
|
||||
gap: var(--spacing-md);
|
||||
margin-top: var(--spacing-sm);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.platform-meta-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.platform-meta-item svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.platform-missing-text {
|
||||
color: var(--text-tertiary);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* No data state */
|
||||
.no-data {
|
||||
text-align: center;
|
||||
padding: var(--spacing-2xl);
|
||||
background: var(--surface);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.no-data svg {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
color: var(--text-tertiary);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.no-data h3 {
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.no-data p {
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-xs);
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
border-radius: var(--radius);
|
||||
font-weight: 500;
|
||||
font-size: var(--font-size-sm);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: #a855f7;
|
||||
color: white;
|
||||
border-color: #a855f7;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: #9333ea;
|
||||
border-color: #9333ea;
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background: transparent;
|
||||
color: var(--text-secondary);
|
||||
border-color: var(--border);
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
background: var(--background);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: var(--spacing-xs) var(--spacing-sm);
|
||||
font-size: var(--font-size-xs);
|
||||
}
|
||||
|
||||
/* Recommendations */
|
||||
.recommendations {
|
||||
background: var(--surface);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--spacing-lg);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.recommendation-item {
|
||||
display: flex;
|
||||
gap: var(--spacing-sm);
|
||||
padding: var(--spacing-sm) 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.recommendation-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.recommendation-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.recommendation-icon.priority-high {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
.recommendation-icon.priority-medium {
|
||||
background: rgba(245, 158, 11, 0.1);
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
.recommendation-icon.priority-low {
|
||||
background: rgba(34, 197, 94, 0.1);
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.recommendation-text {
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.recommendation-text strong {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Breadcrumb -->
|
||||
<div class="breadcrumb">
|
||||
<a href="{{ url_for('index') }}">Firmy</a>
|
||||
<span class="breadcrumb-separator">/</span>
|
||||
<a href="{{ url_for('company_detail', company_id=company.id) }}">{{ company.name }}</a>
|
||||
<span class="breadcrumb-separator">/</span>
|
||||
<span>Audyt Social Media</span>
|
||||
</div>
|
||||
|
||||
<div class="audit-header">
|
||||
<div class="audit-header-info">
|
||||
<h1>Audyt Social Media</h1>
|
||||
<p>{{ company.name }}</p>
|
||||
<div class="data-source-info">
|
||||
<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 8h2a2 2 0 012 2v6a2 2 0 01-2 2h-2v4l-4-4H9a1.994 1.994 0 01-1.414-.586m0 0L11 14h4a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2v4l.586-.586z"/>
|
||||
</svg>
|
||||
<span>Analiza obecnosci w mediach spolecznosciowych</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<a href="{{ url_for('company_detail', company_id=company.id) }}" class="btn btn-outline btn-sm">
|
||||
<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>
|
||||
Profil firmy
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Score Section -->
|
||||
{% set score = social_data.score %}
|
||||
<div class="score-section">
|
||||
<div class="score-circle" style="--score-percent: {{ score }}; --score-color: {% if score >= 80 %}var(--success){% elif score >= 50 %}var(--warning){% else %}#a855f7{% endif %};">
|
||||
<span class="score-value {% if score >= 80 %}score-good{% elif score >= 50 %}score-medium{% else %}score-poor{% endif %}">{{ score }}</span>
|
||||
<span class="score-label">/ 100</span>
|
||||
</div>
|
||||
<div class="score-details">
|
||||
<div class="score-category {% if score >= 80 %}excellent{% elif score >= 60 %}good{% elif score >= 40 %}average{% else %}poor{% endif %}">
|
||||
{% if score >= 80 %}
|
||||
Doskonala obecnosc w social media
|
||||
{% elif score >= 60 %}
|
||||
Dobra obecnosc w social media
|
||||
{% elif score >= 40 %}
|
||||
Srednia obecnosc w social media
|
||||
{% else %}
|
||||
Slaba obecnosc w social media
|
||||
{% endif %}
|
||||
</div>
|
||||
<p class="score-description">
|
||||
{% if score >= 80 %}
|
||||
Firma jest obecna na wiekszosci waznych platform spolecznosciowych. Utrzymuj aktywnosc i rozwijaj zaangazowanie.
|
||||
{% elif score >= 60 %}
|
||||
Firma ma dobra obecnosc w social media. Rozważ dodanie brakujacych platform dla pelniejszego zasiegu.
|
||||
{% elif score >= 40 %}
|
||||
Firma jest obecna na kilku platformach. Warto rozszerzyc obecnosc o kolejne kanaly komunikacji.
|
||||
{% else %}
|
||||
Firma ma ograniczona obecnosc w social media. Zalecamy utworzenie profili na kluczowych platformach.
|
||||
{% endif %}
|
||||
</p>
|
||||
<div class="platforms-summary">
|
||||
<div class="platforms-summary-item found">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
||||
</svg>
|
||||
<span>{{ social_data.platforms_count }} {{ 'platforma' if social_data.platforms_count == 1 else ('platformy' if social_data.platforms_count in [2,3,4] else 'platform') }}</span>
|
||||
</div>
|
||||
<div class="platforms-summary-item missing">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
<span>{{ social_data.total_platforms - social_data.platforms_count }} brakujacych</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Platforms Grid -->
|
||||
<h2 class="section-title">
|
||||
<svg width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8h2a2 2 0 012 2v6a2 2 0 01-2 2h-2v4l-4-4H9a1.994 1.994 0 01-1.414-.586m0 0L11 14h4a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2v4l.586-.586z"/>
|
||||
</svg>
|
||||
Platformy Social Media
|
||||
</h2>
|
||||
|
||||
<div class="platforms-grid">
|
||||
{% set platform_names = {'facebook': 'Facebook', 'instagram': 'Instagram', 'linkedin': 'LinkedIn', 'youtube': 'YouTube', 'twitter': 'X (Twitter)', 'tiktok': 'TikTok'} %}
|
||||
{% set platform_icons = {'facebook': 'f', 'instagram': 'ig', 'linkedin': 'in', 'youtube': 'yt', 'twitter': 'X', 'tiktok': 'tk'} %}
|
||||
|
||||
{% for platform in social_data.all_platforms %}
|
||||
{% set profile = social_data.profiles.get(platform) %}
|
||||
<div class="platform-card {{ 'found' if profile else 'missing' }}">
|
||||
<div class="platform-header">
|
||||
<div class="platform-icon {{ platform }}">
|
||||
{% if platform == 'facebook' %}
|
||||
<svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24"><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 platform == 'instagram' %}
|
||||
<svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24"><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-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.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.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/></svg>
|
||||
{% elif platform == 'linkedin' %}
|
||||
<svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24"><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.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 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 platform == 'youtube' %}
|
||||
<svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24"><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.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 platform == 'twitter' %}
|
||||
<svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24"><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>
|
||||
{% elif platform == 'tiktok' %}
|
||||
<svg width="20" height="20" fill="currentColor" viewBox="0 0 24 24"><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>
|
||||
{% endif %}
|
||||
</div>
|
||||
<span class="platform-name">{{ platform_names.get(platform, platform|title) }}</span>
|
||||
<span class="platform-status {{ 'active' if profile else 'inactive' }}">
|
||||
{% if profile %}
|
||||
<svg width="12" height="12" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
||||
</svg>
|
||||
Aktywny
|
||||
{% else %}
|
||||
<svg width="12" height="12" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
Brak profilu
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="platform-details">
|
||||
{% if profile %}
|
||||
<div class="platform-url">
|
||||
<svg width="14" height="14" 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>
|
||||
<a href="{{ profile.url }}" target="_blank" rel="noopener">{{ profile.url|truncate(40) }}</a>
|
||||
</div>
|
||||
<div class="platform-meta">
|
||||
{% if profile.page_name %}
|
||||
<div class="platform-meta-item">
|
||||
<svg 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>
|
||||
{{ profile.page_name }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if profile.followers_count %}
|
||||
<div class="platform-meta-item">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 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 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"/>
|
||||
</svg>
|
||||
{{ '{:,}'.format(profile.followers_count).replace(',', ' ') }} obserwujacych
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if profile.verified_at %}
|
||||
<div class="platform-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>
|
||||
{{ profile.verified_at.strftime('%d.%m.%Y') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="platform-missing-text">Nie znaleziono profilu na tej platformie</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% if social_data.total_platforms - social_data.platforms_count > 0 %}
|
||||
<!-- Recommendations -->
|
||||
<h2 class="section-title">
|
||||
<svg width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/>
|
||||
</svg>
|
||||
Rekomendacje
|
||||
</h2>
|
||||
|
||||
<div class="recommendations">
|
||||
{% set missing_platforms = [] %}
|
||||
{% for platform in social_data.all_platforms %}
|
||||
{% if platform not in social_data.profiles %}
|
||||
{% set _ = missing_platforms.append(platform) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if 'facebook' in missing_platforms %}
|
||||
<div class="recommendation-item">
|
||||
<div class="recommendation-icon priority-high">!</div>
|
||||
<div class="recommendation-text">
|
||||
<strong>Facebook</strong> - Najpopularniejsza platforma w Polsce. Zalozenie strony firmowej pozwoli dotrzec do szerokiego grona klientow.
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if 'linkedin' in missing_platforms %}
|
||||
<div class="recommendation-item">
|
||||
<div class="recommendation-icon priority-high">!</div>
|
||||
<div class="recommendation-text">
|
||||
<strong>LinkedIn</strong> - Kluczowa platforma dla firm B2B. Idealna do budowania relacji biznesowych i employer brandingu.
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if 'instagram' in missing_platforms %}
|
||||
<div class="recommendation-item">
|
||||
<div class="recommendation-icon priority-medium">!</div>
|
||||
<div class="recommendation-text">
|
||||
<strong>Instagram</strong> - Swietna platforma do prezentacji wizualnej firmy. Szczegolnie wazna dla firm z produktami/uslugami wizualnymi.
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if 'youtube' in missing_platforms %}
|
||||
<div class="recommendation-item">
|
||||
<div class="recommendation-icon priority-medium">!</div>
|
||||
<div class="recommendation-text">
|
||||
<strong>YouTube</strong> - Druga najwieksza wyszukiwarka na swiecie. Video content buduje zaufanie i pokazuje ekspertyze.
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if 'tiktok' in missing_platforms %}
|
||||
<div class="recommendation-item">
|
||||
<div class="recommendation-icon priority-low">!</div>
|
||||
<div class="recommendation-text">
|
||||
<strong>TikTok</strong> - Najszybciej rosnaca platforma. Warto rozwazyc jesli celujecie w mlodszych odbiorców.
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if 'twitter' in missing_platforms %}
|
||||
<div class="recommendation-item">
|
||||
<div class="recommendation-icon priority-low">!</div>
|
||||
<div class="recommendation-text">
|
||||
<strong>X (Twitter)</strong> - Platforma do szybkiej komunikacji i budowania wizerunku eksperta. Przydatna w branzy tech/media.
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
Loading…
Reference in New Issue
Block a user