diff --git a/docker-compose.yml b/docker-compose.yml
index dce8137..e624a1d 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -7,9 +7,15 @@ services:
- "3040:3000" # Kannst du später sogar löschen, wenn es nur noch über Caddy laufen soll
environment:
- NODE_ENV=production
+ - SES_SMTP_HOST=${SES_SMTP_HOST:-email-smtp.us-east-2.amazonaws.com}
+ - SES_SMTP_PORT=${SES_SMTP_PORT:-587}
+ - SES_SMTP_USER=${SES_SMTP_USER}
+ - SES_SMTP_PASS=${SES_SMTP_PASS}
+ - SES_FROM_EMAIL=${SES_FROM_EMAIL:-website@buddelectric.net}
+ - SES_TO_EMAIL=${SES_TO_EMAIL:-buddelectric@grandecom.net}
networks:
- bizmatch # <-- NEU: Container ins selbe Netz wie Caddy hängen
networks: # <-- NEU: Netzwerk deklarieren
bizmatch:
- external: true
\ No newline at end of file
+ external: true
diff --git a/package-lock.json b/package-lock.json
index 2c5ed31..a54d9c2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,12 +10,14 @@
"dependencies": {
"lucide-react": "^0.563.0",
"next": "16.1.6",
+ "nodemailer": "^9.0.1",
"react": "19.2.3",
"react-dom": "19.2.3"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
+ "@types/nodemailer": "^8.0.1",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
@@ -1556,6 +1558,16 @@
"undici-types": "~6.21.0"
}
},
+ "node_modules/@types/nodemailer": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-8.0.1.tgz",
+ "integrity": "sha512-PxpaInm8V1JQDd4j0ds5HfvWQk8JupS1C0Picb96QJsrrRDjBH+DlK7L4ZdNSqNULhiZRQHc40nLVShaGxXAMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/react": {
"version": "19.2.13",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.13.tgz",
@@ -5046,6 +5058,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/nodemailer": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-9.0.1.tgz",
+ "integrity": "sha512-Gwv8SQewT616ZM/URn0H54b8PWo/Wum7md3EW2aWy1lO27+WZCX+Xyak3J+NlmHUjDh5ME+uesJUDRbR3Ye8Bw==",
+ "license": "MIT-0",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
diff --git a/package.json b/package.json
index 3eec582..77893fd 100644
--- a/package.json
+++ b/package.json
@@ -11,12 +11,14 @@
"dependencies": {
"lucide-react": "^0.563.0",
"next": "16.1.6",
+ "nodemailer": "^9.0.1",
"react": "19.2.3",
"react-dom": "19.2.3"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
+ "@types/nodemailer": "^8.0.1",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
diff --git a/public/images/newspaper.webp b/public/images/newspaper.webp
new file mode 100644
index 0000000..8144aa1
Binary files /dev/null and b/public/images/newspaper.webp differ
diff --git a/src/app/about-us/page.tsx b/src/app/about-us/page.tsx
index a39ae7e..b4d8f04 100644
--- a/src/app/about-us/page.tsx
+++ b/src/app/about-us/page.tsx
@@ -1,7 +1,8 @@
-import { Shield, CheckCircle2, Award, Clock } from "lucide-react";
+import { Shield, Award, Clock } from "lucide-react";
import Link from "next/link";
import Image from "next/image";
import { Metadata } from "next";
+import NewspaperClipping from "@/components/NewspaperClipping";
export const metadata: Metadata = {
title: "About Budd Electric Co. | Family-Owned Since 1969",
@@ -37,18 +38,8 @@ export default function AboutUs() {
Who We Are
Three Generations of Excellence
@@ -65,13 +56,13 @@ export default function AboutUs() {
1969
Established
-
- 3rd Gen
- Master Electricians
-
+
+ 3rd Gen
+ Master Electricians
+
-
+
diff --git a/src/app/api/contact/route.ts b/src/app/api/contact/route.ts
new file mode 100644
index 0000000..30cb40a
--- /dev/null
+++ b/src/app/api/contact/route.ts
@@ -0,0 +1,79 @@
+import { NextRequest, NextResponse } from "next/server";
+import nodemailer from "nodemailer";
+
+export async function POST(request: NextRequest) {
+ try {
+ const body = await request.json();
+ const { firstName, lastName, email, phone, serviceType, message } = body;
+
+ if (!firstName || typeof firstName !== "string" || firstName.trim().length === 0) {
+ return NextResponse.json({ error: "First name is required." }, { status: 400 });
+ }
+ if (!lastName || typeof lastName !== "string" || lastName.trim().length === 0) {
+ return NextResponse.json({ error: "Last name is required." }, { status: 400 });
+ }
+ if (!email || typeof email !== "string" || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
+ return NextResponse.json({ error: "A valid email address is required." }, { status: 400 });
+ }
+ if (!phone || typeof phone !== "string" || phone.trim().length === 0) {
+ return NextResponse.json({ error: "Phone number is required." }, { status: 400 });
+ }
+ if (!serviceType || typeof serviceType !== "string" || serviceType.trim().length === 0) {
+ return NextResponse.json({ error: "Please select a service type." }, { status: 400 });
+ }
+ if (!message || typeof message !== "string" || message.trim().length === 0) {
+ return NextResponse.json({ error: "Message is required." }, { status: 400 });
+ }
+
+ const smtpHost = process.env.SES_SMTP_HOST || "email-smtp.us-east-2.amazonaws.com";
+ const smtpPort = parseInt(process.env.SES_SMTP_PORT || "587", 10);
+ const smtpUser = process.env.SES_SMTP_USER;
+ const smtpPass = process.env.SES_SMTP_PASS;
+ const fromEmail = process.env.SES_FROM_EMAIL || "website@buddelectric.net";
+ const toEmail = process.env.SES_TO_EMAIL || "buddelectric@grandecom.net";
+
+ if (!smtpUser || !smtpPass) {
+ return NextResponse.json({ error: "Email service is not configured." }, { status: 500 });
+ }
+
+ const transporter = nodemailer.createTransport({
+ host: smtpHost,
+ port: smtpPort,
+ secure: false,
+ auth: {
+ user: smtpUser,
+ pass: smtpPass,
+ },
+ });
+
+ const serviceTypeLabels: Record = {
+ residential: "Residential Service",
+ commercial: "Commercial Project",
+ generator: "Generator Quote",
+ other: "Other",
+ };
+
+ const htmlBody = `
+ New Contact Form Submission
+
+ Name ${firstName} ${lastName}
+ Email ${email}
+ Phone ${phone}
+ Service Type ${serviceTypeLabels[serviceType] || serviceType}
+ Message ${message}
+
+ `;
+
+ await transporter.sendMail({
+ from: fromEmail,
+ to: toEmail,
+ replyTo: email,
+ subject: `New Contact Form Submission from ${firstName} ${lastName}`,
+ html: htmlBody,
+ });
+
+ return NextResponse.json({ success: true }, { status: 200 });
+ } catch {
+ return NextResponse.json({ error: "Failed to send your message. Please try again or call us directly." }, { status: 500 });
+ }
+}
diff --git a/src/app/contact-us/page.tsx b/src/app/contact-us/page.tsx
index 4d42425..2154d37 100644
--- a/src/app/contact-us/page.tsx
+++ b/src/app/contact-us/page.tsx
@@ -1,6 +1,7 @@
-import { MapPin, Phone, Mail, Clock } from "lucide-react";
-import { Metadata } from "next";
-import Image from "next/image";
+import { MapPin, Phone, Mail, Clock } from "lucide-react";
+import { Metadata } from "next";
+import Image from "next/image";
+import ContactForm from "@/components/ContactForm";
export const metadata: Metadata = {
title: "Contact Budd Electric Co. | Corpus Christi Electrician",
@@ -99,41 +100,7 @@ export default function Contact() {
{/* FORM */}
diff --git a/src/app/electrical-services/page.tsx b/src/app/electrical-services/page.tsx
index e8984d6..7127e0a 100644
--- a/src/app/electrical-services/page.tsx
+++ b/src/app/electrical-services/page.tsx
@@ -1,12 +1,12 @@
-import { Home, Phone, Zap, Factory } from "lucide-react";
+import { Home, Zap, Building2 } from "lucide-react";
import Link from "next/link";
import Image from "next/image";
import { ArrowRight } from "lucide-react";
import { Metadata } from "next";
export const metadata: Metadata = {
- title: "Electrical Services Corpus Christi | Residential & Commercial",
- description: "Professional residential, commercial, and industrial electrical services in Corpus Christi, TX. Licensed electricians for all your electrical needs. Call (361) 855-2255.",
+ title: "Electrical Services Corpus Christi | Commercial & Residential",
+ description: "Professional commercial and residential electrical services in Corpus Christi, TX. Licensed electricians for all your electrical needs. Call (361) 855-2255.",
};
export default function Services() {
@@ -28,7 +28,7 @@ export default function Services() {
Electrical Services
- Comprehensive solutions for every need. Residential, Commercial, and Industrial.
+ Comprehensive solutions for every need. Commercial and Residential electrical services.
@@ -36,15 +36,79 @@ export default function Services() {
{/* SERVICE LIST */}
+ {/* COMMERCIAL */}
+
+
+
+
+
+
Commercial & Residential Electrical Remodels
+
+ We are your wiring, lighting and electrical service upgrade specialists in Corpus Christi and all of South Texas. We have encountered all the standard common electrical problems and have the experience, knowledge, skill, and expertise to solve them all. Our electrical repair expertise includes faulty outlets, panel reinstallation, meter replacement, new lighting fixtures, and adding circuits to your fuse box. Call Budd Electric Co. for a complimentary electrical repair consultation or free quote at (361) 855-2255.
+
+
+ {["Commercial & Residential", "Complete Electrical Service Upgrades", "Electrical Repairs"].map((item, i) => (
+
+
+ {item}
+
+ ))}
+
+
+
+
+
+
+
+ {/* GENERATORS */}
+
+
+
+
+
+
+
+
+
Kohler Generators
+
+ Don't be left in the dark during a storm. As an authorized Kohler dealer, we sell, install, and service standby generators to keep your power on when the grid goes down.
+
+
+ {["Sales & Consultation", "Professional Installation", "Maintenance Plans", "Warranty Service", "Transfer Switch Install"].map((item, i) => (
+
+
+ {item}
+
+ ))}
+
+
+
+
{/* RESIDENTIAL */}
-
+
Residential Services
- Your home is your sanctuary. We ensure it's powered safely and efficiently. From simple outlet repairs to full-home rewiring, no job is too small or too complex.
+ Your home is your sanctuary. We ensure it's powered safely and efficiently. From simple outlet repairs to full-home rewiring, no job is too small or too complex.
{["Service Upgrades", "Safety Inspections", "Lighting Installation", "Ceiling Fans", "Outlet Repair", "Panel Replacement"].map((item, i) => (
@@ -56,83 +120,19 @@ export default function Services() {
-
-
-
-
- {/* COMMERCIAL */}
-
-
-
-
-
-
-
-
-
Commercial & Industrial
-
- Keep your business running smoothly with our expert commercial services. We handle everything from new construction build-outs to ongoing maintenance contracts.
-
-
- {["New Construction Wiring", "Tenant Build-outs", "Parking Lot Lighting", "Emergency Lighting", "Data Cabling", "Troubleshooting"].map((item, i) => (
-
-
- {item}
-
- ))}
-
-
-
-
- {/* GENERATORS */}
-
-
-
-
-
-
Kohler Generators
-
- Don't be left in the dark during a storm. As an authorized Kohler dealer, we sell, install, and service standby generators to keep your power on when the grid goes down.
-
-
- {["Sales & Consultation", "Professional Installation", "Maintenance Plans", "Warranty Service", "Transfer Switch Install"].map((item, i) => (
-
-
- {item}
-
- ))}
-
-
-
-
+
-
+
{/* CTA */}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index f6dce27..71d8e4c 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,6 +1,6 @@
import Link from "next/link";
import Image from "next/image";
-import { ArrowRight, Zap, Shield, Home as HomeIcon, Factory, HardHat, CheckCircle2, Star, Clock, MapPin, Phone } from "lucide-react";
+import { ArrowRight, Zap, Shield, Home as HomeIcon, Building2, CheckCircle2, Star, Clock, MapPin, Phone } from "lucide-react";
import ReviewCarousel from "@/components/ReviewCarousel";
import HeroCarousel from "@/components/HeroCarousel";
import FAQSection from "@/components/FAQSection";
@@ -56,16 +56,12 @@ export default function Home() {
-
-
-
- Licensed & Insured
-
-
-
- 24/7 Emergency Support
-
-
+
+
+
+ Licensed & Insured
+
+
@@ -94,31 +90,31 @@ export default function Home() {
-
Residential
+
Residential Services
Complete home electrical services including safety inspections, repairs, lighting, and fan installations.
-
Residential Services
+
Residential Services
- {/* Card 2 */}
-
-
-
-
-
-
-
-
-
-
Commercial
-
- Reliable power for your business. New construction, maintenance, and industrial-grade solutions.
-
-
Commercial Services
-
-
+ {/* Card 2 */}
+
+
+
+
+
+
+
+
+
+
Commercial & Residential Electrical Remodels
+
+ Commercial & residential electrical remodels, wiring, lighting, and service upgrades for Corpus Christi and South Texas.
+
+
Commercial Services
+
+
{/* Card 3 */}
@@ -127,11 +123,11 @@ export default function Home() {
-
Generators
+
Kohler Generators
Authorized Kohler dealer. Keep your lights on when the grid goes down with standby power.
-
Generator Services
+
Kohler Generator Services
diff --git a/src/components/ContactForm.tsx b/src/components/ContactForm.tsx
new file mode 100644
index 0000000..670d0d4
--- /dev/null
+++ b/src/components/ContactForm.tsx
@@ -0,0 +1,95 @@
+"use client";
+
+import { useState } from "react";
+
+export default function ContactForm() {
+ const [formData, setFormData] = useState({
+ firstName: "",
+ lastName: "",
+ email: "",
+ phone: "",
+ serviceType: "",
+ message: "",
+ });
+ const [status, setStatus] = useState<"idle" | "loading" | "success" | "error">("idle");
+ const [statusMessage, setStatusMessage] = useState("");
+
+ const handleChange = (e: React.ChangeEvent) => {
+ setFormData((prev) => ({ ...prev, [e.target.name]: e.target.value }));
+ };
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setStatus("loading");
+ setStatusMessage("");
+
+ try {
+ const res = await fetch("/api/contact", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(formData),
+ });
+ const data = await res.json();
+
+ if (res.ok) {
+ setStatus("success");
+ setStatusMessage("Thank you! Your message has been sent. We'll get back to you shortly.");
+ setFormData({ firstName: "", lastName: "", email: "", phone: "", serviceType: "", message: "" });
+ } else {
+ setStatus("error");
+ setStatusMessage(data.error || "Something went wrong. Please try again.");
+ }
+ } catch {
+ setStatus("error");
+ setStatusMessage("Network error. Please check your connection and try again.");
+ }
+ };
+
+ return (
+
+
+
+ Email
+
+
+
+ Phone
+
+
+
+ Service Type
+
+ Select a service type
+ Commercial Project
+ Residential Service
+ Generator Quote
+ Other
+
+
+
+ Message
+
+
+
+ {status === "success" && (
+ {statusMessage}
+ )}
+ {status === "error" && (
+ {statusMessage}
+ )}
+
+
+ {status === "loading" ? "Sending..." : "Send Message"}
+
+
+ );
+}
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 314c39f..15aafa4 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -45,7 +45,7 @@ export default function Header() {
href="/contact-us"
className="hidden lg:flex items-center gap-2 rounded bg-[color:var(--brand)] px-5 py-2.5 text-sm font-bold text-white shadow-lg shadow-red-900/20 transition hover:bg-[color:var(--brand-strong)] uppercase tracking-wider"
>
- Free Quote
+ Contact Us
setMobileMenuOpen(false)}
className="flex items-center justify-center gap-2 rounded bg-[color:var(--brand)] px-7 py-4 text-sm font-bold text-white shadow-lg shadow-red-900/20 transition hover:bg-[color:var(--brand-strong)] hover:shadow-red-900/40 uppercase tracking-wider w-full"
>
- Get a Quote
+ Contact Us
diff --git a/src/components/NewspaperClipping.tsx b/src/components/NewspaperClipping.tsx
new file mode 100644
index 0000000..fcab9a0
--- /dev/null
+++ b/src/components/NewspaperClipping.tsx
@@ -0,0 +1,74 @@
+"use client";
+
+import { useState, useEffect, useCallback } from "react";
+import Image from "next/image";
+import { X } from "lucide-react";
+
+export default function NewspaperClipping() {
+ const [open, setOpen] = useState(false);
+
+ const close = useCallback(() => setOpen(false), []);
+
+ useEffect(() => {
+ if (!open) return;
+ const handleKey = (e: KeyboardEvent) => {
+ if (e.key === "Escape") close();
+ };
+ document.addEventListener("keydown", handleKey);
+ document.body.style.overflow = "hidden";
+ return () => {
+ document.removeEventListener("keydown", handleKey);
+ document.body.style.overflow = "";
+ };
+ }, [open, close]);
+
+ return (
+ <>
+ setOpen(true)}
+ >
+
+
+ Click to enlarge
+
+
+ Featured in the local press
+
+ {open && (
+
+
+
+
+
e.stopPropagation()}
+ >
+
+
+
+ )}
+ >
+ );
+}