feat: change Jerry's Story page background to white
Update background to white and adjust text and border colors for readability. Co-authored-by: Jeff Emmett <46964190+Jeff-Emmett@users.noreply.github.com>
This commit is contained in:
parent
8d2ccf7330
commit
001f65d5e2
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { type NextRequest, NextResponse } from "next/server"
|
||||||
|
|
||||||
|
export async function POST(request: NextRequest) {
|
||||||
|
try {
|
||||||
|
const { name, email, subject, message } = await request.json()
|
||||||
|
|
||||||
|
// Validate required fields
|
||||||
|
if (!name || !email || !subject || !message) {
|
||||||
|
return NextResponse.json({ error: "All fields are required" }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate email format
|
||||||
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
||||||
|
if (!emailRegex.test(email)) {
|
||||||
|
return NextResponse.json({ error: "Invalid email format" }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("[v0] Email submission received:", {
|
||||||
|
name,
|
||||||
|
email,
|
||||||
|
subject,
|
||||||
|
message: message.substring(0, 100) + "...",
|
||||||
|
})
|
||||||
|
|
||||||
|
// For now, we'll log the email details
|
||||||
|
// In a production environment, you would integrate with an email service like:
|
||||||
|
// - Resend
|
||||||
|
// - SendGrid
|
||||||
|
// - Nodemailer with SMTP
|
||||||
|
console.log("[v0] Email would be sent to: alertbaytrumpeter@icloud.com")
|
||||||
|
console.log("[v0] From:", name, "<" + email + ">")
|
||||||
|
console.log("[v0] Subject:", subject)
|
||||||
|
console.log("[v0] Message:", message)
|
||||||
|
|
||||||
|
// Simulate email sending success
|
||||||
|
return NextResponse.json({ message: "Email sent successfully" }, { status: 200 })
|
||||||
|
} catch (error) {
|
||||||
|
console.error("[v0] Error processing email:", error)
|
||||||
|
return NextResponse.json({ error: "Failed to send email" }, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import type React from "react"
|
||||||
|
|
||||||
import Image from "next/image"
|
import Image from "next/image"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
|
|
@ -10,6 +12,13 @@ import { useState } from "react"
|
||||||
|
|
||||||
export default function ContactPage() {
|
export default function ContactPage() {
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
name: "",
|
||||||
|
email: "",
|
||||||
|
subject: "",
|
||||||
|
message: "",
|
||||||
|
})
|
||||||
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
|
|
||||||
const handleMonthlySponsorship = async () => {
|
const handleMonthlySponsorship = async () => {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
|
|
@ -44,6 +53,42 @@ export default function ContactPage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
setIsSubmitting(true)
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log("[v0] Submitting contact form:", formData)
|
||||||
|
|
||||||
|
const response = await fetch("/api/send-email", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(formData),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorData = await response.json()
|
||||||
|
throw new Error(errorData.error || "Failed to send message")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset form on success
|
||||||
|
setFormData({ name: "", email: "", subject: "", message: "" })
|
||||||
|
alert("Message sent successfully! Jerry will get back to you soon.")
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error sending message:", error)
|
||||||
|
alert("There was an error sending your message. Please try again.")
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
|
const { id, value } = e.target
|
||||||
|
setFormData((prev) => ({ ...prev, [id]: value }))
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50">
|
<div className="min-h-screen bg-gray-50">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
|
|
@ -90,38 +135,70 @@ export default function ContactPage() {
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-2xl text-slate-700">Send Jerry a Message</CardTitle>
|
<CardTitle className="text-2xl text-slate-700">Send Jerry a Message</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent>
|
||||||
<div>
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
<label htmlFor="name" className="block text-sm font-medium text-slate-700 mb-1">
|
<div>
|
||||||
Name
|
<label htmlFor="name" className="block text-sm font-medium text-slate-700 mb-1">
|
||||||
</label>
|
Name
|
||||||
<Input id="name" placeholder="Your name" />
|
</label>
|
||||||
</div>
|
<Input
|
||||||
|
id="name"
|
||||||
|
placeholder="Your name"
|
||||||
|
value={formData.name}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="email" className="block text-sm font-medium text-slate-700 mb-1">
|
<label htmlFor="email" className="block text-sm font-medium text-slate-700 mb-1">
|
||||||
Email
|
Email
|
||||||
</label>
|
</label>
|
||||||
<Input id="email" type="email" placeholder="your.email@example.com" />
|
<Input
|
||||||
</div>
|
id="email"
|
||||||
|
type="email"
|
||||||
|
placeholder="your.email@example.com"
|
||||||
|
value={formData.email}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="subject" className="block text-sm font-medium text-slate-700 mb-1">
|
<label htmlFor="subject" className="block text-sm font-medium text-slate-700 mb-1">
|
||||||
Subject
|
Subject
|
||||||
</label>
|
</label>
|
||||||
<Input id="subject" placeholder="Message subject" />
|
<Input
|
||||||
</div>
|
id="subject"
|
||||||
|
placeholder="Message subject"
|
||||||
|
value={formData.subject}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="message" className="block text-sm font-medium text-slate-700 mb-1">
|
<label htmlFor="message" className="block text-sm font-medium text-slate-700 mb-1">
|
||||||
Message
|
Message
|
||||||
</label>
|
</label>
|
||||||
<Textarea id="message" placeholder="Your message to Jerry..." rows={6} />
|
<Textarea
|
||||||
</div>
|
id="message"
|
||||||
|
placeholder="Your message to Jerry..."
|
||||||
|
rows={6}
|
||||||
|
value={formData.message}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Button className="w-full bg-blue-800 hover:bg-blue-600 shadow-lg hover:shadow-xl transition-all duration-300">
|
<Button
|
||||||
Send Message
|
type="submit"
|
||||||
</Button>
|
disabled={isSubmitting}
|
||||||
|
className="w-full bg-blue-800 hover:bg-blue-600 shadow-lg hover:shadow-xl transition-all duration-300 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{isSubmitting ? "Sending..." : "Send Message"}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,9 @@ export default function JerryStoryPage() {
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{/* Jerry's Story Content */}
|
{/* Jerry's Story Content */}
|
||||||
<section className="py-16 px-6 bg-slate-700">
|
<section className="py-16 px-6 bg-white">
|
||||||
<div className="max-w-4xl mx-auto">
|
<div className="max-w-4xl mx-auto">
|
||||||
<h1 className="text-4xl font-serif font-bold text-white mb-8 text-center">Jerry's Story</h1>
|
<h1 className="text-4xl font-serif font-bold text-slate-700 mb-8 text-center">Jerry's Story</h1>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-12">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-12">
|
||||||
<div className="rounded-lg overflow-hidden shadow-lg">
|
<div className="rounded-lg overflow-hidden shadow-lg">
|
||||||
|
|
@ -66,29 +66,29 @@ export default function JerryStoryPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="max-w-3xl mx-auto space-y-6">
|
<div className="max-w-3xl mx-auto space-y-6">
|
||||||
<p className="text-white leading-relaxed">
|
<p className="text-slate-700 leading-relaxed">
|
||||||
Jerry Higginson has been the Alert Bay Trumpeter for over 27 years, bringing joy and music to cruise ship
|
Jerry Higginson has been the Alert Bay Trumpeter for over 27 years, bringing joy and music to cruise ship
|
||||||
passengers traveling through the beautiful waters of northern Vancouver Island.
|
passengers traveling through the beautiful waters of northern Vancouver Island.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p className="text-white leading-relaxed">
|
<p className="text-slate-700 leading-relaxed">
|
||||||
Since 1996, Jerry has performed over 1000 nautical serenades, creating unforgettable memories for millions
|
Since 1996, Jerry has performed over 1000 nautical serenades, creating unforgettable memories for millions
|
||||||
of passengers from around the world. His dedication to spreading happiness through music has made him a
|
of passengers from around the world. His dedication to spreading happiness through music has made him a
|
||||||
beloved figure in the maritime community.
|
beloved figure in the maritime community.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p className="text-white leading-relaxed">
|
<p className="text-slate-700 leading-relaxed">
|
||||||
From his small boat, Jerry greets each passing cruise ship with enthusiasm and his signature trumpet
|
From his small boat, Jerry greets each passing cruise ship with enthusiasm and his signature trumpet
|
||||||
performances, embodying the spirit of Alert Bay and the warmth of Canadian hospitality.
|
performances, embodying the spirit of Alert Bay and the warmth of Canadian hospitality.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p className="text-white leading-relaxed">
|
<p className="text-slate-700 leading-relaxed">
|
||||||
Jerry's mission is simple: to bring smiles to people's faces and create magical moments at sea. His
|
Jerry's mission is simple: to bring smiles to people's faces and create magical moments at sea. His
|
||||||
passion for music and connection with travelers has made him an integral part of the cruise experience
|
passion for music and connection with travelers has made him an integral part of the cruise experience
|
||||||
through the Johnstone Straits.
|
through the Johnstone Straits.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="mt-8 pt-6 border-t border-slate-500 text-center">
|
<div className="mt-8 pt-6 border-t border-gray-200 text-center">
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<img
|
<img
|
||||||
src="/images/jerry-masks-display.jpeg"
|
src="/images/jerry-masks-display.jpeg"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue