feat: add 'Nowe na portalu' section to homepage
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

Shows 2 latest forum topics + 2 latest B2B classifieds in a 4-column
grid between events and NordaGPT banner. Responsive 2-col on mobile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-04-10 07:28:36 +02:00
parent d10c6620d8
commit 3ede8739e8
2 changed files with 125 additions and 1 deletions

View File

@ -205,6 +205,37 @@ def index():
except Exception:
pass
# Latest forum topics (2 different topics with recent activity)
latest_forum_topics = []
try:
from database import ForumTopic, ForumReply
from sqlalchemy import func
# Get 2 most recently active topics (by latest reply or creation date)
topics_with_activity = db.query(
ForumTopic,
func.coalesce(func.max(ForumReply.created_at), ForumTopic.created_at).label('last_activity')
).outerjoin(
ForumReply, (ForumReply.topic_id == ForumTopic.id) & (ForumReply.is_deleted == False)
).filter(
ForumTopic.is_deleted == False
).group_by(ForumTopic.id).order_by(
func.coalesce(func.max(ForumReply.created_at), ForumTopic.created_at).desc()
).limit(2).all()
latest_forum_topics = [t[0] for t in topics_with_activity]
except Exception:
pass
# Latest B2B classifieds (2 newest active)
latest_classifieds = []
try:
from database import Classified
latest_classifieds = db.query(Classified).filter(
Classified.is_active == True,
Classified.is_test == False
).order_by(Classified.created_at.desc()).limit(2).all()
except Exception:
pass
# New members — find newest board meeting that has admitted companies
latest_admitted = []
last_meeting = None
@ -239,7 +270,9 @@ def index():
latest_forum_reply=latest_forum_reply,
latest_forum_topic_for_reply=latest_forum_topic_for_reply,
latest_admitted=latest_admitted,
last_meeting=last_meeting
last_meeting=last_meeting,
latest_forum_topics=latest_forum_topics,
latest_classifieds=latest_classifieds
)
finally:
db.close()

View File

@ -979,6 +979,69 @@
margin-top: 0;
}
}
/* New on portal section */
.new-on-portal {
margin-bottom: var(--spacing-lg);
}
.new-on-portal h2 {
font-size: var(--font-size-lg);
color: var(--text-primary);
margin-bottom: var(--spacing-md);
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.new-on-portal-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: var(--spacing-md);
}
.new-card {
text-decoration: none;
display: block;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: var(--spacing-md);
transition: all 0.2s;
}
.new-card:hover {
border-color: var(--primary);
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
.new-card-badge {
display: inline-block;
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
padding: 2px 8px;
border-radius: 4px;
margin-bottom: var(--spacing-sm);
}
.new-card-badge.forum { background: #dbeafe; color: #1e40af; }
.new-card-badge.b2b { background: #dcfce7; color: #166534; }
.new-card-title {
font-weight: 600;
color: var(--text-primary);
font-size: var(--font-size-sm);
line-height: 1.4;
margin-bottom: var(--spacing-sm);
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.new-card-meta {
font-size: var(--font-size-xs);
color: var(--text-secondary);
}
@media (max-width: 768px) {
.new-on-portal-grid {
grid-template-columns: repeat(2, 1fr);
}
}
{% endblock %}
{% block content %}
@ -1213,6 +1276,34 @@
{% endif %}
<!-- New on Portal -->
{% if latest_forum_topics or latest_classifieds %}
<div class="new-on-portal" data-animate="fadeIn">
<h2>📋 Nowe na portalu</h2>
<div class="new-on-portal-grid">
{% for topic in latest_forum_topics %}
<a href="{{ url_for('forum.forum_topic', topic_id=topic.id) }}" class="new-card">
<span class="new-card-badge forum">💬 Forum</span>
<div class="new-card-title">{{ topic.title }}</div>
<div class="new-card-meta">
{{ topic.author.name if topic.author else 'Anonim' }} · {{ topic.created_at|local_time('%d.%m.%Y') }}
{% if topic.replies_count is defined and topic.replies_count %}· {{ topic.replies_count }} odp.{% endif %}
</div>
</a>
{% endfor %}
{% for cl in latest_classifieds %}
<a href="{{ url_for('classifieds.classifieds_view', classified_id=cl.id) }}" class="new-card">
<span class="new-card-badge b2b">🏢 B2B {% if cl.listing_type == 'szukam' %}Szukam{% else %}Oferuję{% endif %}</span>
<div class="new-card-title">{{ cl.title }}</div>
<div class="new-card-meta">
{{ cl.author.name if cl.author else 'Anonim' }} · {{ cl.created_at|local_time('%d.%m.%Y') }}
</div>
</a>
{% endfor %}
</div>
</div>
{% endif %}
<!-- NordaGPT Chat Banner -->
{% if current_user.is_authenticated %}
<a href="{{ url_for('chat') }}" class="chat-banner" id="chatBanner" style="cursor: pointer; text-decoration: none;" data-animate="fadeIn">