feat: Implementierung von Phase 6 (Frontend und finale Anpassungen)

This commit is contained in:
Matthias Nagel 2025-10-01 09:33:29 +02:00
parent 51bf727885
commit 1d61821f9f
16 changed files with 246 additions and 73 deletions

View File

@ -11,9 +11,16 @@ def handle_absence_period(sender, instance, **kwargs):
start_time__date__gte=instance.start_date, start_time__date__gte=instance.start_date,
start_time__date__lte=instance.end_date start_time__date__lte=instance.end_date
) )
for event in events_in_period:
EventParticipation.objects.update_or_create( # Get existing participations for the user and events in the period
user=user, existing_participations = EventParticipation.objects.filter(user=user, event__in=events_in_period).values_list('event_id', flat=True)
event=event,
defaults={'status': 'rejected'} # Bulk update existing participations
) EventParticipation.objects.filter(user=user, event__in=events_in_period).update(status='rejected')
# Bulk create new participations
new_participations = [
EventParticipation(user=user, event=event, status='rejected')
for event in events_in_period if event.id not in existing_participations
]
EventParticipation.objects.bulk_create(new_participations)

View File

@ -1,10 +1,20 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<h2>Edit Profile</h2> <div class="row justify-content-center">
<form method="post"> <div class="col-md-6">
{% csrf_token %} <div class="card">
{{ form.as_p }} <div class="card-header">
<button type="submit">Save Changes</button> <h2>Edit Profile</h2>
</form> </div>
<div class="card-body">
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Save Changes</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -1,10 +1,20 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<h2>Enter Invitation Code</h2> <div class="row justify-content-center">
<form method="post"> <div class="col-md-6">
{% csrf_token %} <div class="card">
{{ form.as_p }} <div class="card-header">
<button type="submit">Submit</button> <h2>Enter Invitation Code</h2>
</form> </div>
<div class="card-body">
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -1,10 +1,20 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<h2>Login</h2> <div class="row justify-content-center">
<form method="post"> <div class="col-md-6">
{% csrf_token %} <div class="card">
{{ form.as_p }} <div class="card-header">
<button type="submit">Login</button> <h2>Login</h2>
</form> </div>
<div class="card-body">
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Login</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -1,10 +1,20 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<h2>Create Player</h2> <div class="row justify-content-center">
<form method="post"> <div class="col-md-6">
{% csrf_token %} <div class="card">
{{ form.as_p }} <div class="card-header">
<button type="submit">Create Player</button> <h2>Create Player</h2>
</form> </div>
<div class="card-body">
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Create Player</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -1,10 +1,20 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<h2>Register</h2> <div class="row justify-content-center">
<form method="post"> <div class="col-md-6">
{% csrf_token %} <div class="card">
{{ form.as_p }} <div class="card-header">
<button type="submit">Register</button> <h2>Register</h2>
</form> </div>
<div class="card-body">
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Register</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -58,7 +58,7 @@ ROOT_URLCONF = 'baseball_organisator.urls'
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', 'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [], 'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True, 'APP_DIRS': True,
'OPTIONS': { 'OPTIONS': {
'context_processors': [ 'context_processors': [
@ -81,6 +81,14 @@ DATABASES = {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3',
} }
# 'default': {
# 'ENGINE': 'django.db.backends.mysql',
# 'NAME': 'baseball_organisator',
# 'USER': 'your_mysql_user',
# 'PASSWORD': 'your_mysql_password',
# 'HOST': 'localhost',
# 'PORT': '3306',
# }
} }
@ -120,6 +128,8 @@ USE_TZ = True
STATIC_URL = 'static/' STATIC_URL = 'static/'
STATICFILES_DIRS = [BASE_DIR / 'static']
# Default primary key field type # Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field

View File

@ -1,11 +1,21 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<h2>Delete Event</h2> <div class="row justify-content-center">
<p>Are you sure you want to delete "{{ object.title }}"?</p> <div class="col-md-6">
<form method="post"> <div class="card">
{% csrf_token %} <div class="card-header">
<button type="submit">Confirm Delete</button> <h2>Delete Event</h2>
<a href="{% url 'dashboard' %}">Cancel</a> </div>
</form> <div class="card-body">
<p>Are you sure you want to delete "{{ object.title }}"?</p>
<form method="post">
{% csrf_token %}
<button type="submit" class="btn btn-danger">Confirm Delete</button>
<a href="{% url 'dashboard' %}" class="btn btn-secondary">Cancel</a>
</form>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -1,10 +1,20 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<h2>{% if object %}Edit Event{% else %}Create Event{% endif %}</h2> <div class="row justify-content-center">
<form method="post"> <div class="col-md-6">
{% csrf_token %} <div class="card">
{{ form.as_p }} <div class="card-header">
<button type="submit">Save</button> <h2>{% if object %}Edit Event{% else %}Create Event{% endif %}</h2>
</form> </div>
<div class="card-body">
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Save</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -1,28 +1,32 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<h2>Dashboard</h2> <div class="d-flex justify-content-between align-items-center mb-3">
<h2>Dashboard</h2>
{% if user.coached_teams.all or user.assisted_teams.all %} {% if user.coached_teams.all or user.assisted_teams.all %}
<a href="{% url 'event-add' %}">Create New Event</a> <a href="{% url 'event-add' %}" class="btn btn-primary">Create New Event</a>
{% endif %} {% endif %}
</div>
<h3>Your Team's Events</h3> <h3>Your Team's Events</h3>
{% if events %} {% if events %}
<ul> <div class="list-group">
{% for event in events %} {% for event in events %}
<li> <div class="list-group-item list-group-item-action flex-column align-items-start">
<strong>{{ event.title }}</strong> ({{ event.start_time }}) <div class="d-flex w-100 justify-content-between">
<p>{{ event.description }}</p> <h5 class="mb-1">{{ event.title }}</h5>
<p>Location: {{ event.location_address }}</p> <small>{{ event.start_time }}</small>
<a href="{{ event.maps_shortlink }}" target="_blank">View on Map</a> </div>
<p class="mb-1">{{ event.description }}</p>
<small>Location: {{ event.location_address }}</small>
<a href="{{ event.maps_shortlink }}" target="_blank" class="btn btn-secondary btn-sm">View on Map</a>
{% if user == event.team.head_coach or user in event.team.assistant_coaches.all %} {% if user == event.team.head_coach or user in event.team.assistant_coaches.all %}
<a href="{% url 'event-update' event.pk %}">Edit</a> <a href="{% url 'event-update' event.pk %}" class="btn btn-warning btn-sm">Edit</a>
<a href="{% url 'event-delete' event.pk %}">Delete</a> <a href="{% url 'event-delete' event.pk %}" class="btn btn-danger btn-sm">Delete</a>
{% endif %} {% endif %}
</li> </div>
{% endfor %} {% endfor %}
</ul> </div>
{% else %} {% else %}
<p>No events found for your team.</p> <p>No events found for your team.</p>
{% endif %} {% endif %}

25
docs/phase6.md Normal file
View File

@ -0,0 +1,25 @@
## Phase 6: Frontend und finale Anpassungen
Dies ist die letzte Phase, in der das Layout und die Leistung optimiert werden.
Schritt 1: Django Templates erstellen
Erstelle die HTML-Templates für alle Views (Login, Dashboard, Termine erstellen, etc.) im templates-Verzeichnis.
Sorge für ein modernes, responsives Layout, das der Projektbeschreibung entspricht.
Schritt 2: Statische Dateien verwalten
Konfiguriere STATICFILES_DIRS in settings.py.
Stelle sicher, dass CSS, JavaScript und Bilder korrekt geladen werden.
Schritt 3: Code-Optimierung und Performance
Führe Performance-Tests durch, um sicherzustellen, dass die App performant ist, besonders bei der Anzeige von Kalendern mit vielen Terminen.
Schritt 4: Dokumentation und Fertigstellung
Führe die finalen Migrationen aus.
Die App ist nun einsatzbereit für die Bereitstellung auf dem Webserver mit MySQL als Backend, wie in den Anforderungen definiert. Die Übergabe des Codes vom Entwicklungsrechner zum Webspeicher sollte, wie gefordert, unkompliziert möglich sein.

6
static/css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

7
static/js/bootstrap.bundle.min.js vendored Normal file

File diff suppressed because one or more lines are too long

44
templates/base.html Normal file
View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
{% load static %}
<html>
<head>
<title>Baseball Organisator</title>
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'dashboard' %}">Baseball Organisator</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
{% if user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{% url 'edit_profile' %}">Profile</a>
</li>
<li class="nav-item">
<form method="post" action="{% url 'logout' %}">
{% csrf_token %}
<button type="submit" class="btn btn-link nav-link">Log Out</button>
</form>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'login' %}">Login</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<div class="container mt-4">
{% block content %}
{% endblock %}
</div>
<script src="{% static 'js/bootstrap.bundle.min.js' %}"></script>
</body>
</html>