This commit is contained in:
pacnpal
2024-10-29 23:11:55 -04:00
parent 6880f36b99
commit c58968a24a
20 changed files with 175 additions and 153 deletions

View File

@@ -6,7 +6,7 @@ from django.utils import timezone
import json
from .models import EditSubmission, PhotoSubmission
class EditSubmissionMixin(LoginRequiredMixin):
class EditSubmissionMixin:
"""
Mixin for handling edit submissions with proper moderation.
"""
@@ -67,6 +67,12 @@ class EditSubmissionMixin(LoginRequiredMixin):
def post(self, request, *args, **kwargs):
"""Handle POST requests for editing"""
if not request.user.is_authenticated:
return JsonResponse({
'status': 'error',
'message': 'You must be logged in to make edits.'
}, status=403)
try:
data = json.loads(request.body)
changes = data.get('changes', {})
@@ -101,12 +107,18 @@ class EditSubmissionMixin(LoginRequiredMixin):
'message': str(e)
}, status=500)
class PhotoSubmissionMixin(LoginRequiredMixin):
class PhotoSubmissionMixin:
"""
Mixin for handling photo submissions with proper moderation.
"""
def handle_photo_submission(self, request):
"""Handle a photo submission based on user's role"""
if not request.user.is_authenticated:
return JsonResponse({
'status': 'error',
'message': 'You must be logged in to upload photos.'
}, status=403)
if not request.FILES.get('photo'):
return JsonResponse({
'status': 'error',

View File

@@ -1,6 +1,5 @@
from django.urls import path
from . import views
from rides.views import RideDetailView
app_name = 'parks'
@@ -8,5 +7,4 @@ urlpatterns = [
path('', views.ParkListView.as_view(), name='park_list'),
path('create/', views.ParkCreateView.as_view(), name='park_create'),
path('<slug:slug>/', views.ParkDetailView.as_view(), name='park_detail'),
path('<slug:park_slug>/<slug:ride_slug>/', RideDetailView.as_view(), name='ride_detail'),
]

View File

@@ -37,10 +37,10 @@ class ParkCreateView(LoginRequiredMixin, CreateView):
reason=self.request.POST.get('reason', ''),
source=self.request.POST.get('source', '')
)
return HttpResponseRedirect(reverse('parks:park_list'))
return HttpResponseRedirect(reverse('park_list'))
def get_success_url(self):
return reverse('parks:park_detail', kwargs={'slug': self.object.slug})
return reverse('park_detail', kwargs={'slug': self.object.slug})
class ParkDetailView(SlugRedirectMixin, EditSubmissionMixin, PhotoSubmissionMixin, InlineEditMixin, HistoryMixin, DetailView):
model = Park
@@ -63,7 +63,7 @@ class ParkDetailView(SlugRedirectMixin, EditSubmissionMixin, PhotoSubmissionMixi
return context
def get_redirect_url_pattern(self):
return 'parks:park_detail'
return 'park_detail'
class ParkAreaDetailView(SlugRedirectMixin, EditSubmissionMixin, PhotoSubmissionMixin, InlineEditMixin, HistoryMixin, DetailView):
model = ParkArea
@@ -90,7 +90,7 @@ class ParkAreaDetailView(SlugRedirectMixin, EditSubmissionMixin, PhotoSubmission
return context
def get_redirect_url_pattern(self):
return 'parks:area_detail'
return 'park_detail'
def get_redirect_url_kwargs(self):
return {

View File

@@ -6,5 +6,4 @@ app_name = 'rides'
urlpatterns = [
path('', views.RideListView.as_view(), name='ride_list'),
path('create/', views.RideCreateView.as_view(), name='ride_create'),
path('<slug:park_slug>/<slug:ride_slug>/', views.RideDetailView.as_view(), name='ride_detail'),
]

View File

@@ -43,10 +43,10 @@ class RideCreateView(LoginRequiredMixin, CreateView):
reason=self.request.POST.get('reason', ''),
source=self.request.POST.get('source', '')
)
return HttpResponseRedirect(reverse('rides:ride_list'))
return HttpResponseRedirect(reverse('ride_list'))
def get_success_url(self):
return reverse('rides:ride_detail', kwargs={
return reverse('ride_detail', kwargs={
'park_slug': self.object.park.slug,
'ride_slug': self.object.slug
})
@@ -75,7 +75,7 @@ class RideDetailView(SlugRedirectMixin, EditSubmissionMixin, PhotoSubmissionMixi
return context
def get_redirect_url_pattern(self):
return 'rides:ride_detail'
return 'ride_detail'
def get_redirect_url_kwargs(self):
return {

View File

@@ -2943,14 +2943,14 @@ select {
--tw-gradient-stops: var(--tw-gradient-from), #eff6ff var(--tw-gradient-via-position), var(--tw-gradient-to);
}
.to-secondary {
--tw-gradient-to: #e11d48 var(--tw-gradient-to-position);
}
.to-indigo-50 {
--tw-gradient-to: #eef2ff var(--tw-gradient-to-position);
}
.to-secondary {
--tw-gradient-to: #e11d48 var(--tw-gradient-to-position);
}
.bg-clip-text {
-webkit-background-clip: text;
background-clip: text;

View File

@@ -8,17 +8,15 @@
id="turnstile-widget"
class="cf-turnstile"
data-sitekey="{{ site_key }}"
data-theme="dark"
></div>
</div>
<script>
// Apply theme to the Turnstile widget based on system preference
// Apply theme to the Turnstile widget based on the retrieved theme
document.addEventListener("DOMContentLoaded", function () {
const turnstileWidget = document.getElementById("turnstile-widget");
if (turnstileWidget) {
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
turnstileWidget.setAttribute("data-theme", prefersDark ? "dark" : "light");
turnstileWidget.setAttribute("data-theme", theme);
}
});
</script>

View File

@@ -4,7 +4,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="csrf-token" content="{{ csrf_token }}">
<meta name="csrf-token" content="{{ csrf_token }}" />
<title>{% block title %}ThrillWiki{% endblock %}</title>
<!-- Google Fonts -->
@@ -101,78 +101,74 @@
</label>
<!-- User Menu -->
{% if user.is_authenticated %}
{% if has_moderation_access %}
<a href="{% url 'moderation:edit_submissions' %}" class="nav-link">
<i class="fas fa-shield-alt"></i>
<span>Moderation</span>
</a>
{% endif %}
<div class="relative" x-data="{ open: false }">
<button
@click="open = !open"
class="flex items-center space-x-2 transition-transform hover:scale-105"
>
{% if user.profile.avatar %}
<img
src="{{ user.profile.avatar.url }}"
alt="{{ user.username }}"
class="w-8 h-8 rounded-full ring-2 ring-primary/20"
/>
{% else %}
<div
class="flex items-center justify-center w-8 h-8 text-white rounded-full bg-gradient-to-br from-primary to-secondary"
>
{{ user.username.0|upper }}
</div>
{% endif %}
<span>{{ user.username }}</span>
</button>
<!-- Dropdown Menu -->
{% if user.is_authenticated %} {% if has_moderation_access %}
<a href="{% url 'moderation:edit_submissions' %}" class="nav-link">
<i class="fas fa-shield-alt"></i>
<span>Moderation</span>
</a>
{% endif %}
<div class="relative" x-data="{ open: false }">
<button
@click="open = !open"
class="flex items-center space-x-2 transition-transform hover:scale-105"
>
{% if user.profile.avatar %}
<img
src="{{ user.profile.avatar.url }}"
alt="{{ user.username }}"
class="w-8 h-8 rounded-full ring-2 ring-primary/20"
/>
{% else %}
<div
x-show="open"
@click.away="open = false"
class="absolute right-0 w-48 py-1 mt-2 bg-white rounded-md shadow-lg dark:bg-gray-800"
class="flex items-center justify-center w-8 h-8 text-white rounded-full bg-gradient-to-br from-primary to-secondary"
>
<a
href="{% url 'profile' user.username %}"
class="menu-item"
>
<i class="w-5 fas fa-user"></i>
<span>Profile</span>
</a>
<a href="{% url 'settings' %}" class="menu-item">
<i class="w-5 fas fa-cog"></i>
<span>Settings</span>
</a>
{% if has_admin_access %}
<a href="{% url 'admin:index' %}" class="menu-item">
<i class="w-5 fas fa-shield-alt"></i>
<span>Admin</span>
</a>
{% endif %}
<form method="post" action="{% url 'account_logout' %}">
{% csrf_token %}
<button type="submit" class="w-full menu-item">
<i class="w-5 fas fa-sign-out-alt"></i>
<span>Logout</span>
</button>
</form>
{{ user.username.0|upper }}
</div>
{% endif %}
<span>{{ user.username }}</span>
</button>
<!-- Dropdown Menu -->
<div
x-show="open"
@click.away="open = false"
class="absolute right-0 w-48 py-1 mt-2 bg-white rounded-md shadow-lg dark:bg-gray-800"
>
<a href="{% url 'profile' user.username %}" class="menu-item">
<i class="w-5 fas fa-user"></i>
<span>Profile</span>
</a>
<a href="{% url 'settings' %}" class="menu-item">
<i class="w-5 fas fa-cog"></i>
<span>Settings</span>
</a>
{% if has_admin_access %}
<a href="{% url 'admin:index' %}" class="menu-item">
<i class="w-5 fas fa-shield-alt"></i>
<span>Admin</span>
</a>
{% endif %}
<form method="post" action="{% url 'account_logout' %}">
{% csrf_token %}
<button type="submit" class="w-full menu-item">
<i class="w-5 fas fa-sign-out-alt"></i>
<span>Logout</span>
</button>
</form>
</div>
</div>
{% else %}
<!-- Login/Register (Desktop) -->
<div class="hidden space-x-3 lg:flex">
<a href="{% url 'account_login' %}" class="btn-secondary">
<i class="mr-2 fas fa-sign-in-alt"></i>
Login
</a>
<a href="{% url 'account_signup' %}" class="btn-primary">
<i class="mr-2 fas fa-user-plus"></i>
Register
</a>
</div>
<!-- Login/Register (Desktop) -->
<div class="hidden space-x-3 lg:flex">
<a href="{% url 'account_login' %}" class="btn-secondary">
<i class="mr-2 fas fa-sign-in-alt"></i>
Login
</a>
<a href="{% url 'account_signup' %}" class="btn-primary">
<i class="mr-2 fas fa-user-plus"></i>
Register
</a>
</div>
{% endif %}
<!-- Mobile Menu Button -->

View File

@@ -5,21 +5,21 @@
{% block content %}
<!-- Hero Section -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 mb-12">
<div class="py-12 px-4 text-center">
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold mb-6 text-gray-900 dark:text-white">
<div class="mb-12 bg-white border border-gray-200 rounded-lg shadow-lg dark:bg-gray-800 dark:border-gray-700">
<div class="px-4 py-12 text-center">
<h1 class="mb-6 text-4xl font-bold text-gray-900 md:text-5xl lg:text-6xl dark:text-white">
Welcome to ThrillWiki
</h1>
<p class="text-xl md:text-2xl text-gray-600 dark:text-gray-300 mb-8 max-w-3xl mx-auto">
<p class="max-w-3xl mx-auto mb-8 text-xl text-gray-600 md:text-2xl dark:text-gray-300">
Your ultimate guide to theme parks and attractions worldwide
</p>
<div class="flex flex-wrap justify-center gap-4">
<a href="{% url 'parks:park_list' %}"
class="btn-primary text-lg px-8 py-3">
class="px-8 py-3 text-lg btn-primary">
Explore Parks
</a>
<a href="{% url 'rides:ride_list' %}"
class="btn-secondary text-lg px-8 py-3">
class="px-8 py-3 text-lg btn-secondary">
View Rides
</a>
</div>
@@ -27,10 +27,10 @@
</div>
<!-- Stats Section -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-12">
<div class="grid grid-cols-1 gap-6 mb-12 md:grid-cols-3">
<!-- Total Parks -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-6 text-center transform transition-transform hover:-translate-y-1">
<div class="text-4xl font-bold text-blue-600 dark:text-blue-400 mb-2">
<div class="p-6 text-center transition-transform transform bg-white rounded-lg shadow-lg dark:bg-gray-800 hover:-translate-y-1">
<div class="mb-2 text-4xl font-bold text-blue-600 dark:text-blue-400">
{{ stats.total_parks }}
</div>
<div class="text-xl text-gray-600 dark:text-gray-300">
@@ -39,8 +39,8 @@
</div>
<!-- Total Attractions -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-6 text-center transform transition-transform hover:-translate-y-1">
<div class="text-4xl font-bold text-blue-600 dark:text-blue-400 mb-2">
<div class="p-6 text-center transition-transform transform bg-white rounded-lg shadow-lg dark:bg-gray-800 hover:-translate-y-1">
<div class="mb-2 text-4xl font-bold text-blue-600 dark:text-blue-400">
{{ stats.total_rides }}
</div>
<div class="text-xl text-gray-600 dark:text-gray-300">
@@ -49,8 +49,8 @@
</div>
<!-- Total Roller Coasters -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-6 text-center transform transition-transform hover:-translate-y-1">
<div class="text-4xl font-bold text-blue-600 dark:text-blue-400 mb-2">
<div class="p-6 text-center transition-transform transform bg-white rounded-lg shadow-lg dark:bg-gray-800 hover:-translate-y-1">
<div class="mb-2 text-4xl font-bold text-blue-600 dark:text-blue-400">
{{ stats.total_roller_coasters }}
</div>
<div class="text-xl text-gray-600 dark:text-gray-300">
@@ -60,15 +60,15 @@
</div>
<!-- Featured Content -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
<!-- Popular Parks -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-6">
<h2 class="text-2xl font-bold mb-6 text-gray-900 dark:text-white">
<div class="p-6 bg-white rounded-lg shadow-lg dark:bg-gray-800">
<h2 class="mb-6 text-2xl font-bold text-gray-900 dark:text-white">
Popular Parks
</h2>
{% for park in popular_parks %}
<a href="{% url 'parks:park_detail' park.slug %}"
class="block mb-4 p-4 rounded-lg transition-all hover:bg-gray-50 dark:hover:bg-gray-700 hover:translate-x-2">
class="block p-4 mb-4 transition-all rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 hover:translate-x-2">
<div class="text-lg font-semibold text-blue-600 dark:text-blue-400">
{{ park.name }}
</div>
@@ -76,7 +76,7 @@
{{ park.location }}
</div>
{% if park.average_rating %}
<div class="mt-1 flex items-center text-yellow-500">
<div class="flex items-center mt-1 text-yellow-500">
<span class="mr-1"></span>
<span>{{ park.average_rating|floatformat:1 }}/10</span>
</div>
@@ -88,13 +88,13 @@
</div>
<!-- Popular Rides -->
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-6">
<h2 class="text-2xl font-bold mb-6 text-gray-900 dark:text-white">
<div class="p-6 bg-white rounded-lg shadow-lg dark:bg-gray-800">
<h2 class="mb-6 text-2xl font-bold text-gray-900 dark:text-white">
Popular Rides
</h2>
{% for ride in popular_rides %}
<a href="{% url 'rides:ride_detail' ride.park.slug ride.slug %}"
class="block mb-4 p-4 rounded-lg transition-all hover:bg-gray-50 dark:hover:bg-gray-700 hover:translate-x-2">
class="block p-4 mb-4 transition-all rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 hover:translate-x-2">
<div class="text-lg font-semibold text-blue-600 dark:text-blue-400">
{{ ride.name }}
</div>
@@ -102,7 +102,7 @@
at {{ ride.park.name }}
</div>
{% if ride.average_rating %}
<div class="mt-1 flex items-center text-yellow-500">
<div class="flex items-center mt-1 text-yellow-500">
<span class="mr-1"></span>
<span>{{ ride.average_rating|floatformat:1 }}/10</span>
</div>

View File

@@ -116,7 +116,7 @@
{% for area in areas %}
<div class="p-4 transition-transform transform rounded-lg bg-gray-50 dark:bg-gray-700/50 hover:-translate-y-1">
<h3 class="mb-2 text-lg font-semibold text-gray-900 dark:text-white">
<a href="{% url 'parks:area_detail' park.slug area.slug %}">{{ area.name }}</a>
{{ area.name }}
</h3>
{% if area.description %}
<p class="mb-2 text-gray-600 dark:text-gray-300">
@@ -281,7 +281,7 @@
</div>
</div>
{% empty %}
<p class="text-gray-500 dark:text-gray-400">No history available.</p>
<p class="text-gray-500">No history available.</p>
{% endfor %}
</div>
</div>

View File

@@ -8,7 +8,7 @@
<div class="flex flex-col items-start justify-between gap-4 mb-6 md:flex-row md:items-center">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white">Parks</h1>
{% if user.is_authenticated %}
<a href="{% url 'parks:park_create' %}" class="btn-primary">
<a href="{% url 'park_create' %}" class="btn-primary">
<i class="mr-2 fas fa-plus"></i>Add Park
</a>
{% endif %}
@@ -70,7 +70,7 @@
{% endif %}
<div class="p-4">
<h2 class="mb-2 text-xl font-bold">
<a href="{% url 'parks:park_detail' park.slug %}"
<a href="{% url 'park_detail' park.slug %}"
class="text-gray-900 hover:text-blue-600 dark:text-white dark:hover:text-blue-400">
{{ park.name }}
</a>

View File

@@ -275,6 +275,22 @@
{% endfor %}
</div>
</div>
<!-- Photos -->
{% if ride.photos.exists %}
<div class="p-6 bg-white rounded-lg shadow dark:bg-gray-800">
<h2 class="mb-4 text-xl font-semibold text-gray-900 dark:text-white">Photos</h2>
<div class="grid grid-cols-2 gap-2">
{% for photo in ride.photos.all %}
<div class="aspect-w-16 aspect-h-9">
<img src="{{ photo.image.url }}"
alt="{{ photo.caption|default:ride.name }}"
class="object-cover rounded-lg">
</div>
{% endfor %}
</div>
</div>
{% endif %}
</div>
</div>

View File

@@ -83,7 +83,7 @@
</a>
</p>
<div class="flex flex-wrap gap-2">
<span class="text-blue-800 bg-blue-100 status-badge dark:bg-blue-700 dark:text-blue-50">
<span class="text-blue-800 bg-blue-100 status-badge dark:bg-blue-400/30 dark:text-blue-200 dark:ring-1 dark:ring-blue-400/30">
{{ ride.get_category_display }}
</span>
<span class="status-badge {% if ride.status == 'OPERATING' %}status-operating

View File

@@ -4,10 +4,10 @@
{% block title %}Search Results - ThrillWiki{% endblock %}
{% block content %}
<div class="container mx-auto px-4 py-8">
<div class="container px-4 py-8 mx-auto">
<!-- Search Header -->
<div class="mb-8">
<h1 class="text-3xl font-bold mb-2">Search Results</h1>
<h1 class="mb-2 text-3xl font-bold">Search Results</h1>
<p class="text-gray-600 dark:text-gray-400">
{% if request.GET.q %}
Results for "{{ request.GET.q }}"
@@ -19,36 +19,36 @@
{% if request.GET.q %}
<!-- Parks Results -->
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6 mb-6">
<h2 class="text-xl font-semibold mb-4">Theme Parks</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div class="p-6 mb-6 bg-white rounded-lg shadow dark:bg-gray-800">
<h2 class="mb-4 text-xl font-semibold">Theme Parks</h2>
<div class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
{% for park in parks %}
<div class="bg-gray-50 dark:bg-gray-700 rounded-lg overflow-hidden">
<div class="overflow-hidden rounded-lg bg-gray-50 dark:bg-gray-700">
{% if park.photos.exists %}
<img src="{{ park.photos.first.image.url }}"
alt="{{ park.name }}"
class="w-full h-48 object-cover">
class="object-cover w-full h-48">
{% else %}
<div class="w-full h-48 bg-gray-200 dark:bg-gray-600 flex items-center justify-center">
<div class="flex items-center justify-center w-full h-48 bg-gray-200 dark:bg-gray-600">
<span class="text-gray-400">No image available</span>
</div>
{% endif %}
<div class="p-4">
<h3 class="text-lg font-semibold mb-2">
<h3 class="mb-2 text-lg font-semibold">
<a href="{% url 'parks:park_detail' park.slug %}"
class="text-blue-600 dark:text-blue-400 hover:underline">
class="text-blue-600 hover:underline dark:text-blue-400">
{{ park.name }}
</a>
</h3>
<p class="text-gray-600 dark:text-gray-400 mb-2">{{ park.location }}</p>
<div class="flex justify-between items-center">
<p class="mb-2 text-gray-600 dark:text-gray-400">{{ park.location }}</p>
<div class="flex items-center justify-between">
<span class="text-sm text-gray-500 dark:text-gray-400">
{{ park.rides.count }} attractions
</span>
{% if park.average_rating %}
<div class="flex items-center">
<span class="text-yellow-400 mr-1"></span>
<span class="mr-1 text-yellow-400"></span>
<span>{{ park.average_rating|floatformat:1 }}/10</span>
</div>
{% endif %}
@@ -56,7 +56,7 @@
</div>
</div>
{% empty %}
<div class="col-span-full text-center py-4">
<div class="py-4 text-center col-span-full">
<p class="text-gray-500 dark:text-gray-400">No parks found matching your search.</p>
</div>
{% endfor %}
@@ -64,39 +64,39 @@
</div>
<!-- Rides Results -->
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6 mb-6">
<h2 class="text-xl font-semibold mb-4">Rides & Attractions</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div class="p-6 mb-6 bg-white rounded-lg shadow dark:bg-gray-800">
<h2 class="mb-4 text-xl font-semibold">Rides & Attractions</h2>
<div class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
{% for ride in rides %}
<div class="bg-gray-50 dark:bg-gray-700 rounded-lg overflow-hidden">
<div class="overflow-hidden rounded-lg bg-gray-50 dark:bg-gray-700">
{% if ride.photos.exists %}
<img src="{{ ride.photos.first.image.url }}"
alt="{{ ride.name }}"
class="w-full h-48 object-cover">
class="object-cover w-full h-48">
{% else %}
<div class="w-full h-48 bg-gray-200 dark:bg-gray-600 flex items-center justify-center">
<div class="flex items-center justify-center w-full h-48 bg-gray-200 dark:bg-gray-600">
<span class="text-gray-400">No image available</span>
</div>
{% endif %}
<div class="p-4">
<h3 class="text-lg font-semibold mb-2">
<h3 class="mb-2 text-lg font-semibold">
<a href="{% url 'rides:ride_detail' ride.park.slug ride.slug %}"
class="text-blue-600 dark:text-blue-400 hover:underline">
class="text-blue-600 hover:underline dark:text-blue-400">
{{ ride.name }}
</a>
</h3>
<p class="text-gray-600 dark:text-gray-400 mb-2">
<p class="mb-2 text-gray-600 dark:text-gray-400">
at <a href="{% url 'parks:park_detail' ride.park.slug %}"
class="hover:underline">{{ ride.park.name }}</a>
</p>
<div class="flex flex-wrap gap-2 mb-2">
<span class="px-2 py-1 text-xs rounded-full bg-blue-100 text-blue-800">
<span class="px-2 py-1 text-xs text-blue-800 bg-blue-100 rounded-full">
{{ ride.get_category_display }}
</span>
{% if ride.average_rating %}
<div class="flex items-center">
<span class="text-yellow-400 mr-1"></span>
<span class="mr-1 text-yellow-400"></span>
<span>{{ ride.average_rating|floatformat:1 }}/10</span>
</div>
{% endif %}
@@ -104,7 +104,7 @@
</div>
</div>
{% empty %}
<div class="col-span-full text-center py-4">
<div class="py-4 text-center col-span-full">
<p class="text-gray-500 dark:text-gray-400">No rides found matching your search.</p>
</div>
{% endfor %}
@@ -112,26 +112,26 @@
</div>
<!-- Companies Results -->
<div class="bg-white dark:bg-gray-800 shadow rounded-lg p-6">
<h2 class="text-xl font-semibold mb-4">Companies</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div class="p-6 bg-white rounded-lg shadow dark:bg-gray-800">
<h2 class="mb-4 text-xl font-semibold">Companies</h2>
<div class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
{% for company in companies %}
<div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-4">
<h3 class="text-lg font-semibold mb-2">
<div class="p-4 rounded-lg bg-gray-50 dark:bg-gray-700">
<h3 class="mb-2 text-lg font-semibold">
<a href="{% url 'companies:company_detail' company.slug %}"
class="text-blue-600 dark:text-blue-400 hover:underline">
class="text-blue-600 hover:underline dark:text-blue-400">
{{ company.name }}
</a>
</h3>
{% if company.headquarters %}
<p class="text-gray-600 dark:text-gray-400 mb-2">{{ company.headquarters }}</p>
<p class="mb-2 text-gray-600 dark:text-gray-400">{{ company.headquarters }}</p>
{% endif %}
<div class="text-sm text-gray-500 dark:text-gray-400">
{{ company.parks.count }} parks owned
</div>
</div>
{% empty %}
<div class="col-span-full text-center py-4">
<div class="py-4 text-center col-span-full">
<p class="text-gray-500 dark:text-gray-400">No companies found matching your search.</p>
</div>
{% endfor %}

View File

@@ -11,8 +11,12 @@ urlpatterns = [
# Main app URLs
path('', HomeView.as_view(), name='home'),
path('parks/', include('parks.urls')),
path('rides/', include('rides.urls')),
# Parks URLs
path('parks/', include('parks.urls', namespace='parks')),
path('rides/', include('rides.urls', namespace='rides')),
# Other URLs
path('reviews/', include('reviews.urls')),
path('companies/', include('companies.urls')),
path('search/', SearchView.as_view(), name='search'),
@@ -28,8 +32,7 @@ urlpatterns = [
path('accounts/email-required/', accounts_views.email_required, name='email_required'),
# User profile URLs
path('users/<str:username>/', accounts_views.ProfileView.as_view(), name='user_profile'),
path('user/<str:username>/', accounts_views.ProfileView.as_view(), name='single_user_profile'),
path('user/<str:username>/', accounts_views.ProfileView.as_view(), name='user_profile'),
path('profile/<str:username>/', accounts_views.ProfileView.as_view(), name='profile'),
path('settings/', accounts_views.SettingsView.as_view(), name='settings'),