d-branch-2 (#18)
* ✨ refactor: streamline sitemap generation and contact form logic * ✨ refactor: update sendEmail function to handle JSON data
This commit is contained in:
@@ -7,7 +7,12 @@ import dotenv from "dotenv";
|
|||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
export async function POST(request: NextRequest) {
|
export async function POST(request: NextRequest) {
|
||||||
const { email, name, message } = await request.json();
|
const body = (await request.json()) as {
|
||||||
|
email: string;
|
||||||
|
name: string;
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
const { email, name, message } = body;
|
||||||
|
|
||||||
const user = process.env.MY_EMAIL ?? "";
|
const user = process.env.MY_EMAIL ?? "";
|
||||||
const pass = process.env.MY_PASSWORD ?? "";
|
const pass = process.env.MY_PASSWORD ?? "";
|
||||||
@@ -38,7 +43,7 @@ export async function POST(request: NextRequest) {
|
|||||||
from: user,
|
from: user,
|
||||||
to: user, // Ensure this is the correct email address
|
to: user, // Ensure this is the correct email address
|
||||||
subject: `Message from ${name} (${email})`,
|
subject: `Message from ${name} (${email})`,
|
||||||
text: message + `\n\nSent from ${email}`,
|
text: message + "\n\n" + email,
|
||||||
};
|
};
|
||||||
|
|
||||||
const sendMailPromise = () =>
|
const sendMailPromise = () =>
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ interface SitemapRoute {
|
|||||||
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "https://dki.one";
|
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || "https://dki.one";
|
||||||
|
|
||||||
const generateSitemap = async (): Promise<SitemapRoute[]> => {
|
const generateSitemap = async (): Promise<SitemapRoute[]> => {
|
||||||
try {
|
|
||||||
// Static pages
|
// Static pages
|
||||||
const staticRoutes: SitemapRoute[] = [
|
const staticRoutes: SitemapRoute[] = [
|
||||||
{ url: `${baseUrl}/`, lastModified: new Date().toISOString() },
|
{ url: `${baseUrl}/`, lastModified: new Date().toISOString() },
|
||||||
@@ -31,26 +30,7 @@ const generateSitemap = async (): Promise<SitemapRoute[]> => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Check if running in build environment
|
try {
|
||||||
if (process.env.IS_BUILD) {
|
|
||||||
console.log("Running in build mode - using mock data");
|
|
||||||
const mockProjectsData: ProjectsData = {
|
|
||||||
posts: [
|
|
||||||
{ slug: "project-1" },
|
|
||||||
{ slug: "project-2" },
|
|
||||||
{ slug: "project-3" },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
const projectRoutes: SitemapRoute[] = mockProjectsData.posts.map(
|
|
||||||
(project) => ({
|
|
||||||
url: `${baseUrl}/projects/${project.slug}`,
|
|
||||||
lastModified: new Date().toISOString(),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return [...staticRoutes, ...projectRoutes];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch project data from API
|
|
||||||
console.log("Fetching project data from API...");
|
console.log("Fetching project data from API...");
|
||||||
const response = await fetch(`${baseUrl}/api/fetchAllProjects`, {
|
const response = await fetch(`${baseUrl}/api/fetchAllProjects`, {
|
||||||
headers: { "Cache-Control": "no-cache" },
|
headers: { "Cache-Control": "no-cache" },
|
||||||
@@ -58,13 +38,13 @@ const generateSitemap = async (): Promise<SitemapRoute[]> => {
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
console.error(`Failed to fetch projects: ${response.statusText}`);
|
console.error(`Failed to fetch projects: ${response.statusText}`);
|
||||||
return staticRoutes; // Return static pages instead of throwing an error
|
return staticRoutes; // Fallback auf statische Seiten
|
||||||
}
|
}
|
||||||
|
|
||||||
const projectsData = (await response.json()) as ProjectsData;
|
const projectsData = (await response.json()) as ProjectsData;
|
||||||
console.log("Fetched project data:", projectsData);
|
console.log("Fetched project data:", projectsData);
|
||||||
|
|
||||||
// Generate dynamic routes for projects
|
// Dynamische Projekt-Routen generieren
|
||||||
const projectRoutes: SitemapRoute[] = projectsData.posts.map((project) => ({
|
const projectRoutes: SitemapRoute[] = projectsData.posts.map((project) => ({
|
||||||
url: `${baseUrl}/projects/${project.slug}`,
|
url: `${baseUrl}/projects/${project.slug}`,
|
||||||
lastModified: project.updated_at
|
lastModified: project.updated_at
|
||||||
@@ -75,7 +55,7 @@ const generateSitemap = async (): Promise<SitemapRoute[]> => {
|
|||||||
return [...staticRoutes, ...projectRoutes];
|
return [...staticRoutes, ...projectRoutes];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to generate sitemap:", error);
|
console.error("Failed to generate sitemap:", error);
|
||||||
return staticRoutes; // Return static pages in case of failure
|
return staticRoutes; // Fallback nur auf statische Seiten
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
import React, {useEffect, useState} from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import {sendEmail} from "@/app/utils/send-email";
|
import { sendEmail } from "@/app/utils/send-email";
|
||||||
|
|
||||||
export type FormData = {
|
export type ContactFormData = {
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
message: string;
|
message: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default function Contact() {
|
export default function Contact() {
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
const [banner, setBanner] = useState<{ show: boolean, message: string, type: 'success' | 'error' }>({
|
const [banner, setBanner] = useState<{
|
||||||
|
show: boolean;
|
||||||
|
message: string;
|
||||||
|
type: "success" | "error";
|
||||||
|
}>({
|
||||||
show: false,
|
show: false,
|
||||||
message: '',
|
message: "",
|
||||||
type: 'success'
|
type: "success",
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -23,32 +27,47 @@ export default function Contact() {
|
|||||||
|
|
||||||
async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
|
async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const form = e.currentTarget;
|
|
||||||
const data: FormData = {
|
const form = e.currentTarget as HTMLFormElement;
|
||||||
name: (form.elements.namedItem('name') as HTMLInputElement).value,
|
const formData = new FormData(form);
|
||||||
email: (form.elements.namedItem('email') as HTMLInputElement).value,
|
|
||||||
message: (form.elements.namedItem('message') as HTMLTextAreaElement).value,
|
const data: ContactFormData = {
|
||||||
|
name: formData.get("name") as string,
|
||||||
|
email: formData.get("email") as string,
|
||||||
|
message: formData.get("message") as string,
|
||||||
};
|
};
|
||||||
const response = await sendEmail(data);
|
|
||||||
|
// Convert FormData to a plain object
|
||||||
|
const jsonData = JSON.stringify(data);
|
||||||
|
|
||||||
|
const response = await sendEmail(jsonData);
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
form.reset();
|
form.reset();
|
||||||
}
|
}
|
||||||
setBanner({show: true, message: response.message, type: response.success ? 'success' : 'error'});
|
|
||||||
|
setBanner({
|
||||||
|
show: true,
|
||||||
|
message: response.message,
|
||||||
|
type: response.success ? "success" : "error",
|
||||||
|
});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setBanner({...banner, show: false});
|
setBanner((prev) => ({ ...prev, show: false }));
|
||||||
}, 3000); // Hide banner after 3 seconds
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section id="contact" className={`p-10 ${isVisible ? 'animate-fly-in' : 'opacity-0'}`}>
|
<section
|
||||||
|
id="contact"
|
||||||
|
className={`p-10 ${isVisible ? "animate-fly-in" : "opacity-0"}`}
|
||||||
|
>
|
||||||
<h2 className="text-3xl font-bold text-center text-gray-800 dark:text-white">
|
<h2 className="text-3xl font-bold text-center text-gray-800 dark:text-white">
|
||||||
Contact Me
|
Contact Me
|
||||||
</h2>
|
</h2>
|
||||||
<div
|
<div className="flex flex-col items-center p-8 bg-gradient-to-br from-white/60 to-white/30 backdrop-blur-lg rounded-2xl shadow-xl max-w-lg mx-auto mt-6 relative">
|
||||||
className="flex flex-col items-center p-8 bg-gradient-to-br from-white/60 to-white/30 backdrop-blur-lg rounded-2xl shadow-xl max-w-lg mx-auto mt-6 relative">
|
|
||||||
{banner.show && (
|
{banner.show && (
|
||||||
<div
|
<div
|
||||||
className={`absolute top-0 left-0 right-0 text-white text-center py-2 rounded-2xl animate-fade-out ${banner.type === 'success' ? 'bg-green-500' : 'bg-red-500'}`}>
|
className={`absolute top-0 left-0 right-0 text-white text-center py-2 rounded-2xl animate-fade-out ${banner.type === "success" ? "bg-green-500" : "bg-red-500"}`}
|
||||||
|
>
|
||||||
{banner.message}
|
{banner.message}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
import {FormData} from "@/app/components/Contact";
|
export function sendEmail(
|
||||||
|
data: string,
|
||||||
export function sendEmail(data: FormData): Promise<{ success: boolean, message: string }> {
|
): Promise<{ success: boolean; message: string }> {
|
||||||
const apiEndpoint = '/api/email';
|
const apiEndpoint = "/api/email";
|
||||||
|
|
||||||
return fetch(apiEndpoint, {
|
return fetch(apiEndpoint, {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
body: JSON.stringify(data),
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: data,
|
||||||
})
|
})
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
return {success: true, message: response.message};
|
return { success: true, message: response.message };
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
return {success: false, message: err.message};
|
return { success: false, message: err.message };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user