diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index a5ed392..9759da7 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index e061640..9e26940 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 5a69659..f73949b 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 2a36fd6..f2e321d 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/admin.py b/core/admin.py index 8c38f3f..6a2fb67 100644 --- a/core/admin.py +++ b/core/admin.py @@ -1,3 +1,21 @@ from django.contrib import admin +from .models import School, Event, Registration -# Register your models here. +@admin.register(School) +class SchoolAdmin(admin.ModelAdmin): + list_display = ('name', 'slug', 'created_at') + prepopulated_fields = {'slug': ('name',)} + search_fields = ('name',) + +@admin.register(Event) +class EventAdmin(admin.ModelAdmin): + list_display = ('title', 'school', 'event_type', 'start_date', 'is_published') + list_filter = ('school', 'event_type', 'is_published') + search_fields = ('title', 'description', 'location') + date_hierarchy = 'start_date' + +@admin.register(Registration) +class RegistrationAdmin(admin.ModelAdmin): + list_display = ('user', 'event', 'registered_at', 'attended') + list_filter = ('event', 'attended') + search_fields = ('user__username', 'event__title') \ No newline at end of file diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100644 index 0000000..5f7d492 --- /dev/null +++ b/core/migrations/0001_initial.py @@ -0,0 +1,57 @@ +# Generated by Django 5.2.7 on 2026-01-31 10:14 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='School', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('slug', models.SlugField(blank=True, unique=True)), + ('description', models.TextField(blank=True)), + ('logo_url', models.URLField(blank=True, help_text='URL to the school logo', null=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name='Event', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=255)), + ('description', models.TextField()), + ('event_type', models.CharField(choices=[('assembly', 'Assembly'), ('field_trip', 'Field Trip'), ('parent_teacher', 'Parent-Teacher Night'), ('sports', 'Sports Event'), ('performance', 'Performance/Arts'), ('other', 'Other')], default='other', max_length=50)), + ('start_date', models.DateTimeField()), + ('end_date', models.DateTimeField()), + ('location', models.CharField(max_length=255)), + ('capacity', models.PositiveIntegerField(default=100)), + ('is_published', models.BooleanField(default=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('school', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='events', to='core.school')), + ], + ), + migrations.CreateModel( + name='Registration', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('registered_at', models.DateTimeField(auto_now_add=True)), + ('attended', models.BooleanField(default=False)), + ('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='registrations', to='core.event')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'unique_together': {('event', 'user')}, + }, + ), + ] diff --git a/core/migrations/__pycache__/0001_initial.cpython-311.pyc b/core/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000..f20e64e Binary files /dev/null and b/core/migrations/__pycache__/0001_initial.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 71a8362..af1c1ba 100644 --- a/core/models.py +++ b/core/models.py @@ -1,3 +1,53 @@ from django.db import models +from django.conf import settings +from django.utils.text import slugify -# Create your models here. +class School(models.Model): + name = models.CharField(max_length=255) + slug = models.SlugField(unique=True, blank=True) + description = models.TextField(blank=True) + logo_url = models.URLField(blank=True, null=True, help_text="URL to the school logo") + created_at = models.DateTimeField(auto_now_add=True) + + def save(self, *args, **kwargs): + if not self.slug: + self.slug = slugify(self.name) + super().save(*args, **kwargs) + + def __str__(self): + return self.name + +class Event(models.Model): + EVENT_TYPES = [ + ('assembly', 'Assembly'), + ('field_trip', 'Field Trip'), + ('parent_teacher', 'Parent-Teacher Night'), + ('sports', 'Sports Event'), + ('performance', 'Performance/Arts'), + ('other', 'Other'), + ] + school = models.ForeignKey(School, on_delete=models.CASCADE, related_name='events') + title = models.CharField(max_length=255) + description = models.TextField() + event_type = models.CharField(max_length=50, choices=EVENT_TYPES, default='other') + start_date = models.DateTimeField() + end_date = models.DateTimeField() + location = models.CharField(max_length=255) + capacity = models.PositiveIntegerField(default=100) + is_published = models.BooleanField(default=True) + created_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"{self.title} ({self.school.name})" + +class Registration(models.Model): + event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='registrations') + user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) + registered_at = models.DateTimeField(auto_now_add=True) + attended = models.BooleanField(default=False) + + class Meta: + unique_together = ('event', 'user') + + def __str__(self): + return f"{self.user.username} - {self.event.title}" \ No newline at end of file diff --git a/core/templates/base.html b/core/templates/base.html index 1e7e5fb..ffab868 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -3,23 +3,78 @@ - {% block title %}Knowledge Base{% endblock %} + + {% block title %}School Event Hub{% endblock %} + {% if project_description %} - - - {% endif %} - {% if project_image_url %} - - {% endif %} + {% load static %} + + + + + + + + + + {% block head %}{% endblock %} - {% block content %}{% endblock %} + + +
+ {% block content %}{% endblock %} +
+ + + + - + \ No newline at end of file diff --git a/core/templates/core/event_detail.html b/core/templates/core/event_detail.html new file mode 100644 index 0000000..9d001ba --- /dev/null +++ b/core/templates/core/event_detail.html @@ -0,0 +1,71 @@ +{% extends 'base.html' %} +{% load static %} + +{% block title %}{{ event.title }} - EduEvents{% endblock %} + +{% block content %} +
+ + +
+
+
+ {{ event.get_event_type_display }} +

