Compare commits

...

11 Commits

36 changed files with 2736 additions and 453 deletions

View File

@@ -53,7 +53,7 @@ MIDDLEWARE = [
]
ROOT_URLCONF = "scha.urls"
CSRF_TRUSTED_ORIGINS = ["https://schawheaton.aimloperations.com","https://www.schawheaton.aimloperations.com", "https://www.schawheaton.com", "https://schawheaton.com"]
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",

View File

@@ -24,6 +24,7 @@ from schasite.views import stripe_cancelled, stripe_success, stripe_webhook
urlpatterns = [
path("schasite/", include("schasite.urls")),
path("", include("schasite.urls")),
path("success/", stripe_success),
path("cancelled/", stripe_cancelled),
path("webhook/", stripe_webhook),

View File

@@ -2,6 +2,7 @@ from django import forms
from django.forms import ModelForm
from .models import (
Membership,
CommunityPost,
AddressModel1,
MembershipPerson,
MembershipCommittee,
@@ -10,21 +11,20 @@ from .models import (
from phonenumber_field.formfields import PhoneNumberField
from django.core.exceptions import ValidationError
# from django_recaptcha.fields import ReCaptchaField
# from django.conf import settings
# from django_recaptcha.widgets import ReCaptchaV3
from django_recaptcha.fields import ReCaptchaField
from django.conf import settings
from django_recaptcha.widgets import ReCaptchaV3
# class CaptchaForm(forms.Form):
# captcha = ReCaptchaField(
# public_key=settings.RECAPTCHA_PUBLIC_KEY,
# private_key=settings.RECAPTCHA_PRIVATE_KEY,
# widget=ReCaptchaV3(
# attrs={
# 'required_score':0.85,
# }
# ),
# )
class CaptchaForm(forms.Form):
captcha = ReCaptchaField(
public_key=settings.RECAPTCHA_PUBLIC_KEY,
private_key=settings.RECAPTCHA_PRIVATE_KEY,
widget=ReCaptchaV3(
attrs={
'required_score':0.85,
}
),
)
class ChildrenForm(ModelForm):
@@ -38,6 +38,10 @@ class AddressForm(ModelForm):
model = AddressModel1
fields = ["address_1", "address_2", "city", "state", "zip_code"]
class CommunityPostForm(ModelForm):
class Meta:
model = CommunityPost
fields = ['title','category','content']
class PeopleForm(ModelForm):
phone_number = PhoneNumberField(required=False)

View File

@@ -0,0 +1,290 @@
# Generated by Django 5.2 on 2025-04-21 17:42
import datetime
import django.db.models.deletion
import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("schasite", "0009_schaofficer_alter_payments_date"),
]
operations = [
migrations.CreateModel(
name="CommunityParks",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created", models.DateTimeField(default=django.utils.timezone.now)),
(
"last_modified",
models.DateTimeField(default=django.utils.timezone.now),
),
("name", models.CharField(max_length=255)),
("distance", models.DecimalField(decimal_places=1, max_digits=3)),
("description", models.CharField(max_length=1024)),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="CommunityPost",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created", models.DateTimeField(default=django.utils.timezone.now)),
(
"last_modified",
models.DateTimeField(default=django.utils.timezone.now),
),
("title", models.CharField(max_length=255)),
("category", models.CharField(max_length=255)),
("content", models.CharField(max_length=8192)),
("likes", models.IntegerField(default=0)),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="CommunitySchools",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created", models.DateTimeField(default=django.utils.timezone.now)),
(
"last_modified",
models.DateTimeField(default=django.utils.timezone.now),
),
("name", models.CharField(max_length=255)),
("name_school_url", models.URLField(max_length=256)),
("rating_url", models.URLField(max_length=256)),
("rating", models.DecimalField(decimal_places=2, max_digits=5)),
("distance", models.DecimalField(decimal_places=1, max_digits=3)),
("principal", models.CharField(max_length=255)),
("grades", models.CharField(max_length=255)),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="CommunityShoppingAndDining",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created", models.DateTimeField(default=django.utils.timezone.now)),
(
"last_modified",
models.DateTimeField(default=django.utils.timezone.now),
),
("name", models.CharField(max_length=255)),
("distance", models.DecimalField(decimal_places=1, max_digits=3)),
("description", models.CharField(max_length=1024)),
],
options={
"abstract": False,
},
),
migrations.AddField(
model_name="addressmodel1",
name="created",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="addressmodel1",
name="last_modified",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="calendarevent",
name="created",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="calendarevent",
name="last_modified",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="calendareventaddressmodel",
name="created",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="calendareventaddressmodel",
name="last_modified",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="membership",
name="created",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="membership",
name="last_modified",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="membershipcommittee",
name="created",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="membershipcommittee",
name="last_modified",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="membershipperson",
name="created",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="membershipperson",
name="last_modified",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="membershipservices",
name="created",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="membershipservices",
name="last_modified",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="payments",
name="created",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="payments",
name="last_modified",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="schaofficer",
name="created",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="schaofficer",
name="last_modified",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="usefullinks",
name="created",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AddField(
model_name="usefullinks",
name="last_modified",
field=models.DateTimeField(default=django.utils.timezone.now),
),
migrations.AlterField(
model_name="payments",
name="date",
field=models.DateField(
default=datetime.datetime(
2025, 4, 21, 17, 42, 47, 893058, tzinfo=datetime.timezone.utc
)
),
),
migrations.CreateModel(
name="CommunityComment",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created", models.DateTimeField(default=django.utils.timezone.now)),
(
"last_modified",
models.DateTimeField(default=django.utils.timezone.now),
),
("content", models.CharField(max_length=8192)),
("likes", models.IntegerField(default=0)),
(
"post",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="schasite.communitypost",
),
),
],
options={
"abstract": False,
},
),
migrations.CreateModel(
name="CommunityPostReports",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created", models.DateTimeField(default=django.utils.timezone.now)),
(
"last_modified",
models.DateTimeField(default=django.utils.timezone.now),
),
(
"post",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="schasite.communitypost",
),
),
],
options={
"abstract": False,
},
),
]

View File

@@ -2,15 +2,31 @@ from django.db import models
from phonenumber_field.modelfields import PhoneNumberField
import datetime
from django.utils import timezone
from django.conf import settings
class TimeInfoBase(models.Model):
created = models.DateTimeField(default=timezone.now)
last_modified = models.DateTimeField(default=timezone.now)
class Meta:
abstract = True
def save(self, *args, **kwargs):
if not kwargs.pop("skip_last_modified", False) and not hasattr(self, "skip_last_modified"):
self.last_modified = timezone.now()
if kwargs.get("update_fields") is not None:
kwargs["update_fields"] = list({*kwargs["update_fields"], "last_modified"})
super().save(*args, **kwargs)
# Create your models here.
class UsefulLinks(models.Model):
class UsefulLinks(TimeInfoBase):
name = models.CharField(max_length=256)
url = models.CharField(max_length=256)
class Membership(models.Model):
class Membership(TimeInfoBase):
children = models.CharField(max_length=256, default="", blank=True, null=True)
def get_address_str(self):
@@ -37,7 +53,7 @@ class Membership(models.Model):
return self.get_address_str() + " | " + self.get_person_1()
class AddressModel1(models.Model):
class AddressModel1(TimeInfoBase):
membership = models.OneToOneField(Membership, on_delete=models.CASCADE)
address_1 = models.CharField(max_length=128)
address_2 = models.CharField(max_length=128, blank=True)
@@ -46,7 +62,7 @@ class AddressModel1(models.Model):
zip_code = models.CharField(max_length=5)
class CalendarEvent(models.Model):
class CalendarEvent(TimeInfoBase):
event_name = models.CharField(max_length=256)
start_date = models.DateField(blank=True, null=True)
end_date = models.DateField(blank=True, null=True)
@@ -54,7 +70,7 @@ class CalendarEvent(models.Model):
coordinator_email = models.EmailField(max_length=256, blank=True, null=True)
event_link_name = models.CharField(max_length=64, blank=True, null=True)
event_url = models.URLField(max_length=256, blank=True, null=True)
description= models.CharField(max_length=1024, default="")
#description= models.CharField(max_length=1024, default="")
def has_date(self):
return not self.start_date is None
@@ -75,7 +91,7 @@ class CalendarEvent(models.Model):
return not self.has_date()
class CalendarEventAddressModel(models.Model):
class CalendarEventAddressModel(TimeInfoBase):
calendar_event = models.OneToOneField(CalendarEvent, on_delete=models.CASCADE)
address_1 = models.CharField(max_length=128)
address_2 = models.CharField(max_length=128, blank=True)
@@ -89,7 +105,7 @@ class CalendarEventAddressModel(models.Model):
)
class MembershipPerson(models.Model):
class MembershipPerson(TimeInfoBase):
membership = models.ForeignKey(
Membership, on_delete=models.CASCADE, blank=True, null=True
)
@@ -102,7 +118,7 @@ class MembershipPerson(models.Model):
return self.email if self.email else "No email"
class MembershipCommittee(models.Model):
class MembershipCommittee(TimeInfoBase):
membership = models.OneToOneField(Membership, on_delete=models.CASCADE)
block_captain = models.BooleanField(default=False, blank=True, null=True)
coordinator = models.BooleanField(default=False, blank=True, null=True)
@@ -119,7 +135,7 @@ class MembershipCommittee(models.Model):
no_preference = models.BooleanField(default=False, blank=True, null=True)
class MembershipServices(models.Model):
class MembershipServices(TimeInfoBase):
membership = models.OneToOneField(Membership, on_delete=models.CASCADE)
babysitting = models.BooleanField(default=False, blank=True, null=True)
lawn_mowing = models.BooleanField(default=False, blank=True, null=True)
@@ -131,7 +147,7 @@ class MembershipServices(models.Model):
other_desc = models.CharField(default="", blank=True, null=True, max_length=256)
class Payments(models.Model):
class Payments(TimeInfoBase):
date = models.DateField(default=timezone.now())
status = models.CharField(default="Completed", max_length=256)
email = models.EmailField(blank=True, null=True)
@@ -140,26 +156,58 @@ class Payments(models.Model):
)
class SCHAOfficer(models.Model):
class SCHAOfficer(TimeInfoBase):
name = models.CharField(max_length=255)
position = models.CharField(max_length=255)
email = models.EmailField(max_length=255)
# class CommunitySchools(models.Model):
# name = models.CharField(max_length=255)
# name_school_url = models.URLField(max_length=256)
# rating_url = models.URLField(max_length=256)
# rating = models.DecimalField(max_digits=5, decimal_places=2)
# distance = models.DecimalField(max_digits=3, decimal_places=1)
# principal = models.CharField(max_length=255)
# grades = models.CharField(max_length=255)
### NOT USED YET ###
# class CommunityShoppingAndDining(models.Model):
# name = models.CharField(max_length=255)
# distance = models.DecimalField(max_digits=3, decimal_places=1)
# description = models.CharField(max_length=1024)
class CommunitySchools(TimeInfoBase):
name = models.CharField(max_length=255)
name_school_url = models.URLField(max_length=256)
rating_url = models.URLField(max_length=256)
rating = models.DecimalField(max_digits=5, decimal_places=2)
distance = models.DecimalField(max_digits=3, decimal_places=1)
principal = models.CharField(max_length=255)
grades = models.CharField(max_length=255)
# class CommunityParks(models.Model):
# name = models.CharField(max_length=255)
# distance = models.DecimalField(max_digits=3, decimal_places=1)
# description = models.CharField(max_length=1024)
class CommunityShoppingAndDining(TimeInfoBase):
name = models.CharField(max_length=255)
distance = models.DecimalField(max_digits=3, decimal_places=1)
description = models.CharField(max_length=1024)
class CommunityParks(TimeInfoBase):
name = models.CharField(max_length=255)
distance = models.DecimalField(max_digits=3, decimal_places=1)
description = models.CharField(max_length=1024)
### Member only models
class CommunityMember(TimeInfoBase):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
membership_person = models.OneToOneField(MembershipPerson, on_delete=models.CASCADE)
class CommunityPost(TimeInfoBase):
title = models.CharField(max_length=255)
category = models.CharField(max_length=255)
content = models.CharField(max_length=1024*8)
likes = models.IntegerField(default=0)
author = models.OneToOneField(CommunityMember, on_delete=models.CASCADE)
class CommunityPostReports(TimeInfoBase):
# for anyone who reports a post
post = models.ForeignKey(CommunityPost, on_delete=models.CASCADE)
reporter = models.OneToOneField(CommunityMember, on_delete=models.CASCADE)
class CommunityPostLikes(TimeInfoBase):
# for anyone who likes a post
post = models.ForeignKey(CommunityPost, on_delete=models.CASCADE)
reporter = models.OneToOneField(CommunityMember, on_delete=models.CASCADE)
class CommunityComment(TimeInfoBase):
post = models.ForeignKey(CommunityPost, on_delete=models.CASCADE)
content = models.CharField(max_length=1024*8)
likes = models.IntegerField(default=0)
author = models.OneToOneField(CommunityMember, on_delete=models.CASCADE)

View File

