Compare commits

...

3 Commits

Author SHA1 Message Date
Timo Knuth e378ce4a97 Deploy ready 2025-10-03 18:50:40 +02:00
Timo Knuth d64695225c Merge branch 'main' of git.bizmatch.net:aknuth/annaville-sda-site 2025-10-03 18:48:34 +02:00
Timo Knuth de2d82da75 Launch 2025-10-03 18:27:44 +02:00
15 changed files with 766 additions and 1039 deletions

View File

View File

@ -1,62 +1,63 @@
import express from 'express' import express from "express";
import cors from 'cors' import cors from "cors";
import { fileURLToPath } from 'url' import { fileURLToPath } from "url";
import { promises as fs } from 'fs' import { promises as fs } from "fs";
import path from 'path' import path from "path";
import crypto from 'crypto' import crypto from "crypto";
import multer from 'multer' import multer from "multer";
const app = express() const app = express();
const port = process.env.PORT || 3070 const port = process.env.PORT || 3070;
const adminToken = process.env.ADMIN_TOKEN || 'Driver1' const adminToken = process.env.ADMIN_TOKEN || "Driver1";
const __filename = fileURLToPath(import.meta.url) const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename) const __dirname = path.dirname(__filename);
const dataDir = path.join(__dirname, 'data') const dataDir = path.join(__dirname, "data");
const dataPath = path.join(dataDir, 'events.json') const dataPath = path.join(dataDir, "events.json");
const uploadsDir = path.join(__dirname, 'uploads') const uploadsDir = path.join(__dirname, "uploads");
await fs.mkdir(uploadsDir, { recursive: true }) await fs.mkdir(uploadsDir, { recursive: true });
const storage = multer.diskStorage({ const storage = multer.diskStorage({
destination: (req, file, cb) => cb(null, uploadsDir), destination: (req, file, cb) => cb(null, uploadsDir),
filename: (req, file, cb) => { filename: (req, file, cb) => {
const ext = path.extname(file.originalname || '') || '.png' const ext = path.extname(file.originalname || "") || ".png";
const base = (file.originalname || 'upload') const base =
.replace(/[^a-z0-9]+/gi, '-') (file.originalname || "upload")
.replace(/^-+|-+$/g, '') .replace(/[^a-z0-9]+/gi, "-")
.toLowerCase() || 'upload' .replace(/^-+|-+$/g, "")
const unique = `${base}-${Date.now()}${ext}` .toLowerCase() || "upload";
cb(null, unique) const unique = `${base}-${Date.now()}${ext}`;
} cb(null, unique);
}) },
});
const allowedMimeTypes = new Set([ const allowedMimeTypes = new Set([
'image/png', "image/png",
'image/jpeg', "image/jpeg",
'image/gif', "image/gif",
'image/webp', "image/webp",
'image/svg+xml' "image/svg+xml",
]) ]);
const upload = multer({ const upload = multer({
storage, storage,
limits: { fileSize: 5 * 1024 * 1024 }, limits: { fileSize: 5 * 1024 * 1024 },
fileFilter: (req, file, cb) => { fileFilter: (req, file, cb) => {
if (allowedMimeTypes.has(file.mimetype)) { if (allowedMimeTypes.has(file.mimetype)) {
cb(null, true) cb(null, true);
} else { } else {
cb(new Error('Only image uploads are allowed')) cb(new Error("Only image uploads are allowed"));
} }
} },
}) });
async function ensureDataFile() { async function ensureDataFile() {
try { try {
await fs.access(dataPath) await fs.access(dataPath);
} catch { } catch {
await fs.mkdir(dataDir, { recursive: true }) await fs.mkdir(dataDir, { recursive: true });
await fs.writeFile(dataPath, '[]', 'utf-8') await fs.writeFile(dataPath, "[]", "utf-8");
} }
} }
@ -65,170 +66,200 @@ function slugify(text) {
.toString() .toString()
.toLowerCase() .toLowerCase()
.trim() .trim()
.replace(/[^a-z0-9]+/g, '-') .replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, '') .replace(/^-+|-+$/g, "");
} }
async function readEvents() { async function readEvents() {
await ensureDataFile() await ensureDataFile();
const raw = await fs.readFile(dataPath, 'utf-8') const raw = await fs.readFile(dataPath, "utf-8");
try { try {
return JSON.parse(raw) return JSON.parse(raw);
} catch (error) { } catch (error) {
console.error('Failed to parse events file, resetting to []', error) console.error("Failed to parse events file, resetting to []", error);
await fs.writeFile(dataPath, '[]', 'utf-8') await fs.writeFile(dataPath, "[]", "utf-8");
return [] return [];
} }
} }
async function writeEvents(events) { async function writeEvents(events) {
await fs.writeFile(dataPath, JSON.stringify(events, null, 2), 'utf-8') await fs.writeFile(dataPath, JSON.stringify(events, null, 2), "utf-8");
} }
function requireAuth(req, res, next) { function requireAuth(req, res, next) {
const token = req.header('x-admin-token') const token = req.header("x-admin-token");
if (!token || token !== adminToken) { if (!token || token !== adminToken) {
return res.status(401).json({ error: 'Unauthorized' }) return res.status(401).json({ error: "Unauthorized" });
} }
return next() return next();
} }
function asyncHandler(fn) { function asyncHandler(fn) {
return (req, res, next) => { return (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next) Promise.resolve(fn(req, res, next)).catch(next);
} };
} }
function buildEventPayload(input, base = {}) { function buildEventPayload(input, base = {}) {
const allowed = ['title', 'description', 'date', 'time', 'location', 'category', 'image'] const allowed = [
const payload = { ...base } "title",
"description",
"date",
"time",
"location",
"category",
"image",
];
const payload = { ...base };
for (const key of allowed) { for (const key of allowed) {
if (key in input && input[key] !== undefined) { if (key in input && input[key] !== undefined) {
payload[key] = typeof input[key] === 'string' ? input[key].trim() : input[key] payload[key] =
typeof input[key] === "string" ? input[key].trim() : input[key];
} }
} }
return payload return payload;
} }
app.use(cors()) app.use(cors());
app.use(express.json({ limit: '1mb' })) app.use(express.json({ limit: "1mb" }));
app.use('/uploads', express.static(uploadsDir)) app.use("/uploads", express.static(uploadsDir));
app.get('/api/health', (req, res) => { app.get("/api/health", (req, res) => {
res.json({ status: 'ok' }) res.json({ status: "ok" });
}) });
app.get('/api/events', asyncHandler(async (req, res) => { app.get(
const events = await readEvents() "/api/events",
const sorted = events.slice().sort((a, b) => new Date(a.date) - new Date(b.date)) asyncHandler(async (req, res) => {
res.json(sorted) const events = await readEvents();
})) const sorted = events
.slice()
.sort((a, b) => new Date(a.date) - new Date(b.date));
res.json(sorted);
})
);
app.get('/api/events/:slug', asyncHandler(async (req, res) => { app.get(
const events = await readEvents() "/api/events/:slug",
const event = events.find(e => e.slug === req.params.slug) asyncHandler(async (req, res) => {
if (!event) { const events = await readEvents();
return res.status(404).json({ error: 'Event not found' }) const event = events.find((e) => e.slug === req.params.slug);
} if (!event) {
res.json(event) return res.status(404).json({ error: "Event not found" });
}))
app.post('/api/events', requireAuth, asyncHandler(async (req, res) => {
const data = buildEventPayload(req.body)
if (!data.title || !data.date) {
return res.status(400).json({ error: 'title and date are required' })
}
const events = await readEvents()
const baseSlug = slugify(req.body.slug || data.title || '') || `event-${Date.now()}`
let uniqueSlug = baseSlug
let suffix = 1
while (events.some(event => event.slug === uniqueSlug)) {
uniqueSlug = `${baseSlug}-${suffix++}`
}
const now = new Date().toISOString()
const newEvent = {
id: crypto.randomUUID(),
slug: uniqueSlug,
createdAt: now,
updatedAt: now,
...data,
}
events.push(newEvent)
await writeEvents(events)
res.status(201).json(newEvent)
}))
app.patch('/api/events/:slug', requireAuth, asyncHandler(async (req, res) => {
const events = await readEvents()
const index = events.findIndex(event => event.slug === req.params.slug)
if (index === -1) {
return res.status(404).json({ error: 'Event not found' })
}
const event = events[index]
const updated = buildEventPayload(req.body, event)
let slugToUse = event.slug
if (req.body.slug && req.body.slug !== event.slug) {
const requestedSlug = slugify(req.body.slug)
let uniqueSlug = requestedSlug || event.slug
let suffix = 1
while (events.some((e, i) => i !== index && e.slug === uniqueSlug)) {
uniqueSlug = `${requestedSlug}-${suffix++}`
} }
slugToUse = uniqueSlug res.json(event);
} })
);
const merged = { app.post(
...event, "/api/events",
...updated, requireAuth,
slug: slugToUse, asyncHandler(async (req, res) => {
updatedAt: new Date().toISOString(), const data = buildEventPayload(req.body);
} if (!data.title || !data.date) {
return res.status(400).json({ error: "title and date are required" });
}
events[index] = merged const events = await readEvents();
await writeEvents(events) const baseSlug =
res.json(merged) slugify(req.body.slug || data.title || "") || `event-${Date.now()}`;
})) let uniqueSlug = baseSlug;
let suffix = 1;
while (events.some((event) => event.slug === uniqueSlug)) {
uniqueSlug = `${baseSlug}-${suffix++}`;
}
app.delete('/api/events/:slug', requireAuth, asyncHandler(async (req, res) => { const now = new Date().toISOString();
const events = await readEvents() const newEvent = {
const index = events.findIndex(event => event.slug === req.params.slug) id: crypto.randomUUID(),
if (index === -1) { slug: uniqueSlug,
return res.status(404).json({ error: 'Event not found' }) createdAt: now,
} updatedAt: now,
...data,
};
const [removed] = events.splice(index, 1) events.push(newEvent);
await writeEvents(events) await writeEvents(events);
res.json({ success: true, removed }) res.status(201).json(newEvent);
})) })
);
app.post('/api/uploads', requireAuth, upload.single('file'), (req, res) => { app.patch(
"/api/events/:slug",
requireAuth,
asyncHandler(async (req, res) => {
const events = await readEvents();
const index = events.findIndex((event) => event.slug === req.params.slug);
if (index === -1) {
return res.status(404).json({ error: "Event not found" });
}
const event = events[index];
const updated = buildEventPayload(req.body, event);
let slugToUse = event.slug;
if (req.body.slug && req.body.slug !== event.slug) {
const requestedSlug = slugify(req.body.slug);
let uniqueSlug = requestedSlug || event.slug;
let suffix = 1;
while (events.some((e, i) => i !== index && e.slug === uniqueSlug)) {
uniqueSlug = `${requestedSlug}-${suffix++}`;
}
slugToUse = uniqueSlug;
}
const merged = {
...event,
...updated,
slug: slugToUse,
updatedAt: new Date().toISOString(),
};
events[index] = merged;
await writeEvents(events);
res.json(merged);
})
);
app.delete(
"/api/events/:slug",
requireAuth,
asyncHandler(async (req, res) => {
const events = await readEvents();
const index = events.findIndex((event) => event.slug === req.params.slug);
if (index === -1) {
return res.status(404).json({ error: "Event not found" });
}
const [removed] = events.splice(index, 1);
await writeEvents(events);
res.json({ success: true, removed });
})
);
app.post("/api/uploads", requireAuth, upload.single("file"), (req, res) => {
if (!req.file) { if (!req.file) {
return res.status(400).json({ error: 'No file uploaded' }) return res.status(400).json({ error: "No file uploaded" });
} }
const relativeUrl = `/uploads/${req.file.filename}` const relativeUrl = `/uploads/${req.file.filename}`;
const absoluteUrl = `${req.protocol}://${req.get('host')}${relativeUrl}` const absoluteUrl = `${req.protocol}://${req.get("host")}${relativeUrl}`;
res.status(201).json({ url: absoluteUrl, path: relativeUrl }) res.status(201).json({ url: absoluteUrl, path: relativeUrl });
}) });
app.get('/api/admin/verify', requireAuth, (req, res) => { app.get("/api/admin/verify", requireAuth, (req, res) => {
res.json({ ok: true }) res.json({ ok: true });
}) });
app.use((err, req, res, next) => { app.use((err, req, res, next) => {
if (err instanceof multer.MulterError) { if (err instanceof multer.MulterError) {
return res.status(400).json({ error: err.message }) return res.status(400).json({ error: err.message });
} }
if (err && err.message === 'Only image uploads are allowed') { if (err && err.message === "Only image uploads are allowed") {
return res.status(400).json({ error: err.message }) return res.status(400).json({ error: err.message });
} }
console.error(err) console.error(err);
res.status(500).json({ error: 'Internal server error' }) res.status(500).json({ error: "Internal server error" });
}) });
app.listen(port, () => { app.listen(port, () => {
console.log(`Events API listening on port ${port}`) console.log(`Events API listening on port ${port}`);
}) });

