Compare commits
11 Commits
b9aee578c3
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| b97d5ac792 | |||
| fc64549c00 | |||
| b9964b22a9 | |||
| 5bd7a37e52 | |||
| 627bff8074 | |||
| 992750dc55 | |||
| 0e1ddbcf1a | |||
| 4c0605474c | |||
| 77ccc5c2fe | |||
| 636cf3d45d | |||
| b1e372ff9d |
@@ -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",
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -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)
|
||||
@@ -4,7 +4,6 @@
|
||||
}
|
||||
|
||||
body {
|
||||
padding-top: 56px;
|
||||
}
|
||||
|
||||
section {
|
||||
|
||||
BIN
schasite/static/images/District_200.png
Normal file
|
After Width: | Height: | Size: 474 KiB |
BIN
schasite/static/images/brighton.jpg
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
schasite/static/images/danada.jpeg
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
schasite/static/images/downtown_naperville.jpeg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
schasite/static/images/downtown_wheaton.jpeg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
schasite/static/images/seven_gables.jpg
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
schasite/static/images/wheaton_farmers_market.jpeg
Normal file
|
After Width: | Height: | Size: 14 KiB |
@@ -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">
|
||||
@@ -261,7 +261,7 @@
|
||||
<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>Basketball Court</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>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>
|
||||
|
||||
174
schasite/templates/schasite/authenticated_base.html
Normal 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">© 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>
|
||||
@@ -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">© Stonehedge Community Homeowners Association 2010-<script>document.write( new Date().getFullYear() );</script>. All rights reserved
|
||||
<div id="footer">
|
||||
<p>© 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>
|
||||
|
||||
@@ -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 %}
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'schasite/base.html' %}
|
||||
{% extends 'schasite/base2.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block pagetitle %}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends 'schasite/base.html' %}
|
||||
{% extends 'schasite/base2.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block pagetitle %}
|
||||
|
||||
@@ -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>
|
||||
<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 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>
|
||||
|
||||
123
schasite/templates/schasite/member_dashboard.html
Normal 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 %}
|
||||
229
schasite/templates/schasite/member_directory.html
Normal 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 %}
|
||||
166
schasite/templates/schasite/member_posts.html
Normal 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 %}
|
||||
124
schasite/templates/schasite/member_posts_create.html
Normal 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 %}
|
||||
328
schasite/templates/schasite/member_posts_detail.html
Normal 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 %}
|
||||
@@ -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 %}
|
||||
|
||||
|
||||
|
||||
47
schasite/templates/schasite/password_reset.html
Normal 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 %}
|
||||
396
schasite/templates/schasite/profile.html
Normal 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 %}
|
||||
@@ -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 %}
|
||||
127
schasite/templates/schasite/set_password.html
Normal 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 %}
|
||||
66
schasite/templates/schasite/signin.html
Normal 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 %}
|
||||
104
schasite/templates/schasite/signup.html
Normal 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 %}
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
]
|
||||
|
||||
|
||||
@@ -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=[
|
||||
{
|
||||
line_items = [{
|
||||
# 'name':'SCHA Dues',
|
||||
"quantity": 1,
|
||||
'quantity': 1,
|
||||
# 'currency': 'usd',
|
||||
"price": "price_1OxZLfDV0RPXOyxG5ipjhUXk",
|
||||
}
|
||||
],
|
||||
'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,40 +188,91 @@ 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"]
|
||||
)
|
||||
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"),
|
||||
}
|
||||
)
|
||||
post_data.update(
|
||||
{
|
||||
"person2-phone_number": sanitize_phone_number(
|
||||
post_data["person2-phone_number"]
|
||||
)
|
||||
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,
|
||||
|
||||
}
|
||||
)
|
||||
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)
|
||||
|
||||
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)
|
||||
@@ -234,21 +295,23 @@ def membership_form2(request):
|
||||
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",{})
|
||||
|
||||