feat: add "Pokaż więcej" button to ZOPK facts widget
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
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
- Add /api/zopk-facts endpoint returning paginated facts from distinct source articles, ordered by recency - Add "Pokaż więcej" button with AJAX loading and fade-in animation - New cards are clickable with same hover effect as initial ones Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
39fc5e0fac
commit
825d40e770
@ -9,7 +9,7 @@ connections map, release notes, dashboard.
|
||||
import logging
|
||||
from datetime import datetime, timedelta, date
|
||||
|
||||
from flask import render_template, request, redirect, url_for, flash, session, current_app, Response
|
||||
from flask import render_template, request, redirect, url_for, flash, session, current_app, Response, jsonify
|
||||
from flask_login import login_required, current_user
|
||||
from sqlalchemy import or_, func
|
||||
|
||||
@ -182,6 +182,48 @@ def index():
|
||||
db.close()
|
||||
|
||||
|
||||
@bp.route('/api/zopk-facts')
|
||||
@login_required
|
||||
def api_zopk_facts():
|
||||
"""API endpoint for loading more ZOPK facts (for homepage widget)."""
|
||||
from database import ZOPKKnowledgeFact, ZOPKNews
|
||||
offset = request.args.get('offset', 0, type=int)
|
||||
db = SessionLocal()
|
||||
try:
|
||||
recent_news_ids = db.query(
|
||||
ZOPKKnowledgeFact.source_news_id
|
||||
).join(ZOPKNews).filter(
|
||||
ZOPKKnowledgeFact.confidence_score >= 0.5,
|
||||
ZOPKNews.published_at.isnot(None)
|
||||
).group_by(
|
||||
ZOPKKnowledgeFact.source_news_id, ZOPKNews.published_at
|
||||
).order_by(ZOPKNews.published_at.desc()).offset(offset).limit(3).all()
|
||||
news_ids = [r[0] for r in recent_news_ids]
|
||||
facts = []
|
||||
for nid in news_ids:
|
||||
fact = db.query(ZOPKKnowledgeFact).join(ZOPKNews).filter(
|
||||
ZOPKKnowledgeFact.source_news_id == nid
|
||||
).first()
|
||||
if fact:
|
||||
type_labels = {'investment': 'inwestycja', 'decision': 'decyzja', 'event': 'wydarzenie',
|
||||
'milestone': 'kamień milowy', 'statistic': 'dane', 'partnership': 'współpraca',
|
||||
'project': 'projekt'}
|
||||
facts.append({
|
||||
'text': fact.full_text[:200],
|
||||
'type': fact.fact_type,
|
||||
'type_label': type_labels.get(fact.fact_type, 'fakt'),
|
||||
'source_name': fact.source_news.source_name or fact.source_news.source_domain if fact.source_news else '',
|
||||
'source_date': fact.source_news.published_at.strftime('%d.%m.%Y') if fact.source_news and fact.source_news.published_at else '',
|
||||
'source_url': fact.source_news.url if fact.source_news else '',
|
||||
})
|
||||
return jsonify({'facts': facts, 'has_more': len(facts) == 3})
|
||||
except Exception:
|
||||
db.rollback()
|
||||
return jsonify({'facts': [], 'has_more': False})
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@bp.route('/company/<int:company_id>')
|
||||
def company_detail(company_id):
|
||||
"""Company detail page - requires login and NORDA membership"""
|
||||
|
||||
@ -1085,6 +1085,12 @@
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div style="text-align: center; margin-top: var(--spacing-md);">
|
||||
<button id="zopkMoreBtn" onclick="loadMoreFacts()" style="background: rgba(255,255,255,0.15); border: 1px solid rgba(255,255,255,0.3); color: white; padding: 8px 20px; border-radius: var(--radius); cursor: pointer; font-size: var(--font-size-sm); transition: background 0.2s;"
|
||||
onmouseover="this.style.background='rgba(255,255,255,0.25)';" onmouseout="this.style.background='rgba(255,255,255,0.15)';">
|
||||
Pokaż więcej
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@ -1686,4 +1692,51 @@
|
||||
minimizeNordaGPT();
|
||||
}
|
||||
});
|
||||
|
||||
// ZOPK "Czy wiesz, że..." — load more facts
|
||||
let zopkOffset = 3;
|
||||
async function loadMoreFacts() {
|
||||
const btn = document.getElementById('zopkMoreBtn');
|
||||
btn.textContent = 'Ładowanie...';
|
||||
btn.disabled = true;
|
||||
try {
|
||||
const resp = await fetch('/api/zopk-facts?offset=' + zopkOffset);
|
||||
const data = await resp.json();
|
||||
if (data.facts && data.facts.length > 0) {
|
||||
const grid = btn.closest('div[data-animate]').querySelector('[style*="display: grid"]');
|
||||
const typeColors = {investment:'rgba(16,185,129,0.3)',event:'rgba(59,130,246,0.3)',decision:'rgba(245,158,11,0.3)',milestone:'rgba(139,92,246,0.3)'};
|
||||
data.facts.forEach(f => {
|
||||
const card = document.createElement('a');
|
||||
card.href = f.source_url || '/zopk';
|
||||
card.target = '_blank';
|
||||
card.rel = 'noopener';
|
||||
card.style.cssText = 'background:rgba(255,255,255,0.12);border-radius:var(--radius);padding:var(--spacing-md);text-decoration:none;color:white;display:block;transition:background 0.2s,transform 0.2s;cursor:pointer;opacity:0;';
|
||||
card.onmouseover = function(){this.style.background='rgba(255,255,255,0.22)';this.style.transform='translateY(-2px)';};
|
||||
card.onmouseout = function(){this.style.background='rgba(255,255,255,0.12)';this.style.transform='none';};
|
||||
const color = typeColors[f.type] || 'rgba(255,255,255,0.2)';
|
||||
card.innerHTML = '<span style="display:inline-block;padding:1px 8px;border-radius:4px;font-size:11px;font-weight:600;margin-bottom:var(--spacing-xs);background:'+color+';">'+f.type_label+'</span>'
|
||||
+ '<p style="font-size:var(--font-size-sm);line-height:1.5;margin:0;opacity:0.95;">'+f.text+(f.text.length>=200?'...':'')+'</p>'
|
||||
+ '<div style="font-size:11px;margin-top:var(--spacing-xs);opacity:0.7;">'+f.source_name+' • '+f.source_date+'<span style="float:right;opacity:0.8;">Czytaj →</span></div>';
|
||||
grid.appendChild(card);
|
||||
requestAnimationFrame(() => { card.style.transition = 'opacity 0.4s'; card.style.opacity = '1'; });
|
||||
});
|
||||
zopkOffset += data.facts.length;
|
||||
if (!data.has_more) {
|
||||
btn.textContent = 'To wszystko';
|
||||
btn.disabled = true;
|
||||
btn.style.opacity = '0.5';
|
||||
} else {
|
||||
btn.textContent = 'Pokaż więcej';
|
||||
btn.disabled = false;
|
||||
}
|
||||
} else {
|
||||
btn.textContent = 'Brak więcej faktów';
|
||||
btn.disabled = true;
|
||||
btn.style.opacity = '0.5';
|
||||
}
|
||||
} catch(e) {
|
||||
btn.textContent = 'Pokaż więcej';
|
||||
btn.disabled = false;
|
||||
}
|
||||
}
|
||||
{% endblock %}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user