@@ -4,7 +4,6 @@
}
body {
padding-top: 56px;
}
section {

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -11,7 +11,7 @@
<div class="container">
<div class="row align-items-center">
<div class="col-lg-6 mb-4 mb-lg-0">
<img src="../images/schools.jpg" alt="Local Schools" class="img-fluid rounded shadow">
<img src="{% static 'images/District_200.png' %}" alt="Local Schools" class="img-fluid rounded shadow">
</div>
<div class="col-lg-6">
<h2 class="text-success mb-4">Excellent Schools Serving Our Community</h2>
@@ -95,7 +95,7 @@
<strong>Grades:</strong> 9-12<br>
<strong>Enrollment:</strong> 698<br>
<strong>Distance:</strong> 2.7 miles from community entrance<br>
<strong>Principal:</strong> TBD</p>
<strong>Principal:</strong> Raeann Huhn </p>
<a href="https://www.sfhscollegeprep.org/" target="_blank" class="btn btn-sm btn-outline-success">Visit Website</a>
</div>
</div>
@@ -111,7 +111,7 @@
<strong>Grades:</strong> 9-12<br>
<strong>Enrollment:</strong> 1265<br>
<strong>Distance:</strong> 5.9 miles from community entrance<br>
<strong>Principal:</strong> TBD</p>
<strong>Principal:</strong> Sheri Costello </p>
<a href="http://www.cusd200.org/Domain/140" target="_blank" class="btn btn-sm btn-outline-success">Visit Website</a>
</div>
</div>
@@ -127,7 +127,7 @@
<div class="container">
<div class="row align-items-center">
<div class="col-lg-6 order-lg-2 mb-4 mb-lg-0">
<img src="../images/history.jpg" alt="Community History" class="img-fluid rounded shadow">
<img src="{% static 'images/header.gif' %}" alt="Community History" class="img-fluid rounded shadow">
</div>
<div class="col-lg-6 order-lg-1">
<h2 class="text-success mb-4">Our Rich History</h2>
@@ -161,7 +161,7 @@
<div class="row g-4">
<div class="col-md-6">
<div class="card h-100 shadow-sm">
<img src="../images/greenwood-mall.jpg" class="card-img-top" alt="Greenwood Mall">
<img src="{% static 'images/danada.jpeg' %}" class="card-img-top" alt="Greenwood Mall">
<div class="card-body">
<h5 class="card-title">Danada</h5>
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>1.0 miles from community</p>
@@ -174,7 +174,7 @@
</div>
<div class="col-md-6">
<div class="card h-100 shadow-sm">
<img src="../images/farmers-market.jpg" class="card-img-top" alt="Farmers Market">
<img src="{% static 'images/downtown_wheaton.jpeg' %}" class="card-img-top" alt="Farmers Market">
<div class="card-body">
<h5 class="card-title">Downtown Wheaton</h5>
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>2.7 miles from community</p>
@@ -188,7 +188,7 @@
<div class="col-md-6">
<div class="card h-100 shadow-sm">
<img src="../images/farmers-market.jpg" class="card-img-top" alt="Farmers Market">
<img src="{% static 'images/wheaton_farmers_market.jpeg' %}" class="card-img-top" alt="Farmers Market">
<div class="card-body">
<h5 class="card-title">Wheaton Farmersmarket</h5>
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>2.8 miles from community</p>
@@ -201,7 +201,7 @@
</div>
<div class="col-md-6">
<div class="card h-100 shadow-sm">
<img src="../images/dining-district.jpg" class="card-img-top" alt="Dining District">
<img src="{% static 'images/downtown_naperville.jpeg' %}" class="card-img-top" alt="Dining District">
<div class="card-body">
<h5 class="card-title">Downtown Naperville</h5>
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>6.2 miles from community</p>
@@ -227,7 +227,7 @@
<div class="card shadow-sm h-100">
<div class="row g-0 h-100">
<div class="col-md-5">
<img src="../images/community-park.jpg" class="img-fluid rounded-start h-100" alt="Community Park" style="object-fit: cover;">
<img src="{% static 'images/brighton.jpg' %}" class="img-fluid rounded-start h-100" alt="Community Park" style="object-fit: cover;">
</div>
<div class="col-md-7">
<div class="card-body">
@@ -249,7 +249,7 @@
<div class="card shadow-sm h-100">
<div class="row g-0 h-100">
<div class="col-md-5">
<img src="../images/nature-preserve.jpg" class="img-fluid rounded-start h-100" alt="Nature Preserve" style="object-fit: cover;">
<img src="{% static 'images/seven_gables.jpg' %}" class="img-fluid rounded-start h-100" alt="Nature Preserve" style="object-fit: cover;">
</div>
<div class="col-md-7">
<div class="card-body">
@@ -260,8 +260,8 @@
<li class="list-group-item"><i class="bi bi-check text-success me-2"></i>Playground</li>
<li class="list-group-item"><i class="bi bi-check text-success me-2"></i>Baseball Field</li>
<li class="list-group-item"><i class="bi bi-check text-success me-2"></i>Tennis Court</li>
<li class="list-group-item"><i class="bi bi-check text-success me-2"></i>BasketballCourt</li>
<li class="list-group-item"><i class="bi bi-check text-success me-2"></i>Picninc Tables</li>
<li class="list-group-item"><i class="bi bi-check text-success me-2"></i>Basketball Court</li>
<li class="list-group-item"><i class="bi bi-check text-success me-2"></i>Picnic Tables</li>
<li class="list-group-item"><i class="bi bi-check text-success me-2"></i>Dogs Allowed</li>
</ul>
<p class="card-text"><small class="text-muted">Open daily from 8am to sunset</small></p>

View File

@@ -0,0 +1,174 @@
<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% block pagetitle %}
{% endblock %}
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
<!-- Custom CSS -->
<link href="{% static 'css/style2.css' %}" rel="stylesheet" type="text/css" />
<script async defer src="https://tianji.aimloperations.com/tracker.js" data-website-id="cm9qziuid9vr7v6dtdbnx8406"></script>
<script type="text/css">
.bg-light {
background-color: #f8f9fa!important;
}
.auth-card {
max-width: 500px;
margin: 0 auto;
}
/* Member Portal */
.member-navbar {
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.member-navbar .nav-link {
padding: 0.5rem 1rem;
}
/* Directory */
.directory-table th {
white-space: nowrap;
}
/* Posts */
.post-card {
transition: transform 0.2s ease;
}
.post-card:hover {
transform: translateY(-2px);
}
.post-avatar {
width: 40px;
height: 40px;
}
/* Responsive adjustments */
@media (max-width: 767.98px) {
.member-navbar .navbar-nav {
margin-top: 1rem;
}
.directory-table {
font-size: 0.875rem;
}
}
</script>
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-dark bg-success sticky-top">
<div class="container">
<a class="navbar-brand" href="{% url 'index2' %}">Stonehedge Community Homeowners Association</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link" href="{% url 'dashboard' %}"><i class="bi bi-speedometer2 me-1"></i>Dashboard</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="{% url 'directory' %}"><i class="bi bi-people me-1"></i>Directory</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'posts' %}"><i class="bi bi-chat-square-text me-1"></i>Community Posts</a>
</li>
</ul>
<ul class="navbar-nav">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-bs-toggle="dropdown">
<i class="bi bi-person-circle me-1"></i>John D.
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="#"><i class="bi bi-person me-2"></i>Profile</a></li>
<li><a class="dropdown-item" href="#"><i class="bi bi-gear me-2"></i>Settings</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="../../auth/login.html"><i class="bi bi-box-arrow-right me-2"></i>Logout</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
{% block content %}
{% endblock %}
<!-- Footer -->
<footer class="bg-dark text-white pt-4 pb-3">
<div class="container">
<div class="row">
<div class="col-md-6">
<h5 class="text-uppercase mb-4">Stonehedge Community Homeowners Association</h5>
<p class="text-white-50">1900 Spring Rd. #200<br>Oak Brook, IL 60523</p>
</div>
<div class="col-md-3">
<h5 class="text-uppercase">Quick Links</h5>
<ul class="list-unstyled">
<li><a href="index.html" class="text-white-50">Dashboard</a></li>
<li><a href="directory.html" class="text-white-50">Directory</a></li>
<li><a href="posts/" class="text-white-50">Community Posts</a></li>
</ul>
</div>
<div class="col-md-3">
<h5 class="text-uppercase">Account</h5>
<ul class="list-unstyled">
<li><a href="#" class="text-white-50">Profile</a></li>
<li><a href="#" class="text-white-50">Settings</a></li>
<li><a href="../../auth/login.html" class="text-white-50">Logout</a></li>
</ul>
</div>
</div>
<hr class="my-3">
<div class="row">
<div class="col-12 text-center">
<p class="mb-0 small">&copy; 2023 Greenwood Estates HOA. All rights reserved.</p>
</div>
</div>
</div>
</footer>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<!-- Directory Script -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Search functionality
const searchInput = document.getElementById('directorySearch');
const tableRows = document.querySelectorAll('tbody tr');
searchInput.addEventListener('input', function() {
const searchTerm = this.value.toLowerCase();
tableRows.forEach(row => {
const rowText = row.textContent.toLowerCase();
if (rowText.includes(searchTerm)) {
row.style.display = '';
} else {
row.style.display = 'none';
}
});
});
// Filter functionality
const filterSelect = document.getElementById('directoryFilter');
filterSelect.addEventListener('change', function() {
const filterValue = this.value;
// In a real implementation, this would filter the directory
console.log('Filter by:', filterValue);
});
});
</script>
</body>
</html>

View File

@@ -12,8 +12,11 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
<!-- Custom CSS -->
<link href="{% static 'css/style2.css' %}" rel="stylesheet" type="text/css" />
<script async defer src="https://tianji.aimloperations.com/tracker.js" data-website-id="cm9qziuid9vr7v6dtdbnx8406"></script>
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-dark bg-success sticky-top">
<div class="container">
@@ -59,7 +62,6 @@
<div class="row">
<div class="col-lg-6 mb-4 mb-lg-0">
<h5 class="text-uppercase mb-4">Stonehedge Community Homeowners Association</h5>
<p class="text-white-50">1234 Greenwood Lane<br>Anytown, ST 12345</p>
</div>
<div class="col-lg-4 offset-lg-2 mb-4 mb-lg-0">
<h5 class="text-uppercase mb-4">Quick Links</h5>
@@ -76,7 +78,9 @@
</div>
<hr class="my-4 text-white-50">
<div class="row align-items-center">
<div id="footer">&copy; Stonehedge Community Homeowners Association 2010-<script>document.write( new Date().getFullYear() );</script>. All rights reserved
<div id="footer">
<p>&copy; Stonehedge Community Homeowners Association 2010-<script>document.write( new Date().getFullYear() );</script>. All rights reserved </p>
<p> Developed by <a href="https://aimloperations.com">AI ML Operations, LLC</a></p>
</div>
</div>
</footer>
@@ -87,4 +91,4 @@
{% block extra_js %}
{% endblock %}
</body>
</html>
</html>

View File

@@ -109,9 +109,8 @@
<i class="bi bi-credit-card text-success display-4 mb-3"></i>
<h4 class="text-success">Credit/Debit Card</h4>
<p class="card-text">Pay securely with Visa, Mastercard, American Express, or Discover.</p>
<a href="https://buy.stripe.com/test_14k6rE7jD3hQ2SQ144" class="btn btn-success mt-3" target="_blank" id="submitBtn">
Pay with Card
</a>
<button class="btn btn-success mt-3" id="submitBtn">Pay Dues</button>
</div>
</div>
</div>
@@ -192,39 +191,6 @@
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<!-- Stripe Integration Script (example) -->
<script>
// This would be replaced with your actual Stripe integration code
document.addEventListener('DOMContentLoaded', function() {
// Example: Track outbound links to Stripe
const stripeLinks = document.querySelectorAll('a[href*="stripe.com"]');
stripeLinks.forEach(link => {
link.addEventListener('click', function(e) {
// You could add analytics tracking here
console.log('Redirecting to Stripe payment');
});
});
// Example: Dynamic balance loading (would connect to your backend)
function loadAccountBalance() {
// In a real implementation, this would fetch from your database
// This is just a placeholder example
return {
member: "John Doe (Lot #42)",
balance: "$600.00",
dueDate: "January 15, 2024",
lastPayment: "$600.00 on January 10, 2023"
};
}
// Update the account info section (example)
const accountInfo = loadAccountBalance();
document.querySelector('.bg-light p:nth-child(1)').innerHTML =
`<strong>Member:</strong> ${accountInfo.member}`;
document.querySelector('.bg-light p:nth-child(2)').innerHTML =
`<strong>Current Balance:</strong> ${accountInfo.balance} (Due ${accountInfo.dueDate})`;
document.querySelector('.bg-light p:nth-child(3)').innerHTML =
`<strong>Last Payment:</strong> ${accountInfo.lastPayment}`;
});
</script>
<script src="https://js.stripe.com/v3/"></script>
<script src="{% static 'main.js' %}"></script>
{% endblock %}
{% endblock %}

View File

@@ -1,4 +1,4 @@
{% extends 'schasite/base.html' %}
{% extends 'schasite/base2.html' %}
{% load static %}
{% block pagetitle %}

View File

@@ -1,4 +1,4 @@
{% extends 'schasite/base.html' %}
{% extends 'schasite/base2.html' %}
{% load static %}
{% block pagetitle %}

View File

