--wip-- [skip ci]
This commit is contained in:
@@ -30,6 +30,7 @@ dotenv.load_dotenv(BASE_DIR / ".env")
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
"course_calendar",
|
||||
"home",
|
||||
"search",
|
||||
"purchase",
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Course Calendar" %}{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@6.1.20/index.global.min.js" integrity="sha256-sQEgS6I+FEeOlX4oTVi7qW/HMRAh0O6vifpeZXIMRsg=" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
function showModal(occurrenceId) {
|
||||
// get event's url
|
||||
const eventApiUrl = `/api/calendar/occurrences/${occurrenceId}`;
|
||||
|
||||
const eventApi = fetch(eventApiUrl)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
eventUrl = `/occurrence/${occurrenceId}/`;
|
||||
|
||||
const modal = document.createElement('div');
|
||||
modal.classList.add('fixed', 'inset-0', 'flex', 'items-center', 'justify-center', 'z-50', 'shadow-lg', 'overflow-auto');
|
||||
modal.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; // semi-transparent background
|
||||
|
||||
const modalContent = document.createElement('div');
|
||||
modalContent.classList.add('bg-white', 'rounded-lg', 'p-6', 'max-w-3xl', 'relative', 'overflow-auto', 'max-h-[80vh]');
|
||||
modalContent.innerHTML = '<p class="text-gray-500">{% trans "Loading..." %}</p>';
|
||||
|
||||
if (eventUrl) {
|
||||
fetch(eventUrl)
|
||||
.then(response => response.text())
|
||||
.then(html => {
|
||||
modalContent.innerHTML = html;
|
||||
})
|
||||
.catch(error => {
|
||||
modalContent.innerHTML = '<p class="text-red-500">Failed to load event details.</p>';
|
||||
});
|
||||
|
||||
modal.appendChild(modalContent);
|
||||
document.body.appendChild(modal);
|
||||
|
||||
// Close modal when clicking outside modalContent
|
||||
modal.addEventListener('click', function(e) {
|
||||
if (e.target === modal) {
|
||||
document.body.removeChild(modal);
|
||||
|
||||
// remove ?modal=occurrenceId from the url
|
||||
const url = new URL(window.location);
|
||||
url.searchParams.delete('modal');
|
||||
window.history.pushState({}, '', url);
|
||||
}
|
||||
});
|
||||
|
||||
// Close modal on ESC key
|
||||
document.addEventListener('keydown', function escHandler(e) {
|
||||
if (e.key === 'Escape') {
|
||||
if (document.body.contains(modal)) {
|
||||
document.body.removeChild(modal);
|
||||
}
|
||||
document.removeEventListener('keydown', escHandler);
|
||||
// remove ?modal=occurrenceId from the url
|
||||
const url = new URL(window.location);
|
||||
url.searchParams.delete('modal');
|
||||
window.history.pushState({}, '', url);
|
||||
}
|
||||
});
|
||||
|
||||
const closeButton = document.createElement('button');
|
||||
closeButton.classList.add('absolute', 'top-2', 'right-2', 'text-red-500', 'cursor-pointer', 'hover:text-gray-700', 'text-5xl', 'translate-x-[-50%]');
|
||||
closeButton.innerHTML = '×';
|
||||
closeButton.addEventListener('click', function() {
|
||||
if (document.body.contains(modal)) {
|
||||
document.body.removeChild(modal);
|
||||
}
|
||||
// remove ?modal=occurrenceId from the url
|
||||
const url = new URL(window.location);
|
||||
url.searchParams.delete('modal');
|
||||
window.history.pushState({}, '', url);
|
||||
});
|
||||
modal.appendChild(closeButton);
|
||||
|
||||
// add ?modal=occurrenceId to the url
|
||||
const url = new URL(window.location);
|
||||
url.searchParams.set('modal', occurrenceId);
|
||||
window.history.pushState({}, '', url);
|
||||
}
|
||||
return data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching event details:', error);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
// if ?modal=event_id is in the url, open the modal for that event
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const modalEventId = urlParams.get('modal');
|
||||
if (modalEventId) {
|
||||
showModal(modalEventId);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var calendarEl = document.getElementById('calendar');
|
||||
var calendar = new FullCalendar.Calendar(calendarEl, {
|
||||
height: "auto",
|
||||
initialView: 'timeGridWeek',
|
||||
firstDay: 1,
|
||||
nowIndicator: true,
|
||||
views: {
|
||||
timeGridWeek: {
|
||||
titleFormat: { month: 'long', year: 'numeric' },
|
||||
slotLabelFormat: { hour: '2-digit', minute: '2-digit' },
|
||||
slotMinTime: '08:00:00',
|
||||
slotMaxTime: '22:00:00',
|
||||
},
|
||||
listWeek: {
|
||||
titleFormat: { month: 'long', year: 'numeric' },
|
||||
listDaySideFormat: false,
|
||||
},
|
||||
},
|
||||
headerToolbar: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'timeGridWeek,listMonth',
|
||||
},
|
||||
locale: "{% get_current_language as LANGUAGE_CODE %}{{ LANGUAGE_CODE }}",
|
||||
events: "/api/calendar/occurrences/",
|
||||
eventClick: function(info) {
|
||||
// prevent default navigation
|
||||
info.jsEvent.preventDefault();
|
||||
const eventUrl = info.event.url;
|
||||
if (eventUrl) {
|
||||
showModal(info.event.id);
|
||||
}
|
||||
},
|
||||
});
|
||||
calendar.render();
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="overflow-auto">
|
||||
<div id="calendar" class="min-w-xl"></div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -5,7 +5,7 @@
|
||||
<nav class="flex items-center gap-4">
|
||||
<a class="text-xl font-bold" href="/">{{ current_site.site_name }}</a>
|
||||
<a href="{% slugurl 'courses' %}" class="hover:underline">{% trans "Courses" %}</a>
|
||||
<a href="{% url 'calendar' %}" class="hover:underline">{% trans "Calendar" %}</a>
|
||||
<a href="{% url 'calendar_view' %}" class="hover:underline">{% trans "Calendar" %}</a>
|
||||
</nav>
|
||||
|
||||
<nav class="flex items-center gap-4">
|
||||
|
||||
@@ -23,33 +23,8 @@ urlpatterns = [
|
||||
path("oauth2/", include("oauth2_provider.urls", namespace="oauth2_provider")),
|
||||
path("", include("home.urls")),
|
||||
path("", include("purchase.urls")),
|
||||
path("calendar/", views.calendar, name="calendar"),
|
||||
path("calendar/", include("course_calendar.urls"), name="calendar"),
|
||||
# TODO: move occurrence related urls to home app
|
||||
path(
|
||||
"occurrence/<int:occurrence_id>/",
|
||||
views.occurrence_detail,
|
||||
name="occurrence_detail",
|
||||
),
|
||||
path(
|
||||
"api/calendar/occurrences/",
|
||||
views.get_calendar_occurrences,
|
||||
name="get_calendar_occurrences",
|
||||
),
|
||||
path(
|
||||
"api/calendar/occurrences/<int:occurrence_id>/",
|
||||
views.get_calendar_occurrence,
|
||||
name="get_calendar_occurrence",
|
||||
),
|
||||
path(
|
||||
"occurrence/<int:occurrence_id>/signup/",
|
||||
views.occurrence_signup,
|
||||
name="occurrence_signup",
|
||||
),
|
||||
path(
|
||||
"occurrence/<int:occurrence_id>/signout/",
|
||||
views.occurrence_signout,
|
||||
name="occurrence_signout",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
||||
101
kursy/views.py
101
kursy/views.py
@@ -3,7 +3,7 @@ from django.contrib.auth.decorators import login_required
|
||||
from django.http import JsonResponse
|
||||
from django.shortcuts import redirect, render
|
||||
|
||||
from home.models import EventOccurrence, EventPage
|
||||
# from home.models import EventOccurrence, EventPage
|
||||
|
||||
from .forms import SignUpForm
|
||||
|
||||
@@ -23,102 +23,3 @@ def signup(request):
|
||||
@login_required
|
||||
def profile(request):
|
||||
return render(request, "profile.html", {"user": request.user})
|
||||
|
||||
|
||||
def calendar(request):
|
||||
return render(request, "calendar.html")
|
||||
|
||||
|
||||
def occurrence_detail(request, occurrence_id):
|
||||
occ = (
|
||||
EventOccurrence.objects.select_related("event").filter(id=occurrence_id).first()
|
||||
)
|
||||
if not occ:
|
||||
return redirect("calendar")
|
||||
event = occ.event.specific
|
||||
return render(
|
||||
request,
|
||||
"occurrence_detail.html",
|
||||
{
|
||||
"occurrence": occ,
|
||||
"event": event,
|
||||
"user_signed_up": occ.user_signed_up(request.user),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def get_calendar_occurrences(request):
|
||||
# get occurrences from database (EventOccurrence model)
|
||||
start = request.GET.get("start")
|
||||
end = request.GET.get("end")
|
||||
occurrences = EventOccurrence.objects.filter(
|
||||
start__gte=start, end__lte=end
|
||||
).select_related("event")
|
||||
|
||||
events_list = []
|
||||
for occ in occurrences:
|
||||
event = occ.event.specific
|
||||
events_list.append(
|
||||
{
|
||||
"id": occ.id,
|
||||
"event_id": event.id,
|
||||
"title": event.title,
|
||||
"start": occ.start,
|
||||
"end": occ.end,
|
||||
"location": event.location,
|
||||
"url": event.url,
|
||||
"color": "#666666" if occ.is_past else event.color,
|
||||
"tags": list(event.tags.values_list("name", flat=True)),
|
||||
}
|
||||
)
|
||||
|
||||
return JsonResponse(events_list, safe=False)
|
||||
|
||||
|
||||
def get_calendar_occurrence(request, occurrence_id):
|
||||
occ = (
|
||||
EventOccurrence.objects.select_related("event").filter(id=occurrence_id).first()
|
||||
)
|
||||
if not occ:
|
||||
return JsonResponse({"error": "Occurrence not found"}, status=404)
|
||||
event = occ.event.specific
|
||||
event_dict = {
|
||||
"id": occ.id,
|
||||
"event_id": event.id,
|
||||
"title": event.title,
|
||||
"start": occ.start,
|
||||
"end": occ.end,
|
||||
"location": event.location,
|
||||
"url": event.url,
|
||||
"color": "#666666" if occ.is_past else event.color,
|
||||
"tags": list(event.tags.values_list("name", flat=True)),
|
||||
"attendees_count": occ.attendees_count,
|
||||
}
|
||||
return JsonResponse(event_dict)
|
||||
|
||||
|
||||
def occurrence_signup(request, occurrence_id):
|
||||
if not request.user.is_authenticated:
|
||||
return redirect("login")
|
||||
|
||||
occ = EventOccurrence.objects.filter(id=occurrence_id).first()
|
||||
if not occ:
|
||||
return redirect("calendar")
|
||||
|
||||
occ.signed_up_users.add(request.user)
|
||||
occ.save()
|
||||
# redirect to calendar page with ?modal=occurrence_id to show modal with event details
|
||||
return redirect(urls.reverse("calendar") + f"?modal={occurrence_id}")
|
||||
|
||||
|
||||
def occurrence_signout(request, occurrence_id):
|
||||
if not request.user.is_authenticated:
|
||||
return redirect("login")
|
||||
|
||||
occ = EventOccurrence.objects.filter(id=occurrence_id).first()
|
||||
if not occ:
|
||||
return redirect("calendar")
|
||||
|
||||
occ.signed_up_users.remove(request.user)
|
||||
occ.save()
|
||||
return redirect(urls.reverse("calendar") + f"?modal={occurrence_id}")
|
||||
|
||||
Reference in New Issue
Block a user