Layout Kursübersicht

This commit is contained in:
Bkolb 2026-04-11 19:08:26 +02:00
parent 1778bd1bae
commit 6789ac73c8
6 changed files with 292 additions and 13 deletions

View File

@ -1048,13 +1048,73 @@ def useradmin_user_edit(user_id):
@app.route("/courses") @app.route("/courses")
@login_required @login_required
def course_list(): def course_list():
courses = get_available_courses_for_user() user_id = session.get("user_id")
mandant_level = session.get("mandant_level", 0)
conn = get_connection()
cur = conn.cursor()
# Alle aktiven Kurse laden
cur.execute("""
SELECT id, code, title, description, video_file, sort_order, is_active
FROM course
WHERE is_active = TRUE
ORDER BY code
""")
all_courses = fetchall_dict(cur)
# Filter nach Level
available_courses = [
c for c in all_courses
if is_course_allowed_for_level(c["code"], mandant_level)
]
# Bestandene Assessments laden
cur.execute("""
SELECT DISTINCT course_id
FROM user_assessment
WHERE user_id = %s
AND passed = TRUE
""", (user_id,))
passed_rows = cur.fetchall()
passed_course_ids = {row[0] for row in passed_rows}
cur.close()
conn.close()
# Kurse markieren + Modul bestimmen
for course in available_courses:
course["is_completed"] = course["id"] in passed_course_ids
course["module_code"] = (course["code"] or "")[:1].upper()
# Gruppieren + Fortschritt berechnen
grouped_courses = {}
module_progress = {}
for module_code in ("A", "B", "C"):
module_courses = [
c for c in available_courses
if c["module_code"] == module_code
]
grouped_courses[module_code] = module_courses
total = len(module_courses)
completed = sum(1 for c in module_courses if c["is_completed"])
percent = int((completed / total) * 100) if total > 0 else 0
module_progress[module_code] = {
"total": total,
"completed": completed,
"percent": percent
}
return render_template( return render_template(
"course_list.html", "courses.html",
grouped_courses=grouped_courses,
module_progress=module_progress,
page_title="Kurse", page_title="Kurse",
active_page="courses", active_page="courses",
courses=courses,
**get_current_user() **get_current_user()
) )

View File

@ -19,14 +19,13 @@
</div> </div>
<nav class="top-nav"> <nav class="top-nav">
<!-- <a href="/home" class="{% if active_page == 'home' %}active{% endif %}">Home</a> -->
<a href="/preise" class="{% if active_page == 'preise' %}active{% endif %}">Preise</a>
<!-- <a href="/allgemein" class="{% if active_page == 'allgemein' %}active{% endif %}">Allgemein</a> -->
{% if is_logged_in %} {% if is_logged_in %}
<a href="/courses" class="{% if active_page == 'courses' %}active{% endif %}"> <a href="/courses" class="{% if active_page == 'courses' %}active{% endif %}">
Kurse Kurse
</a> </a>
{% else %}
<a href="/preise" class="{% if active_page == 'preise' %}active{% endif %}">Preise</a>
{% endif %} {% endif %}
{% if is_logged_in %} {% if is_logged_in %}

View File

