From b93226ad6f947152bfa3e7814113d1d0bf409c61 Mon Sep 17 00:00:00 2001 From: Denshooter Date: Wed, 12 Feb 2025 17:18:22 +0100 Subject: [PATCH] fix: improve project data handling and sitemap generation Refactor project data parsing to ensure type safety by casting the project data as a string. Enhance the sitemap generation by fetching data from a dynamic API route, allowing for more accurate and up-to-date sitemap entries. Remove unused project markdown files to clean up the project structure. These changes improve code reliability and maintainability. --- app/Projects/[slug]/page.tsx | 50 ++++++----- app/api/sitemap/route.tsx | 68 ++++++++++++++ app/api/stats/route.ts | 29 ------ app/components/Projects.tsx | 8 +- app/sitemap.tsx | 67 +++++++++----- app/stats/page.tsx | 89 ------------------- .../projects/private/project-marie-dennis.md | 29 ------ public/projects/project-one.md | 41 --------- public/projects/project-three.md | 45 ---------- public/projects/project-two.md | 37 -------- 10 files changed, 146 insertions(+), 317 deletions(-) create mode 100644 app/api/sitemap/route.tsx delete mode 100644 app/api/stats/route.ts delete mode 100644 app/stats/page.tsx delete mode 100644 public/projects/private/project-marie-dennis.md delete mode 100644 public/projects/project-one.md delete mode 100644 public/projects/project-three.md delete mode 100644 public/projects/project-two.md diff --git a/app/Projects/[slug]/page.tsx b/app/Projects/[slug]/page.tsx index 86fcf0d..9724d06 100644 --- a/app/Projects/[slug]/page.tsx +++ b/app/Projects/[slug]/page.tsx @@ -43,11 +43,16 @@ const ProjectDetails = () => { useEffect(() => { const projectData = searchParams.get("project"); if (projectData) { - setProject(JSON.parse(projectData)); + setProject(JSON.parse(projectData as string)); // Remove the project data from the URL without reloading the page - const url = new URL(window.location.href); - url.searchParams.delete("project"); - window.history.replaceState({}, "", url.toString()); + // @ts-expect-error window is defined + if (typeof window !== "undefined") { + // @ts-expect-error window is defined + const url = new URL(window.location.href); + url.searchParams.delete("project"); + // @ts-expect-error window is defined + window.history.replaceState({}, "", url.toString()); + } } else { // Fetch project data based on slug from URL const slug = params.slug as string; @@ -61,8 +66,8 @@ const ProjectDetails = () => { if (!response.ok) { throw new Error("Failed to fetch project data"); } - const projectData = await response.json(); - setProject(projectData.posts[0]); // Assuming the API returns an array of posts + const projectData = (await response.json()) as { posts: Project[] }; + setProject(projectData.posts[0]); } catch (error) { console.error("Failed to fetch project data:", error); } @@ -80,7 +85,9 @@ const ProjectDetails = () => { ); } - const featureImageUrl = `/api/fetchImage?url=${encodeURIComponent(project.feature_image)}`; + const featureImageUrl = project.feature_image + ? `/api/fetchImage?url=${encodeURIComponent(project.feature_image)}` + : ""; return (
{ >
- {/* Hero Section */} -
-
- {" "} - {/* 16:9 Aspect Ratio */} - {project.title} -
+
+ {featureImageUrl && ( +
+ {project.title} +
+ )}
-

+

{project.title}

diff --git a/app/api/sitemap/route.tsx b/app/api/sitemap/route.tsx new file mode 100644 index 0000000..852e56a --- /dev/null +++ b/app/api/sitemap/route.tsx @@ -0,0 +1,68 @@ +import { NextResponse } from "next/server"; + +interface Project { + slug: string; +} + +interface ProjectsData { + posts: Project[]; +} + +interface SitemapRoute { + url: string; + lastModified: string; +} + +const baseUrl = "http://localhost:3000"; + +const generateSitemap = async (): Promise => { + try { + // Static pages + const staticRoutes: SitemapRoute[] = [ + { url: `${baseUrl}/`, lastModified: new Date().toISOString() }, + { + url: `${baseUrl}/privacy-policy`, + lastModified: new Date().toISOString(), + }, + { + url: `${baseUrl}/legal-notice`, + lastModified: new Date().toISOString(), + }, + ]; + + // Fetch project data from your API + console.log("Fetching project data from API..."); + const response = await fetch(`${baseUrl}/api/fetchAllProjects`); + if (!response.ok) { + throw new Error( + `Failed to fetch projects from Ghost: ${response.statusText}`, + ); + } + const projectsData = (await response.json()) as ProjectsData; + console.log("Fetched project data:", projectsData); + + // Generate dynamic routes for projects + const projectRoutes: SitemapRoute[] = projectsData.posts.map((project) => ({ + url: `${baseUrl}/projects/${project.slug}`, + lastModified: new Date().toISOString(), + })); + + return [...staticRoutes, ...projectRoutes]; + } catch (error) { + console.error("Error generating sitemap:", error); + throw error; + } +}; + +export async function GET() { + try { + const sitemap = await generateSitemap(); + return NextResponse.json(sitemap); + } catch (error) { + console.error("Failed to generate sitemap:", error); + return NextResponse.json( + { error: "Failed to generate sitemap" }, + { status: 500 }, + ); + } +} diff --git a/app/api/stats/route.ts b/app/api/stats/route.ts deleted file mode 100644 index 53c0869..0000000 --- a/app/api/stats/route.ts +++ /dev/null @@ -1,29 +0,0 @@ -// app/api/stats/route.tsx -import {NextResponse} from "next/server"; - -const stats = { - views: 0, - projectsViewed: {} as { [key: string]: number }, -}; - -export async function GET() { - return NextResponse.json(stats); -} - -export async function POST(request: Request) { - const {type, projectId} = await request.json(); - - if (type === "page_view") { - stats.views += 1; - } - - if (type === "project_view" && projectId) { - if (stats.projectsViewed[projectId]) { - stats.projectsViewed[projectId] += 1; - } else { - stats.projectsViewed[projectId] = 1; - } - } - - return NextResponse.json({message: "Stats updated", stats}); -} diff --git a/app/components/Projects.tsx b/app/components/Projects.tsx index 4c11c97..94290ed 100644 --- a/app/components/Projects.tsx +++ b/app/components/Projects.tsx @@ -14,6 +14,10 @@ interface Project { meta_description: string; } +interface ProjectsData { + posts: Project[]; +} + export default function Projects() { const [projects, setProjects] = useState([]); const [isVisible, setIsVisible] = useState(false); @@ -25,7 +29,7 @@ export default function Projects() { if (!response.ok) { throw new Error("Failed to fetch projects from Ghost"); } - const projectsData = await response.json(); + const projectsData = (await response.json()) as ProjectsData; setProjects(projectsData.posts); setTimeout(() => { @@ -52,7 +56,7 @@ export default function Projects() { { + const baseUrl = "http://localhost:3000"; - // Read project markdown files from the public folder - const projectsDirectory = path.join(process.cwd(), "public/projects"); - let projectRoutes: { url: string; lastModified: string; }[] = []; + // Fetch the sitemap data from the dynamic API route + const response = await fetch(`${baseUrl}/api/sitemap`); + if (!response.ok) { + throw new Error(`Failed to fetch sitemap: ${response.statusText}`); + } + const sitemapData = (await response.json()) as SitemapRoute[]; - if (fs.existsSync(projectsDirectory)) { - const projectFiles = fs.readdirSync(projectsDirectory).filter(file => file.endsWith(".md")); + return sitemapData.map((route) => { + let changeFrequency: SitemapRoute["changeFrequency"]; + let priority: number; - projectRoutes = projectFiles.map((file) => { - const slug = file.replace(".md", ""); - return { - url: `${baseUrl}/projects/${slug}`, - lastModified: new Date().toISOString(), - }; - }); + if (route.url === `${baseUrl}/`) { + changeFrequency = "weekly"; + priority = 1.0; + } else if (route.url.startsWith(`${baseUrl}/projects`)) { + changeFrequency = "monthly"; + priority = 0.8; + } else if (route.url.startsWith(`${baseUrl}/Blog`)) { + changeFrequency = "weekly"; + priority = 0.6; + } else { + changeFrequency = "monthly"; + priority = 0.5; } - return [...staticRoutes, ...projectRoutes]; + return { + url: route.url, + lastModified: route.lastModified, + changeFrequency, + priority, + }; + }); } diff --git a/app/stats/page.tsx b/app/stats/page.tsx deleted file mode 100644 index 75056bf..0000000 --- a/app/stats/page.tsx +++ /dev/null @@ -1,89 +0,0 @@ -"use client"; - -import { useState } from "react"; - -export default function StatsDashboard() { - const [authenticated, setAuthenticated] = useState(false); - const [password, setPassword] = useState(""); - const [stats, setStats] = useState<{ - views: number; - projectsViewed: Record; - } | null>(null); - const [error, setError] = useState(""); - - const handleLogin = () => { - // Simple password check. Replace with secure authentication. - if (password === "admin123") { - setAuthenticated(true); - fetchStats(); - } else { - setError("Incorrect password."); - } - }; - - const fetchStats = async () => { - try { - const res = await fetch("/api/stats"); - const data = await res.json(); - setStats(data); - } catch (err) { - console.error(err); - setError("Failed to fetch stats."); - } - }; - - if (!authenticated) { - return ( -
-
-

- Admin Login -

- {error &&

{error}

} - setPassword(e.target.value)} - /> - -
-
- ); - } - - return ( -
-

- Statistics Dashboard -

- {stats ? ( -
-

- Total Views: {stats.views} -

-

- Project Views: -

-
    - {Object.entries(stats.projectsViewed).map(([projectId, count]) => ( -
  • - Project ID {projectId}: {count} view{count !== 1 ? "s" : ""} -
  • - ))} -
-
- ) : ( -

- Loading statistics... -

- )} -
- ); -} diff --git a/public/projects/private/project-marie-dennis.md b/public/projects/private/project-marie-dennis.md deleted file mode 100644 index 9a9b898..0000000 --- a/public/projects/private/project-marie-dennis.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -id: "4" -title: "Project Marie/Dennis" -description: "Ein liebevolles Projekt über die gemeinsame Reise von Marie und Dennis." ---- - -# Project Marie/Dennis - -**Project Marie/Dennis** ist ein Herzensprojekt, das die tiefe Liebe zwischen Marie und Dennis feiert. Es dokumentiert -ihre schönsten gemeinsamen Erinnerungen, besondere Momente und die vielen kleinen Dinge, die ihre Beziehung -so einzigartig machen. - -## Unsere Liebesgeschichte - -Von den ersten Blicken bis zu den vielen gemeinsamen Abenteuern – Marie und Dennis verbindet eine besondere -Geschichte voller Liebe, Vertrauen und Zusammenhalt. In jeder Herausforderung haben sie sich gegenseitig unterstützt, -in jedem glücklichen Moment haben sie gemeinsam gelacht. - -## Besondere Erinnerungen - -- **Erstes Treffen** – Der magische Anfang einer wunderbaren Reise. -- **Gemeinsame Rituale** – Vom Adventskalender voller liebevoller Überraschungen bis zu alltäglichen kleinen Gesten. -- **Erfolgreiche Meilensteine** – Marie’s Abschlussarbeit, Dennis’ persönliche Entwicklungen und gemeinsame - Zukunftspläne. - -## Warum dieses Projekt? - -Es ist ein digitales Denkmal für eine wunderschöne Liebe – ein Ort voller Erinnerungen, voller Emotionen und voller -Dankbarkeit. Dieses Projekt wird wachsen, so wie die Liebe zwischen Marie und Dennis mit jedem Tag stärker wird. diff --git a/public/projects/project-one.md b/public/projects/project-one.md deleted file mode 100644 index fb72a19..0000000 --- a/public/projects/project-one.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -id: "1" -title: "AI-Powered Chatbot" -description: "An intelligent chatbot designed to enhance customer service through natural language processing." ---- - -# AI-Powered Chatbot - -The AI-Powered Chatbot is a sophisticated conversational agent designed to assist businesses in automating customer -interactions. Utilizing **Natural Language Processing (NLP)** and **Machine Learning (ML)**, it understands user queries -and responds appropriately. - -## Overview - -With the increasing demand for instant customer support, businesses are shifting towards AI-driven solutions to handle -customer interactions more efficiently. The AI-powered chatbot leverages state-of-the-art NLP techniques to process and -interpret customer messages, ensuring accurate and helpful responses. This chatbot is built to learn and adapt, refining -its accuracy with each conversation. - -Customer engagement is critical in today's digital landscape. A well-implemented chatbot improves user experience by -reducing response times, ensuring accurate assistance, and enabling businesses to provide 24/7 support. Whether used -in e-commerce, banking, healthcare, or IT services, the AI chatbot enhances operational efficiency while reducing costs. - -## Features - -- **Multi-language support**: Communicate with customers in various languages to break language barriers and - reach a global audience. -- **24/7 availability**: Always online to handle customer inquiries, ensuring businesses never miss a potential lead or - support request. -- **Integration with CRM**: Seamlessly connect with customer relationship management systems to provide personalized - and context-aware responses. -- **Sentiment analysis**: Detect customer emotions to tailor responses accordingly, improving user satisfaction. -- **Self-learning capabilities**: Uses machine learning to improve responses over time based on user interactions. -- **Secure authentication**: Ensures secure user verification, protecting sensitive customer data. - -## Use Cases - -- **E-commerce support**: Automate order tracking, refunds, and general customer inquiries. -- **Healthcare industry**: Assist patients with appointment scheduling and medical inquiries. -- **Financial services**: Provide instant banking support and transaction details. -- **IT helpdesk**: Troubleshoot user issues with automated responses and guided solutions. \ No newline at end of file diff --git a/public/projects/project-three.md b/public/projects/project-three.md deleted file mode 100644 index a1ea265..0000000 --- a/public/projects/project-three.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -id: "3" -title: "Smart IoT Home Automation System" -description: "An IoT-powered system to enhance home automation and energy efficiency." ---- - -# Smart IoT Home Automation System - -The Smart IoT Home Automation System is designed to provide convenience, security, and energy efficiency by -interconnecting household devices via the Internet of Things (IoT). Users can remotely monitor and control their homes -through a mobile app or voice commands. - -## Overview - -Smart home technology is rapidly transforming the way people interact with their living spaces. By integrating -IoT-enabled -devices, homeowners can automate routine tasks, enhance security, and optimize energy usage. This system connects -various smart devices, allowing seamless communication between them. - -With the rise of artificial intelligence and machine learning, smart home automation can now learn user preferences -and adjust device settings accordingly. This creates a highly personalized and efficient home environment that not only -offers convenience but also contributes to significant energy savings. - -## Features - -- **Voice and app control**: Operate devices via smartphone applications or virtual assistants like Alexa and Google - Assistant. -- **Energy management**: Optimize power consumption by monitoring and adjusting electricity usage, leading to reduced - energy bills. -- **Security integration**: Connect smart locks, cameras, and alarm systems to enhance home security. -- **Customizable automation**: Set schedules and rules for devices to function automatically based on user preferences. -- **Remote monitoring**: Check and control home appliances from anywhere using a mobile application. -- **Emergency alerts**: Receive real-time alerts in case of fire, gas leaks, or unauthorized access. -- **AI-driven automation**: Learn user habits and optimize home settings accordingly. - -## Use Cases - -- **Smart lighting**: Automatically adjust brightness based on time of day and room occupancy. -- **Home security**: Monitor security cameras, lock doors remotely, and receive alerts for unusual activity. -- **Climate control**: Adjust thermostats based on weather conditions and occupancy to maintain comfort and efficiency. -- **Elderly assistance**: Improve quality of life for seniors by automating tasks and ensuring their safety. -- **Energy efficiency**: Monitor and reduce power consumption dynamically based on usage patterns. - -This IoT-based system not only makes daily life easier but also contributes to a more sustainable future by ensuring -intelligent energy usage and minimizing waste. diff --git a/public/projects/project-two.md b/public/projects/project-two.md deleted file mode 100644 index c1b62dc..0000000 --- a/public/projects/project-two.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -id: "2" -title: "Blockchain-Based Voting System" -description: "A secure and transparent voting system leveraging blockchain technology." ---- - -# Blockchain-Based Voting System - -This project aims to revolutionize voting systems by leveraging **blockchain** to ensure security, transparency, and -immutability. The system enables safe and verifiable elections while preventing voter fraud and manipulation. - -## Overview - -Traditional voting systems are prone to various security risks such as hacking, ballot tampering, and voter fraud. -Blockchain technology offers a decentralized approach where every vote is securely recorded, making the process -transparent and tamper-proof. By eliminating the need for intermediaries, blockchain voting provides a direct, -cost-effective, -and highly secure method of conducting elections. - -The system ensures that each vote is unique, immutable, and instantly verifiable, thereby eliminating common voting -challenges such as multiple voting, unauthorized access, and discrepancies in counting. Voter anonymity is also -maintained through advanced cryptographic techniques, ensuring that privacy is never compromised. - -## Features - -- **Decentralized ledger**: Ensures tamper-proof voting records by storing votes on a distributed network. -- **Anonymous yet verifiable**: Protects voter privacy while ensuring authenticity through cryptographic verification. -- **Smart contracts**: Automates vote counting and validation, reducing the risk of human error. -- **Public auditing**: Allows independent parties to audit election results without compromising voter anonymity. -- **Remote voting**: Enables secure voting from anywhere, increasing accessibility and voter participation. -- **Immutable transactions**: Once recorded, votes cannot be altered, ensuring trust and fairness. - -## Use Cases - -- **National elections**: Ensure transparency and security in presidential and parliamentary elections. -- **Corporate voting**: Facilitate decision-making in organizations and shareholder meetings. -- **University elections**: Implement secure and transparent voting systems for student bodies. \ No newline at end of file