@@ -3,21 +3,42 @@
{% block pagetitle %}
<title>Stonehedge Community Homeowners Association</title>
<style type="text/css">
.hero-section {
background: url({% static 'images/header.gif' %});
height: 60vh;
display: flex;
background-repeat:no-repeat;
background-position: center center;
align-items: center;
justify-content: center;
flex-direction: column;
color: white;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}
</style>
{% endblock %}
{% block content %}
<!-- Hero Section -->
<section id="home" class="py-5 bg-success bg-opacity-10">
<div class="container py-5">
<div class="row align-items-center">
<div class="col-lg-8 mb-4 mb-lg-0">
<h1 class="display-4 fw-bold mb-3">Welcome to Stonehedge Community Homeowners Association</h1>
<h1 class="display-4 fw-bold mb-3">Welcome to Stonehedge Community Homeowners Association</h1>
<p class="lead mb-4">A premier community dedicated to maintaining beautiful homes, safe neighborhoods, and a high quality of life for all residents.</p>
<a href="{% url 'about_us2' %}" class="btn btn-success btn-lg px-4">Learn More</a>
</div>
<div class="col-lg-4">
<img src='{% static "images/bricks.jpg" %}' alt="Stonehedge Community Homeowners Association" class="img-fluid rounded-circle shadow">
</div>
</div>
<!-- <div class="col-lg-4">
<img src="{% static 'images/header.gif' %}" alt="Stonehedge Community Homeowners Association" class="img-fluid rounded-circle shadow">
</div> -->
</div>
</div>
</section>
@@ -27,112 +48,39 @@
<div class="container">
<h2 class="text-center text-success mb-5">About Our Community</h2>
<div class="row g-4">
<div class="col-md-4">
<div class="col-md-6">
<div class="card h-100 shadow-sm">
<img src="images/amenities.jpg" class="card-img-top" alt="Community Amenities" style="height: 200px; object-fit: cover;">
<div class="card-body">
<h5 class="card-title">Amenities</h5>
<p class="card-text">Our community features a swimming pool, playground, walking trails, and clubhouse available for resident use.</p>
<h5 class="card-title"><a href="{% url 'dues2' %}">Pay Dues</a></h5>
<p class="card-text">Make sure to pay your dues</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="col-md-6">
<div class="card h-100 shadow-sm">
<img src="images/board.jpg" class="card-img-top" alt="HOA Board" style="height: 200px; object-fit: cover;">
<div class="card-body">
<h5 class="card-title">HOA Board</h5>
<h5 class="card-title"><a href="{% url 'membership_form2' %}">Join</a></h5>
<p class="card-text">Fill out the membership form and be added to the mailing list</p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100 shadow-sm">
<div class="card-body">
<h5 class="card-title"><a href="{% url 'calendar2' %}">Events</a></h5>
<p class="card-text">Checkout out the upcoming and past events!</p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100 shadow-sm">
<div class="card-body">
<h5 class="card-title"><a href="{% url 'scha_board2' %}">HOA Board</a></h5>
<p class="card-text">Meet our elected board members who volunteer their time to maintain and improve our neighborhood.</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card h-100 shadow-sm">
<img src="images/rules.jpg" class="card-img-top" alt="Community Rules" style="height: 200px; object-fit: cover;">
<div class="card-body">
<h5 class="card-title">Community Rules</h5>
<p class="card-text">Learn about our community guidelines designed to maintain property values and quality of life for all residents.</p>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- News Section -->
<section id="news" class="py-5 bg-success bg-opacity-10">
<div class="container">
<h2 class="text-center text-success mb-5">Community News & Events</h2>
<div class="row g-4">
<div class="col-md-6">
<div class="card h-100 shadow-sm">
<div class="card-body">
<h5 class="card-title">Annual Community Picnic</h5>
<p class="card-text">Join us on June 15th for our annual community picnic at the clubhouse. Food, games, and fun for the whole family!</p>
</div>
<div class="card-footer bg-transparent border-0">
<a href="#" class="btn btn-outline-success">RSVP Now</a>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100 shadow-sm">
<div class="card-body">
<h5 class="card-title">Landscaping Updates</h5>
<p class="card-text">New landscaping will be installed in common areas beginning next month. Expect temporary parking restrictions.</p>
</div>
<div class="card-footer bg-transparent border-0">
<a href="#" class="btn btn-outline-success">View Schedule</a>
</div>
</div>
</div>
</div>
<div class="text-center mt-4">
<a href="#" class="btn btn-success px-4">View All News</a>
</div>
</div>
</section>
<!-- Documents Section -->
<section id="documents" class="py-5">
<div class="container">
<h2 class="text-center text-success mb-5">Community Documents</h2>
<div class="row g-4">
<div class="col-md-4">
<div class="card h-100 shadow-sm">
<div class="card-header bg-success text-white">
<h5 class="mb-0">Governing Documents</h5>
</div>
<div class="list-group list-group-flush">
<a href="#" class="list-group-item list-group-item-action">CC&Rs</a>
<a href="#" class="list-group-item list-group-item-action">Bylaws</a>
<a href="#" class="list-group-item list-group-item-action">Articles of Incorporation</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card h-100 shadow-sm">
<div class="card-header bg-success text-white">
<h5 class="mb-0">Meeting Minutes</h5>
</div>
<div class="list-group list-group-flush">
<a href="#" class="list-group-item list-group-item-action">2023 Meetings</a>
<a href="#" class="list-group-item list-group-item-action">2022 Meetings</a>
<a href="#" class="list-group-item list-group-item-action">Archive</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card h-100 shadow-sm">
<div class="card-header bg-success text-white">
<h5 class="mb-0">Forms</h5>
</div>
<div class="list-group list-group-flush">
<a href="#" class="list-group-item list-group-item-action">Architectural Request</a>
<a href="#" class="list-group-item list-group-item-action">Complaint Form</a>
<a href="#" class="list-group-item list-group-item-action">Resale Certificate Request</a>
</div>
</div>
</div>
</div>
</div>
</section>

View File

@@ -0,0 +1,123 @@
{% extends 'schasite/authenticated_base.html' %}
{% load static %}
{% block pagetitle %}
<title>Dashboard | SCHA</title>
{% endblock %}
{% block content %}
<main class="py-5">
<div class="container">
<div class="row mb-4">
<div class="col-12">
<h1 class="display-6">Member Dashboard</h1>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item active" aria-current="page">Home</li>
</ol>
</nav>
</div>
</div>
<div class="row g-4">
<!-- Welcome Card -->
<div class="col-md-6">
<div class="card shadow-sm h-100">
<div class="card-header bg-success text-white">
<h3 class="h5 mb-0"><i class="bi bi-house-door me-2"></i>Welcome</h3>
</div>
<div class="card-body">
<h4 class="card-title">Hello, John Doe!</h4>
<p class="card-text">Welcome to your Greenwood Estates member portal. From here you can access community resources, connect with neighbors, and stay informed.</p>
<div class="alert alert-success">
<i class="bi bi-info-circle-fill me-2"></i>
Your membership is active through December 31, 2024.
</div>
</div>
</div>
</div>
<!-- Quick Links -->
<div class="col-md-6">
<div class="card shadow-sm h-100">
<div class="card-header bg-success text-white">
<h3 class="h5 mb-0"><i class="bi bi-lightning me-2"></i>Quick Actions</h3>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-sm-6">
<a href="{% url 'directory' %}" class="btn btn-outline-success w-100 py-3">
<i class="bi bi-people display-6 d-block mb-2"></i>
Member Directory
</a>
</div>
<div class="col-sm-6">
<a href="{% url 'posts' %}" class="btn btn-outline-success w-100 py-3">
<i class="bi bi-chat-square-text display-6 d-block mb-2"></i>
Community Posts
</a>
</div>
<div class="col-sm-6">
<a href="{% url 'posts_create' %}" class="btn btn-outline-success w-100 py-3">
<i class="bi bi-plus-circle display-6 d-block mb-2"></i>
Create Post
</a>
</div>
<!-- <div class="col-sm-6">
<a href="#" class="btn btn-outline-success w-100 py-3">
<i class="bi bi-calendar-event display-6 d-block mb-2"></i>
View Calendar
</a>
</div> -->
</div>
</div>
</div>
</div>
<!-- Recent Activity -->
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header bg-success text-white">
<h3 class="h5 mb-0"><i class="bi bi-activity me-2"></i>Your Recently Updated Posts</h3>
</div>
<div class="card-body">
<div class="list-group">
{% for recent_post in member_recent_posts %}
<a href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">{{ recent_post.title }}</h5>
<small>3 days ago</small>
</div>
<p class="mb-1">{{ recent_post.content }}</p>
<small>Posted by Sarah Johnson</small>
</a>
{% endfor %}
</div>
</div>
</div>
<div class="card shadow-sm">
<div class="card-header bg-success text-white">
<h3 class="h5 mb-0"><i class="bi bi-activity me-2"></i>Recent Community Posts</h3>
</div>
<div class="card-body">
<div class="list-group">
{% for recent_post in recent_posts %}
<a href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">{{ recent_post.title }}</h5>
<small>3 days ago</small>
</div>
<p class="mb-1">{{ recent_post.content }}</p>
<small>Posted by Sarah Johnson</small>
</a>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</div>
</main>
{% endblock %}
{% block extra_js %}
{% endblock %}

View File

@@ -0,0 +1,229 @@
{% extends 'schasite/authenticated_base.html' %}
{% load static %}
{% block pagetitle %}
<title>Directory | SCHA</title>
{% endblock %}
{% block content %}
<main class="py-5">
<div class="container">
<div class="row mb-4">
<div class="col-12">
<h1 class="display-6">Member Directory</h1>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'dashboard' %}">Home</a></li>
<li class="breadcrumb-item active" aria-current="page">Directory</li>
</ol>
</nav>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6 mb-3 mb-md-0">
<div class="input-group">
<span class="input-group-text"><i class="bi bi-search"></i></span>
<input type="text" class="form-control" placeholder="Search members..." id="directorySearch">
</div>
</div>
<div class="col-md-6">
<div class="input-group">
<span class="input-group-text">Filter</span>
<select class="form-select" id="directoryFilter">
<option selected>All Members</option>
<option>Committee Members</option>
<option>Board Members</option>
<option>By Street</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header bg-success text-white">
<div class="d-flex justify-content-between align-items-center">
<h3 class="h5 mb-0"><i class="bi bi-people-fill me-2"></i>Community Members</h3>
<span class="badge bg-light text-success">142 Members</span>
</div>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-success">
<tr>
<th>Name</th>
<th>Address</th>
<th>Contact</th>
<th>Committees</th>
<th>Services</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<div class="bg-success bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
<i class="bi bi-person-fill text-success"></i>
</div>
</div>
<div class="flex-grow-1 ms-3">
<h6 class="mb-0">John & Sarah Smith</h6>
<small class="text-muted">Lot #42</small>
</div>
</div>
</td>
<td>123 Oak Drive</td>
<td>
<a href="mailto:john.smith@example.com" class="text-decoration-none"><i class="bi bi-envelope me-1"></i>Email</a><br>
<a href="tel:5551234567" class="text-decoration-none"><i class="bi bi-telephone me-1"></i>555-123-4567</a>
</td>
<td>
<span class="badge bg-success bg-opacity-10 text-success mb-1">Social Committee</span>
<span class="badge bg-success bg-opacity-10 text-success">Welcoming</span>
</td>
<td>
<span class="badge bg-info bg-opacity-10 text-info">Pet Care</span>
</td>
</tr>
<tr>
<td>
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<div class="bg-success bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
<i class="bi bi-person-fill text-success"></i>
</div>
</div>
<div class="flex-grow-1 ms-3">
<h6 class="mb-0">Robert Wilson</h6>
<small class="text-muted">Lot #18</small>
</div>
</div>
</td>
<td>456 Maple Street</td>
<td>
<a href="mailto:rwilson@example.com" class="text-decoration-none"><i class="bi bi-envelope me-1"></i>Email</a><br>
<a href="tel:5559876543" class="text-decoration-none"><i class="bi bi-telephone me-1"></i>555-987-6543</a>
</td>
<td>
<span class="badge bg-success bg-opacity-10 text-success mb-1">Architectural</span>
<span class="badge bg-success bg-opacity-10 text-success">Board</span>
</td>
<td>
<span class="badge bg-info bg-opacity-10 text-info">Lawn Mowing</span>
<span class="badge bg-info bg-opacity-10 text-info">Snow Shoveling</span>
</td>
</tr>
<tr>
<td>
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<div class="bg-success bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
<i class="bi bi-person-fill text-success"></i>
</div>
</div>
<div class="flex-grow-1 ms-3">
<h6 class="mb-0">Emily Davis</h6>
<small class="text-muted">Lot #75</small>
</div>
</div>
</td>
<td>789 Pine Road</td>
<td>
<a href="mailto:emily.d@example.com" class="text-decoration-none"><i class="bi bi-envelope me-1"></i>Email</a><br>
<a href="tel:5554567890" class="text-decoration-none"><i class="bi bi-telephone me-1"></i>555-456-7890</a>
</td>
<td>
<span class="badge bg-success bg-opacity-10 text-success mb-1">Communications</span>
</td>
<td>
<span class="badge bg-info bg-opacity-10 text-info">Babysitting</span>
<span class="badge bg-info bg-opacity-10 text-info">House Sitting</span>
</td>
</tr>
<tr>
<td>
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<div class="bg-success bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
<i class="bi bi-person-fill text-success"></i>
</div>
</div>
<div class="flex-grow-1 ms-3">
<h6 class="mb-0">Michael & Lisa Brown</h6>
<small class="text-muted">Lot #33</small>
</div>
</div>
</td>
<td>321 Elm Avenue</td>
<td>
<a href="mailto:mbrown@example.com" class="text-decoration-none"><i class="bi bi-envelope me-1"></i>Email</a><br>
<a href="tel:5557890123" class="text-decoration-none"><i class="bi bi-telephone me-1"></i>555-789-0123</a>
</td>
<td>
<span class="badge bg-success bg-opacity-10 text-success mb-1">Landscape</span>
<span class="badge bg-success bg-opacity-10 text-success">Safety</span>
</td>
<td>
<span class="badge bg-info bg-opacity-10 text-info">Other (Handyman)</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="card-footer">
<nav aria-label="Directory navigation">
<ul class="pagination justify-content-center mb-0">
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1">Previous</a>
</li>
<li class="page-item active"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item">
<a class="page-link" href="#">Next</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
</div>
</div>
</main>
{% endblock %}
{% block extra_js %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Search functionality
const searchInput = document.getElementById('directorySearch');
const tableRows = document.querySelectorAll('tbody tr');
searchInput.addEventListener('input', function() {
const searchTerm = this.value.toLowerCase();
tableRows.forEach(row => {
const rowText = row.textContent.toLowerCase();
if (rowText.includes(searchTerm)) {
row.style.display = '';
} else {
row.style.display = 'none';
}
});
});
// Filter functionality
const filterSelect = document.getElementById('directoryFilter');
filterSelect.addEventListener('change', function() {
const filterValue = this.value;
// In a real implementation, this would filter the directory
console.log('Filter by:', filterValue);
});
});
</script>
{% endblock %}

View File

