Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: refactor to more modular components #3

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
.env
100 changes: 2 additions & 98 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,101 +1,5 @@
import Image from "next/image";

export default function Home() {
export default async function Home() {
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
<Image
className="dark:invert"
src="https://nextjs.org/icons/next.svg"
alt="Next.js logo"
width={180}
height={38}
priority
/>
<ol className="list-inside list-decimal text-sm text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
<li className="mb-2">
Get started by editing{" "}
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-semibold">
app/page.tsx
</code>
.
</li>
<li>Save and see your changes instantly.</li>
</ol>

<div className="flex gap-4 items-center flex-col sm:flex-row">
<a
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="https://nextjs.org/icons/vercel.svg"
alt="Vercel logomark"
width={20}
height={20}
/>
Deploy now
</a>
<a
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Read our docs
</a>
</div>
</main>
<footer className="row-start-3 flex gap-6 flex-wrap items-center justify-center">
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="https://nextjs.org/icons/file.svg"
alt="File icon"
width={16}
height={16}
/>
Learn
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="https://nextjs.org/icons/window.svg"
alt="Window icon"
width={16}
height={16}
/>
Examples
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="https://nextjs.org/icons/globe.svg"
alt="Globe icon"
width={16}
height={16}
/>
Go to nextjs.org →
</a>
</footer>
</div>
<div className="bg-red-700">Home</div>
);
}
18 changes: 18 additions & 0 deletions components/AliasRedirect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useEffect } from "react";
import { useRouter } from "next/router";

interface AliasRedirectProps {
redirectUrl: string | null
}

export const AliasRedirect = ({ redirectUrl }: AliasRedirectProps) => {
const router = useRouter()

useEffect(() => {
if (redirectUrl) {
router.push(redirectUrl)
}
}, [redirectUrl])

return null
}
24 changes: 24 additions & 0 deletions components/Breadcrumbs.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Link from "next/link";

export default function Breadcrumbs({ breadcrumbs }) {
if (!breadcrumbs || breadcrumbs.length === 0) {
return null
}

return (
<nav aria-label="breadcrumb" className="mb-4 bg-red-400">
<ol className="flex list-none space-x-2">
{breadcrumbs.map((item, index) => (
<li key={index} className="flex items-center text-blue-300">
<Link href={item.url}>
{item.label}
</Link>
{index < breadcrumbs.length - 1 && (
<span className="mx-2 text-gray-500">/</span>
)}
</li>
))}
</ol>
</nav>
);
}
18 changes: 18 additions & 0 deletions components/DynamicComponent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import dynamic from "next/dynamic";

const components = {
node: dynamic(() => import('./Node')),
'node-article-full': dynamic(() => import('./NodeArticleFull')),
'layout-section': dynamic(() => import('./LayoutSection')),
'teaser-list': dynamic(() => import('./TeaserList')),
};

export default function DynamicComponent({ element, content }) {
const ComponentToRender = components[element];

if (!ComponentToRender) {
return <div>Component "{element}" not found</div>;
}

return <ComponentToRender content={content} />;
}
12 changes: 12 additions & 0 deletions components/LayoutSection.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import DynamicComponent from "./DynamicComponent";

export default function LayoutSection({ content }) {
return (
<div>
<h2>{content.settings.label || 'Section'}</h2>
{content.content.map((childElement, index) => (
<DynamicComponent key={index} element={childElement.element} content={childElement} />
))}
</div>
);
}
11 changes: 11 additions & 0 deletions components/Node.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import DynamicComponent from "./DynamicComponent";

export default function Node({ content }) {
return (
<div>
{content.sections.map((section, index) => (
<DynamicComponent key={index} element={section.element} content={section} />
))}
</div>
);
}
9 changes: 9 additions & 0 deletions components/NodeArticleFull.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default function NodeArticleFull({ content }) {
const { title, uid} = content
return (
<div>
<p>Title: {title}</p>
<span>node id: {uid}</span>
</div>
)
}
24 changes: 24 additions & 0 deletions components/NodePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Breadcrumbs from "./Breadcrumbs";
import DynamicComponent from "./DynamicComponent";

interface NodePageProps {
nodeData: {
breadcrumbs: [],
title: string,
content: {
element: string
}
}
}

export const NodePage = ({ nodeData }: NodePageProps) => {
if (!nodeData) return <div>No data found</div>

return (
<div>
<Breadcrumbs breadcrumbs={nodeData.breadcrumbs} />
<h1>{nodeData.title}</h1>
<DynamicComponent element={nodeData.content.element} content={nodeData.content} />
</div>
)
}
14 changes: 14 additions & 0 deletions components/TeaserList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export default function TeaserList({ content }) {
return (
<div>
{content.teasers.map((teaser) => (
<div key={teaser.title}>
<a href={teaser.href}>
<img src={teaser.image.src} alt={teaser.image.alt} />
<h3>{teaser.title}</h3>
</a>
</div>
))}
</div>
);
}
7 changes: 7 additions & 0 deletions components/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import dynamic from "next/dynamic";

const components = {
'node-article-full': dynamic(() => import('./NodeArticleFull')),
};

export default components;
2 changes: 2 additions & 0 deletions hooks/useDrupal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { useState, useEffect } from "react"
import { fetchPage, fetchMenu } from "../lib/drupalClient"
43 changes: 43 additions & 0 deletions lib/drupalClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import axios from "axios"

const drupalBaseUrl = process.env.NEXT_PUBLIC_DRUPAL_BASE_URL;
const ceApiEndpoint = '/ce-api'
import { mockData, mockData2, redirectMockData } from "../mockData"

const drupalClient = axios.create({
baseURL: `${drupalBaseUrl}${ceApiEndpoint}`,
withCredentials: true
});

export async function fetchMenu() {
try {
const response = await drupalClient.get('/api/menu_items/main');
return response.data;
} catch (error) {
console.error('Failed to fetch menu:', error);
throw error;
}
}

export async function fetchPage(nodeId: string) {
try {
const response = await drupalClient.get(`node/${nodeId}`);
// const response = mockData
return response.data;
// return response
} catch (error) {
console.error('Failed to fetch page:', error);
throw error;
}
}

export async function fetchAlias(alias: string) {
try {
const response = await drupalClient.get(`${drupalBaseUrl}/${alias}`)
// const response = redirectMockData
return response.data
} catch(error) {
console.error("Failed to fetch alias:", error)
throw error
}
}
Loading