{{ event.title }}

+ +
+
+

When

+

{{ event.start_date|date:"l, F j, Y" }}
{{ event.start_date|date:"g:i A" }} - {{ event.end_date|date:"g:i A" }}

+
+
+

Where

+

{{ event.location }}

+
+
+

Organizer

+

{{ event.school.name }}

+
+
+ +
+

About this Event

+
+ {{ event.description|linebreaks }} +
+
+
+
+ +
+
+
+

Registration

+ +
+ Capacity + {{ event.capacity }} slots +
+
+ Available + {{ event.capacity }} slots left +
+ + +

You must be logged in to register.

+
+ +
+

Need Help?

+

Contact {{ event.school.name }} administrative office for any queries regarding this event.

+
+
+
+
+
+{% endblock %} diff --git a/core/templates/core/index.html b/core/templates/core/index.html index faec813..c76cae3 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,145 +1,112 @@ -{% extends "base.html" %} +{% extends 'base.html' %} +{% load static %} -{% block title %}{{ project_name }}{% endblock %} - -{% block head %} - - - - -{% endblock %} +{% block title %}EduEvents - School Event Management{% endblock %} {% block content %} -
-
-

Analyzing your requirements and generating your app…

-
- Loading… + +
+
+
+
+

Manage School Events with Ease.

+

The all-in-one platform for schools to create, manage, and track event registrations and attendance. Join the community today.

+ +
+
+ +
+
+ School Events +
+
-

AppWizzy AI is collecting your requirements and applying the first changes.

-

This page will refresh automatically as the plan is implemented.

-

- Runtime: Django {{ django_version }} · Python {{ python_version }} - — UTC {{ current_time|date:"Y-m-d H:i:s" }} -

-
- -{% endblock %} \ No newline at end of file + + + +
+
+
+
+

Upcoming Events

+

Stay informed about the latest assemblies, field trips, and school nights.

+
+
+ +
+
+ +
+ {% for event in events %} +
+
+
+ {{ event.get_event_type_display }} +
+

{{ event.title }}

+

{{ event.description|truncatewords:20 }}

+ +
+
+ + + + + {{ event.start_date|date:"M d, Y @ H:i" }} +
+
+ + + + {{ event.location }} +
+
+ +
+
+ {{ event.school.name }} + View Details → +
+
+
+
+ {% empty %} +
+
+

No upcoming events scheduled at the moment. Please check back later!

+
+
+ {% endfor %} +
+
+
+ + +
+
+
+
+

50+

+

Schools Registered

+
+
+

10k+

+

Events Managed

+
+
+

100k+

+

Tickets Issued