@@ -0,0 +1,166 @@
{% extends 'schasite/authenticated_base.html' %}
{% load static %}
{% block pagetitle %}
<title>Posts | SCHA</title>
{% endblock %}
{% block content %}
<main class="py-5">
<div class="container">
<div class="row mb-4">
<div class="col-12">
<h1 class="display-6">Community Posts</h1>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'dashboard' %}">Home</a></li>
<li class="breadcrumb-item active" aria-current="page">Community Posts</li>
</ol>
</nav>
</div>
</div>
<div class="row mb-4">
<div class="col-md-8 mb-3 mb-md-0">
<div class="input-group">
<span class="input-group-text"><i class="bi bi-search"></i></span>
<input type="text" class="form-control" placeholder="Search posts...">
<button class="btn btn-success" type="button">Search</button>
</div>
</div>
<div class="col-md-4 text-md-end">
<a href="{% url 'posts_create' %}" class="btn btn-success">
<i class="bi bi-plus-circle me-2"></i>New Post
</a>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="card shadow-sm mb-4">
<div class="card-header bg-success text-white">
<div class="d-flex justify-content-between align-items-center">
<h3 class="h5 mb-0"><i class="bi bi-pin-angle me-2"></i>Pinned Post</h3>
<span class="badge bg-light text-success">Announcement</span>
</div>
</div>
<div class="card-body">
<div class="d-flex mb-3">
<div class="flex-shrink-0">
<div class="bg-success bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
<i class="bi bi-person-fill text-success"></i>
</div>
</div>
<div class="flex-grow-1 ms-3">
<h5 class="mb-1">Annual Community Picnic</h5>
<div class="d-flex flex-wrap text-muted small mb-2">
<div class="me-3"><i class="bi bi-person me-1"></i>Sarah Johnson</div>
<div class="me-3"><i class="bi bi-calendar me-1"></i>June 5, 2023</div>
<div><i class="bi bi-chat me-1"></i>12 comments</div>
</div>
</div>
</div>
<p class="card-text">Our annual community picnic is scheduled for Saturday, June 15th from 11am-3pm at the Greenwood Park. This year we'll have a bounce house, face painting, and a pie baking contest. Please RSVP by June 10th so we can plan for food quantities.</p>
<div class="mt-3">
<a href="#" class="btn btn-sm btn-outline-success me-2"><i class="bi bi-hand-thumbs-up me-1"></i>Like (24)</a>
<a href="#" class="btn btn-sm btn-outline-success"><i class="bi bi-chat me-1"></i>Comment</a>
</div>
</div>
</div>
{% for post in posts %}
<div class="card shadow-sm mb-4">
<div class="card-body">
<div class="d-flex mb-3">
<div class="flex-shrink-0">
<div class="bg-success bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
<i class="bi bi-person-fill text-success"></i>
</div>
</div>
<div class="flex-grow-1 ms-3">
<h5 class="mb-1"><a href="{% url 'posts_detail' post_id=post.id %}">{{ post.title }}</a></h5>
<div class="d-flex flex-wrap text-muted small mb-2">
<div class="me-3"><i class="bi bi-person me-1"></i>Emily Davis</div>
<div class="me-3"><i class="bi bi-calendar me-1"></i>June 3, 2023</div>
<div><i class="bi bi-chat me-1"></i>8 comments</div>
</div>
</div>
</div>
<p class="card-text">{{ post.content }}</p>
<div class="mt-3">
<a href="#" class="btn btn-sm btn-outline-success me-2"><i class="bi bi-hand-thumbs-up me-1"></i>Like (15)</a>
<a href="#" class="btn btn-sm btn-outline-success"><i class="bi bi-chat me-1"></i>Comment</a>
</div>
</div>
</div>
{% endfor %}
<div class="card shadow-sm mb-4">
<div class="card-body">
<div class="d-flex mb-3">
<div class="flex-shrink-0">
<div class="bg-success bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
<i class="bi bi-person-fill text-success"></i>
</div>
</div>
<div class="flex-grow-1 ms-3">
<h5 class="mb-1">Lost Dog - Please Help!</h5>
<div class="d-flex flex-wrap text-muted small mb-2">
<div class="me-3"><i class="bi bi-person me-1"></i>Emily Davis</div>
<div class="me-3"><i class="bi bi-calendar me-1"></i>June 3, 2023</div>
<div><i class="bi bi-chat me-1"></i>8 comments</div>
</div>
</div>
</div>
<p class="card-text">Our golden retriever Max got out of our yard this morning around 9am. He was last seen near the corner of Oak Drive and Maple Street. He's friendly, wearing a blue collar with our contact info. Please call me at 555-456-7890 if you see him!</p>
<div class="mt-3">
<a href="#" class="btn btn-sm btn-outline-success me-2"><i class="bi bi-hand-thumbs-up me-1"></i>Like (15)</a>
<a href="#" class="btn btn-sm btn-outline-success"><i class="bi bi-chat me-1"></i>Comment</a>
</div>
</div>
</div>
<div class="card shadow-sm mb-4">
<div class="card-body">
<div class="d-flex mb-3">
<div class="flex-shrink-0">
<div class="bg-success bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
<i class="bi bi-person-fill text-success"></i>
</div>
</div>
<div class="flex-grow-1 ms-3">
<h5 class="mb-1">Yard Sale This Weekend</h5>
<div class="d-flex flex-wrap text-muted small mb-2">
<div class="me-3"><i class="bi bi-person me-1"></i>Michael Brown</div>
<div class="me-3"><i class="bi bi-calendar me-1"></i>June 1, 2023</div>
<div><i class="bi bi-chat me-1"></i>5 comments</div>
</div>
</div>
</div>
<p class="card-text">We're having a yard sale at 321 Elm Avenue this Saturday from 8am-2pm. Lots of household items, kids' clothes, and furniture. Everything must go!</p>
<div class="mt-3">
<a href="#" class="btn btn-sm btn-outline-success me-2"><i class="bi bi-hand-thumbs-up me-1"></i>Like (7)</a>
<a href="#" class="btn btn-sm btn-outline-success"><i class="bi bi-chat me-1"></i>Comment</a>
</div>
</div>
</div>
<nav aria-label="Posts navigation">
<ul class="pagination justify-content-center">
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1">Previous</a>
</li>
<li class="page-item active"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item">
<a class="page-link" href="#">Next</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
</main>
{% endblock %}
{% block extra_js %}
{% endblock %}

View File

@@ -0,0 +1,124 @@
{% extends 'schasite/authenticated_base.html' %}
{% load static %}
{% block pagetitle %}
<title>Create Post | SCHA</title>
{% endblock %}
{% block content %}
<main class="py-5">
<div class="container">
<div class="row mb-4">
<div class="col-12">
<h1 class="display-6">Create New Post</h1>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'dashboard' %}">Home</a></li>
<li class="breadcrumb-item"><a href="{% url 'posts' %}">Community Posts</a></li>
<li class="breadcrumb-item active" aria-current="page">Create Post</li>
</ol>
</nav>
</div>
</div>
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="card shadow-sm">
<div class="card-header bg-success text-white">
<h3 class="h5 mb-0"><i class="bi bi-pencil me-2"></i>New Community Post</h3>
</div>
<div class="card-body">
<form id="createPostForm" method="POST" action='{% url "posts_create" %}' class="needs-validation" novalidate>
{% csrf_token %}
{% if community_post.errors %}
<div class="alert alert-danger">
<i class="bi bi-info-circle-fill me-2"></i>
<p> Need to fix the following errors</p>
{{ community_post.errors | safe }}
</div>
{% endif %}
<div class="mb-3">
<label for="title" class="form-label">Title*</label>
<input type="text" class="form-control" value='{{ community_post.title.value|default_if_none:"" }}' name="title" id="title" required>
<div class="invalid-feedback">
Please provide a title for your post.
</div>
</div>
<div class="mb-3">
<label for="category" class="form-label">Category*</label>
<select class="form-select" name="category" id="category" required>
<option value='{{ community_post.category.value|default_if_none:"" }}' selected disabled>Select a category</option>
<option>Announcement</option>
<option>Discussion</option>
<option>For Sale</option>
<option>Help Needed</option>
<option>Event</option>
<option>Other</option>
</select>
<div class="invalid-feedback">
Please select a category.
</div>
</div>
<div class="mb-3">
<label for="content" class="form-label">Content*</label>
<textarea class="form-control" value='{{ community_post.content.value|default_if_none:"" }}' name="content" id="content" rows="6" required></textarea>
<div class="invalid-feedback">
Please provide content for your post.
</div>
</div>
<div class="mb-3">
<label for="postImage" class="form-label">Image (optional)</label>
<input class="form-control" type="file" id="postImage" accept="image/*">
<div class="form-text">
Maximum file size: 5MB. Allowed formats: JPG, PNG, GIF.
</div>
</div>
<div class="mb-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="notifyMembers">
<label class="form-check-label" for="notifyMembers">
Notify all members via email about this post
</label>
</div>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<a href="posts_create" class="btn btn-outline-secondary me-md-2">Cancel</a>
<button type="submit" class="btn btn-success">Post to Community</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</main>
{% endblock %}
{% block extra_js %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Form validation
const form = document.getElementById('createPostForm');
form.addEventListener('submit', function(event) {
event.preventDefault();
event.stopPropagation();
if (form.checkValidity()) {
// In a real implementation, this would submit the post
alert('Post created successfully (simulated)');
window.location.href = "../index.html";
}
form.classList.add('was-validated');
}, false);
// Image preview functionality would go here
});
</script>
{% endblock %}

View File

