diff --git a/package-lock.json b/package-lock.json index 73cec81..8c0aae3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,8 @@ "@astrojs/node": "^11.0.2", "@astrojs/sitemap": "^3.7.3", "astro": "^7.1.4", - "dotenv": "^17.4.2" + "dotenv": "^17.4.2", + "resend": "^6.22.0" }, "engines": { "node": ">=22.12.0" @@ -1903,6 +1904,12 @@ "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", "license": "MIT" }, + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", + "license": "MIT" + }, "node_modules/@tybys/wasm-util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", @@ -2630,6 +2637,12 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "license": "Unlicense" + }, "node_modules/fast-string-truncated-width": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", @@ -3629,6 +3642,12 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/postal-mime": { + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/postal-mime/-/postal-mime-2.7.5.tgz", + "integrity": "sha512-GNEXKvWFQnbgO5NlrGzVa0FmWzBZ24PersAWErttSg1Hjpf0ATxTwS5DOMGaOpTG6bUh5cTr7xi0jAD942wCJA==", + "license": "MIT-0" + }, "node_modules/postcss": { "version": "8.5.23", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz", @@ -3741,6 +3760,27 @@ "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", "license": "MIT" }, + "node_modules/resend": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/resend/-/resend-6.22.0.tgz", + "integrity": "sha512-dP1jyl0n1Dx7GYDb0bcsbv9Yx0oBRLhUtSyNFRIOsSzV9MvCVbua/3WP6YUP2JptAU5BciEWGInV+hFjUuYLUw==", + "license": "MIT", + "dependencies": { + "postal-mime": "2.7.5", + "standardwebhooks": "1.0.0" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@react-email/render": "*" + }, + "peerDependenciesMeta": { + "@react-email/render": { + "optional": true + } + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -4005,6 +4045,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/standardwebhooks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz", + "integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==", + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "fast-sha256": "^1.3.0" + } + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", diff --git a/package.json b/package.json index fe43ac9..2619d46 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@astrojs/node": "^11.0.2", "@astrojs/sitemap": "^3.7.3", "astro": "^7.1.4", - "dotenv": "^17.4.2" + "dotenv": "^17.4.2", + "resend": "^6.22.0" } } diff --git a/src/components/Header.astro b/src/components/Header.astro index 0d12057..36373bd 100644 --- a/src/components/Header.astro +++ b/src/components/Header.astro @@ -34,6 +34,7 @@ const projects = [ + Contact About diff --git a/src/pages/about.astro b/src/pages/about.astro index cd8d8cb..4386270 100644 --- a/src/pages/about.astro +++ b/src/pages/about.astro @@ -10,7 +10,7 @@ import noelleImage2 from '../assets/images/brand-package/noelle-paris2.jpg';
-

About Noelle

+

Noelle Paris, MA, Realtor®

Design for Well-Being, Inside & Out

diff --git a/src/pages/api/send-message.ts b/src/pages/api/send-message.ts new file mode 100644 index 0000000..aa40b00 --- /dev/null +++ b/src/pages/api/send-message.ts @@ -0,0 +1,39 @@ +import type { APIRoute } from 'astro'; +import { Resend } from 'resend'; + +const resend = new Resend(import.meta.env.RESEND_API_KEY); + +export const POST: APIRoute = async ({ request }) => { + try { + const data = await request.json(); + const { name, email, phone, message } = data; + + if (!name || !email || !message) { + return new Response( + JSON.stringify({ message: 'Missing required fields' }), + { status: 400, headers: { 'Content-Type': 'application/json' } } + ); + } + + // Send email via Resend + await resend.emails.send({ + from: 'Noelle Paris Design Contact Form ', // Update to your domain once verified in Resend + //to: 'github@juchatz.com', + to: 'inquiries@noelleparisdesign.com', + replyTo: email, + subject: `New Inquiry from ${name}`, + text: `Name: ${name}\nEmail: ${email}\nPhone: ${phone || 'N/A'}\n\nMessage:\n${message}`, + }); + + return new Response( + JSON.stringify({ message: 'Message sent successfully' }), + { status: 200, headers: { 'Content-Type': 'application/json' } } + ); + } catch (error) { + console.error('Email error:', error); + return new Response( + JSON.stringify({ message: 'Error sending email' }), + { status: 500, headers: { 'Content-Type': 'application/json' } } + ); + } +}; diff --git a/src/pages/contact.astro b/src/pages/contact.astro new file mode 100644 index 0000000..cebb850 --- /dev/null +++ b/src/pages/contact.astro @@ -0,0 +1,194 @@ +--- +import Layout from '../layouts/Layout.astro'; +--- + + +
+
+

Contact

+

Let's discuss your project

+
+ +
+
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +

+
+
+
+
+ + + +