+
+
+
+
+{% endblock %} diff --git a/core/urls.py b/core/urls.py index 6299e3d..4566ee2 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,7 +1,7 @@ from django.urls import path - -from .views import home +from .views import home, event_detail urlpatterns = [ path("", home, name="home"), -] + path("event//", event_detail, name="event_detail"), +] \ No newline at end of file diff --git a/core/views.py b/core/views.py index c9aed12..f411e8a 100644 --- a/core/views.py +++ b/core/views.py @@ -1,25 +1,18 @@ -import os -import platform - -from django import get_version as django_version -from django.shortcuts import render -from django.utils import timezone - +from django.shortcuts import render, get_object_or_404 +from .models import Event, School def home(request): - """Render the landing screen with loader and environment details.""" - host_name = request.get_host().lower() - agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic" - now = timezone.now() - + """Render the landing screen with upcoming events.""" + events = Event.objects.filter(is_published=True).order_by('start_date')[:6] + schools = School.objects.all() + context = { - "project_name": "New Style", - "agent_brand": agent_brand, - "django_version": django_version(), - "python_version": platform.python_version(), - "current_time": now, - "host_name": host_name, - "project_description": os.getenv("PROJECT_DESCRIPTION", ""), - "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""), + "events": events, + "schools": schools, } return render(request, "core/index.html", context) + +def event_detail(request, event_id): + """Render the detailed view for a specific school event.""" + event = get_object_or_404(Event, id=event_id) + return render(request, "core/event_detail.html", {"event": event}) \ No newline at end of file diff --git a/static/css/custom.css b/static/css/custom.css index 925f6ed..55e7dfa 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -1,4 +1,131 @@ -/* Custom styles for the application */ -body { - font-family: system-ui, -apple-system, sans-serif; +:root { + --primary-color: #2D3436; + --accent-color: #00B894; + --bg-light: #F9FAFB; + --text-muted: #636E72; + --white: #ffffff; } + +body { + font-family: 'Inter', sans-serif; + background-color: var(--bg-light); + color: var(--primary-color); + line-height: 1.6; +} + +h1, h2, h3, h4, h5, .brand-font { + font-family: 'Playfair Display', serif; + font-weight: 700; +} + +.text-accent { + color: var(--accent-color) !important; +} + +.bg-accent { + background-color: var(--accent-color) !important; +} + +.btn-primary { + background-color: var(--accent-color); + border-color: var(--accent-color); + padding: 0.75rem 1.75rem; + font-weight: 600; + border-radius: 10px; + transition: all 0.3s ease; +} + +.btn-primary:hover { + background-color: #009476; + border-color: #009476; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 184, 148, 0.2); +} + +.navbar { + background: var(--white); + box-shadow: 0 2px 15px rgba(0,0,0,0.04); + padding: 1.25rem 0; +} + +.navbar-brand { + font-weight: 700; + font-size: 1.6rem; + letter-spacing: -0.5px; +} + +.hero-section { + padding: 100px 0; + background: radial-gradient(circle at top right, #e3fcf7, var(--bg-light)); + position: relative; + overflow: hidden; +} + +.hero-section::before { + content: ''; + position: absolute; + top: -10%; + right: -5%; + width: 300px; + height: 300px; + background: rgba(0, 184, 148, 0.05); + border-radius: 50%; + z-index: 0; +} + +.event-card { + border: none; + border-radius: 16px; + overflow: hidden; + transition: all 0.4s cubic-bezier(0.165, 0.84, 0.44, 1); + background: var(--white); + height: 100%; + box-shadow: 0 4px 6px rgba(0,0,0,0.02); +} + +.event-card:hover { + transform: translateY(-10px); + box-shadow: 0 20px 40px rgba(0,0,0,0.08); +} + +.event-type-badge { + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 1px; + font-weight: 700; + padding: 6px 12px; + border-radius: 30px; + display: inline-block; + margin-bottom: 12px; +} + +.badge-assembly { background: #e3fcf7; color: #00b894; } +.badge-field_trip { background: #fff4e6; color: #fd7e14; } +.badge-parent_teacher { background: #f0f0ff; color: #6c5ce7; } +.badge-sports { background: #fff0f0; color: #ff7675; } +.badge-performance { background: #fdf2ff; color: #a29bfe; } +.badge-other { background: #f1f2f6; color: #2d3436; } + +.section-title { + margin-bottom: 3rem; + position: relative; + display: inline-block; +} + +.section-title::after { + content: ''; + position: absolute; + bottom: -10px; + left: 0; + width: 40px; + height: 4px; + background: var(--accent-color); + border-radius: 2px; +} + +.footer { + padding: 4rem 0; + background: var(--white); + border-top: 1px solid #eee; + margin-top: 5rem; +} \ No newline at end of file diff --git a/staticfiles/css/custom.css b/staticfiles/css/custom.css index 108056f..55e7dfa 100644 --- a/staticfiles/css/custom.css +++ b/staticfiles/css/custom.css @@ -1,21 +1,131 @@ - :root { - --bg-color-start: #6a11cb; - --bg-color-end: #2575fc; - --text-color: #ffffff; - --card-bg-color: rgba(255, 255, 255, 0.01); - --card-border-color: rgba(255, 255, 255, 0.1); + --primary-color: #2D3436; + --accent-color: #00B894; + --bg-light: #F9FAFB; + --text-muted: #636E72; + --white: #ffffff; } + body { - margin: 0; - font-family: 'Inter', sans-serif; - background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end)); - color: var(--text-color); - display: flex; - justify-content: center; - align-items: center; - min-height: 100vh; - text-align: center; - overflow: hidden; - position: relative; + font-family: 'Inter', sans-serif; + background-color: var(--bg-light); + color: var(--primary-color); + line-height: 1.6; } + +h1, h2, h3, h4, h5, .brand-font { + font-family: 'Playfair Display', serif; + font-weight: 700; +} + +.text-accent { + color: var(--accent-color) !important; +} + +.bg-accent { + background-color: var(--accent-color) !important; +} + +.btn-primary { + background-color: var(--accent-color); + border-color: var(--accent-color); + padding: 0.75rem 1.75rem; + font-weight: 600; + border-radius: 10px; + transition: all 0.3s ease; +} + +.btn-primary:hover { + background-color: #009476; + border-color: #009476; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 184, 148, 0.2); +} + +.navbar { + background: var(--white); + box-shadow: 0 2px 15px rgba(0,0,0,0.04); + padding: 1.25rem 0; +} + +.navbar-brand { + font-weight: 700; + font-size: 1.6rem; + letter-spacing: -0.5px; +} + +.hero-section { + padding: 100px 0; + background: radial-gradient(circle at top right, #e3fcf7, var(--bg-light)); + position: relative; + overflow: hidden; +} + +.hero-section::before { + content: ''; + position: absolute; + top: -10%; + right: -5%; + width: 300px; + height: 300px; + background: rgba(0, 184, 148, 0.05); + border-radius: 50%; + z-index: 0; +} + +.event-card { + border: none; + border-radius: 16px; + overflow: hidden; + transition: all 0.4s cubic-bezier(0.165, 0.84, 0.44, 1); + background: var(--white); + height: 100%; + box-shadow: 0 4px 6px rgba(0,0,0,0.02); +} + +.event-card:hover { + transform: translateY(-10px); + box-shadow: 0 20px 40px rgba(0,0,0,0.08); +} + +.event-type-badge { + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 1px; + font-weight: 700; + padding: 6px 12px; + border-radius: 30px; + display: inline-block; + margin-bottom: 12px; +} + +.badge-assembly { background: #e3fcf7; color: #00b894; } +.badge-field_trip { background: #fff4e6; color: #fd7e14; } +.badge-parent_teacher { background: #f0f0ff; color: #6c5ce7; } +.badge-sports { background: #fff0f0; color: #ff7675; } +.badge-performance { background: #fdf2ff; color: #a29bfe; } +.badge-other { background: #f1f2f6; color: #2d3436; } + +.section-title { + margin-bottom: 3rem; + position: relative; + display: inline-block; +} + +.section-title::after { + content: ''; + position: absolute; + bottom: -10px; + left: 0; + width: 40px; + height: 4px; + background: var(--accent-color); + border-radius: 2px; +} + +.footer { + padding: 4rem 0; + background: var(--white); + border-top: 1px solid #eee; + margin-top: 5rem; +} \ No newline at end of file