@@ -0,0 +1,328 @@
{% extends 'schasite/authenticated_base.html' %}
{% load static %}
{% block pagetitle %}
<title>Posts | SCHA</title>
<script type="text/css">
.post-detail .card-header {
padding: 1rem 1.25rem;
}
.comment-list {
max-height: 500px;
overflow-y: auto;
padding-right: 0.5rem;
}
.comment-list::-webkit-scrollbar {
width: 8px;
}
.comment-list::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
.comment-list::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 10px;
}
.comment-list::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
/* Responsive adjustments */
@media (max-width: 767.98px) {
.comment-list {
max-height: none;
}
.post-detail .card-header h3 {
font-size: 1.1rem;
}
}
/* Interaction buttons */
.btn-outline-success:hover .bi-hand-thumbs-up,
.text-success .bi-hand-thumbs-up {
fill: currentColor;
}
</script>
{% endblock %}
{% block content %}
<main class="py-5">
<div class="container">
<div class="row mb-4">
<div class="col-12">
<h1 class="display-6">Community Post</h1>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="../../index.html">Home</a></li>
<li class="breadcrumb-item"><a href="../index.html">Community Posts</a></li>
<li class="breadcrumb-item active" aria-current="page">Post Details</li>
</ol>
</nav>
</div>
</div>
<div class="row justify-content-center">
<div class="col-lg-8">
<!-- Main Post Card -->
<div class="card shadow-sm mb-4">
<div class="card-header bg-success text-white">
<div class="d-flex justify-content-between align-items-center">
<h3 class="h5 mb-0">Annual Community Picnic</h3>
<span class="badge bg-light text-success">Announcement</span>
</div>
</div>
<div class="card-body">
<div class="d-flex mb-4">
<div class="flex-shrink-0">
<div class="bg-success bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center" style="width: 50px; height: 50px;">
<i class="bi bi-person-fill text-success fs-4"></i>
</div>
</div>
<div class="flex-grow-1 ms-3">
<h5 class="mb-1">Sarah Johnson</h5>
<div class="d-flex flex-wrap text-muted small">
<div class="me-3"><i class="bi bi-calendar me-1"></i>Posted on June 5, 2023</div>
<div><i class="bi bi-chat me-1"></i>12 comments</div>
</div>
</div>
</div>
<div class="mb-4">
<img src="../../../images/events/picnic.jpg" alt="Community picnic" class="img-fluid rounded mb-3">
<p>Our annual community picnic is scheduled for <strong>Saturday, June 15th from 11am-3pm</strong> at the Greenwood Park. This is always one of our most popular events, bringing together neighbors of all ages for a day of fun and community building.</p>
<h5 class="mt-4">Event Details</h5>
<ul>
<li><strong>Date:</strong> June 15, 2024</li>
<li><strong>Time:</strong> 11:00 AM - 3:00 PM</li>
<li><strong>Location:</strong> Greenwood Community Park</li>
<li><strong>Address:</strong> 1234 Greenwood Lane, Anytown, ST</li>
<li><strong>RSVP Deadline:</strong> June 10, 2024</li>
</ul>
<h5 class="mt-4">What to Expect</h5>
<p>This year we're excited to offer:</p>
<ul>
<li>Bounce house and playground activities for kids</li>
<li>Face painting and balloon animals</li>
<li>Pie baking contest (sign up below!)</li>
<li>Potluck lunch (main dishes provided by HOA)</li>
<li>Live acoustic music from 1-3pm</li>
</ul>
<div class="alert alert-success mt-4">
<h5><i class="bi bi-info-circle me-2"></i>Volunteers Needed</h5>
<p>We're looking for volunteers to help with setup (10-11am), food service (11:30am-1:30pm), and cleanup (3-4pm). Please email me if you can help!</p>
</div>
</div>
<div class="d-flex justify-content-between align-items-center">
<div>
<button class="btn btn-sm btn-outline-success me-2">
<i class="bi bi-hand-thumbs-up me-1"></i>Like (24)
</button>
<button class="btn btn-sm btn-outline-success">
<i class="bi bi-share me-1"></i>Share
</button>
</div>
<div>
<a href="#" class="text-decoration-none text-success small">
<i class="bi bi-flag me-1"></i>Report
</a>
</div>
</div>
</div>
</div>
<!-- Comments Section -->
<div class="card shadow-sm mb-4">
<div class="card-header bg-success text-white">
<h3 class="h5 mb-0"><i class="bi bi-chat-square-text me-2"></i>Comments (12)</h3>
</div>
<div class="card-body">
<!-- Comment Form -->
<div class="mb-4">
<form>
<div class="mb-3">
<label for="commentText" class="form-label">Add a comment</label>
<textarea class="form-control" id="commentText" rows="3" placeholder="Share your thoughts..."></textarea>
</div>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-success">Post Comment</button>
</div>
</form>
</div>
<hr>
<!-- Comment List -->
<div class="comment-list">
<!-- Comment 1 -->
<div class="d-flex mb-4">
<div class="flex-shrink-0">
<div class="bg-success bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
<i class="bi bi-person-fill text-success"></i>
</div>
</div>
<div class="flex-grow-1 ms-3">
<div class="d-flex justify-content-between align-items-center mb-1">
<h6 class="mb-0">Robert Wilson</h6>
<small class="text-muted">June 5, 2023 at 2:30 PM</small>
</div>
<p class="mb-2">Looking forward to it! I'll bring my famous potato salad. Can I sign up to help with setup?</p>
<div>
<a href="#" class="text-decoration-none text-success small me-3">
<i class="bi bi-hand-thumbs-up me-1"></i>Like (5)
</a>
<a href="#" class="text-decoration-none text-success small">
<i class="bi bi-reply me-1"></i>Reply
</a>
</div>
<!-- Reply -->
<div class="d-flex mt-3">
<div class="flex-shrink-0">
<div class="bg-success bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center" style="width: 32px; height: 32px;">
<i class="bi bi-person-fill text-success small"></i>
</div>
</div>
<div class="flex-grow-1 ms-3">
<div class="d-flex justify-content-between align-items-center mb-1">
<h6 class="mb-0">Sarah Johnson</h6>
<small class="text-muted">June 5, 2023 at 3:15 PM</small>
</div>
<p class="mb-2">That would be great Robert! I'll put you down for setup crew.</p>
<div>
<a href="#" class="text-decoration-none text-success small me-3">
<i class="bi bi-hand-thumbs-up me-1"></i>Like (2)
</a>
</div>
</div>
</div>
</div>
</div>
<!-- Comment 2 -->
<div class="d-flex mb-4">
<div class="flex-shrink-0">
<div class="bg-success bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
<i class="bi bi-person-fill text-success"></i>
</div>
</div>
<div class="flex-grow-1 ms-3">
<div class="d-flex justify-content-between align-items-center mb-1">
<h6 class="mb-0">Emily Davis</h6>
<small class="text-muted">June 6, 2023 at 9:45 AM</small>
</div>
<p class="mb-2">I'd love to enter the pie contest! Are there any category restrictions?</p>
<div>
<a href="#" class="text-decoration-none text-success small me-3">
<i class="bi bi-hand-thumbs-up me-1"></i>Like (3)
</a>
<a href="#" class="text-decoration-none text-success small">
<i class="bi bi-reply me-1"></i>Reply
</a>
</div>
</div>
</div>
<!-- Comment 3 -->
<div class="d-flex">
<div class="flex-shrink-0">
<div class="bg-success bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
<i class="bi bi-person-fill text-success"></i>
</div>
</div>
<div class="flex-grow-1 ms-3">
<div class="d-flex justify-content-between align-items-center mb-1">
<h6 class="mb-0">Michael Brown</h6>
<small class="text-muted">June 6, 2023 at 11:20 AM</small>
</div>
<p class="mb-2">I'll bring my guitar and play during the music time if that's okay!</p>
<div>
<a href="#" class="text-decoration-none text-success small me-3">
<i class="bi bi-hand-thumbs-up me-1"></i>Like (8)
</a>
<a href="#" class="text-decoration-none text-success small">
<i class="bi bi-reply me-1"></i>Reply
</a>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer text-center">
<a href="#" class="text-decoration-none">Load more comments</a>
</div>
</div>
<!-- Related Posts -->
<div class="card shadow-sm">
<div class="card-header bg-success text-white">
<h3 class="h5 mb-0"><i class="bi bi-collection me-2"></i>Related Posts</h3>
</div>
<div class="card-body">
<div class="list-group list-group-flush">
<a href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h6 class="mb-1">Summer Pool Schedule</h6>
<small class="text-muted">May 28, 2023</small>
</div>
<p class="mb-1 small">Pool hours and rules for the summer season</p>
<small class="text-muted">Posted by Michael Brown</small>
</a>
<a href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h6 class="mb-1">Neighborhood Yard Sale</h6>
<small class="text-muted">May 15, 2023</small>
</div>
<p class="mb-1 small">Community-wide yard sale August 3-4</p>
<small class="text-muted">Posted by Emily Davis</small>
</a>
<a href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h6 class="mb-1">Landscaping Updates</h6>
<small class="text-muted">April 30, 2023</small>
</div>
<p class="mb-1 small">New plants and improvements in common areas</p>
<small class="text-muted">Posted by Robert Wilson</small>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
{% endblock %}
{% block extra_js %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Like button functionality
document.querySelectorAll('.bi-hand-thumbs-up').forEach(icon => {
icon.addEventListener('click', function() {
// In a real implementation, this would track likes
this.classList.toggle('text-success');
});
});
// Comment submission
const commentForm = document.querySelector('.comment-list').previousElementSibling.querySelector('form');
commentForm.addEventListener('submit', function(e) {
e.preventDefault();
const commentText = document.getElementById('commentText').value;
if (commentText.trim() !== '') {
// In a real implementation, this would submit the comment
alert('Comment posted successfully (simulated)');
document.getElementById('commentText').value = '';
}
});
});
</script>
{% endblock %}

View File

