-
+
LOAF Board of Directors 2025
@@ -41,7 +41,7 @@ const BoardOfDirectors = () => {
{/* Officers Grid */}
-
+
Officers
@@ -62,7 +62,7 @@ const BoardOfDirectors = () => {
{/* Board Members Grid */}
-
+
Board of Directors
@@ -80,7 +80,7 @@ const BoardOfDirectors = () => {
{/* Join the Board Section */}
-
+
Join the Board of Directors
diff --git a/src/pages/ContactUs.js b/src/pages/ContactUs.js
new file mode 100644
index 0000000..4d76221
--- /dev/null
+++ b/src/pages/ContactUs.js
@@ -0,0 +1,279 @@
+import React, { useState } from 'react';
+import PublicNavbar from '../components/PublicNavbar';
+import PublicFooter from '../components/PublicFooter';
+import { Button } from '../components/ui/button';
+import { Card } from '../components/ui/card';
+import { Input } from '../components/ui/input';
+import { Label } from '../components/ui/label';
+import { Textarea } from '../components/ui/textarea';
+import { Checkbox } from '../components/ui/checkbox';
+import { Mail, MapPin, Loader2 } from 'lucide-react';
+import api from '../utils/api';
+import { toast } from 'sonner';
+
+const ContactUs = () => {
+ const [formData, setFormData] = useState({
+ firstName: '',
+ lastName: '',
+ email: '',
+ subject: '',
+ message: '',
+ consent: false
+ });
+ const [loading, setLoading] = useState(false);
+
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setFormData(prev => ({
+ ...prev,
+ [name]: value
+ }));
+ };
+
+ const handleConsentChange = (checked) => {
+ setFormData(prev => ({
+ ...prev,
+ consent: checked
+ }));
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+
+ // Validation
+ if (!formData.firstName.trim()) {
+ toast.error('Please enter your first name');
+ return;
+ }
+ if (!formData.lastName.trim()) {
+ toast.error('Please enter your last name');
+ return;
+ }
+ if (!formData.email.trim()) {
+ toast.error('Please enter your email');
+ return;
+ }
+ if (!formData.subject.trim()) {
+ toast.error('Please enter a subject');
+ return;
+ }
+ if (!formData.message.trim()) {
+ toast.error('Please enter your message');
+ return;
+ }
+ if (!formData.consent) {
+ toast.error('Please consent to LOAF storing your information');
+ return;
+ }
+
+ setLoading(true);
+ try {
+ await api.post('/contact', {
+ first_name: formData.firstName,
+ last_name: formData.lastName,
+ email: formData.email,
+ subject: formData.subject,
+ message: formData.message
+ });
+
+ toast.success('Message sent successfully! We\'ll get back to you soon.');
+
+ // Reset form
+ setFormData({
+ firstName: '',
+ lastName: '',
+ email: '',
+ subject: '',
+ message: '',
+ consent: false
+ });
+ } catch (error) {
+ console.error('Failed to send message:', error);
+ toast.error(error.response?.data?.detail || 'Failed to send message. Please try again.');
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+
+
+
+
+ {/* Contact Form */}
+
+
+ Contact Form
+
+
+
+
+
+ {/* Contact Information */}
+
+ {/* Message Card */}
+
+
+ If you have questions, or are interested in joining, we would love hearing from you.
+
+
+
+ {/* Email Card */}
+
+
+
+
+ {/* Address Card */}
+
+
+
+
+
+
+
+ LOAF
+
+
+ P.O. Box 7207
+ Houston, Texas 77248-7207
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ContactUs;
diff --git a/src/pages/Donate.js b/src/pages/Donate.js
index 278ce2f..e7477b4 100644
--- a/src/pages/Donate.js
+++ b/src/pages/Donate.js
@@ -58,14 +58,14 @@ const Donate = () => {
-
+
{/* Hero Section */}

e.target.style.display = 'none'} />
-
+
Donate
diff --git a/src/pages/DonationSuccess.js b/src/pages/DonationSuccess.js
index 0a49e26..aa18db7 100644
--- a/src/pages/DonationSuccess.js
+++ b/src/pages/DonationSuccess.js
@@ -16,7 +16,7 @@ const DonationSuccess = () => {
-
+
{/* Success Icon */}
![]()
{
{/* Title */}
-
+
Thank You for Your Donation!
diff --git a/src/pages/Events.js b/src/pages/Events.js
index ce63666..51e809a 100644
--- a/src/pages/Events.js
+++ b/src/pages/Events.js
@@ -64,7 +64,7 @@ const Events = () => {
Loading events...
) : events.length > 0 ? (
-
+
{events.map((event) => (
{
-
+
{/* Hero Section */}
-
History of LOAF
diff --git a/src/pages/Landing.js b/src/pages/Landing.js
index 7e8f58d..3d98790 100644
--- a/src/pages/Landing.js
+++ b/src/pages/Landing.js
@@ -19,31 +19,31 @@ const Landing = () => {
{/* Hero Section */}
-
-
+
+
-

+
-
-
-
-
-

+
+
{/* About Section */}
-
+
-
+
Welcome to LOAF
@@ -54,9 +54,9 @@ const Landing = () => {
{/* Feature Cards Section */}
-
+
-
+
Meet and Greet
@@ -69,7 +69,7 @@ const Landing = () => {
-
+
Socials
@@ -81,7 +81,7 @@ const Landing = () => {
-
+
Active LOAFers
@@ -94,15 +94,15 @@ const Landing = () => {
{/* CTA Section */}
-
-
-
-
+
+
+
+
Become a Member
-
+
No matter your age or ability, there is something for everyone.
diff --git a/src/pages/MissionValues.js b/src/pages/MissionValues.js
index 664cff7..06ff904 100644
--- a/src/pages/MissionValues.js
+++ b/src/pages/MissionValues.js
@@ -10,12 +10,12 @@ const MissionValues = () => {
-
+
{/* Left Card - Mission (Purple Gradient) */}
-
LOAF Mission
@@ -26,13 +26,13 @@ const MissionValues = () => {
in Houston and the surrounding areas.
-

+
{/* Right Card - Values */}
-
LOAF Values
diff --git a/src/pages/Plans.js b/src/pages/Plans.js
index 47c6bd1..8459c55 100644
--- a/src/pages/Plans.js
+++ b/src/pages/Plans.js
@@ -232,7 +232,7 @@ const Plans = () => {
Loading plans...
) : plans.length > 0 ? (
-
+
{plans.map((plan) => {
const minimumPrice = plan.minimum_price_cents || plan.price_cents || 3000;
const suggestedPrice = plan.suggested_price_cents || minimumPrice;
@@ -263,7 +263,7 @@ const Plans = () => {
Starting at
-
+
{formatPrice(minimumPrice)}
{suggestedPrice > minimumPrice && (
diff --git a/src/pages/Profile.js b/src/pages/Profile.js
index 0fe551f..ee84621 100644
--- a/src/pages/Profile.js
+++ b/src/pages/Profile.js
@@ -171,7 +171,7 @@ const Profile = () => {
Account Information
-
+
Email
{profileData.email}
@@ -211,7 +211,7 @@ const Profile = () => {
Personal Information
-
+
{
/>
-
+
{
Partner Information
-
+
{
+ const [openAccordions, setOpenAccordions] = useState({});
+
+ const toggleAccordion = (categoryIndex, resourceIndex) => {
+ const key = `${categoryIndex}-${resourceIndex}`;
+ setOpenAccordions(prev => ({
+ ...prev,
+ [key]: !prev[key]
+ }));
+ };
+
+ const isOpen = (categoryIndex, resourceIndex) => {
+ const key = `${categoryIndex}-${resourceIndex}`;
+ return openAccordions[key] || false;
+ };
+
+ const categories = [
+ {
+ title: 'General LGBTQ+',
+ resources: [
+ {
+ name: 'SPRY (Seniors Preparing for Rainbow Years)',
+ description: 'Social and recreational activities, health and wellness education plus drop-in center',
+ location: 'Law Harrington Senior Center, 2222 Cleburne St, Houston, TX 77004',
+ contact: 'Fred Reninger',
+ phone: '(713) 485-5056',
+ email: '[email protected]',
+ link: 'https://montrosecenter.org/services/seniors/'
+ },
+ {
+ name: 'SAGE - Advocacy and Services for LGBTQ Elders',
+ description: 'SageCents program offering financial management assistance in retirement',
+ link: 'https://www.sageusa.org/'
+ },
+ {
+ name: 'Houston LGBTQ+ Chamber of Commerce',
+ description: 'Member directory to support inclusive businesses advocating for LGBTQ+ community',
+ link: 'https://www.houstonlgbtchamber.com'
+ },
+ {
+ name: 'AARP',
+ description: 'News, finance, wellness topics for lesbian, gay, bisexual, transgender, queer community',
+ link: 'https://www.aarp.org/home-family/voices/lgbtq/'
+ }
+ ]
+ },
+ {
+ title: 'Healthcare',
+ resources: [
+ {
+ name: 'LHI (Lesbian Health Initiative)',
+ description: 'Eliminates healthcare barriers, helps find LGBTQ+ friendly providers and insurance assistance',
+ link: 'https://montrosecenter.org/services/gender-services/lhi/'
+ },
+ {
+ name: 'Legacy Community Health',
+ description: 'Full-service healthcare system with 50+ Texas Gulf Coast locations offering primary care, pediatrics, behavioral health, HIV/AIDS care, dental, vision services',
+ link: 'https://www.legacycommunityhealth.org/'
+ }
+ ]
+ },
+ {
+ title: 'Food Assistance',
+ resources: [
+ {
+ name: 'Meals on Wheels',
+ description: 'Home-delivered meals for seniors',
+ link: 'https://www.mealsonwheelsamerica.org/find-meals'
+ },
+ {
+ name: 'Senior Services (United Way)',
+ description: 'Referral services for senior assistance programs',
+ link: 'https://referral.unitedwayhouston.org/'
+ },
+ {
+ name: 'Food Pantries',
+ description: 'Directory of food pantries in the Houston area',
+ link: 'https://referral.unitedwayhouston.org/MatchList.aspx?k;;0;;N;0;2448611;Food%20Pantries;Food%20Pantries;Partial'
+ },
+ {
+ name: '211 Texas/United Way Helpline',
+ description: 'Free, confidential helpline for utility, rent, housing, benefits, food, childcare assistance',
+ link: 'https://unitedwayhouston.org/what-we-do/211-texas-united-way-helpline/'
+ }
+ ]
+ }
+ ];
+
+ return (
+
+
+
+
+ {/* Header Section */}
+
+
+ Resources
+
+
+ Tap or click on each purple tab below to open and read its contents
+
+
+
+ {/* Resources Grid */}
+
+
+ {categories.map((category, categoryIndex) => (
+
+ {/* Category Title */}
+
+ {category.title}
+
+
+ {/* Resources Accordions */}
+
+ {category.resources.map((resource, resourceIndex) => {
+ const isExpanded = isOpen(categoryIndex, resourceIndex);
+
+ return (
+
+ {/* Accordion Button */}
+
toggleAccordion(categoryIndex, resourceIndex)}
+ className="w-full bg-[#664fa3] hover:bg-[#5a4290] text-white px-6 py-4 rounded-full flex items-center justify-between transition-all shadow-lg hover:shadow-xl"
+ >
+
+ {resource.name}
+
+
+
+
+ {/* Accordion Content */}
+
+
+ {/* Description */}
+
+ {resource.description}
+
+
+ {/* Additional Details */}
+
+ {/* Location */}
+ {resource.location && (
+
+
+
+ {resource.location}
+
+
+ )}
+
+ {/* Contact */}
+ {resource.contact && (
+
+
+ Contact: {resource.contact}
+
+
+ {resource.phone && (
+
+ )}
+ {resource.email && (
+
+ )}
+
+
+ )}
+
+ {/* Website Link */}
+ {resource.link && (
+
+ Visit Website
+
+
+ )}
+
+
+
+
+ );
+ })}
+
+
+ ))}
+
+
+
+ {/* Additional Help Section */}
+
+
+
+ Need Additional Support?
+
+
+ If you need help finding resources or have questions about the services listed above, please don't hesitate to reach out.
+
+
+ Contact Us
+
+
+
+
+
+
+
+ );
+};
+
+export default Resources;
diff --git a/src/pages/VerifyEmail.js b/src/pages/VerifyEmail.js
index 608aacf..1fdeb43 100644
--- a/src/pages/VerifyEmail.js
+++ b/src/pages/VerifyEmail.js
@@ -49,7 +49,7 @@ const VerifyEmail = () => {
-
+
{status === 'loading' && (
<>
diff --git a/src/pages/admin/AdminEvents.js b/src/pages/admin/AdminEvents.js
index 8d9fbf4..7eb418d 100644
--- a/src/pages/admin/AdminEvents.js
+++ b/src/pages/admin/AdminEvents.js
@@ -131,7 +131,7 @@ const AdminEvents = () => {
return (
<>
{/* Header */}
-
+
Event Management
@@ -156,7 +156,7 @@ const AdminEvents = () => {
-
+
{editingEvent ? 'Edit Event' : 'Create New Event'}
@@ -188,7 +188,7 @@ const AdminEvents = () => {
/>
-
+
-
-
- {editingEvent ? 'Update Event' : 'Create Event'}
-
+
{
>
Cancel
+
+ {editingEvent ? 'Update Event' : 'Create Event'}
+
@@ -281,7 +281,7 @@ const AdminEvents = () => {
Loading events...
) : events.length > 0 ? (
-
+
{events.map((event) => (
{
{/* Stats */}
-
+
Total Members
@@ -129,7 +129,7 @@ const AdminMembers = () => {
{/* Filters */}
-
+
{
{/* Stats */}
-
+
Total Plans
@@ -183,7 +183,7 @@ const AdminPlans = () => {
{/* Filters */}
-
+
) : filteredPlans.length > 0 ? (
-
+
{filteredPlans.map((plan) => (
{
{/* Actions */}
-
+
handleEditPlan(plan)}
variant="outline"
@@ -350,16 +350,16 @@ const AdminPlans = () => {
{/* Delete Confirmation Dialog */}
{deleteDialogOpen && (
-
-
-
+
+
+
Delete Plan
-
+
Are you sure you want to delete "{planToDelete?.name}"? This action
will deactivate the plan and it won't be available for new subscriptions.
-
+
setDeleteDialogOpen(false)}
variant="outline"
diff --git a/src/pages/admin/AdminSubscriptions.js b/src/pages/admin/AdminSubscriptions.js
index 37fa334..32e19ab 100644
--- a/src/pages/admin/AdminSubscriptions.js
+++ b/src/pages/admin/AdminSubscriptions.js
@@ -314,7 +314,98 @@ const AdminSubscriptions = () => {
{/* Subscriptions Table */}
-
+ {/* Mobile Card View */}
+
+ {filteredSubscriptions.length > 0 ? (
+ filteredSubscriptions.map((sub) => (
+
+
+ {/* Member Info */}
+
+
+
+ {sub.user.first_name} {sub.user.last_name}
+
+
+ {sub.user.email}
+
+
+
{sub.status}
+
+
+ {/* Plan & Period */}
+
+
+
Plan
+
{sub.plan.name}
+
{sub.plan.billing_cycle}
+
+
+
Period
+
+ {new Date(sub.current_period_start).toLocaleDateString()} -
+ {new Date(sub.current_period_end).toLocaleDateString()}
+
+
+
+
+ {/* Pricing */}
+
+
+
Base Fee
+
+ ${(sub.base_fee_cents / 100).toFixed(2)}
+
+
+
+
Donation
+
+ ${(sub.donation_cents / 100).toFixed(2)}
+
+
+
+
Total
+
+ ${(sub.total_cents / 100).toFixed(2)}
+
+
+
+
+ {/* Actions */}
+
+ handleEdit(sub)}
+ className="flex-1 text-[#664fa3] hover:bg-[#DDD8EB]"
+ >
+
+ Edit
+
+ {sub.status === 'active' && (
+ handleCancelSubscription(sub.id)}
+ className="flex-1 text-red-600 hover:bg-red-50"
+ >
+
+ Cancel
+
+ )}
+
+
+
+ ))
+ ) : (
+
+ No subscriptions found
+
+ )}
+
+
+ {/* Desktop Table View */}
+