feat: display FB category, phone, website, address from API on profile card
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

Store extra Graph API fields in content_types JSONB. Show category tag,
contact pills with icons, and description in styled quote block.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-02-19 14:06:04 +01:00
parent 553c48b054
commit 0ddde6af22
2 changed files with 54 additions and 8 deletions

View File

@ -392,6 +392,18 @@ def sync_facebook_to_social_media(db, company_id: int) -> dict:
csm.verified_at = now
csm.last_checked_at = now
# Store extra API fields in content_types JSONB (no migration needed)
extra = csm.content_types or {}
if page_info.get('category'):
extra['category'] = page_info['category']
if page_info.get('website'):
extra['website'] = page_info['website']
if page_info.get('phone'):
extra['phone'] = page_info['phone']
if page_info.get('single_line_address'):
extra['address'] = page_info['single_line_address']
csm.content_types = extra
# Append to followers_history
history = csm.followers_history or []
if followers > 0:

View File

@ -2627,21 +2627,55 @@
</div>
</div>
{% if sm.profile_description %}
{% if sm.source == 'facebook_api' and sm.content_types %}
{% set fb_extra = sm.content_types %}
{% if fb_extra.get('category') %}
<div style="margin-bottom: var(--spacing-sm);">
<span style="font-size: var(--font-size-sm); color: var(--text-secondary);">Opis:</span>
<div style="font-size: var(--font-size-sm); color: var(--text-primary); line-height: 1.4;">{{ sm.profile_description|truncate(200) }}</div>
<span style="display: inline-block; font-size: var(--font-size-xs); padding: 2px 8px; background: #f0f0ff; color: #4b5563; border-radius: 10px;">{{ fb_extra['category'] }}</span>
</div>
{% endif %}
{% endif %}
{% if sm.profile_description %}
<div style="margin-bottom: var(--spacing-sm); padding: var(--spacing-sm); background: #f8fafc; border-left: 3px solid #cbd5e1; border-radius: 0 var(--radius-sm) var(--radius-sm) 0;">
<div style="font-size: var(--font-size-xs); color: var(--text-secondary); line-height: 1.5;">{{ sm.profile_description|truncate(150) }}</div>
</div>
{% endif %}
{% if sm.source == 'facebook_api' and sm.content_types %}
{% set fb_extra = sm.content_types %}
{% if fb_extra.get('phone') or fb_extra.get('website') or fb_extra.get('address') %}
<div style="display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: var(--spacing-sm);">
{% if fb_extra.get('phone') %}
<span style="display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--text-secondary); background: #f3f4f6; padding: 2px 8px; border-radius: 10px;">
<svg width="11" height="11" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"/></svg>
{{ fb_extra['phone'] }}
</span>
{% endif %}
{% if fb_extra.get('website') %}
<a href="{{ fb_extra['website'] }}" target="_blank" rel="noopener" style="display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--primary); background: #f3f4f6; padding: 2px 8px; border-radius: 10px; text-decoration: none;">
<svg width="11" height="11" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9"/></svg>
{{ fb_extra['website']|replace('https://', '')|replace('http://', '')|truncate(25) }}
</a>
{% endif %}
{% if fb_extra.get('address') %}
<span style="display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--text-secondary); background: #f3f4f6; padding: 2px 8px; border-radius: 10px;">
<svg width="11" height="11" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 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 stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
{{ fb_extra['address']|truncate(30) }}
</span>
{% endif %}
</div>
{% endif %}
{% endif %}
{% if sm.source == 'facebook_api' and sm.profile_completeness_score is not none %}
<div style="margin-bottom: var(--spacing-sm);">
<span style="font-size: var(--font-size-sm); color: var(--text-secondary);">Kompletność profilu:</span>
<div style="display: flex; align-items: center; gap: var(--spacing-sm); margin-top: 4px;">
<div style="flex: 1; height: 6px; background: #e5e7eb; border-radius: 3px; overflow: hidden;">
<div style="height: 100%; width: {{ sm.profile_completeness_score }}%; background: {% if sm.profile_completeness_score >= 75 %}#10b981{% elif sm.profile_completeness_score >= 50 %}#f59e0b{% else %}#ef4444{% endif %}; border-radius: 3px;"></div>
<div style="display: flex; align-items: center; gap: var(--spacing-sm);">
<span style="font-size: 11px; color: var(--text-secondary); white-space: nowrap;">Profil</span>
<div style="flex: 1; height: 4px; background: #e5e7eb; border-radius: 2px; overflow: hidden;">
<div style="height: 100%; width: {{ sm.profile_completeness_score }}%; background: {% if sm.profile_completeness_score >= 75 %}#10b981{% elif sm.profile_completeness_score >= 50 %}#f59e0b{% else %}#ef4444{% endif %}; border-radius: 2px;"></div>
</div>
<span style="font-size: var(--font-size-xs); font-weight: 600; color: var(--text-secondary);">{{ sm.profile_completeness_score }}%</span>
<span style="font-size: 11px; font-weight: 600; color: var(--text-secondary);">{{ sm.profile_completeness_score }}%</span>
</div>
</div>
{% endif %}