@@ -74,7 +74,8 @@
<h2 class="h4 mb-0">New Member Information</h2>
</div>
<div class="card-body">
<form id="membershipForm" class="needs-validation" novalidate>
<form id="membershipForm" method="POST" action='{% url "membership_form2" %}' class="needs-validation" novalidate>
{% csrf_token %}
<!-- Household Information -->
<fieldset class="mb-4">
<legend class="h5 text-success border-bottom pb-2">Household Information</legend>
@@ -83,30 +84,27 @@
<div class="row g-3 mb-4">
<div class="col-md-6">
<label for="streetAddress" class="form-label">Street Address*</label>
<input type="text" class="form-control" id="streetAddress" required>
<input type="text" class="form-control" id="streetAddress" name="streetAddress" required>
<div class="invalid-feedback">
Please provide your street address.
</div>
</div>
<div class="col-md-6">
<label for="unit" class="form-label">Unit/Apt #</label>
<input type="text" class="form-control" id="unit">
<input type="text" class="form-control" id="unit" name="unit">
</div>
<div class="col-md-4">
<label for="city" class="form-label">City*</label>
<input type="text" class="form-control" id="city" required>
<input type="text" class="form-control" id="city" name="city" value="Wheaton" required>
<div class="invalid-feedback">
Please provide your city.
</div>
</div>
<div class="col-md-4">
<label for="state" class="form-label">State*</label>
<select class="form-select" id="state" required>
<select class="form-select" id="state" name="state" value="Illinois" required>
<option value="" selected disabled>Choose...</option>
<option>Alabama</option>
<option>Alaska</option>
<!-- Add all states -->
<option>Wyoming</option>
<option>IL</option>
</select>
<div class="invalid-feedback">
Please select your state.
@@ -114,7 +112,7 @@
</div>
<div class="col-md-4">
<label for="zipCode" class="form-label">ZIP Code*</label>
<input type="text" class="form-control" id="zipCode" required>
<input type="text" class="form-control" id="zipCode" value="zipCode" value="60189" required>
<div class="invalid-feedback">
Please provide your ZIP code.
</div>
@@ -128,28 +126,28 @@
</div>
<div class="col-md-6">
<label for="firstName1" class="form-label">First Name*</label>
<input type="text" class="form-control" id="firstName1" required>
<input type="text" class="form-control" id="firstName1" name="firstName1" required>
<div class="invalid-feedback">
Please provide first name.
</div>
</div>
<div class="col-md-6">
<label for="lastName1" class="form-label">Last Name*</label>
<input type="text" class="form-control" id="lastName1" required>
<input type="text" class="form-control" id="lastName1" name="lastName1" required>
<div class="invalid-feedback">
Please provide last name.
</div>
</div>
<div class="col-md-6">
<label for="email1" class="form-label">Email*</label>
<input type="email" class="form-control" id="email1" required>
<input type="email" class="form-control" id="email1" name="email1" required>
<div class="invalid-feedback">
Please provide a valid email.
</div>
</div>
<div class="col-md-6">
<label for="phone1" class="form-label">Phone*</label>
<input type="tel" class="form-control" id="phone1" required>
<input type="tel" class="form-control" id="phone1" name="phone1" required>
<div class="invalid-feedback">
Please provide phone number.
</div>
@@ -174,19 +172,19 @@
</div>
<div class="col-md-6">
<label for="firstName2" class="form-label">First Name</label>
<input type="text" class="form-control" id="firstName2">
<input type="text" class="form-control" id="firstName2" name="firstName2">
</div>
<div class="col-md-6">
<label for="lastName2" class="form-label">Last Name</label>
<input type="text" class="form-control" id="lastName2">
<input type="text" class="form-control" id="lastName2" name="lastName2">
</div>
<div class="col-md-6">
<label for="email2" class="form-label">Email</label>
<input type="email" class="form-control" id="email2">
<input type="email" class="form-control" id="email2" name="email2">
</div>
<div class="col-md-6">
<label for="phone2" class="form-label">Phone</label>
<input type="tel" class="form-control" id="phone2">
<input type="tel" class="form-control" id="phone2" name="phone2">
</div>
</div>
</fieldset>
@@ -199,50 +197,82 @@
<div class="row">
<div class="col-md-6">
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="socialCommittee">
<label class="form-check-label" for="socialCommittee">
Social & Events Committee
<input class="form-check-input" type="checkbox" id="block_captain" for="block_captain" name="block_captain">
<label class="form-check-label" id="block_captain">
BlockCaptain
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="landscapeCommittee">
<label class="form-check-label" for="landscapeCommittee">
Landscape & Maintenance Committee
<input class="form-check-input" type="checkbox" id="coordinator" for="coordinator" name="coordinator">
<label class="form-check-label" id="coordinator">
Coordinator
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="safetyCommittee">
<label class="form-check-label" for="safetyCommittee">
Safety & Neighborhood Watch
<input class="form-check-input" type="checkbox" id="egg_hunt" for="egg_hunt" name="egg_hunt">
<label class="form-check-label" id="egg_hunt">
Easter Egg Hunt
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="spring_garage_sale" for="spring_garage_sale" name="spring_garage_sale">
<label class="form-check-label" id="spring_garage_sale">
Spring Garage Sale
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="golf_outing" for="golf_outing" name="golf_outing">
<label class="form-check-label" id="golf_outing">
Golf Outing
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="ice_cream_social" for="ice_cream_social" name="ice_cream_social">
<label class="form-check-label" id="ice_cream_social">
Ice Creame Social
</label>
</div>
</div>
<div class="col-md-6">
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="architecturalCommittee">
<label class="form-check-label" for="architecturalCommittee">
Architectural Review Committee
<input class="form-check-input" type="checkbox" id="fall_garage_sale" for="fall_garage_sale" name="fall_garage_sale">
<label class="form-check-label" id="fall_garage_sale">
Fall Garage Sale
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="communicationsCommittee">
<label class="form-check-label" for="communicationsCommittee">
Communications Committee
<input class="form-check-input" type="checkbox" id="halloween_party" for="halloween_party" name="halloween_party">
<label class="form-check-label" id="halloween_party">
Halloween Party
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="welcomingCommittee">
<label class="form-check-label" for="welcomingCommittee">
Welcoming Committee
<input class="form-check-input" type="checkbox" id="santa_visit" for="santa_visit" name="santa_visit">
<label class="form-check-label" id="santa_visit">
Santa Visits
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="civic_affair" for="civic_affair" name="civic_affair">
<label class="form-check-label" id="civic_affair">
Civic Affairs Journalist
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="phone_directory" for="phone_directory" name="phone_directory">
<label class="form-check-label" id="phone_directory">
Annual Phone Director
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="no_preference" for="no_preference" name="no_preference">
<label class="form-check-label" id="no_preference">
No Preference
</label>
</div>
</div>
</div>
<div class="mt-3">
<label for="otherCommitteeInterest" class="form-label">Other interests or skills you'd like to contribute:</label>
<textarea class="form-control" id="otherCommitteeInterest" rows="2"></textarea>
</div>
</fieldset>
<!-- Services Section -->
@@ -253,44 +283,54 @@
<div class="row">
<div class="col-md-6">
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="babysitting">
<input class="form-check-input" type="checkbox" id="babysitting" for="babysitting" name="babysitting">
<label class="form-check-label" for="babysitting">
Babysitting
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="lawnMowing">
<label class="form-check-label" for="lawnMowing">
<input class="form-check-input" type="checkbox" id="lawn_mowing" for="lawn_mowing" name="lawn_mowing">
<label class="form-check-label" for="lawn_mowing">
Lawn Mowing
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="snowShoveling">
<label class="form-check-label" for="snowShoveling">
<input class="form-check-input" type="checkbox" id="snow_shoveling" for="snow_shoveling" name="snow_shoveling">
<label class="form-check-label" for="snow_shoveling">
Snow Shoveling
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="leaf_raking" for="leaf_raking" name="leaf_raking">
<label class="form-check-label" for="leaf_raking">
Lead Raking
</label>
</div>
</div>
<div class="col-md-6">
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="houseSitting">
<label class="form-check-label" for="houseSitting">
<input class="form-check-input" type="checkbox" id="house_sitting" for="house_sitting" name="house_sitting">
<label class="form-check-label" for="house_sitting">
House Sitting
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="petCare">
<label class="form-check-label" for="petCare">
Pet Care
<input class="form-check-input" type="checkbox" id="petsitting" for="petsitting" name="petsitting">
<label class="form-check-label" for="petsitting">
Pet Sitting
</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="otherService">
<label class="form-check-label" for="otherService">
<input class="form-check-input" type="checkbox" id="other" for="other" name="other">
<label class="form-check-label" for="other">
Other (please specify)
</label>
</div>
</div>
<div class="mt-3">
<label for="other_desc" class="form-label">Other interests or skills you'd like to contribute:</label>
<textarea class="form-control" id="other_desc" for="other_desc" name="other_desc" rows="2"></textarea>
</div>
</div>
<div class="mt-3" id="otherServiceSpecify" style="display: none;">
@@ -299,20 +339,10 @@
</div>
</fieldset>
<!-- Terms & Submit -->
<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="agreeTerms" required>
<label class="form-check-label" for="agreeTerms">
I agree to the <a href="#" data-bs-toggle="modal" data-bs-target="#termsModal">Terms and Conditions</a>*
</label>
<div class="invalid-feedback">
You must agree before submitting.
</div>
</div>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
{% if captchaForm %}
{{ captchaForm }}
{% endif %}
<button class="btn btn-outline-secondary me-md-2" type="reset">Reset Form</button>
<button class="btn btn-success" type="submit">Submit Membership</button>
</div>
@@ -324,35 +354,6 @@
</div>
</main>
<!-- Terms Modal -->
<div class="modal fade" id="termsModal" tabindex="-1" aria-labelledby="termsModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="termsModalLabel">Membership Terms and Conditions</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<h6>Greenwood Estates HOA Membership Agreement</h6>
<p>By joining the Greenwood Estates Homeowners Association, you agree to:</p>
<ol>
<li>Abide by the community covenants, conditions, and restrictions (CC&Rs)</li>
<li>Pay annual membership dues in a timely manner</li>
<li>Participate in community standards and guidelines</li>
<li>Receive communications from the HOA board and committees</li>
<li>Have your contact information shared with other members for community purposes</li>
</ol>
<p>Your membership helps maintain our community's quality and property values. The HOA board reserves the right to approve or deny membership applications.</p>
<h6>Privacy Policy</h6>
<p>Your personal information will be used solely for HOA communications and operations. We do not sell or share member information with third parties except as required for community management.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-success" data-bs-dismiss="modal">I Understand</button>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,47 @@
{% extends 'schasite/base2.html' %}
{% load static %}
{% block pagetitle %}
<title>Password Reset | SCHA</title>
{% endblock %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8 col-lg-6">
<div class="card shadow-sm">
<div class="card-header bg-success text-white text-center">
<h2><i class="bi bi-key me-2"></i>Reset Password</h2>
</div>
<div class="card-body p-4">
<form id="resetForm" class="needs-validation" novalidate>
<div class="mb-4 text-center">
<p>Enter your email address and we'll send you a link to reset your password.</p>
</div>
<div class="mb-3">
<label for="resetEmail" class="form-label">Email Address</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-envelope"></i></span>
<input type="email" class="form-control" id="resetEmail" required>
<div class="invalid-feedback">
Please provide a valid email address.
</div>
</div>
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-success">
<i class="bi bi-send me-2"></i>Send Reset Link
</button>
</div>
</form>
</div>
<div class="card-footer text-center">
<a href="login.html" class="text-decoration-none"><i class="bi bi-arrow-left me-1"></i>Back to Login</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,396 @@
{% extends 'schasite/authenticated_base.html' %}
{% load static %}
{% block pagetitle %}
<title>Profile | SCHA</title>
<script type="text/css">
.profile-avatar {
width: 120px;
height: 120px;
margin: 0 auto 1rem;
}
.dues-history table {
font-size: 0.875rem;
}
.dues-history th,
.dues-history td {
padding: 0.5rem;
}
.list-group-item-action:hover {
background-color: rgba(25, 135, 84, 0.05);
}
/* Communication Preferences */
#preferencesForm .form-check {
margin-bottom: 0.5rem;
}
/* Responsive adjustments */
@media (max-width: 991.98px) {
.profile-avatar {
width: 80px;
height: 80px;
}
}
@media (max-width: 767.98px) {
.profile-avatar {
width: 100px;
height: 100px;
}
}
</script>
{% endblock %}
{% block content %}
<main class="py-5">
<div class="container">
<div class="row mb-4">
<div class="col-12">
<h1 class="display-6">My Profile</h1>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="../index.html">Home</a></li>
<li class="breadcrumb-item active" aria-current="page">Profile</li>
</ol>
</nav>
</div>
</div>
<div class="row g-4">
<!-- Left Column -->
<div class="col-lg-4">
<!-- Member Card -->
<div class="card shadow-sm mb-4">
<div class="card-header bg-success text-white">
<h3 class="h5 mb-0"><i class="bi bi-person-badge me-2"></i>Profile</h3>
</div>
<div class="card-body text-center">
<div class="mb-3">
<div class="bg-success bg-opacity-10 rounded-circle d-flex align-items-center justify-content-center mx-auto" style="width: 120px; height: 120px;">
<i class="bi bi-person-fill text-success fs-1"></i>
</div>
</div>
<h4 class="card-title">John Doe</h4>
<p class="text-muted">Member since: January 15, 2020</p>
<hr>
<button class="btn btn-outline-success btn-sm mb-3">
<i class="bi bi-pencil me-1"></i>Edit Profile
</button>
<button class="btn btn-outline-success btn-sm mb-3">
<i class="bi bi-lock me-1"></i>Change Password
</button>
</div>
</div>
<!-- Dues Payment History -->
<div class="card shadow-sm">
<div class="card-header bg-success text-white">
<h3 class="h5 mb-0"><i class="bi bi-credit-card me-2"></i>Dues Payment History</h3>
</div>
<div class="card-body">
<div class="alert alert-success">
<i class="bi bi-check-circle-fill me-2"></i>
<strong>Current Status:</strong> Paid through December 2024
</div>
<div class="table-responsive">
<table class="table table-sm">
<thead>
<tr>
<th>Date</th>
<th>Amount</th>
<th>Method</th>
<th>Receipt</th>
</tr>
</thead>
<tbody>
<tr>
<td>Jan 10, 2024</td>
<td>$600.00</td>
<td>Credit Card</td>
<td><a href="#" class="text-success">View</a></td>
</tr>
<tr>
<td>Jan 5, 2023</td>
<td>$550.00</td>
<td>Bank Transfer</td>
<td><a href="#" class="text-success">View</a></td>
</tr>
<tr>
<td>Jan 8, 2022</td>
<td>$525.00</td>
<td>Check</td>
<td><a href="#" class="text-success">View</a></td>
</tr>
<tr>
<td>Jan 12, 2021</td>
<td>$500.00</td>
<td>Credit Card</td>
<td><a href="#" class="text-success">View</a></td>
</tr>
<tr>
<td>Jan 15, 2020</td>
<td>$500.00</td>
<td>Check</td>
<td><a href="#" class="text-success">View</a></td>
</tr>
</tbody>
</table>
</div>
<div class="text-center mt-2">
<a href="#" class="btn btn-sm btn-success">
<i class="bi bi-printer me-1"></i>Print Full History
</a>
</div>
</div>
</div>
</div>
<!-- Right Column -->
<div class="col-lg-8">
<!-- Member Details -->
<div class="card shadow-sm mb-4">
<div class="card-header bg-success text-white">
<div class="d-flex justify-content-between align-items-center">
<h3 class="h5 mb-0"><i class="bi bi-house-heart me-2"></i>Member Details</h3>
<button class="btn btn-sm btn-light" id="editDetailsBtn">
<i class="bi bi-pencil me-1"></i>Edit
</button>
</div>
</div>
<div class="card-body">
<form id="memberDetailsForm">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">First Name</label>
<input type="text" class="form-control" value="John" disabled>
</div>
<div class="col-md-6">
<label class="form-label">Last Name</label>
<input type="text" class="form-control" value="Doe" disabled>
</div>
<div class="col-md-6">
<label class="form-label">Email</label>
<input type="email" class="form-control" value="john.doe@example.com" disabled>
</div>
<div class="col-md-6">
<label class="form-label">Phone</label>
<input type="tel" class="form-control" value="(555) 123-4567" disabled>
</div>
<div class="col-12">
<label class="form-label">Street Address</label>
<input type="text" class="form-control" value="123 Oak Drive" disabled>
</div>
<div class="col-md-4">
<label class="form-label">City</label>
<input type="text" class="form-control" value="Anytown" disabled>
</div>
<div class="col-md-4">
<label class="form-label">State</label>
<input type="text" class="form-control" value="ST" disabled>
</div>
<div class="col-md-4">
<label class="form-label">ZIP Code</label>
<input type="text" class="form-control" value="12345" disabled>
</div>
<div class="col-12 mt-3" id="saveDetailsBtn" style="display: none;">
<button type="submit" class="btn btn-success me-2">Save Changes</button>
<button type="button" class="btn btn-outline-secondary" id="cancelEditBtn">Cancel</button>
</div>
</div>
</form>
</div>
</div>
<!-- My Posts -->
<div class="card shadow-sm mb-4">
<div class="card-header bg-success text-white">
<h3 class="h5 mb-0"><i class="bi bi-pencil-square me-2"></i>My Posts</h3>
</div>
<div class="card-body">
<div class="list-group list-group-flush">
<a href="../posts/detail.html" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h6 class="mb-1">Looking for lawn service recommendations</h6>
<small class="text-muted">May 28, 2024</small>
</div>
<p class="mb-1 small">Does anyone have a landscaper they would recommend for weekly mowing?</p>
<small><span class="badge bg-success bg-opacity-10 text-success">Discussion</span> • 5 comments</small>
</a>
<a href="../posts/detail.html" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h6 class="mb-1">Lost cat - gray tabby</h6>
<small class="text-muted">April 15, 2024</small>
</div>
<p class="mb-1 small">Our cat Mittens got out last night near Oak Drive. Please contact if seen!</p>
<small><span class="badge bg-success bg-opacity-10 text-success">Help Needed</span> • 12 comments</small>
</a>
<a href="../posts/detail.html" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h6 class="mb-1">Garage sale this weekend</h6>
<small class="text-muted">March 30, 2024</small>
</div>
<p class="mb-1 small">We're having a garage sale Saturday 8am-2pm with furniture, tools, and more.</p>
<small><span class="badge bg-success bg-opacity-10 text-success">For Sale</span> • 3 comments</small>
</a>
</div>
<div class="text-center mt-3">
<a href="../posts/" class="btn btn-sm btn-outline-success">View All My Posts</a>
</div>
</div>
</div>
<!-- My Comments -->
<div class="card shadow-sm mb-4">
<div class="card-header bg-success text-white">
<h3 class="h5 mb-0"><i class="bi bi-chat-left-text me-2"></i>Posts I've Commented On</h3>
</div>
<div class="card-body">
<div class="list-group list-group-flush">
<a href="../posts/detail.html" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h6 class="mb-1">Annual Community Picnic</h6>
<small class="text-muted">June 5, 2024</small>
</div>
<p class="mb-1 small"><strong>My comment:</strong> "Looking forward to it! I'll bring potato salad."</p>
<small><span class="badge bg-success bg-opacity-10 text-success">Announcement</span> • 24 comments total</small>
</a>
<a href="../posts/detail.html" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h6 class="mb-1">Pool opening delayed</h6>
<small class="text-muted">May 20, 2024</small>
</div>
<p class="mb-1 small"><strong>My comment:</strong> "Thanks for the update. Any estimate on opening date?"</p>
<small><span class="badge bg-success bg-opacity-10 text-success">Announcement</span> • 8 comments total</small>
</a>
<a href="../posts/detail.html" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h6 class="mb-1">Neighborhood watch meeting</h6>
<small class="text-muted">April 10, 2024</small>
</div>
<p class="mb-1 small"><strong>My comment:</strong> "I can help organize the next meeting."</p>
<small><span class="badge bg-success bg-opacity-10 text-success">Event</span> • 15 comments total</small>
</a>
</div>
<div class="text-center mt-3">
<a href="../posts/" class="btn btn-sm btn-outline-success">View All My Comments</a>
</div>
</div>
</div>
<!-- Communication Preferences -->
<div class="card shadow-sm">
<div class="card-header bg-success text-white">
<h3 class="h5 mb-0"><i class="bi bi-envelope me-2"></i>Communication Preferences</h3>
</div>
<div class="card-body">
<form id="preferencesForm">
<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="emailNotifications" checked>
<label class="form-check-label" for="emailNotifications">
Receive email notifications
</label>
</div>
</div>
<div class="mb-3">
<h6 class="mb-2">Notification Types:</h6>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="postReplies" checked>
<label class="form-check-label" for="postReplies">
When someone replies to my posts
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="commentReplies" checked>
<label class="form-check-label" for="commentReplies">
When someone replies to my comments
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="communityAnnouncements" checked>
<label class="form-check-label" for="communityAnnouncements">
Community announcements
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="eventReminders">
<label class="form-check-label" for="eventReminders">
Event reminders
</label>
</div>
</div>
<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="showInDirectory" checked>
<label class="form-check-label" for="showInDirectory">
Include my contact information in the member directory
</label>
</div>
<div class="form-text">
Uncheck to hide your email and phone number from other members
</div>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-success">Save Preferences</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</main>
{% endblock %}
{% block extra_js %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Edit details toggle
const editBtn = document.getElementById('editDetailsBtn');
const cancelBtn = document.getElementById('cancelEditBtn');
const saveBtn = document.getElementById('saveDetailsBtn');
const formInputs = document.querySelectorAll('#memberDetailsForm input');
editBtn.addEventListener('click', function() {
formInputs.forEach(input => {
input.disabled = false;
});
saveBtn.style.display = 'block';
editBtn.style.display = 'none';
});
cancelBtn.addEventListener('click', function() {
formInputs.forEach(input => {
input.disabled = true;
});
saveBtn.style.display = 'none';
editBtn.style.display = 'block';
});
// Form submissions
document.getElementById('memberDetailsForm').addEventListener('submit', function(e) {
e.preventDefault();
// In a real implementation, this would save the changes
alert('Profile details updated successfully (simulated)');
formInputs.forEach(input => {
input.disabled = true;
});
saveBtn.style.display = 'none';
editBtn.style.display = 'block';
});
document.getElementById('preferencesForm').addEventListener('submit', function(e) {
e.preventDefault();
// In a real implementation, this would save preferences
alert('Communication preferences saved (simulated)');
});
});
</script>
{% endblock %}