@ -0,0 +1,85 @@
{% extends "base.html" %}
{% block content %}
<div class="page-header">
<h1>Kurse</h1>
<p class="intro-text">Ihre verfügbaren Schulungsmodule und Kurse.</p>
</div>
{% for module_code, module_courses in grouped_courses.items() %}
{% if module_courses %}
<section class="admin-section">
<div class="admin-panel">
<!-- Modul Titel -->
<div class="admin-panel-header">
<h2>Modul {{ module_code }}</h2>
</div>
<!-- Fortschritt -->
<div class="progress-box">
<div class="progress-header">
<span>
{{ module_progress[module_code].completed }}
/
{{ module_progress[module_code].total }}
abgeschlossen
</span>
<span>{{ module_progress[module_code].percent }}%</span>
</div>
<div class="progress-bar">
<div class="progress-fill"
style="width: {{ module_progress[module_code].percent }}%;">
</div>
</div>
{% if module_progress[module_code].percent == 100 %}
<div style="margin-top:6px; font-size:12px; color:#15803d; font-weight:600;">
✔ Modul abgeschlossen
</div>
{% endif %}
</div>
<!-- Kurse -->
<div class="course-grid">
{% for course in module_courses %}
<article class="course-card {% if course.is_completed %}course-card-completed{% endif %}">
<div class="course-card-header">
<div class="course-code">{{ course.code }}</div>
{% if course.is_completed %}
<span class="course-badge course-badge-completed">
✔ abgeschlossen
</span>
{% endif %}
</div>
<h3>{{ course.title }}</h3>
{% if course.description %}
<p>{{ course.description }}</p>
{% endif %}
<div class="course-actions">
<a href="/course/{{ course.id }}" class="btn-primary btn-small">
Kurs öffnen
</a>
</div>
</article>
{% endfor %}
</div>
</div>
</section>
{% endif %}
{% endfor %}
{% endblock %}

View File

@ -2,7 +2,7 @@
{% block content %} {% block content %}
<h1>Login</h1> <h1>Melden Sie sich mit Ihrer email-adresse an</h1>
{% if error_message %} {% if error_message %}
<div class="error-box">{{ error_message }}</div> <div class="error-box">{{ error_message }}</div>

View File

@ -133,10 +133,6 @@
</article> </article>
</section> </section>
<section class="pricing-bottom-note">
<div class="image-panel">
<img src="/images/TabelleUebersicht.png" alt="Paketübersicht">
</div>
</section>
{% endblock %} {% endblock %}

View File

@ -1304,4 +1304,143 @@ button {
padding: 16px; padding: 16px;
border-radius: 10px; border-radius: 10px;
font-weight: 600; font-weight: 600;
}
/* ===============================
Kursübersicht User
=============================== */
.course-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 20px;
}
.course-card {
background: #ffffff;
border: 1px solid #dce3ea;
border-radius: 16px;
padding: 20px;
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.04);
}
.course-card-completed {
background: #eaf8ee;
border: 1px solid #9fd3ac;
}
.course-card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
gap: 10px;
}
.course-code {
font-size: 14px;
font-weight: 800;
color: #0d2f57;
letter-spacing: 0.04em;
}
.course-badge {
display: inline-block;
padding: 6px 12px;
border-radius: 999px;
font-size: 12px;
font-weight: 700;
}
.course-badge-completed {
background: #22c55e;
color: #ffffff;
}
.course-card h3 {
margin: 0 0 10px;
color: #0d2f57;
}
.course-card p {
margin: 0 0 16px;
color: #475569;
}
.course-actions {
margin-top: 10px;
}
/* Kurs Grid */
.course-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 20px;
}
/* Karte */
.course-card {
background: #ffffff;
border: 1px solid #dce3ea;
border-radius: 16px;
padding: 20px;
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.04);
}
/* Fertig */
.course-card-completed {
background: #eaf8ee;
border: 1px solid #9fd3ac;
}
/* Header */
.course-card-header {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
/* Code */
.course-code {
font-weight: 800;
color: #0d2f57;
}
/* Badge */
.course-badge {
padding: 5px 10px;
border-radius: 999px;
font-size: 12px;
font-weight: 700;
}
.course-badge-completed {
background: #22c55e;
color: white;
}
/* Progress */
.progress-box {
margin: 10px 0 20px;
}
.progress-header {
display: flex;
justify-content: space-between;
font-size: 13px;
margin-bottom: 6px;
color: #475569;
font-weight: 600;
}
.progress-bar {
width: 100%;
height: 10px;
background: #e5eaf0;
border-radius: 8px;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #22c55e, #15803d);
} }