View File

@ -2,82 +2,47 @@
import React from 'react' import React from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
export default function Footer(){ export default function Footer() {
const year = new Date().getFullYear() const year = new Date().getFullYear()
return ( return (
<footer id="footer" role="contentinfo" className="bg-sand border-t border-subtle mt-12"> <footer id="footer" role="contentinfo" className="bg-sand border-t border-subtle mt-12">
<div className="container grid md:grid-cols-3 gap-8 py-16"> <div className="container grid md:grid-cols-2 gap-8 py-16">
<div> <div>
<h3 className="font-heading text-h3 mb-4">Annaville Seventh-day Adventist Church</h3> <h3 className="font-heading text-h3 mb-4">Annaville Seventh-day Adventist Church</h3>
<p className="text-body mb-2">2710 Violet Rd<br/>Corpus Christi, TX 78410</p> <p className="text-body mb-2">2710 Violet Rd<br />Corpus Christi, TX 78410</p>
<p className="mb-2"> <p className="mb-2">
<a href="tel:+13612415501" className="text-primary underline hover:text-primaryHover"> <a href="tel:+13612415501" className="text-primary underline hover:text-primaryHover">
Call (361) 241-5501 Call (361) 241-5501
</a> </a>
</p> </p>
<p className="mb-2"> <p className="mb-2">
<a href="https://maps.google.com/?q=2710+Violet+Rd,+Corpus+Christi,+TX+78410" <a href="https://maps.google.com/?q=2710+Violet+Rd,+Corpus+Christi,+TX+78410"
className="text-primary underline hover:text-primaryHover"> className="text-primary underline hover:text-primaryHover">
Get Directions Get Directions
</a> </a>
</p> </p>
<p className="text-muted text-small">Sabbath School 9:30 AM Divine Worship 11:00 AM</p> <p className="text-muted text-small">Sabbath School 9:45 AM Divine Worship 11:00 AM</p>
{/* Leadership Information */} {/* Leadership Information */}
<div className="mt-6 text-small text-muted"> <div className="mt-6 text-small text-muted">
<p><strong>Pastor:</strong> Matt McMearty</p> <p><strong>Pastor:</strong> Matt McMearty</p>
<p><strong>Head Elder:</strong> Regena Simms</p> <p><strong>Head Elder:</strong> Regena Simms</p>
</div> </div>
</div> </div>
<div> <div>
<h3 className="font-heading text-h3 mb-4">Quick Links</h3> <h3 className="font-heading text-h3 mb-4">Quick Links</h3>
<ul className="space-y-3"> <ul className="space-y-3">
<li><Link to="/about" className="text-body hover:text-primary transition-colors">About Us</Link></li> <li><Link to="/about" className="text-body hover:text-primary transition-colors">About Us</Link></li>
<li><Link to="/services" className="text-body hover:text-primary transition-colors">Services</Link></li> <li><Link to="/services" className="text-body hover:text-primary transition-colors">Services</Link></li>
<li><Link to="/resources" className="text-body hover:text-primary transition-colors">Resources</Link></li> <li><Link to="/resources" className="text-body hover:text-primary transition-colors">Resources</Link></li>
<li><Link to="/prayer-requests" className="text-body hover:text-primary transition-colors">Prayer Requests</Link></li>
<li><Link to="/calendar" className="text-body hover:text-primary transition-colors">Calendar</Link></li> <li><Link to="/calendar" className="text-body hover:text-primary transition-colors">Calendar</Link></li>
<li><Link to="/beliefs" className="text-body hover:text-primary transition-colors">Our Beliefs</Link></li> <li><Link to="/beliefs" className="text-body hover:text-primary transition-colors">Our Beliefs</Link></li>
<li><Link to="/contact" className="text-body hover:text-primary transition-colors">Contact</Link></li> <li><Link to="/contact" className="text-body hover:text-primary transition-colors">Contact</Link></li>
</ul> </ul>
</div> </div>
<div>
<h3 className="font-heading text-h3 mb-4">Newsletter</h3>
<p className="text-body mb-4">
If you would like to receive our newsletter please fill out the form below.
</p>
<form className="space-y-4">
<div>
<label htmlFor="footer-newsletter-name" className="block text-sm font-medium text-ink mb-2">
Name:
</label>
<input
id="footer-newsletter-name"
type="text"
className="w-full border border-subtle rounded-lg px-4 py-3 focus:ring-2 focus:ring-primary focus:border-transparent transition-colors"
placeholder="Your name"
/>
</div>
<div>
<label htmlFor="footer-newsletter-email" className="block text-sm font-medium text-ink mb-2">
Email Address:
</label>
<input
id="footer-newsletter-email"
type="email"
className="w-full border border-subtle rounded-lg px-4 py-3 focus:ring-2 focus:ring-primary focus:border-transparent transition-colors"
placeholder="your.email@example.com"
/>
</div>
<button type="submit" className="btn w-full">
Subscribe to Newsletter
</button>
</form>
</div>
</div> </div>
<div className="border-t border-subtle py-6"> <div className="border-t border-subtle py-6">
<div className="container flex flex-wrap items-center gap-4 justify-between"> <div className="container flex flex-wrap items-center gap-4 justify-between">
<div className="text-small text-muted"> <div className="text-small text-muted">
@ -86,7 +51,6 @@ export default function Footer(){
<div className="text-small flex flex-wrap items-center gap-4"> <div className="text-small flex flex-wrap items-center gap-4">
<Link className="text-muted hover:text-primary transition-colors" to="/privacy">Privacy Policy</Link> <Link className="text-muted hover:text-primary transition-colors" to="/privacy">Privacy Policy</Link>
<Link className="text-muted hover:text-primary transition-colors" to="/terms">Terms of Use</Link> <Link className="text-muted hover:text-primary transition-colors" to="/terms">Terms of Use</Link>
<Link className="text-muted hover:text-primary transition-colors" to="/accessibility">Accessibility</Link>
<Link to="/admin/events" className="btn-outline text-xs px-3 py-1">Admin Events</Link> <Link to="/admin/events" className="btn-outline text-xs px-3 py-1">Admin Events</Link>
</div> </div>
</div> </div>

View File

@ -4,25 +4,24 @@ import { Link, NavLink } from 'react-router-dom'
import { track, events } from '../utils/analytics' import { track, events } from '../utils/analytics'
const navItems = [ const navItems = [
{ to:'/about', label:'ABOUT US' }, { to: '/about', label: 'ABOUT US' },
{ to:'/services', label:'SERVICES' }, { to: '/services', label: 'SERVICES' },
{ to:'/resources', label:'RESOURCES' }, { to: '/resources', label: 'RESOURCES' },
{ to:'/events', label:'EVENTS' }, { to: '/events', label: 'EVENTS' },
{ to:'/prayer-requests', label:'PRAYER REQUESTS' }, { to: '/calendar', label: 'CALENDAR' },
{ to:'/calendar', label:'CALENDAR' }, { to: '/beliefs', label: 'OUR BELIEFS' },
{ to:'/beliefs', label:'OUR BELIEFS' },
] ]
export default function Header(){ export default function Header() {
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
return ( return (
<header role="banner" className="z-50 bg-white/90 backdrop-blur border-b border-subtle"> <header role="banner" className="z-50 bg-white/90 backdrop-blur border-b border-subtle">
<nav id="navigation" aria-label="Main navigation" className="container flex items-center justify-between h-20"> <nav id="navigation" aria-label="Main navigation" className="container flex items-center justify-between h-20">
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<Link to="/" className="flex items-center gap-4 font-heading text-lg font-semibold tracking-tight text-ink leading-tight"> <Link to="/" className="flex items-center gap-4 font-heading text-lg font-semibold tracking-tight text-ink leading-tight">
<img <img
src="/assets/favicon.ico.gif" src="/assets/favicon.ico.gif"
alt="Annaville SDA Church Logo" alt="Annaville SDA Church Logo"
className="w-20 h-20 rounded-lg" className="w-20 h-20 rounded-lg"
/> />
<span> <span>
@ -32,60 +31,62 @@ export default function Header(){
</div> </div>
<div className="hidden md:flex items-center gap-6"> <div className="hidden md:flex items-center gap-6">
{navItems.map(item => ( {navItems.map(item => (
<NavLink <NavLink
key={item.to} key={item.to}
to={item.to} to={item.to}
className={({isActive})=>`text-sm font-medium transition-colors ${isActive?'text-primary font-semibold':'text-ink hover:text-primary'}`} className={({ isActive }) => `text-sm font-medium transition-colors ${isActive ? 'text-primary font-semibold' : 'text-ink hover:text-primary'}`}
> >
{item.label} {item.label}
</NavLink> </NavLink>
))} ))}
<Link <Link
to="/contact" to="/contact"
className="btn text-sm px-4 py-2" className="btn text-sm px-4 py-2"
onClick={()=>track(events.CTA_CLICK,{label:'contact'})} onClick={() => track(events.CTA_CLICK, { label: 'contact' })}
> >
Contact Us Contact Us
</Link> </Link>
</div> </div>
<button <button
aria-label="Open menu" aria-label="Open menu"
className="md:hidden btn-ghost" className="md:hidden btn-ghost"
onClick={()=>setOpen(true)} onClick={() => setOpen(true)}
> >
<span aria-hidden className="text-3xl"></span> <span aria-hidden className="text-3xl"></span>
</button> </button>
</nav> </nav>
{open && ( {open && (
<div role="dialog" aria-modal="true" className="md:hidden fixed inset-0 bg-black/30" onClick={()=>setOpen(false)}> <div role="dialog" aria-modal="true" className="md:hidden fixed inset-0 z-[100] bg-white" onClick={() => setOpen(false)}>
<div className="absolute top-0 right-0 w-[80%] h-full bg-white shadow-level1 p-8" onClick={e=>e.stopPropagation()}> <div className="h-full w-full bg-white flex flex-col" onClick={e => e.stopPropagation()}>
<div className="flex justify-between items-center mb-12"> <div className="bg-white border-b border-gray-200 p-4 flex justify-between items-center flex-shrink-0">
<span className="font-heading text-h2">Menu</span> <span className="font-heading text-2xl font-bold text-gray-900">Menu</span>
<button className="btn-ghost" onClick={()=>setOpen(false)} aria-label="Close menu"></button> <button className="text-3xl text-gray-700 leading-none p-2 hover:bg-gray-100 rounded-lg transition-colors" onClick={() => setOpen(false)} aria-label="Close menu"></button>
</div> </div>
<ul className="space-y-6"> <nav className="flex-1 flex flex-col justify-center px-8 py-8 bg-white">
{navItems.map(item => ( <ul className="space-y-4">
<li key={item.to}> {navItems.map(item => (
<NavLink <li key={item.to}>
to={item.to} <NavLink
onClick={()=>setOpen(false)} to={item.to}
className={({isActive})=>`block py-5 text-body ${isActive?'text-primary font-semibold':'text-ink hover:text-primary'}`} onClick={() => setOpen(false)}
className={({ isActive }) => `block py-3 font-semibold text-lg text-center transition-colors ${isActive ? 'text-primary' : 'text-gray-900 hover:text-primary'}`}
>
{item.label}
</NavLink>
</li>
))}
<li className="pt-4 border-t border-gray-200">
<Link
to="/contact"
className="block py-3 font-semibold text-lg text-center text-gray-900 hover:text-primary transition-colors"
onClick={() => { setOpen(false); track(events.CTA_CLICK, { label: 'contact' }) }}
> >
{item.label} Contact Us
</NavLink> </Link>
</li> </li>
))} </ul>
<li> </nav>
<Link
to="/contact"
className="btn w-full"
onClick={()=>{setOpen(false); track(events.CTA_CLICK,{label:'contact'})}}
>
Contact Us
</Link>
</li>
</ul>
</div> </div>
</div> </div>
)} )}

View File

@ -4,7 +4,7 @@ import { Link } from 'react-router-dom'
import { track, events } from '../utils/analytics' import { track, events } from '../utils/analytics'
import LazyImage from './LazyImage' import LazyImage from './LazyImage'
export function TextHero(){ export function TextHero() {
const scrollToServiceTimes = () => { const scrollToServiceTimes = () => {
const element = document.getElementById('service-times') const element = document.getElementById('service-times')
if (element) { if (element) {
@ -13,6 +13,14 @@ export function TextHero(){
track(events.CTA_CLICK, { label: 'service_times' }) track(events.CTA_CLICK, { label: 'service_times' })
} }
const scrollToUpcomingEvents = () => {
const element = document.getElementById('upcoming-events')
if (element) {
element.scrollIntoView({ behavior: 'smooth' })
}
track(events.CTA_CLICK, { label: 'plan_visit' })
}
return ( return (
<section className="relative bg-gradient-to-br from-sand to-surface"> <section className="relative bg-gradient-to-br from-sand to-surface">
<div className="container py-20"> <div className="container py-20">
@ -21,18 +29,17 @@ export function TextHero(){
<div className="order-1 lg:order-1"> <div className="order-1 lg:order-1">
<h1 className="font-heading text-h1 mb-8">Welcome to Annaville Seventh-day Adventist Church</h1> <h1 className="font-heading text-h1 mb-8">Welcome to Annaville Seventh-day Adventist Church</h1>
<p className="text-ink text-body mb-10">The Annaville SDA Church offers worship services for members, non-members, or anyone interested in learning more about practical Christian living from the Word of God.</p> <p className="text-ink text-body mb-10">The Annaville SDA Church offers worship services for members, non-members, or anyone interested in learning more about practical Christian living from the Word of God.</p>
<div className="mb-10 text-muted text-small">Sabbath School 9:30 AM Divine Worship 11:00 AM 2710 Violet Rd</div> <div className="mb-10 text-muted text-small">Sabbath School 9:45 AM Divine Worship 11:00 AM 2710 Violet Rd</div>
<div className="flex flex-wrap gap-6"> <div className="flex flex-wrap gap-6">
<Link <button
to="/visit" className="btn"
className="btn" onClick={scrollToUpcomingEvents}
onClick={() => track(events.CTA_CLICK, { label: 'plan_visit' })}
data-cta="plan_visit" data-cta="plan_visit"
> >
Plan Your Visit Plan Your Visit
</Link> </button>
<button <button
className="btn-outline" className="btn-outline"
onClick={scrollToServiceTimes} onClick={scrollToServiceTimes}
data-cta="service_times" data-cta="service_times"
> >
@ -40,12 +47,12 @@ export function TextHero(){
</button> </button>
</div> </div>
</div> </div>
{/* Large Hero Image on the Right */} {/* Large Hero Image on the Right */}
<div className="order-2 lg:order-2"> <div className="order-2 lg:order-2">
<LazyImage <LazyImage
src="/assets/hero_golden_hour.png" src="/assets/hero_golden_hour.png"
alt="Annaville SDA Church building during golden hour with people walking on the path" alt="Annaville SDA Church building during golden hour with people walking on the path"
className="w-full h-[400px] object-cover rounded-lg shadow-lg" className="w-full h-[400px] object-cover rounded-lg shadow-lg"
/> />
</div> </div>
@ -56,7 +63,7 @@ export function TextHero(){
} }
// Safe photo hero variant with dim overlay; H1 remains text-first // Safe photo hero variant with dim overlay; H1 remains text-first
export function PhotoHeroSafe(){ export function PhotoHeroSafe() {
const scrollToServiceTimes = () => { const scrollToServiceTimes = () => {
const element = document.getElementById('service-times') const element = document.getElementById('service-times')
if (element) { if (element) {
@ -65,6 +72,14 @@ export function PhotoHeroSafe(){
track(events.CTA_CLICK, { label: 'service_times' }) track(events.CTA_CLICK, { label: 'service_times' })
} }
const scrollToUpcomingEvents = () => {
const element = document.getElementById('upcoming-events')
if (element) {
element.scrollIntoView({ behavior: 'smooth' })
}
track(events.CTA_CLICK, { label: 'plan_visit' })
}
return ( return (
<section className="relative"> <section className="relative">
<LazyImage src="/assets/hero_golden_hour.png" alt="Annaville SDA Church building during golden hour" className="absolute right-0 top-8 w-1/4 h-full" /> <LazyImage src="/assets/hero_golden_hour.png" alt="Annaville SDA Church building during golden hour" className="absolute right-0 top-8 w-1/4 h-full" />
@ -72,17 +87,17 @@ export function PhotoHeroSafe(){
<div className="relative container py-40 text-white"> <div className="relative container py-40 text-white">
<h1 className="font-heading text-h1 mb-8">Welcome to Annaville Seventh-day Adventist Church</h1> <h1 className="font-heading text-h1 mb-8">Welcome to Annaville Seventh-day Adventist Church</h1>
<p className="text-white text-body mb-10">The Annaville SDA Church offers worship services for members, non-members, or anyone interested in learning more about practical Christian living from the Word of God.</p> <p className="text-white text-body mb-10">The Annaville SDA Church offers worship services for members, non-members, or anyone interested in learning more about practical Christian living from the Word of God.</p>
<div className="mb-10 text-white/90 text-small">Sabbath School 9:30 AM Divine Worship 11:00 AM 2710 Violet Rd</div> <div className="mb-10 text-white/90 text-small">Sabbath School 9:45 AM Divine Worship 11:00 AM 2710 Violet Rd</div>
<div className="flex flex-wrap gap-6"> <div className="flex flex-wrap gap-6">
<Link <button
to="/visit"
className="btn" className="btn"
onClick={scrollToUpcomingEvents}
data-cta="plan_visit" data-cta="plan_visit"
> >
Plan Your Visit Plan Your Visit
</Link> </button>
<button <button
className="btn-outline text-white border-white hover:bg-white/10" className="btn-outline text-white border-white hover:bg-white/10"
onClick={scrollToServiceTimes} onClick={scrollToServiceTimes}
data-cta="service_times" data-cta="service_times"
> >

View File

@ -2,12 +2,11 @@ import React from 'react'
import { NavLink } from 'react-router-dom' import { NavLink } from 'react-router-dom'
const navItems = [ const navItems = [
{ to:'/about', label:'ABOUT US' }, { to: '/about', label: 'ABOUT US' },
{ to:'/services', label:'SERVICES' }, { to: '/services', label: 'SERVICES' },
{ to:'/resources', label:'RESOURCES' }, { to: '/resources', label: 'RESOURCES' },
{ to:'/prayer-requests', label:'PRAYER REQUESTS' }, { to: '/calendar', label: 'CALENDAR' },
{ to:'/calendar', label:'CALENDAR' }, { to: '/beliefs', label: 'OUR BELIEFS' },
{ to:'/beliefs', label:'OUR BELIEFS' },
] ]
export default function SidebarNav() { export default function SidebarNav() {
@ -15,10 +14,10 @@ export default function SidebarNav() {
<div className="bg-yellow-100 p-4 min-h-screen w-64"> <div className="bg-yellow-100 p-4 min-h-screen w-64">
<nav className="space-y-2"> <nav className="space-y-2">
{navItems.map(item => ( {navItems.map(item => (
<NavLink <NavLink
key={item.to} key={item.to}
to={item.to} to={item.to}
className={({isActive}) => ` className={({ isActive }) => `
block w-full text-left px-4 py-3 text-sm font-bold uppercase block w-full text-left px-4 py-3 text-sm font-bold uppercase
border border-gray-300 bg-gray-200 hover:bg-gray-300 border border-gray-300 bg-gray-200 hover:bg-gray-300
${isActive ? 'bg-gray-400' : ''} ${isActive ? 'bg-gray-400' : ''}
@ -28,13 +27,13 @@ export default function SidebarNav() {
</NavLink> </NavLink>
))} ))}
</nav> </nav>
<div className="mt-6"> <div className="mt-6">
<button className="w-full px-4 py-2 text-sm font-medium text-red-600 bg-yellow-100 border border-red-600 rounded-full hover:bg-red-50"> <button className="w-full px-4 py-2 text-sm font-medium text-red-600 bg-yellow-100 border border-red-600 rounded-full hover:bg-red-50">
Subscribe to our Newsletter &gt;&gt; Subscribe to our Newsletter &gt;&gt;
</button> </button>
</div> </div>
<div className="mt-4"> <div className="mt-4">
<a href="#" className="text-blue-600 underline text-sm">Message Center</a> <a href="#" className="text-blue-600 underline text-sm">Message Center</a>
</div> </div>

View File

@ -8,7 +8,6 @@ import Home from './pages/Home'
import About from './pages/About' import About from './pages/About'
import Services from './pages/Services' import Services from './pages/Services'
import Resources from './pages/Resources' import Resources from './pages/Resources'
import PrayerRequests from './pages/PrayerRequests'
import Calendar from './pages/Calendar' import Calendar from './pages/Calendar'
import Beliefs from './pages/Beliefs' import Beliefs from './pages/Beliefs'
import Contact from './pages/Contact' import Contact from './pages/Contact'
@ -33,7 +32,6 @@ const router = createBrowserRouter([
{ path: 'about', element: <About /> }, { path: 'about', element: <About /> },
{ path: 'services', element: <Services /> }, { path: 'services', element: <Services /> },
{ path: 'resources', element: <Resources /> }, { path: 'resources', element: <Resources /> },
{ path: 'prayer-requests', element: <PrayerRequests /> },
{ path: 'calendar', element: <Calendar /> }, { path: 'calendar', element: <Calendar /> },
{ path: 'beliefs', element: <Beliefs /> }, { path: 'beliefs', element: <Beliefs /> },
{ path: 'contact', element: <Contact /> }, { path: 'contact', element: <Contact /> },
@ -64,7 +62,7 @@ const router = createBrowserRouter([
// Initialize analytics after DOM is ready // Initialize analytics after DOM is ready
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
initAnalytics() initAnalytics()
// Initialize Google Analytics and GTM // Initialize Google Analytics and GTM
// Uncomment these lines and add your tracking IDs in analytics-config.js // Uncomment these lines and add your tracking IDs in analytics-config.js
// initGA() // initGA()

View File

@ -3,7 +3,7 @@ import { Helmet } from 'react-helmet-async'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import StaticMap from '../components/StaticMap' import StaticMap from '../components/StaticMap'
export default function About(){ export default function About() {
return ( return (
<> <>
<Helmet> <Helmet>
@ -60,7 +60,7 @@ export default function About(){
<div className="space-y-4"> <div className="space-y-4">
<div className="p-6 bg-sand/60 rounded-xl border border-subtle"> <div className="p-6 bg-sand/60 rounded-xl border border-subtle">
<p className="font-semibold text-ink">Sabbath School</p> <p className="font-semibold text-ink">Sabbath School</p>
<p className="text-sm text-muted">Saturdays at 9:30 AM</p> <p className="text-sm text-muted">Saturdays at 9:45 AM</p>
</div> </div>
<div className="p-6 bg-sand/60 rounded-xl border border-subtle"> <div className="p-6 bg-sand/60 rounded-xl border border-subtle">
<p className="font-semibold text-ink">Divine Worship</p> <p className="font-semibold text-ink">Divine Worship</p>

View File

@ -1,457 +1,232 @@
import React, { useState } from 'react' import React from 'react'
import { Helmet } from 'react-helmet-async' import { Helmet } from 'react-helmet-async'
export default function Contact() { export default function Contact() {
const [formData, setFormData] = useState({ return (
name: '', <>
email: '', <Helmet>
phone: '', <title>Contact Us - Annaville Seventh-day Adventist Church</title>
department: '', <meta name="description" content="Contact Annaville SDA Church in Corpus Christi, TX. Get in touch with our pastoral team, ministries, or general inquiries. We're here to help!" />
subject: '', <script type="application/ld+json">
message: '', {JSON.stringify({
preferredContact: 'email' "@context": "https://schema.org",
}) "@type": "Church",
"name": "Annaville Seventh-day Adventist Church",
"address": {
"@type": "PostalAddress",
"streetAddress": "2710 Violet Rd",
"addressLocality": "Corpus Christi",
"addressRegion": "TX",
"postalCode": "78410"
},
"telephone": "+1-361-241-5501",
"email": "info@annavillesda.org",
"url": "https://annavillesda.org",
"openingHours": "Sa 09:45-12:00",
"contactPoint": {
"@type": "ContactPoint",
"telephone": "+1-361-241-5501",
"contactType": "customer service",
"availableLanguage": "English"
}
})}
</script>
</Helmet>
const [isSubmitting, setIsSubmitting] = useState(false) {/* Hero Section */}
const [submitStatus, setSubmitStatus] = useState(null) <section className="relative bg-gradient-to-br from-sand to-surface py-24">
<div className="container">
<div className="max-w-4xl mx-auto text-center">
<h1 className="font-heading text-h1 mb-8">Get in Touch</h1>
<p className="text-body text-lg mb-10">
We'd love to hear from you! Whether you have questions, need prayer,
or want to get involved, we're here to help.
</p>
</div>
</div>
</section>
const departments = [ <section className="section">
{ value: '', label: 'Select a Department' }, <div className="container">
{ value: 'general', label: 'General Information', email: 'info@annavillesda.org' }, <div className="grid lg:grid-cols-2 gap-24">
{ value: 'pastor', label: 'Pastoral Care', email: 'pastor@annavillesda.org' },
{ value: 'youth', label: 'Youth Ministry', email: 'youth@annavillesda.org' },
{ value: 'children', label: 'Children\'s Ministry', email: 'children@annavillesda.org' },
{ value: 'outreach', label: 'Community Outreach', email: 'outreach@annavillesda.org' },
{ value: 'treasurer', label: 'Financial/Treasurer', email: 'treasurer@annavillesda.org' },
{ value: 'events', label: 'Events & Activities', email: 'events@annavillesda.org' },
{ value: 'prayer', label: 'Prayer Requests', email: 'prayer@annavillesda.org' }
]
const handleInputChange = (e) => { {/* Contact Information */}
const { name, value } = e.target <div className="space-y-16">
setFormData(prev => ({ <div>
...prev, <h2 className="font-heading text-h2 mb-10">Contact Information</h2>
[name]: value <div className="space-y-10">
})) <div className="flex items-start gap-4 p-6 bg-white border border-subtle rounded-lg">
} <div className="bg-primary/10 p-3 rounded-full">
<span className="text-primary text-2xl">📍</span>
</div>
<div>
<h3 className="font-heading text-h3 mb-2">Visit Us</h3>
<p className="text-body">
2710 Violet Rd<br />
Corpus Christi, TX 78410
</p>
<a
href="https://maps.google.com/?q=2710+Violet+Rd,+Corpus+Christi,+TX+78410"
className="text-primary hover:text-primaryHover transition-colors text-sm"
target="_blank"
rel="noreferrer"
>
Get Directions
</a>
</div>
</div>
const handleSubmit = async (e) => { <div className="flex items-start gap-4 p-6 bg-white border border-subtle rounded-lg">
e.preventDefault() <div className="bg-primary/10 p-3 rounded-full">
setIsSubmitting(true) <span className="text-primary text-2xl">📞</span>
</div>
// Simulate form submission <div>
setTimeout(() => { <h3 className="font-heading text-h3 mb-2">Call Us</h3>
setIsSubmitting(false) <p className="text-body">
setSubmitStatus('success') <a
setFormData({ href="tel:+13612415501"
name: '', className="text-primary hover:text-primaryHover transition-colors"
email: '', >
phone: '', (361) 241-5501
department: '', </a>
subject: '', </p>
message: '', <p className="text-muted text-sm">Available during office hours</p>
preferredContact: 'email' </div>
}) </div>
}, 2000)
}
const selectedDepartment = departments.find(dept => dept.value === formData.department) <div className="flex items-start gap-4 p-6 bg-white border border-subtle rounded-lg">
<div className="bg-primary/10 p-3 rounded-full">
<span className="text-primary text-2xl"></span>
</div>
<div>
<h3 className="font-heading text-h3 mb-2">Email Us</h3>
<p className="text-body">
<a
href="mailto:info@annavillesda.org"
className="text-primary hover:text-primaryHover transition-colors"
>
info@annavillesda.org
</a>
</p>
<p className="text-muted text-sm">We'll respond within 24 hours</p>
</div>
</div>
</div>
</div>
return ( {/* Service Times */}
<> <div className="p-6 bg-sand rounded-lg">
<Helmet> <h3 className="font-heading text-h3 mb-4">Service Times</h3>
<title>Contact Us - Annaville Seventh-day Adventist Church</title> <div className="space-y-2">
<meta name="description" content="Contact Annaville SDA Church in Corpus Christi, TX. Get in touch with our pastoral team, ministries, or general inquiries. We're here to help!" /> <div className="flex justify-between">
<script type="application/ld+json"> <span className="font-medium">Sabbath School:</span>
{JSON.stringify({ <span>9:45 AM</span>
"@context": "https://schema.org", </div>
"@type": "Church", <div className="flex justify-between">
"name": "Annaville Seventh-day Adventist Church", <span className="font-medium">Divine Worship:</span>
"address": { <span>11:00 AM</span>
"@type": "PostalAddress", </div>
"streetAddress": "2710 Violet Rd", <div className="flex justify-between">
"addressLocality": "Corpus Christi", <span className="font-medium">Office Hours:</span>
"addressRegion": "TX", <span>Mon-Fri 9AM-5PM</span>
"postalCode": "78410" </div>
}, </div>
"telephone": "+1-361-241-5501", </div>
"email": "info@annavillesda.org",
"url": "https://annavillesda.org",
"openingHours": "Sa 09:30-12:00",
"contactPoint": {
"@type": "ContactPoint",
"telephone": "+1-361-241-5501",
"contactType": "customer service",
"availableLanguage": "English"
}
})}
</script>
</Helmet>
{/* Hero Section */} {/* Map */}
<section className="relative bg-gradient-to-br from-sand to-surface py-24"> <div>
<div className="container"> <h3 className="font-heading text-h3 mb-4">Find Us</h3>
<div className="max-w-4xl mx-auto text-center"> <iframe
<h1 className="font-heading text-h1 mb-8">Get in Touch</h1> title="Map to Annaville Seventh-day Adventist Church"
<p className="text-body text-lg mb-10"> className="w-full h-64 rounded-lg border border-subtle"
We'd love to hear from you! Whether you have questions, need prayer, loading="lazy"
or want to get involved, we're here to help. src="https://www.google.com/maps?q=2710+Violet+Rd,+Corpus+Christi,+TX+78410&output=embed"
aria-label="Interactive map showing the location of Annaville Seventh-day Adventist Church"
/>
</div>
</div>
{/* Facebook Message */}
<div>
<h2 className="font-heading text-h2 mb-10">Send Us a Message</h2>
<div className="bg-white p-12 rounded-xl shadow-sm border border-subtle text-center space-y-8">
<div className="text-6xl mb-4">💬</div>
<h3 className="font-heading text-h3">Message Us on Facebook</h3>
<p className="text-body text-muted max-w-md mx-auto">
The best way to reach us is through Facebook Messenger.
Send us a message and we'll respond as soon as possible.
</p>
<a
href="https://www.facebook.com/p/Annaville-Seventh-Day-Adventist-Church-100064540276273/"
target="_blank"
rel="noreferrer"
className="btn inline-flex items-center gap-3 text-lg px-8 py-4"
>
<svg className="w-6 h-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" />
</svg>
Send Message on Facebook
</a>
<p className="text-sm text-muted">
You'll need to be logged into Facebook to send us a message
</p> </p>
</div> </div>
</div> </div>
</section> </div>
</div>
</section>
<section className="section"> {/* Discussion Forum Section */}
<div className="container"> <section className="section bg-sand">
<div className="grid lg:grid-cols-2 gap-24"> <div className="container">
<div className="max-w-4xl mx-auto">
{/* Contact Information */} <h2 className="font-heading text-h2 mb-8">Discussion</h2>
<div className="space-y-16">
<div>
<h2 className="font-heading text-h2 mb-10">Contact Information</h2>
<div className="space-y-10">
<div className="flex items-start gap-4 p-6 bg-white border border-subtle rounded-lg">
<div className="bg-primary/10 p-3 rounded-full">
<span className="text-primary text-2xl">📍</span>
</div>
<div>
<h3 className="font-heading text-h3 mb-2">Visit Us</h3>
<p className="text-body">
2710 Violet Rd<br />
Corpus Christi, TX 78410
</p>
<a
href="https://maps.google.com/?q=2710+Violet+Rd,+Corpus+Christi,+TX+78410"
className="text-primary hover:text-primaryHover transition-colors text-sm"
target="_blank"
rel="noreferrer"
>
Get Directions
</a>
</div>
</div>
<div className="flex items-start gap-4 p-6 bg-white border border-subtle rounded-lg"> <div className="max-w-2xl mx-auto">
<div className="bg-primary/10 p-3 rounded-full"> {/* Contents Section */}
<span className="text-primary text-2xl">📞</span> <div className="bg-white p-8 rounded-lg border border-subtle">
</div> <h3 className="font-heading text-h3 mb-6">CONTENTS</h3>
<div> <div className="space-y-3">
<h3 className="font-heading text-h3 mb-2">Call Us</h3> <div className="text-sm">
<p className="text-body"> <a href="#" className="text-primary hover:text-primaryHover font-medium">Jerry Stout</a>
<a <span className="text-muted ml-2">Elvin 27 Feb 2003</span>
href="tel:+13612415501"
className="text-primary hover:text-primaryHover transition-colors"
>
(361) 241-5501
</a>
</p>
<p className="text-muted text-sm">Available during office hours</p>
</div>
</div>
<div className="flex items-start gap-4 p-6 bg-white border border-subtle rounded-lg">
<div className="bg-primary/10 p-3 rounded-full">
<span className="text-primary text-2xl"></span>
</div>
<div>
<h3 className="font-heading text-h3 mb-2">Email Us</h3>
<p className="text-body">
<a
href="mailto:info@annavillesda.org"
className="text-primary hover:text-primaryHover transition-colors"
>
info@annavillesda.org
</a>
</p>
<p className="text-muted text-sm">We'll respond within 24 hours</p>
</div>
</div>
</div>
</div> </div>
<div className="text-sm ml-4">
{/* Service Times */} <a href="#" className="text-primary hover:text-primaryHover">Re: Jerry Stout</a>
<div className="p-6 bg-sand rounded-lg"> <span className="text-muted ml-2">Elvin 27 Feb 2003</span>
<h3 className="font-heading text-h3 mb-4">Service Times</h3>
<div className="space-y-2">
<div className="flex justify-between">
<span className="font-medium">Sabbath School:</span>
<span>9:30 AM</span>
</div>
<div className="flex justify-between">
<span className="font-medium">Divine Worship:</span>
<span>11:00 AM</span>
</div>
<div className="flex justify-between">
<span className="font-medium">Office Hours:</span>
<span>Mon-Fri 9AM-5PM</span>
</div>
</div>
</div> </div>
<div className="text-sm">
{/* Map */} <a href="#" className="text-primary hover:text-primaryHover font-medium">Shelly Family</a>
<div> <span className="text-muted ml-2">Elvin/Wallie 27 Feb 2003</span>
<h3 className="font-heading text-h3 mb-4">Find Us</h3>
<iframe
title="Map to Annaville Seventh-day Adventist Church"
className="w-full h-64 rounded-lg border border-subtle"
loading="lazy"
src="https://www.google.com/maps?q=2710+Violet+Rd,+Corpus+Christi,+TX+78410&output=embed"
aria-label="Interactive map showing the location of Annaville Seventh-day Adventist Church"
/>
</div> </div>
</div> <div className="text-sm">
<a href="#" className="text-primary hover:text-primaryHover font-medium">Bill & Pat</a>
{/* Contact Form */} <span className="text-muted ml-2">Scarboroughs 26 Feb 2003</span>
<div>
<h2 className="font-heading text-h2 mb-10">Send Us a Message</h2>
{submitStatus === 'success' && (
<div className="p-8 bg-green-50 border border-green-200 rounded-lg mb-10">
<p className="text-green-800">
Thank you! Your message has been sent successfully. We'll get back to you soon.
</p>
</div>
)}
<form onSubmit={handleSubmit} className="space-y-10">
<div className="grid md:grid-cols-2 gap-6">
<div>
<label htmlFor="name" className="block text-sm font-medium text-ink mb-3">
Full Name *
</label>
<input
id="name"
name="name"
type="text"
required
value={formData.name}
onChange={handleInputChange}
className="w-full border border-subtle rounded-lg px-5 py-4 focus:ring-2 focus:ring-primary focus:border-transparent transition-colors"
placeholder="Your full name"
aria-describedby="name-error"
/>
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium text-ink mb-3">
Email Address *
</label>
<input
id="email"
name="email"
type="email"
required
value={formData.email}
onChange={handleInputChange}
className="w-full border border-subtle rounded-lg px-5 py-4 focus:ring-2 focus:ring-primary focus:border-transparent transition-colors"
placeholder="your.email@example.com"
aria-describedby="email-error"
/>
</div>
</div>
<div>
<label htmlFor="phone" className="block text-sm font-medium text-ink mb-3">
Phone Number
</label>
<input
id="phone"
name="phone"
type="tel"
value={formData.phone}
onChange={handleInputChange}
className="w-full border border-subtle rounded-lg px-5 py-4 focus:ring-2 focus:ring-primary focus:border-transparent transition-colors"
placeholder="(361) 555-0123"
/>
</div>
<div>
<label htmlFor="department" className="block text-sm font-medium text-ink mb-3">
Department *
</label>
<select
id="department"
name="department"
required
value={formData.department}
onChange={handleInputChange}
className="w-full border border-subtle rounded-lg px-5 py-4 focus:ring-2 focus:ring-primary focus:border-transparent transition-colors"
>
{departments.map(dept => (
<option key={dept.value} value={dept.value}>
{dept.label}
</option>
))}
</select>
{selectedDepartment?.email && (
<p className="text-sm text-muted mt-2">
This will be sent to: {selectedDepartment.email}
</p>
)}
</div>
<div>
<label htmlFor="subject" className="block text-sm font-medium text-ink mb-3">
Subject *
</label>
<input
id="subject"
name="subject"
type="text"
required
value={formData.subject}
onChange={handleInputChange}
className="w-full border border-subtle rounded-lg px-5 py-4 focus:ring-2 focus:ring-primary focus:border-transparent transition-colors"
placeholder="Brief subject of your message"
/>
</div>
<div>
<label htmlFor="message" className="block text-sm font-medium text-ink mb-3">
Message *
</label>
<textarea
id="message"
name="message"
required
rows={6}
value={formData.message}
onChange={handleInputChange}
className="w-full border border-subtle rounded-lg px-5 py-4 focus:ring-2 focus:ring-primary focus:border-transparent transition-colors resize-vertical"
placeholder="Please share your message, question, or prayer request..."
aria-describedby="message-help"
/>
<p id="message-help" className="text-sm text-muted mt-2">
For prayer requests, please indicate if you'd like us to keep it confidential.
</p>
</div>
<div>
<fieldset>
<legend className="block text-sm font-medium text-ink mb-3">
Preferred Contact Method
</legend>
<div className="space-y-3">
<label className="flex items-center">
<input
type="radio"
name="preferredContact"
value="email"
checked={formData.preferredContact === 'email'}
onChange={handleInputChange}
className="mr-3"
/>
Email
</label>
<label className="flex items-center">
<input
type="radio"
name="preferredContact"
value="phone"
checked={formData.preferredContact === 'phone'}
onChange={handleInputChange}
className="mr-3"
/>
Phone
</label>
</div>
</fieldset>
</div>
<button
type="submit"
disabled={isSubmitting}
className="btn w-full py-5 disabled:opacity-50 disabled:cursor-not-allowed"
>
{isSubmitting ? 'Sending...' : 'Send Message'}
</button>
</form>
</div>
</div>
</div>
</section>
{/* Discussion Forum Section */}
<section className="section bg-sand">
<div className="container">
<div className="max-w-4xl mx-auto">
<h2 className="font-heading text-h2 mb-8">Discussion</h2>
<div className="grid lg:grid-cols-2 gap-12">
{/* Search Section */}
<div className="bg-white p-8 rounded-lg border border-subtle">
<h3 className="font-heading text-h3 mb-4">SEARCH FOR ARTICLE</h3>
<p className="text-body mb-6">
Find articles posted to this discussion containing matching words or patterns.
</p>
<form className="space-y-4">
<div>
<label htmlFor="search-term" className="block text-sm font-medium text-ink mb-2">
Search for:
</label>
<input
id="search-term"
type="text"
className="w-full border border-subtle rounded-lg px-4 py-3 focus:ring-2 focus:ring-primary focus:border-transparent transition-colors"
/>
</div>
<div className="flex gap-4">
<button type="submit" className="btn">
Start Search
</button>
<button type="reset" className="btn-outline">
Reset
</button>
</div>
</form>
<p className="text-sm text-muted mt-6">
Last changed: October 28, 2012
</p>
</div> </div>
<div className="text-sm ml-4">
{/* Contents Section */} <a href="#" className="text-primary hover:text-primaryHover">Bill & Pat</a>
<div className="bg-white p-8 rounded-lg border border-subtle"> <span className="text-muted ml-2">Elvin 27 Feb 2003</span>
<h3 className="font-heading text-h3 mb-6">CONTENTS</h3> </div>
<div className="space-y-3"> <div className="text-sm">
<div className="text-sm"> <a href="#" className="text-primary hover:text-primaryHover font-medium">Potluck</a>
<a href="#" className="text-primary hover:text-primaryHover font-medium">Jerry Stout</a> <span className="text-muted ml-2">Wallie 24 Feb 2003</span>
<span className="text-muted ml-2">Elvin 27 Feb 2003</span> </div>
</div> <div className="text-sm ml-4">
<div className="text-sm ml-4"> <a href="#" className="text-primary hover:text-primaryHover">Re: Potluck</a>
<a href="#" className="text-primary hover:text-primaryHover">Re: Jerry Stout</a> <span className="text-muted ml-2">bob 25 Feb 2003</span>
<span className="text-muted ml-2">Elvin 27 Feb 2003</span> </div>
</div> <div className="text-sm ml-4">
<div className="text-sm"> <a href="#" className="text-primary hover:text-primaryHover">Re: Potluck</a>
<a href="#" className="text-primary hover:text-primaryHover font-medium">Shelly Family</a> <span className="text-muted ml-2">bob 25 Feb 2003</span>
<span className="text-muted ml-2">Elvin/Wallie 27 Feb 2003</span>
</div>
<div className="text-sm">
<a href="#" className="text-primary hover:text-primaryHover font-medium">Bill & Pat</a>
<span className="text-muted ml-2">Scarboroughs 26 Feb 2003</span>
</div>
<div className="text-sm ml-4">
<a href="#" className="text-primary hover:text-primaryHover">Bill & Pat</a>
<span className="text-muted ml-2">Elvin 27 Feb 2003</span>
</div>
<div className="text-sm">
<a href="#" className="text-primary hover:text-primaryHover font-medium">Potluck</a>
<span className="text-muted ml-2">Wallie 24 Feb 2003</span>
</div>
<div className="text-sm ml-4">
<a href="#" className="text-primary hover:text-primaryHover">Re: Potluck</a>
<span className="text-muted ml-2">bob 25 Feb 2003</span>
</div>
<div className="text-sm ml-4">
<a href="#" className="text-primary hover:text-primaryHover">Re: Potluck</a>
<span className="text-muted ml-2">bob 25 Feb 2003</span>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</section> </div>
</> </div>
) </section>
} </>
)
}

View File

@ -4,7 +4,7 @@ import { Link } from 'react-router-dom'
import { EventCard } from '../components/Cards' import { EventCard } from '../components/Cards'
import { useEvents } from '../hooks/useEvents' import { useEvents } from '../hooks/useEvents'
const filters = ['All', 'This Month', 'Next Month', 'Family', 'Outreach'] const filters = ['All', 'This Month', 'Next Month']
function isSameMonth(dateStr, baseDate) { function isSameMonth(dateStr, baseDate) {
const date = new Date(dateStr) const date = new Date(dateStr)
@ -89,8 +89,6 @@ export default function Events() {
) )
const totalUpcoming = futureEvents.length const totalUpcoming = futureEvents.length
const familyCount = futureEvents.filter(event => (event.category || '').toLowerCase().includes('family')).length
const outreachCount = futureEvents.filter(event => (event.category || '').toLowerCase().includes('outreach')).length
const nextEventDate = nextEvent ? formatEventDate(nextEvent.date) : null const nextEventDate = nextEvent ? formatEventDate(nextEvent.date) : null
const nextEventTime = nextEvent ? formatEventTime(nextEvent.time) : null const nextEventTime = nextEvent ? formatEventTime(nextEvent.time) : null
@ -112,25 +110,13 @@ export default function Events() {
There is always something happening at Annaville SDA Church. Explore ways to worship, volunteer, There is always something happening at Annaville SDA Church. Explore ways to worship, volunteer,
and connect with families throughout the Corpus Christi community. and connect with families throughout the Corpus Christi community.
</p> </p>
<div className="grid gap-6 sm:grid-cols-3"> <div className="max-w-xs">
<div> <div>
<p className="font-heading text-display20 text-primary"> <p className="font-heading text-display20 text-primary">
{totalUpcoming} {totalUpcoming}
</p> </p>
<p className="text-muted text-sm">Upcoming gatherings</p> <p className="text-muted text-sm">Upcoming gatherings</p>
</div> </div>
<div>
<p className="font-heading text-display20 text-primary">
{familyCount}
</p>
<p className="text-muted text-sm">Family-focused events</p>
</div>
<div>
<p className="font-heading text-display20 text-primary">
{outreachCount}
</p>
<p className="text-muted text-sm">Community outreach</p>
</div>
</div> </div>
</div> </div>

View File

@ -2,8 +2,6 @@
import { Helmet } from 'react-helmet-async' import { Helmet } from 'react-helmet-async'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { TextHero } from '../components/Hero' import { TextHero } from '../components/Hero'
import VisitForm from '../components/VisitForm'
import StaticMap from '../components/StaticMap'
import { useEvents } from '../hooks/useEvents' import { useEvents } from '../hooks/useEvents'
function formatEventDate(dateStr, timeStr) { function formatEventDate(dateStr, timeStr) {
@ -117,17 +115,17 @@ export default function Home() {
<section id="service-times" aria-labelledby="stimes" className="section"> <section id="service-times" aria-labelledby="stimes" className="section">
<div className="container"> <div className="container">
<h2 id="stimes" className="sr-only">Service Times</h2> <h2 id="stimes" className="sr-only">Service Times</h2>
{/* Service Times Cards */} {/* Service Times Cards */}
<div className="grid md:grid-cols-2 gap-8 mb-16"> <div className="grid md:grid-cols-2 gap-8 mb-16">
<div className="bg-white p-8 rounded-xl shadow-sm border border-subtle"> <div className="bg-white p-8 rounded-xl shadow-sm border border-subtle">
<div className="text-center"> <div className="text-center">
<h3 className="font-heading text-h3 text-primary mb-4">Sabbath School</h3> <h3 className="font-heading text-h3 text-primary mb-4">Sabbath School</h3>
<div className="text-4xl font-bold text-ink mb-2">9:30 AM</div> <div className="text-4xl font-bold text-ink mb-2">9:45 AM</div>
<p className="text-body text-muted">Bible Study & Discussion</p> <p className="text-body text-muted">Bible Study & Discussion</p>
</div> </div>
</div> </div>
<div className="bg-white p-8 rounded-xl shadow-sm border border-subtle"> <div className="bg-white p-8 rounded-xl shadow-sm border border-subtle">
<div className="text-center"> <div className="text-center">
<h3 className="font-heading text-h3 text-primary mb-4">Divine Worship</h3> <h3 className="font-heading text-h3 text-primary mb-4">Divine Worship</h3>
@ -136,7 +134,7 @@ export default function Home() {
</div> </div>
</div> </div>
</div> </div>
{/* Potluck Fellowship Information */} {/* Potluck Fellowship Information */}
<div className="max-w-2xl mx-auto p-8 bg-sand rounded-xl text-center"> <div className="max-w-2xl mx-auto p-8 bg-sand rounded-xl text-center">
<h3 className="font-heading text-h3 mb-4 text-primary">Potluck Fellowship Dinner</h3> <h3 className="font-heading text-h3 mb-4 text-primary">Potluck Fellowship Dinner</h3>
@ -147,7 +145,7 @@ export default function Home() {
</div> </div>
</section> </section>
<section className="section bg-sand"> <section id="upcoming-events" className="section bg-sand">
<div className="container"> <div className="container">
<div className="text-center"> <div className="text-center">
<h2 className="font-heading text-h2 mb-8">Upcoming Events</h2> <h2 className="font-heading text-h2 mb-8">Upcoming Events</h2>
@ -186,25 +184,6 @@ export default function Home() {
</div> </div>
</div> </div>
</section> </section>
<section className="section">
<div className="container">
<div className="grid lg:grid-cols-2 gap-24 items-start">
<div>
<h2 className="font-heading text-h2 mb-12">Plan Your Visit</h2>
<p className="text-body mb-12">
We are located at 2710 Violet Road in Corpus Christi, Texas.
Click on the link below to see a map to our church location.
</p>
<VisitForm />
</div>
<div>
<h2 className="font-heading text-h2 mb-12">Location</h2>
<StaticMap />
</div>
</div>
</div>
</section>
</> </>
) )
} }

View File

@ -1,257 +0,0 @@
import React, { useState } from 'react'
import { Helmet } from 'react-helmet-async'
export default function PrayerRequests() {
const [formData, setFormData] = useState({
name: '',
email: '',
phone: '',
prayerType: '',
request: '',
isConfidential: false,
allowSharing: false
})
const [isSubmitted, setIsSubmitted] = useState(false)
const handleInputChange = (e) => {
const { name, value, type, checked } = e.target
setFormData(prev => ({
...prev,
[name]: type === 'checkbox' ? checked : value
}))
}
const handleSubmit = (e) => {
e.preventDefault()
// Here you would typically send the data to your backend
console.log('Prayer request submitted:', formData)
setIsSubmitted(true)
setFormData({
name: '',
email: '',
phone: '',
prayerType: '',
request: '',
isConfidential: false,
allowSharing: false
})
}
if (isSubmitted) {
return (
<>
<Helmet>
<title>Prayer Request Submitted - Annaville Seventh-day Adventist Church</title>
</Helmet>
<section className="bg-gradient-to-br from-green-500 to-green-600 text-white py-20">
<div className="container">
<div className="max-w-4xl mx-auto text-center">
<div className="text-6xl mb-6">🙏</div>
<h1 className="font-heading text-h1 mb-6">Prayer Request Received</h1>
<p className="text-xl text-white/90 leading-relaxed mb-8">
Thank you for sharing your prayer request with us. Our prayer team has been notified
and will be lifting you up in prayer.
</p>
<div className="bg-white/10 backdrop-blur-sm rounded-xl p-8 mb-8">
<h3 className="font-heading text-h3 mb-4">What happens next?</h3>
<ul className="text-left space-y-3 text-white/90">
<li className="flex items-center gap-3">
<span className="text-2xl">📝</span>
<span>Your request has been recorded in our prayer journal</span>
</li>
<li className="flex items-center gap-3">
<span className="text-2xl">🙏</span>
<span>Our prayer team will begin praying for you immediately</span>
</li>
<li className="flex items-center gap-3">
<span className="text-2xl">💌</span>
<span>You'll receive a confirmation email with additional resources</span>
</li>
<li className="flex items-center gap-3">
<span className="text-2xl">📞</span>
<span>If you requested follow-up, someone will contact you soon</span>
</li>
</ul>
</div>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<button
onClick={() => setIsSubmitted(false)}
className="btn bg-white text-green-600 hover:bg-gray-100"
>
Submit Another Request
</button>
<a href="/" className="btn-outline border-white text-white hover:bg-white hover:text-green-600">
Return Home
</a>
</div>
</div>
</div>
</section>
</>
)
}
return (
<>
<Helmet>
<title>Prayer Requests - Annaville Seventh-day Adventist Church</title>
<meta name="description" content="Submit your prayer requests to our caring community. We believe in the power of prayer and are here to support you in your time of need." />
<meta name="keywords" content="prayer requests, prayer support, spiritual care, Annaville SDA, prayer ministry" />
</Helmet>
{/* Hero Section */}
<section className="bg-gradient-to-br from-primary to-primaryDeep text-white py-20">
<div className="container">
<div className="max-w-4xl mx-auto text-center">
<div className="text-6xl mb-6">🙏</div>
<h1 className="font-heading text-h1 mb-6">Prayer Requests</h1>
<p className="text-xl text-white/90 leading-relaxed">
We believe in the power of prayer and the strength of community.
Share your prayer requests with us, and know that you are not alone.
</p>
</div>
</div>
</section>
{/* Prayer Request Form Section */}
<section className="section bg-sand">
<div className="container">
<div className="max-w-4xl mx-auto">
<div className="bg-white rounded-xl shadow-lg p-8 md:p-12">
<div className="text-center mb-12">
<h2 className="font-heading text-h2 mb-6">Share Your Prayer Request</h2>
<p className="text-body text-muted">
Your request will be shared with our prayer team. All information is kept confidential
unless you specifically allow us to share it with the congregation.
</p>
</div>
<form onSubmit={handleSubmit} className="space-y-8">
<div className="grid md:grid-cols-2 gap-6">
<div>
<label htmlFor="name" className="block text-sm font-medium text-ink mb-3">
Your Name *
</label>
<input
id="name"
name="name"
type="text"
required
value={formData.name}
onChange={handleInputChange}
className="w-full border border-subtle rounded-lg px-4 py-3 focus:ring-2 focus:ring-primary focus:border-transparent transition-colors"
placeholder="Enter your full name"
/>
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium text-ink mb-3">
Email Address *
</label>
<input
id="email"
name="email"
type="email"
required
value={formData.email}
onChange={handleInputChange}
className="w-full border border-subtle rounded-lg px-4 py-3 focus:ring-2 focus:ring-primary focus:border-transparent transition-colors"
placeholder="your.email@example.com"
/>
</div>
</div>
<div>
<label htmlFor="phone" className="block text-sm font-medium text-ink mb-3">
Phone Number (Optional)
</label>
<input
id="phone"
name="phone"
type="tel"
value={formData.phone}
onChange={handleInputChange}
className="w-full border border-subtle rounded-lg px-4 py-3 focus:ring-2 focus:ring-primary focus:border-transparent transition-colors"
placeholder="(555) 123-4567"
/>
</div>
<div>
<label htmlFor="request" className="block text-sm font-medium text-ink mb-3">
Your Prayer Request *
</label>
<textarea
id="request"
name="request"
rows="6"
required
value={formData.request}
onChange={handleInputChange}
className="w-full border border-subtle rounded-lg px-4 py-3 focus:ring-2 focus:ring-primary focus:border-transparent transition-colors"
placeholder="Please share your prayer request in detail. What would you like us to pray for?"
></textarea>
</div>
<div className="space-y-4">
<div className="flex items-start gap-3">
<input
id="isConfidential"
name="isConfidential"
type="checkbox"
checked={formData.isConfidential}
onChange={handleInputChange}
className="mt-1 h-4 w-4 text-primary focus:ring-primary border-subtle rounded"
/>
<label htmlFor="isConfidential" className="text-sm text-muted">
Keep this request confidential (only shared with prayer team)
</label>
</div>
<div className="flex items-start gap-3">
<input
id="allowSharing"
name="allowSharing"
type="checkbox"
checked={formData.allowSharing}
onChange={handleInputChange}
className="mt-1 h-4 w-4 text-primary focus:ring-primary border-subtle rounded"
/>
<label htmlFor="allowSharing" className="text-sm text-muted">
Allow us to share this request with the congregation (without personal details)
</label>
</div>
</div>
<div className="flex flex-col sm:flex-row gap-4 pt-6">
<button
type="submit"
className="btn flex-1"
>
Submit Prayer Request
</button>
<button
type="reset"
onClick={() => setFormData({
name: '',
email: '',
phone: '',
prayerType: '',
request: '',
isConfidential: false,
allowSharing: false
})}
className="btn-outline flex-1"
>
Reset Form
</button>
</div>
</form>
</div>
</div>
</div>
</section>
</>
)
}

View File

@ -1,13 +1,126 @@
import React from 'react' import React, { useEffect } from 'react'
import { Helmet } from 'react-helmet-async' import { Helmet } from 'react-helmet-async'
export default function PrivacyPolicy() { export default function PrivacyPolicy() {
useEffect(() => {
window.scrollTo(0, 0)
}, [])
return ( return (
<section className="section"> <section className="section">
<Helmet><title>Privacy Policy | Annaville SDA Church</title></Helmet> <Helmet><title>Privacy Policy | Annaville SDA Church</title></Helmet>
<div className="container"> <div className="container max-w-4xl">
<h1 className="font-heading text-display30 mb-4">Privacy Policy</h1> <h1 className="font-heading text-display30 mb-8">Privacy Policy</h1>
<p className='text-[16px]'>Privacy policy content placeholder.</p>
<div className="prose prose-lg max-w-none">
<p className="text-muted mb-6">
<em>Last updated: {new Date().toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' })}</em>
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Introduction</h2>
<p className="text-body mb-4">
Annaville Seventh-day Adventist Church ("we," "our," or "us") is committed to protecting your privacy.
This Privacy Policy explains how we collect, use, disclose, and safeguard your information when you visit
our website or interact with our services.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Information We Collect</h2>
<h3 className="font-heading text-h3 mt-6 mb-3">Personal Information</h3>
<p className="text-body mb-4">
We may collect personal information that you voluntarily provide to us when you:
</p>
<ul className="list-disc pl-6 mb-4 space-y-2">
<li>Fill out contact forms</li>
<li>Register for events or programs</li>
<li>Subscribe to our newsletter</li>
<li>Make online donations</li>
<li>Submit prayer requests</li>
</ul>
<p className="text-body mb-4">
This information may include your name, email address, phone number, mailing address, and any other
information you choose to provide.
</p>
<h3 className="font-heading text-h3 mt-6 mb-3">Automatically Collected Information</h3>
<p className="text-body mb-4">
When you visit our website, we may automatically collect certain information about your device, including
information about your web browser, IP address, time zone, and some of the cookies that are installed on
your device. This information is used to improve our website and user experience.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">How We Use Your Information</h2>
<p className="text-body mb-4">
We use the information we collect to:
</p>
<ul className="list-disc pl-6 mb-4 space-y-2">
<li>Respond to your inquiries and provide customer service</li>
<li>Send you information about church events, programs, and activities</li>
<li>Process your donations and send you receipts</li>
<li>Improve our website and services</li>
<li>Communicate with you about prayer requests and spiritual support</li>
<li>Comply with legal obligations</li>
</ul>
<h2 className="font-heading text-h2 mt-8 mb-4">Information Sharing</h2>
<p className="text-body mb-4">
We do not sell, trade, or rent your personal information to third parties. We may share your information only in the following circumstances:
</p>
<ul className="list-disc pl-6 mb-4 space-y-2">
<li>With your consent</li>
<li>With service providers who assist us in operating our website or conducting our church activities</li>
<li>To comply with legal obligations or respond to lawful requests</li>
<li>To protect the rights, property, or safety of our church, our members, or others</li>
</ul>
<h2 className="font-heading text-h2 mt-8 mb-4">Data Security</h2>
<p className="text-body mb-4">
We implement appropriate technical and organizational security measures to protect your personal information.
However, please note that no method of transmission over the Internet or electronic storage is 100% secure.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Your Rights</h2>
<p className="text-body mb-4">
You have the right to:
</p>
<ul className="list-disc pl-6 mb-4 space-y-2">
<li>Access the personal information we hold about you</li>
<li>Request correction of inaccurate information</li>
<li>Request deletion of your personal information</li>
<li>Opt-out of receiving communications from us</li>
<li>Withdraw consent where we rely on consent to process your information</li>
</ul>
<h2 className="font-heading text-h2 mt-8 mb-4">Children's Privacy</h2>
<p className="text-body mb-4">
Our website is not directed to children under the age of 13. We do not knowingly collect personal
information from children under 13. If you are a parent or guardian and believe we have collected
information from your child, please contact us.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Cookies</h2>
<p className="text-body mb-4">
We use cookies and similar tracking technologies to track activity on our website and hold certain information.
You can instruct your browser to refuse all cookies or to indicate when a cookie is being sent.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Changes to This Policy</h2>
<p className="text-body mb-4">
We may update this Privacy Policy from time to time. We will notify you of any changes by posting the new
Privacy Policy on this page and updating the "Last updated" date.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Contact Us</h2>
<p className="text-body mb-4">
If you have questions about this Privacy Policy or our privacy practices, please contact us:
</p>
<div className="bg-sand p-6 rounded-lg mb-8">
<p className="mb-2"><strong>Annaville Seventh-day Adventist Church</strong></p>
<p className="mb-2">2710 Violet Rd, Corpus Christi, TX 78410</p>
<p className="mb-2">Phone: <a href="tel:+13612415501" className="text-primary hover:underline">(361) 241-5501</a></p>
<p>Email: <a href="mailto:info@annavillesda.org" className="text-primary hover:underline">info@annavillesda.org</a></p>
</div>
</div>
</div> </div>
</section> </section>
) )

View File

@ -5,7 +5,7 @@ const services = [
{ {
title: 'Sabbath School', title: 'Sabbath School',
image: '/assets/family_entry.png', image: '/assets/family_entry.png',
time: '9:30 AM', time: '9:45 AM',
day: 'Saturday', day: 'Saturday',
description: 'Interactive Bible study and discussion groups for all ages. Join us for meaningful conversations about Scripture and practical Christian living.', description: 'Interactive Bible study and discussion groups for all ages. Join us for meaningful conversations about Scripture and practical Christian living.',
tagColor: 'bg-blue-100 text-blue-800' tagColor: 'bg-blue-100 text-blue-800'
@ -29,11 +29,6 @@ const services = [
] ]
const additionalInfo = [ const additionalInfo = [
{
title: 'Church Bus Service',
description: 'Transportation is available for those who need assistance getting to church. Please contact us to arrange pickup.',
icon: '🚌'
},
{ {
title: 'Family-Friendly Environment', title: 'Family-Friendly Environment',
description: 'Children are welcome in all our services. We also offer age-appropriate activities and care during worship times.', description: 'Children are welcome in all our services. We also offer age-appropriate activities and care during worship times.',
@ -46,7 +41,7 @@ const additionalInfo = [
} }
] ]
export default function Services(){ export default function Services() {
return ( return (
<> <>
<Helmet> <Helmet>
@ -147,7 +142,7 @@ export default function Services(){
</p> </p>
</div> </div>
<div className="grid md:grid-cols-3 gap-8"> <div className="grid md:grid-cols-2 gap-8 max-w-4xl mx-auto">
{additionalInfo.map(item => ( {additionalInfo.map(item => (
<div key={item.title} className="text-center"> <div key={item.title} className="text-center">
<div className="bg-white p-8 rounded-xl shadow-sm border border-subtle"> <div className="bg-white p-8 rounded-xl shadow-sm border border-subtle">

View File

@ -1,13 +1,141 @@
import React from 'react' import React, { useEffect } from 'react'
import { Helmet } from 'react-helmet-async' import { Helmet } from 'react-helmet-async'
export default function TermsofUse() { export default function TermsofUse() {
useEffect(() => {
window.scrollTo(0, 0)
}, [])
return ( return (
<section className="section"> <section className="section">
<Helmet><title>Terms of Use | Annaville SDA Church</title></Helmet> <Helmet><title>Terms of Use | Annaville SDA Church</title></Helmet>
<div className="container"> <div className="container max-w-4xl">
<h1 className="font-heading text-display30 mb-4">Terms of Use</h1> <h1 className="font-heading text-display30 mb-8">Terms of Use</h1>
<p className='text-[16px]'>Terms of use content placeholder.</p>
<div className="prose prose-lg max-w-none">
<p className="text-muted mb-6">
<em>Last updated: {new Date().toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' })}</em>
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Agreement to Terms</h2>
<p className="text-body mb-4">
By accessing and using the Annaville Seventh-day Adventist Church website ("Website"), you accept and agree
to be bound by the terms and provisions of this agreement. If you do not agree to abide by these Terms of Use,
please do not use this Website.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Use of Website</h2>
<p className="text-body mb-4">
This Website is provided for informational and ministry purposes. You may use the Website for lawful purposes
only. You agree not to use the Website:
</p>
<ul className="list-disc pl-6 mb-4 space-y-2">
<li>In any way that violates any applicable federal, state, local, or international law or regulation</li>
<li>To transmit any material that is unlawful, threatening, abusive, harassing, defamatory, vulgar, obscene, or otherwise objectionable</li>
<li>To impersonate or attempt to impersonate the church, a church employee, another user, or any other person or entity</li>
<li>To engage in any conduct that restricts or inhibits anyone's use or enjoyment of the Website</li>
<li>To introduce any viruses, trojan horses, worms, logic bombs, or other material that is malicious or technologically harmful</li>
</ul>
<h2 className="font-heading text-h2 mt-8 mb-4">Intellectual Property Rights</h2>
<p className="text-body mb-4">
The Website and its entire contents, features, and functionality (including but not limited to all information,
software, text, displays, images, video, and audio, and the design, selection, and arrangement thereof) are
owned by Annaville Seventh-day Adventist Church, its licensors, or other providers of such material and are
protected by United States and international copyright, trademark, patent, trade secret, and other intellectual
property or proprietary rights laws.
</p>
<p className="text-body mb-4">
You may view, download, and print pages from the Website for your personal, non-commercial use, subject to the
restrictions set out below and elsewhere in these Terms of Use:
</p>
<ul className="list-disc pl-6 mb-4 space-y-2">
<li>You must not modify copies of any materials from this Website</li>
<li>You must not use any illustrations, photographs, video or audio sequences, or any graphics separately from the accompanying text</li>
<li>You must not delete or alter any copyright, trademark, or other proprietary rights notices from copies of materials from this Website</li>
</ul>
<h2 className="font-heading text-h2 mt-8 mb-4">User Contributions</h2>
<p className="text-body mb-4">
The Website may contain features that allow users to post, submit, publish, display, or transmit content or
materials (collectively, "User Contributions") on or through the Website. All User Contributions must comply
with these Terms of Use.
</p>
<p className="text-body mb-4">
Any User Contribution you post to the Website will be considered non-confidential and non-proprietary. By
providing any User Contribution on the Website, you grant us the right to use, reproduce, modify, perform,
display, distribute, and otherwise disclose to third parties any such material for any purpose.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Donations</h2>
<p className="text-body mb-4">
Donations made through this Website are processed securely through third-party payment processors. All donations
are final and non-refundable unless otherwise required by law. Annaville Seventh-day Adventist Church is a
501(c)(3) nonprofit organization, and donations may be tax-deductible to the extent allowed by law.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Links to Third-Party Websites</h2>
<p className="text-body mb-4">
This Website may contain links to third-party websites or services that are not owned or controlled by
Annaville Seventh-day Adventist Church. We have no control over, and assume no responsibility for, the content,
privacy policies, or practices of any third-party websites or services. You acknowledge and agree that we shall
not be responsible or liable for any damage or loss caused by or in connection with the use of any such content,
goods, or services available on or through any such websites or services.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Disclaimer of Warranties</h2>
<p className="text-body mb-4">
The Website is provided on an "AS IS" and "AS AVAILABLE" basis. We make no representations or warranties of any
kind, express or implied, as to the operation of the Website or the information, content, materials, or products
included on the Website. You expressly agree that your use of the Website is at your sole risk.
</p>
<p className="text-body mb-4">
To the full extent permissible by applicable law, we disclaim all warranties, express or implied, including,
but not limited to, implied warranties of merchantability and fitness for a particular purpose.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Limitation of Liability</h2>
<p className="text-body mb-4">
In no event will Annaville Seventh-day Adventist Church, its officers, directors, employees, or agents be
liable to you or any third party for any direct, indirect, consequential, exemplary, incidental, special, or
punitive damages, including lost profit, lost revenue, loss of data, or other damages arising from your use of
the Website, even if we have been advised of the possibility of such damages.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Indemnification</h2>
<p className="text-body mb-4">
You agree to defend, indemnify, and hold harmless Annaville Seventh-day Adventist Church, its officers,
directors, employees, and agents from and against any claims, liabilities, damages, judgments, awards, losses,
costs, expenses, or fees (including reasonable attorneys' fees) arising out of or relating to your violation of
these Terms of Use or your use of the Website.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Governing Law</h2>
<p className="text-body mb-4">
These Terms of Use shall be governed by and construed in accordance with the laws of the State of Texas,
without regard to its conflict of law provisions. Any legal action or proceeding arising under these Terms of
Use will be brought exclusively in the federal or state courts located in Nueces County, Texas.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Changes to Terms</h2>
<p className="text-body mb-4">
We reserve the right to modify these Terms of Use at any time. We will notify you of any changes by posting
the new Terms of Use on this page and updating the "Last updated" date. Your continued use of the Website
following the posting of changes constitutes your acceptance of such changes.
</p>
<h2 className="font-heading text-h2 mt-8 mb-4">Contact Information</h2>
<p className="text-body mb-4">
If you have any questions about these Terms of Use, please contact us:
</p>
<div className="bg-sand p-6 rounded-lg mb-8">
<p className="mb-2"><strong>Annaville Seventh-day Adventist Church</strong></p>
<p className="mb-2">2710 Violet Rd, Corpus Christi, TX 78410</p>
<p className="mb-2">Phone: <a href="tel:+13612415501" className="text-primary hover:underline">(361) 241-5501</a></p>
<p>Email: <a href="mailto:info@annavillesda.org" className="text-primary hover:underline">info@annavillesda.org</a></p>
</div>
</div>
</div> </div>
</section> </section>
) )