adds month/year filtering for tournament lists

apikeys
Laurent 3 months ago
parent 7fa16f23c4
commit 966beb6599
  1. 4
      tournaments/static/tournaments/css/basics.css
  2. 1
      tournaments/static/tournaments/css/style.css
  3. 49
      tournaments/templates/tournaments/tournaments_list.html
  4. 16
      tournaments/templatetags/tournament_tags.py
  5. 191
      tournaments/views.py

@ -60,6 +60,10 @@
margin: 20px 0px;
}
.bmargin10 {
margin-bottom: 10px;
}
/* WIDTH PERCENTAGE */
.w15 {

@ -1015,7 +1015,6 @@ h-margin {
color: white; /* White text on hover */
}
.download-button {
margin-right: 6px;
color: #fff7ed;
padding: 8px 12px;
background-color: #1a223a;

@ -1,4 +1,5 @@
{% extends 'tournaments/base.html' %}
{% load tournament_tags %}
{% block head_title %}{{ head_title }}{% endblock %}
{% block first_title %}{{ first_title }}{% endblock %}
@ -7,6 +8,42 @@
{% block content %}
{% include 'tournaments/navigation_base.html' %}
{% if filter == 0 or filter == 2 %}
<!-- Year Navigation -->
{% if available_years %}
<div class="topmargin40">
<nav class="margin10">
{% for year in available_years %}
{% if year == selected_year %}
<a href="?filter={{ filter }}{% if club %}&club={{ club }}{% endif %}&year={{ year }}" class="download-button">{{ year }}</a>
{% else %}
<a href="?filter={{ filter }}{% if club %}&club={{ club }}{% endif %}&year={{ year }}" class="orange">{{ year }}</a>
{% endif %}
{% endfor %}
{% if year %}
<a href="?filter={{ filter }}{% if club %}&club={{ club }}{% endif %}" class="orange">Tous</a>
{% endif %}
</nav>
{% endif %}
<!-- Month Navigation -->
{% if available_months and selected_year %}
<nav class="margin10">
{% for month_num in available_months %}
{% if month_num == selected_month %}
<a href="?filter={{ filter }}{% if club %}&club={{ club }}{% endif %}&year={{ selected_year }}&month={{ month_num }}" class="download-button">{{ month_names|array_lookup:month_num }}</a>
{% else %}
<a href="?filter={{ filter }}{% if club %}&club={{ club }}{% endif %}&year={{ selected_year }}&month={{ month_num }}" class="orange">{{ month_names|array_lookup:month_num }}</a>
{% endif %}
{% endfor %}
</nav>
</div>
{% endif %}
{% endif %}
<div class="grid-x">
{% if tournaments %}
<div class="cell medium-12 large-6 topblock padding10">
@ -18,6 +55,18 @@
</div>
</div>
{% elif selected_month and selected_year %}
<div class="cell medium-12 large-6 topblock padding10">
<div class="bubble">
<p>Aucun tournoi trouvé pour {{ month_names|array_lookup:selected_month }} {{ selected_year }}.</p>
</div>
</div>
{% elif selected_year %}
<div class="cell medium-12 large-6 topblock padding10">
<div class="bubble">
<p>Aucun tournoi trouvé pour l'année {{ selected_year }}.</p>
</div>
</div>
{% endif %}
{% if first_tournament_prog_url and tournaments %}

@ -5,3 +5,19 @@ register = template.Library()
@register.filter
def get_player_status(tournament, user):
return tournament.get_player_registration_status_by_licence(user)
@register.filter
def lookup(dictionary, key):
"""Template filter to lookup dictionary values by key"""
return dictionary.get(key, '')
@register.filter
def array_lookup(array, index):
"""Template filter to lookup array values by index"""
try:
index = int(index)
if 0 <= index < len(array):
return array[index]
return ''
except (ValueError, TypeError, IndexError):
return ''

@ -1,58 +1,53 @@
# Standard library imports
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth import login, get_user_model, logout, update_session_auth_hash
from django.contrib.auth.views import PasswordResetCompleteView, PasswordResetConfirmView
from django.contrib.sites.shortcuts import get_current_site
from django.contrib.auth.decorators import login_required
from django.contrib.admin.views.decorators import staff_member_required
from django.shortcuts import redirect, render, get_object_or_404
from django.utils import timezone, formats
from django.utils.encoding import force_str, force_bytes
from django.utils.http import urlsafe_base64_decode
from django.http import JsonResponse, HttpResponse, Http404
from django.urls import reverse, reverse_lazy
from django.conf import settings
from django.db.models import Q
from django.views.generic import View
from django.views.generic.edit import UpdateView
from django.views.decorators.csrf import csrf_protect, csrf_exempt
from django.template.loader import render_to_string
from django.core.mail import EmailMessage
from django.core.exceptions import ValidationError
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
import os
import csv
import locale
import calendar
from api.serializers import GroupStageSerializer, MatchSerializer, PlayerRegistrationSerializer, TeamRegistrationSerializer, TeamScoreSerializer
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth import logout
from .utils.extensions import is_not_sqlite_backend
import stripe
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.views import PasswordResetCompleteView
from django.shortcuts import redirect
from django.contrib.auth import login
from django.contrib.auth import get_user_model
from django.shortcuts import render, get_object_or_404
from django.http import JsonResponse, HttpResponse
from django.utils.encoding import force_str
from django.utils.http import urlsafe_base64_decode
from django.urls import reverse
from django.conf import settings
from django.contrib.admin.views.decorators import staff_member_required
from django.views.generic import View
from django.db.models import Q
from .models import Club, Tournament, CustomUser, Event, Round, Match, TeamScore, TeamRegistration, PlayerRegistration, UserOrigin, Purchase
from .models import Club, Tournament, CustomUser, Event, Round, Match, TeamScore, TeamRegistration, PlayerRegistration, UserOrigin
from datetime import datetime, timedelta
import time
import json
import asyncio
import zipfile
import pandas as pd
from tournaments.utils.extensions import create_random_filename
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from django.utils import formats
from tournaments.utils.extensions import create_random_filename
from api.tokens import account_activation_token
# Third-party imports
from qr_code.qrcode.utils import QRCodeOptions
# Django imports
from django.http import Http404
from django.urls import reverse_lazy
from django.utils import timezone
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from django.template.loader import render_to_string
from django.contrib import messages
from django.contrib.sites.shortcuts import get_current_site
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import PasswordResetConfirmView
from django.core.mail import EmailMessage
from django.views.decorators.csrf import csrf_protect
from .services.tournament_unregistration import TournamentUnregistrationService
from django.core.exceptions import ValidationError
from .forms import (
ProfileUpdateForm,
SimpleCustomUserCreationForm,
@ -62,12 +57,11 @@ from .forms import (
)
from .utils.apns import send_push_notification
from .utils.licence_validator import LicenseValidator
from django.views.generic.edit import UpdateView
from .forms import CustomPasswordChangeForm
from .services.email_service import TournamentEmailService
from .services.tournament_registration import RegistrationCartManager
from .services.payment_service import PaymentService
from django.views.decorators.csrf import csrf_exempt
import logging
@ -171,6 +165,60 @@ def future_tournaments(club_id, limit=None):
tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True, limit)
return [t for t in tournaments if t.display_tournament() and t.starts_in_the_future()]
def future_tournaments_by_month(club_id, year, month):
"""Get future tournaments filtered by year and month"""
logger.info(f'filter {year} {month}')
tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True)
filtered_tournaments = []
for t in tournaments:
if (t.display_tournament() and t.starts_in_the_future() and
t.start_date.year == year and t.start_date.month == month + 1):
filtered_tournaments.append(t)
return filtered_tournaments
def finished_tournaments_by_month(club_id, year, month):
"""Get finished tournaments filtered by year and month"""
clean_ended_tournaments = tournaments_query(Q(end_date__isnull=False), club_id, False)
clean_ended_tournaments = [t for t in clean_ended_tournaments if t.display_tournament()]
one_day_ago = timezone.now() - timedelta(days=1)
ended_tournaments = tournaments_query(
Q(end_date__isnull=True, start_date__lt=one_day_ago),
club_id,
False
)
ended_tournaments = [t for t in ended_tournaments if t.display_tournament() and t.should_be_over()]
# Combine both lists
all_tournaments = clean_ended_tournaments + ended_tournaments
# Filter by year and month
filtered_tournaments = []
for t in all_tournaments:
if t.start_date.year == year and t.start_date.month == month:
filtered_tournaments.append(t)
# Sort by start_date descending
filtered_tournaments.sort(key=lambda t: t.start_date, reverse=True)
return filtered_tournaments
def get_available_years_for_tournaments(club_id, filter_type):
"""Get available years for tournaments based on filter type"""
if filter_type == 0: # Future tournaments
tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True)
tournaments = [t for t in tournaments if t.display_tournament() and t.starts_in_the_future()]
elif filter_type == 2: # Finished tournaments
tournaments = finished_tournaments(club_id)
else:
return []
years = set()
for t in tournaments:
years.add(t.start_date.year)
return sorted(years, reverse=(filter_type == 2))
def tournament_info(request, tournament_id):
tournament = get_object_or_404(Tournament, pk=tournament_id)
registered_user = None
@ -217,18 +265,45 @@ def tournaments(request):
return redirect('/')
club_id = request.GET.get('club')
year_param = request.GET.get('year')
month_param = request.GET.get('month')
title = ''
tournaments = []
if filter==0:
available_years = []
selected_year = None
if month_param:
selected_month = int(month_param)
else:
selected_month = timezone.now().month - 1
if filter == 0:
title = 'À venir'
tournaments = future_tournaments(club_id)
elif filter==1:
available_years, selected_year = handle_year_month_filtering(year_param, club_id, filter, is_future=True)
if selected_year and selected_month:
tournaments = future_tournaments_by_month(club_id, selected_year, selected_month)
elif selected_year:
tournaments = future_tournaments(club_id)
else:
tournaments = future_tournaments(club_id)
elif filter == 1:
title = 'En cours'
tournaments = live_tournaments(club_id)
elif filter==2:
elif filter == 2:
title = 'Terminés'
tournaments = finished_tournaments(club_id)
available_years, selected_year = handle_year_month_filtering(year_param, club_id, filter, is_future=False)
if selected_year and selected_month:
tournaments = finished_tournaments_by_month(club_id, selected_year, selected_month)
elif selected_year:
tournaments = finished_tournaments(club_id)
else:
tournaments = finished_tournaments(club_id)
locale.setlocale(locale.LC_TIME, 'fr_FR.UTF-8') # Define month names in french
return render(
request,
@ -239,9 +314,39 @@ def tournaments(request):
'second_title': title,
'head_title': title,
'club': club_id,
'filter': filter,
'available_years': available_years,
'available_months': range(0, 12),
'selected_year': selected_year,
'selected_month': selected_month,
'month_names': list(calendar.month_name)[1:],
'year': year_param,
'month': month_param,
}
)
def handle_year_month_filtering(year_param, club_id, filter_type, is_future=True):
"""Helper function to handle year/month filtering for future and finished tournaments"""
available_years = get_available_years_for_tournaments(club_id, filter_type)
selected_year = None
# Handle year selection
current_year = timezone.now().year
if not year_param and available_years:
if is_future:
selected_year = current_year if current_year in available_years else available_years[0]
else:
selected_year = available_years[0] # Most recent year for finished tournaments
elif year_param:
try:
selected_year = int(year_param)
if selected_year not in available_years:
selected_year = available_years[0] if available_years else None
except:
selected_year = available_years[0] if available_years else None
return available_years, selected_year
def clubs(request):
all_clubs = Club.objects.all().order_by('name')
clubs = []

Loading…
Cancel
Save