View File

@@ -45,7 +45,6 @@
<div class="card-body text-center">
<h3 class="text-success mb-3">2025-2026 Stonehedge Community Homeowners Association Board</h3>
<p>The Stonehedge Community Homeowners Association is governed by a volunteer board of directors elected by the community members. Board members serve two-year terms and are responsible for overseeing the community's operations, finances, and enforcement of covenants.</p>
<p>Board meetings are held monthly and are open to all residents. <a href="../index.html#documents">View meeting schedule</a>.</p>
</div>
</div>
</div>
@@ -63,7 +62,7 @@
<h4 class="mb-0">{{ officer.position }}</h4>
</div>
<div class="card-body text-center">
<img src="../images/board/john-smith.jpg" alt="John Smith" class="rounded-circle mb-3" width="150" height="150">
<!--<img src="../images/board/john-smith.jpg" alt="John Smith" class="rounded-circle mb-3" width="150" height="150">-->
<h5 class="card-title">{{ officer.name }}</h5>
<!-- <p class="text-muted">Term: 2022-2024</p>
<p class="card-text">John has lived in Greenwood Estates since 2015 and brings 20 years of financial management experience to the board.</p> -->
@@ -85,7 +84,7 @@
<h4 class="mb-0">TBD</h4>
</div>
<div class="card-body text-center">
<img src="../images/board/john-smith.jpg" alt="John Smith" class="rounded-circle mb-3" width="150" height="150">
<!--<img src="../images/board/john-smith.jpg" alt="John Smith" class="rounded-circle mb-3" width="150" height="150">-->
<h5 class="card-title">TBD</h5>
<p class="text-muted">TBD</p>
<p class="card-text">TBD</p>
@@ -97,53 +96,7 @@
{% endfor %}
<!-- Committees Section -->
<div class="row mt-5">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header bg-success text-white">
<h3 class="mb-0">HOA Committees</h3>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-4 mb-4">
<div class="card h-100">
<div class="card-body">
<h5 class="card-title text-success">Architectural Review</h5>
<p class="card-text">Reviews all exterior modification requests to ensure compliance with community standards.</p>
<p><strong>Chair:</strong> Robert Wilson</p>
<a href="mailto:architecture@greenwoodestates.org" class="btn btn-sm btn-outline-success">Contact Committee</a>
</div>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card h-100">
<div class="card-body">
<h5 class="card-title text-success">Social & Events</h5>
<p class="card-text">Plans community events, holiday celebrations, and social gatherings.</p>
<p><strong>Chair:</strong> Lisa Martinez</p>
<a href="mailto:events@greenwoodestates.org" class="btn btn-sm btn-outline-success">Contact Committee</a>
</div>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card h-100">
<div class="card-body">
<h5 class="card-title text-success">Landscape & Maintenance</h5>
<p class="card-text">Oversees common area maintenance and landscaping improvements.</p>
<p><strong>Chair:</strong> David Thompson</p>
<a href="mailto:landscape@greenwoodestates.org" class="btn btn-sm btn-outline-success">Contact Committee</a>
</div>
</div>
</div>
</div>
<div class="text-center mt-3">
<a href="#" class="btn btn-success">Learn About Committee Opportunities</a>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
{% endblock %}
{% endblock %}

View File

@@ -0,0 +1,127 @@
{% extends 'schasite/base2.html' %}
{% load static %}
{% block pagetitle %}
<title>Set Password | SCHA</title>
{% endblock %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8 col-lg-6">
<div class="card shadow-sm">
<div class="card-header bg-success text-white text-center">
<h2><i class="bi bi-key me-2"></i>Set New Password</h2>
</div>
<div class="card-body p-4">
<form id="passwordForm" class="needs-validation" novalidate>
<div class="mb-3">
<label for="newPassword" class="form-label">New Password</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-lock"></i></span>
<input type="password" class="form-control" id="newPassword" required
pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}">
<button class="btn btn-outline-secondary" type="button" id="toggleNewPassword">
<i class="bi bi-eye"></i>
</button>
<div class="invalid-feedback">
Password must contain at least 8 characters with uppercase, lowercase, and a number.
</div>
</div>
<div class="form-text">
<small>Must be at least 8 characters with uppercase, lowercase, and a number.</small>
</div>
</div>
<div class="mb-4">
<label for="confirmPassword" class="form-label">Confirm Password</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-lock"></i></span>
<input type="password" class="form-control" id="confirmPassword" required>
<button class="btn btn-outline-secondary" type="button" id="toggleConfirmPassword">
<i class="bi bi-eye"></i>
</button>
<div class="invalid-feedback">
Passwords must match.
</div>
</div>
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-success">
<i class="bi bi-check-circle me-2"></i>Set Password
</button>
</div>
</form>
</div>
<div class="card-footer text-center">
<a href="login.html" class="text-decoration-none"><i class="bi bi-arrow-left me-1"></i>Back to Login</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Toggle password visibility
const toggleNewPassword = document.getElementById('toggleNewPassword');
const newPasswordInput = document.getElementById('newPassword');
const toggleConfirmPassword = document.getElementById('toggleConfirmPassword');
const confirmPasswordInput = document.getElementById('confirmPassword');
toggleNewPassword.addEventListener('click', function() {
const type = newPasswordInput.getAttribute('type') === 'password' ? 'text' : 'password';
newPasswordInput.setAttribute('type', type);
this.innerHTML = type === 'password' ? '<i class="bi bi-eye"></i>' : '<i class="bi bi-eye-slash"></i>';
});
toggleConfirmPassword.addEventListener('click', function() {
const type = confirmPasswordInput.getAttribute('type') === 'password' ? 'text' : 'password';
confirmPasswordInput.setAttribute('type', type);
this.innerHTML = type === 'password' ? '<i class="bi bi-eye"></i>' : '<i class="bi bi-eye-slash"></i>';
});
// Form validation
const form = document.getElementById('passwordForm');
form.addEventListener('submit', function(event) {
event.preventDefault();
event.stopPropagation();
// Check if passwords match
if (newPasswordInput.value !== confirmPasswordInput.value) {
confirmPasswordInput.setCustomValidity("Passwords must match");
} else {
confirmPasswordInput.setCustomValidity("");
}
if (form.checkValidity()) {
// In a real implementation, this would update the password
alert('Password successfully updated (simulated)');
window.location.href = "login.html";
}
form.classList.add('was-validated');
}, false);
// Live password validation
newPasswordInput.addEventListener('input', function() {
if (this.value !== confirmPasswordInput.value) {
confirmPasswordInput.setCustomValidity("Passwords must match");
} else {
confirmPasswordInput.setCustomValidity("");
}
});
confirmPasswordInput.addEventListener('input', function() {
if (this.value !== newPasswordInput.value) {
this.setCustomValidity("Passwords must match");
} else {
this.setCustomValidity("");
}
});
});
</script>
{% endblock %}

View File

@@ -0,0 +1,66 @@
{% extends 'schasite/base2.html' %}
{% load static %}
{% block pagetitle %}
<title>Login | SCHA</title>
{% endblock %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8 col-lg-6">
<div class="card shadow-sm">
<div class="card-header bg-success text-white text-center">
<h2><i class="bi bi-shield-lock me-2"></i>Member Login</h2>
</div>
<div class="card-body p-4">
<form id="loginForm" class="needs-validation" novalidate>
<div class="mb-3">
<label for="loginEmail" class="form-label">Email Address</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-envelope"></i></span>
<input type="email" class="form-control" id="loginEmail" required>
<div class="invalid-feedback">
Please provide a valid email address.
</div>
</div>
</div>
<div class="mb-3">
<label for="loginPassword" class="form-label">Password</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-key"></i></span>
<input type="password" class="form-control" id="loginPassword" required>
<button class="btn btn-outline-secondary" type="button" id="togglePassword">
<i class="bi bi-eye"></i>
</button>
<div class="invalid-feedback">
Please enter your password.
</div>
</div>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="rememberMe">
<label class="form-check-label" for="rememberMe">Remember me</label>
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-success">
<i class="bi bi-box-arrow-in-right me-2"></i>Sign In
</button>
</div>
<div class="mt-3 text-center">
<a href="{% url 'password_reset' %}" class="text-decoration-none">Forgot password?</a>
</div>
</form>
</div>
<div class="card-footer text-center text-muted">
Not a member? <a href="{% url 'signup' %}" class="text-success">Join our community</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,104 @@
{% extends 'schasite/base2.html' %}
{% load static %}
{% block pagetitle %}
<title>Login | SCHA</title>
{% endblock %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8 col-lg-6">
<div class="card shadow-sm">
<div class="card-header bg-success text-white text-center">
<h2><i class="bi bi-shield-lock me-2"></i>Member Signup</h2>
</div>
<div class="card-body p-4">
<form id="loginForm" class="needs-validation" novalidate>
<div class="card-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">First Name</label>
<input type="text" class="form-control" value="John">
</div>
<div class="col-md-6">
<label class="form-label">Last Name</label>
<input type="text" class="form-control" value="Doe">
</div>
<div class="col-md-6">
<label class="form-label">Email</label>
<input type="email" class="form-control" value="john.doe@example.com">
</div>
<div class="col-md-6">
<label class="form-label">Phone</label>
<input type="tel" class="form-control" value="(555) 123-4567">
</div>
<div class="col-12">
<label class="form-label">Street Address</label>
<input type="text" class="form-control" value="123 Oak Drive">
</div>
<div class="col-md-4">
<label class="form-label">City</label>
<input type="text" class="form-control" value="Anytown">
</div>
<div class="col-md-4">
<label class="form-label">State</label>
<input type="text" class="form-control" value="ST">
</div>
<div class="col-md-4">
<label class="form-label">ZIP Code</label>
<input type="text" class="form-control" value="12345" >
</div>
<div class="col-md-12">
<label for="loginPassword" class="form-label">Password</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-key"></i></span>
<input type="password" class="form-control" id="loginPassword" required>
<button class="btn btn-outline-secondary" type="button" id="togglePassword">
<i class="bi bi-eye"></i>
</button>
<div class="invalid-feedback">
Please enter your password.
</div>
</div>
</div>
<div class="col-md-12">
<label for="loginPassword" class="form-label">Confirm Password</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-key"></i></span>
<input type="password" class="form-control" id="loginPassword" required>
<button class="btn btn-outline-secondary" type="button" id="togglePassword">
<i class="bi bi-eye"></i>
</button>
<div class="invalid-feedback">
Please confirm your password. </div>
</div>
</div>
</div>
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-success">
<i class="bi bi-box-arrow-in-right me-2"></i>Sign Up
</button>
</div>
<div class="mt-3 text-center">
<a href="{% url 'login' %}" class="text-decoration-none">Back to Log In</a>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -51,7 +51,7 @@
<div class="col-lg-10">
<div class="card shadow-sm">
<div class="card-header bg-success text-white">
<h3 class="mb-0"><i class="bi bi-exclamation-triangle me-2"></i>Useful Links</h3>
<h3 class="mb-0">Useful Links</h3>
</div>
<div class="card-body">
<div class="table-responsive">

View File

@@ -1,26 +1,50 @@
from django.urls import path
from django.conf import settings
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("useful_links", views.useful_links, name="useful_links"),
path("about_us", views.about_us, name="about_us"),
path("calendar", views.calendar, name="calendar"),
path("newsletters", views.newsletters, name="newsletters"),
path("dues", views.dues, name="dues"),
path("membership_form", views.membership_form, name="membership_form"),
path("scha_board", views.scha_board, name="scha_board"),
if settings.DEBUG:
authenticated_views = [
path('login/',views.login, name="login"),
path('set_password/',views.set_password, name="set_password"),
path('password_reset/',views.password_reset, name="password_reset"),
path('signup/',views.signup, name="signup"),
path('directory/',views.member_directory, name="directory"),
path('dashboard/',views.member_dashboard, name="dashboard"),
path('posts/',views.member_posts, name="posts"),
path('posts_create/',views.member_posts_create, name="posts_create"),
path('posts/<int:post_id>',views.member_posts_detail, name="posts_detail"),
path('profile/',views.profile, name="profile"),
]
else:
authenticated_views = []
urlpatterns = authenticated_views + [
# path("", views.index, name="index"),
# path("useful_links", views.useful_links, name="useful_links"),
# path("about_us", views.about_us, name="about_us"),
# path("calendar", views.calendar, name="calendar"),
# path("newsletters", views.newsletters, name="newsletters"),
# path("dues", views.dues, name="dues"),
# path("membership_form", views.membership_form, name="membership_form"),
# path("scha_board", views.scha_board, name="scha_board"),
# updated UI urls
path("index2", views.index2, name="index2"),
path("about_us2", views.about_us2, name="about_us2"),
path("calendar2", views.calendar2, name="calendar2"),
path("newsletters2", views.newsletters2, name="newsletters2"),
path("dues2", views.dues2, name="dues2"),
path("membership_form2", views.membership_form2, name="membership_form2"),
path("scha_board2", views.scha_board2, name="scha_board2"),
path("useful_links2", views.useful_links2, name="useful_links2"),
path("", views.index2, name="index2"),
path("about_us", views.about_us2, name="about_us2"),
path("calendar", views.calendar2, name="calendar2"),
path("newsletters", views.newsletters2, name="newsletters2"),
path("dues", views.dues2, name="dues2"),
path("membership_form", views.membership_form2, name="membership_form2"),
path("scha_board", views.scha_board2, name="scha_board2"),
path("useful_links", views.useful_links2, name="useful_links2"),
# stripe specific urls below
path("config/", views.stripe_config),
path("create-checkout-session/", views.create_checkout_session),
# authenticated views
]

View File

@@ -1,20 +1,29 @@
from django.shortcuts import render, redirect
from .models import UsefulLinks, CalendarEvent, MembershipPerson, Payments, SCHAOfficer
from .models import UsefulLinks, CalendarEvent, MembershipPerson, Payments, SCHAOfficer, Membership, CommunityPost
from .forms import (
ChildrenForm,
CommunityPostForm,
AddressForm,
PeopleForm,
CommitteeForm,
ServicesForm,
) # , CaptchaForm
CaptchaForm
)
from django.db import transaction, IntegrityError
# Stripe required imports
from django.conf import settings # new
from django.http.response import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt # new
from django.contrib.auth import logout, authenticate, login
from django.contrib.auth.decorators import login_required
import stripe
import logging
logger = logging.getLogger(__name__)
print(__name__)
"""
Strip Stuff
Tutorial: https://testdriven.io/blog/django-stripe-tutorial/
@@ -34,28 +43,27 @@ def stripe_config(request):
@csrf_exempt
def create_checkout_session(request):
if request.method == "GET":
domain_url = "http://localhost:8000/"
if request.method == 'GET':
domain_url ="https://www.schawheaton.com/"
stripe.api_key = settings.STRIPE_SECRET_KEY
try:
checkout_session = stripe.checkout.Session.create(
success_url=domain_url + "success?session_id={CHECKOUT_SESSION_ID}",
cancel_url=domain_url + "cancelled/",
payment_method_types=["card"],
success_url = domain_url+'success?session_id={CHECKOUT_SESSION_ID}',
cancel_url = domain_url+'cancelled/',
payment_method_types=['card'],
mode="payment",
line_items=[
{
# 'name':'SCHA Dues',
"quantity": 1,
# 'currency': 'usd',
"price": "price_1OxZLfDV0RPXOyxG5ipjhUXk",
}
],
line_items = [{
# 'name':'SCHA Dues',
'quantity': 1,
# 'currency': 'usd',
'price':'price_1P5KBtIbGKYTLTtMJ0Rh1jMu',
#'price_1P5K7uIbGKYTLTtMFNxbkA8X'
#'price_1OxZLfDV0RPXOyxG5ipjhUXk',
}]
)
return JsonResponse({"sessionId": checkout_session["id"]})
return JsonResponse({'sessionId': checkout_session['id']})
except Exception as e:
return JsonResponse({"error": str(e)})
return JsonResponse({'error': str(e)})
def stripe_success(request):
return render(request, "schasite/dues_success.html", {})
@@ -70,11 +78,13 @@ def stripe_webhook(request):
stripe.api_key = settings.STRIPE_SECRET_KEY
endpoint_secret = settings.STRIPE_ENDPOINT_SECRET
payload = request.body
sig_header = request.META["HTTP_STRIPE_SIGNATURE"]
sig_header = request.META['HTTP_STRIPE_SIGNATURE']
event = None
try:
event = stripe.Webhook.construct_event(payload, sig_header, endpoint_secret)
event = stripe.Webhook.construct_event(
payload, sig_header, endpoint_secret
)
except ValueError as e:
# Invalid payload
return HttpResponse(status=400)
@@ -83,17 +93,18 @@ def stripe_webhook(request):
return HttpResponse(status=400)
# Handle the checkout.session.completed event
if event["type"] == "checkout.session.completed":
if event['type'] == 'checkout.session.completed':
email = None
try:
email = event["data"]["object"]["customer_details"]["email"]
email = event['data']['object']['customer_details']['email']
except:
pass
person = MembershipPerson.objects.filter(
email=email
).first() # just take the first
person = MembershipPerson.objects.filter(email=email).first() # just take the first
payment = Payments.objects.create(email=email, person=person)
payment = Payments.objects.create(
email=email,
person = person
)
# try to link to a member
payment.save()
# TODO: run some custom code here
@@ -141,24 +152,23 @@ def calendar2(request):
def scha_board2(request):
def get_officer(position_name):
def get_officers(position_name) -> list[SCHAOfficer]:
try:
return SCHAOfficer.objects.get(position=position_name)
return SCHAOfficer.objects.filter(position=position_name)
except:
return None
officers = [
get_officer("President"),
get_officer("1st Vice President"),
get_officer("2nd Vice President"),
get_officer("Treasurer"),
get_officer("Secretary"),
get_officer("Website"),
get_officer("Membership"),
get_officer("Directory"),
get_officer("Facebook"),
get_officer("Eblasts"),
]
officers = []
for position in ["President","1st Vice President",
"2nd Vice President",
"Treasurer",
"Secretary",
"Website",
"Membership",
"Directory",
"Facebook",
"Eblasts"]:
officers += get_officers(position)
return render(request, "schasite/scha_board2.html", {"officers": officers})
@@ -178,77 +188,130 @@ def membership_form2(request):
if request.method == "POST":
# before we pass in the data we want to sanitize the phone numbers
post_data = request.POST.copy()
post_data.update(
{
"person1-phone_number": sanitize_phone_number(
post_data["person1-phone_number"]
)
}
)
post_data.update(
{
"person2-phone_number": sanitize_phone_number(
post_data["person2-phone_number"]
)
}
)
membershipForm = ChildrenForm(post_data)
addressForm = AddressForm(post_data)
peopleForm1 = PeopleForm(post_data, prefix="person1")
peopleForm2 = PeopleForm(post_data, prefix="person2")
servicesForm = ServicesForm(post_data)
committeeForm = CommitteeForm(post_data)
# captchaForm = CaptchaForm(post_data)
address_data = {
"address_1": request.POST.get("streetAddress", ""),
"address_2": request.POST.get("unit", ""),
"city": request.POST.get("city", "60189"),
"state": request.POST.get("state", "IL"),
"zip_code": request.POST.get("zipCode", "60189"),
}
logging.debug(address_data)
addressForm = AddressForm(address_data)
logging.debug(f"is addressForm valid: {addressForm.is_valid()}")
if not addressForm.is_valid():
logging.error(f"addressForm Errors: {addressForm.errors}")
services_data = {
"babysitting": True if request.POST.get("babysitting", "") == "on" else False,
"lawn_mowing": True if request.POST.get("lawn_mowing", "") == "on" else False,
"snow_shoveling": True if request.POST.get("snow_shoveling", "") == "on" else False,
"leaf_raking": True if request.POST.get("leaf_raking", "") == "on" else False,
"petsitting": True if request.POST.get("petsitting", "") == "on" else False,
"house_sitting": True if request.POST.get("house_sitting", "") == "on" else False,
"other": True if request.POST.get("other", "") == "on" else False,
"other_desc": True if request.POST.get("other_desc", "") == "on" else False,
}
committee_data = {
"block_captain": True if request.POST.get("block_captain", "") == "on" else False,
"coordinator": True if request.POST.get("coordinator", "") == "on" else False,
"egg_hunt": True if request.POST.get("egg_hunt", "") == "on" else False,
"spring_garage_sale": True if request.POST.get("spring_garage_sale", "") == "on" else False,
"golf_outing": True if request.POST.get("golf_outing", "") == "on" else False,
"ice_cream_social": True if request.POST.get("ice_cream_social", "") == "on" else False,
"fall_garage_sale": True if request.POST.get("fall_garage_sale", "") == "on" else False,
"halloween_party": True if request.POST.get("halloween_party", "") == "on" else False,
"santa_visit": True if request.POST.get("santa_visit", "") == "on" else False,
"website": True if request.POST.get("website", "") == "on" else False,
"civic_affair": True if request.POST.get("civic_affair", "") == "on" else False,
"phone_directory": True if request.POST.get("phone_directory", "") == "on" else False,
"no_preference": True if request.POST.get("no_preference", "") == "on" else False,
}
servicesForm = ServicesForm(services_data)
committeeForm = CommitteeForm(committee_data)
person1_data = {
"first_name": request.POST.get("firstName1"),
"last_name": request.POST.get("lastName1"),
"email": request.POST.get("email1"),
"phone_number": sanitize_phone_number(request.POST.get("phone1")),
}
person2_data = {
"frist_name": request.POST.get("firstName2"),
"last_name": request.POST.get("lastName2"),
"email": request.POST.get("email2"),
"phone_number": sanitize_phone_number(request.POST.get("phone2")),
}
peopleForm1 = PeopleForm(person1_data)
peopleForm2 = PeopleForm(person2_data)
logging.debug("Validating the captcha form")
logging.debug(request.POST.get("captcha",""))
captchaForm = CaptchaForm({
"captcha": request.POST.get("captcha","")
})
logging.debug(f"Captch form is: {captchaForm.is_valid()}")
logging.debug(f"peopleForm1 form is: {peopleForm1.is_valid()}")
logging.debug(f"peopleForm2 form is: {peopleForm2.is_valid()}")
logging.debug(f"servicesForm form is: {servicesForm.is_valid()}")
if (
membershipForm.is_valid()
and addressForm.is_valid()
addressForm.is_valid()
and committeeForm.is_valid()
and (peopleForm1.is_valid() or peopleForm2.is_valid())
and servicesForm.is_valid()
): # and captchaForm.is_valid():
and captchaForm.is_valid()
):
with transaction.atomic():
membershipForm = ChildrenForm({**post_data})
membership = membershipForm.save(commit=False)
membership.save()
logging.debug("starting to save")
try:
membership = Membership.objects.create()
if peopleForm1.is_valid():
people1_obj = peopleForm1.save(commit=False)
people1_obj.membership = membership
people1_obj.save()
if peopleForm1.is_valid():
people1_obj = peopleForm1.save(commit=False)
people1_obj.membership = membership
people1_obj.save()
if peopleForm2.is_valid():
people2_obj = peopleForm2.save(commit=False)
people2_obj.membership = membership
people2_obj.save()
if peopleForm2.is_valid():
people2_obj = peopleForm2.save(commit=False)
people2_obj.membership = membership
people2_obj.save()
committee_obj = committeeForm.save(commit=False)
committee_obj.membership = membership
committee_obj.save()
committee_obj = committeeForm.save(commit=False)
committee_obj.membership = membership
committee_obj.save()
services_obj = servicesForm.save(commit=False)
services_obj.membership = membership
services_obj.save()
services_obj = servicesForm.save(commit=False)
services_obj.membership = membership
services_obj.save()
address_obj = addressForm.save(commit=False)
address_obj.membership = membership
address_obj.save()
address_obj = addressForm.save(commit=False)
address_obj.membership = membership
address_obj.save()
except Exception as e:
logging.error(e)
return redirect("index")
return redirect("index2")
else:
logging.warning("Some field is not valid")
return render(
request,
"schasite/membership_form2.html",
{
"membershipForm": ChildrenForm,
"peopleForm1": peopleForm1,
"peopleForm2": peopleForm2,
"addressForm": addressForm,
"committeeForm": committeeForm,
"servicesForm": servicesForm,
# 'captchaForm': captchaForm,
'captchaForm': captchaForm,
},
)
else:
@@ -256,12 +319,11 @@ def membership_form2(request):
request,
"schasite/membership_form2.html",
{
"membershipForm": ChildrenForm(),
"peopleForm1": PeopleForm(prefix="person1"),
"peopleForm2": PeopleForm(prefix="person2"),
"committeeForm": CommitteeForm(),
"servicesForm": ServicesForm(),
# 'captchaForm': CaptchaForm(),
'captchaForm': CaptchaForm(),
"addressForm": AddressForm(
initial={
"city": "Wheaton",
@@ -415,3 +477,102 @@ def membership_form(request):
def scha_board(request):
return render(request, "schasite/scha_board.html", {})
def login(request):
if request.method == "POST":
username = request.POST["username"]
password = request.POST["password"]
user = authenticate(request, username=username, password=password)
if user is not None:
return redirect('dashboard')
else:
return render(request, "schasite/signin.html",{'error_msg': "Invalid username/password"})
else:
return render(request, "schasite/signin.html",{})
def logout(request):
if request.method == "POST":
logout(request)
return redirect('index2')
def password_reset(request):
if request.method == "POST":
raise NotImplementedError()
else:
return render(request, "schasite/password_reset.html",{})
def set_password(request):
if request.method == "POST":
raise NotImplementedError()
return redirect('login')
else:
return render(request, "schasite/set_password.html",{})
def signup(request):
if request.method == "POST":
raise NotImplementedError()
return redirect('login')
else:
return render(request, "schasite/signup.html",{})
@login_required(login_url="/login")
def member_directory(request):
if request.method == "POST":
# these should be filters
raise NotImplementedError()
else:
members = MembershipPerson.objects.all()
return render(request, "schasite/member_directory.html",{'members':members})
@login_required(login_url="/login")
def member_dashboard(request):
current_member = CommunityMember.objects.get(user=request.user)
if request.method == "POST":
raise NotImplementedError()
else:
recent_posts = CommunityPost.objects.all()[:5]
member_recent_posts = CommunityPost.objects.filter(author=current_member)[:5]
return render(request, "schasite/member_dashboard.html",{"recent_posts":recent_posts, "member_recent_posts": member_recent_posts, "current_member": current_member})
@login_required(login_url="/login")
def member_posts(request):
current_member = CommunityMember.objects.get(user=request.user)
if request.method == "POST":
raise NotImplementedError()
else:
posts = CommunityPost.objects.all()[:5]
return render(request, "schasite/member_posts.html",{"posts":posts})
@login_required(login_url="/login")
def member_posts_create(request):
current_member = CommunityMember.objects.get(user=request.user)
if request.method == "POST":
community_post_form = CommunityPostForm(request.POST)
if community_post_form.is_valid():
community_post_form.save()
return render(request, "schasite/member_posts.html",{})
else:
print(f'Error creating the post: {community_post_form.errors}')
return render(request, "schasite/member_posts_create.html",{"community_post": community_post_form})
else:
return render(request, "schasite/member_posts_create.html",{"community_post": CommunityPostForm()})
@login_required(login_url="/login")
def member_posts_detail(request, post_id):
current_member = CommunityMember.objects.get(user=request.user)
if request.method == "POST":
raise NotImplementedError()
else:
return render(request, "schasite/member_posts_detail.html",{})
#@login_required(login_url="/login")
def profile(request):
#current_member = CommunityMember.objects.get(user=request.user)
if request.method == "POST":
raise NotImplementedError()
else:
return render(request, "schasite/profile.html",{})