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/article page #49

Open
wants to merge 5 commits into
base: develop
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
3 changes: 3 additions & 0 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import type { NextConfig } from "next";

const nextConfig: NextConfig = {
/* config options here */
images: {
domains: ["images.unsplash.com"],
},
};

export default nextConfig;
Binary file added public/nurse.avif
Binary file not shown.
126 changes: 126 additions & 0 deletions src/app/[category]/[subcategory]/[article]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// import ArticleCard from "@/app/components/Articles/ArticleCard";
import { API_ENDPOINTS } from "@/config/endpoints";
import { getData } from "@/lib/helpers/dataFetchHelper";
import { ApiResponse, Article } from "@/types/CommonTypes";
import Image from "next/image";
import Link from "next/link";

export default async function Page({
params,
}: {
params: { article: string; category: string; subcategory: string };
}) {
const { category, subcategory } = await params;

const articleSlug = (await params).article;

const response: ApiResponse<Article> = await getData(
`${API_ENDPOINTS.ARTICLES}?filters[slug][$eq]=${articleSlug}`
);
const [{ title, publishedAt, description }] = response.data; // select first object in array, and destructure properties

const publishedDate = new Date(publishedAt).toLocaleDateString("en-US", {
year: "numeric",
month: "short",
day: "numeric",
});

return (
<>
<section className="flex flex-col items-start h-auto bg-gradient-to-r from-blue-100 to-white p-10">
{/* Breadcrumbs Section */}
<nav className="text-sm text-gray-600 mb-4">
<ul className="flex items-center gap-2">
<li>
<Link href={`/${category}`} className="hover:text-blue-600">
{category}
</Link>
</li>
<li className="text-lg">{">"}</li>
<li>
<Link
href={`/${category}/${subcategory}`}
className="hover:text-blue-600"
>
{subcategory}
</Link>
</li>
<li className="text-lg">{">"}</li>
<li className="text-gray-800 font-semibold">{title}</li>
</ul>
</nav>

{/* Article Header Section */}
<h1 className="text-4xl font-bold text-gray-800 mb-4 text-left">
{title}
</h1>
<div className="flex flex-wrap justify-between items-center w-full mb-4">
<p className="text-lg text-gray-600 max-w-2xl text-left">
{publishedDate} | by Dr. Nishantha Perera
</p>

<div className="flex items-center gap-4">
<p className="text-lg text-gray-600 max-w-2xl text-left">
Select Language
</p>
<button
className=" flex items-center gap-2 text-white text-lg px-3 py-1 rounded-md shadow hover:brightness-110 transition"
style={{ backgroundColor: "#2F7CC4" }}
>
English
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
className="size-6"
>
<path
fillRule="evenodd"
d="M12.53 16.28a.75.75 0 0 1-1.06 0l-7.5-7.5a.75.75 0 0 1 1.06-1.06L12 14.69l6.97-6.97a.75.75 0 1 1 1.06 1.06l-7.5 7.5Z"
clipRule="evenodd"
/>
</svg>
</button>
</div>
</div>

<div className="w-full">
<Image
src="/nurse.avif"
alt="Doctor providing medical advice"
width={550}
height={550}
className="w-full h-[300px] object-cover rounded-lg shadow-md mb-4"
priority
/>
</div>

<p className="text-lg text-gray-600 mb-4 text-left">{description}</p>

<section className="flex flex-col items-center justify-center w-full h-[200px] bg-blue-200 rounded-lg p-10">
<h1 className="text-3xl font-bold text-blue-700 mb-8 text-left">
To view the full article, please download.
</h1>
<button
className=" flex gap-2 text-white text-lg px-8 py-3 rounded-md shadow hover:brightness-110 transition"
style={{ backgroundColor: "#2F7CC4" }}
>
Download PDF
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
className="size-6"
>
<path
fillRule="evenodd"
d="M12 2.25a.75.75 0 0 1 .75.75v11.69l3.22-3.22a.75.75 0 1 1 1.06 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 1 1 1.06-1.06l3.22 3.22V3a.75.75 0 0 1 .75-.75Zm-9 13.5a.75.75 0 0 1 .75.75v2.25a1.5 1.5 0 0 0 1.5 1.5h13.5a1.5 1.5 0 0 0 1.5-1.5V16.5a.75.75 0 0 1 1.5 0v2.25a3 3 0 0 1-3 3H5.25a3 3 0 0 1-3-3V16.5a.75.75 0 0 1 .75-.75Z"
clipRule="evenodd"
/>
</svg>
</button>
</section>
</section>
</>
);
}
33 changes: 33 additions & 0 deletions src/app/[category]/[subcategory]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import ArticleCard from "@/app/components/Articles/ArticleCard";
import { API_ENDPOINTS } from "@/config/endpoints";
import { getData } from "@/lib/helpers/dataFetchHelper";
import { ApiResponse, Category } from "@/types/CommonTypes";

export default async function Page({
params,
}: {
params: { subcategory: string };
}) {
const categorySlug = (await params).subcategory;
const response: ApiResponse<Category> = await getData(
`${API_ENDPOINTS.CATEGORIES}?populate=subcategories&filters[slug][$eq]=${categorySlug}`
);

const [{ name, subtitle }] = response.data; // select first object in array, and destructure properties

return (
<>
<section className="flex flex-col items-center justify-center h-[400px] bg-gradient-to-r from-blue-100 to-white text-center px-4">
<h1 className="text-4xl font-bold text-gray-800 mb-4">{name}</h1>
<p className="text-lg text-gray-600 max-w-2xl">{subtitle}</p>
</section>

{/* map & render all article cards here */}
<section className="container mx-auto flex flex-row flex-wrap gap-4 justify-between px-60 my-10">
{/* use articles.map(........) here */}
<ArticleCard /> <ArticleCard />
<ArticleCard />
</section>
</>
);
}
23 changes: 23 additions & 0 deletions src/app/components/Articles/ArticleCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Image from "next/image";

export default function ArticleCard() {
return (
<div className="w-[45%] bg-gradient-to-r from-[#eaf5ff98] to-[#f4f9ff86] p-6 rounded-xl">
<Image
className="w-full h-[100px] object-cover object-center rounded-lg"
src={"https://images.unsplash.com/photo-1734640113825-24dd7c056052"}
alt=""
width={1000}
height={1000}
/>
<h2 className="font-semibold text-2xl text-black">Lorem Ipsum</h2>
<p className="text-black m-1">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed viverra,
dolor non placerat ultricies
</p>
<button className="bg-transparent text-[#2F7CC4] border-2 border-[#2F7CC4] w-full h-10 rounded-[12px] text-[16px] font-medium hover:bg-[#276ca3] hover:text-white transition flex items-center justify-center">
Explore more
</button>
</div>
);
}
10 changes: 6 additions & 4 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import "./globals.css";
import Navbar from "./components/Navbar/Navbar";
import "@fontsource/dm-sans";
import { API_ENDPOINTS } from "@/config/endpoints";
import { API_URL } from "@/config";
import { DM_Sans } from "next/font/google";
import Footer from "./components/Footer";
import { ApiResponseSingle, NavbarType } from "@/types/CommonTypes";
import { getData } from "@/lib/helpers/dataFetchHelper";

const dmSans = DM_Sans({
subsets: ["latin"],
Expand All @@ -23,13 +24,14 @@ export default async function RootLayout({
}: {
children: React.ReactNode;
}) {
const data = await fetch(`${API_URL}${API_ENDPOINTS.NAVBAR}`);
const navbarData = await data.json();
const navbarResponse: ApiResponseSingle<NavbarType> = await getData(
`${API_ENDPOINTS.NAVBAR}`
);

return (
<html lang="en" className={dmSans.variable}>
<body className="antialiased font-sans">
<Navbar data={navbarData?.data} />
<Navbar data={navbarResponse?.data} />
<main>{children}</main>
<Footer />
</body>
Expand Down
1 change: 1 addition & 0 deletions src/config/endpoints.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const API_ENDPOINTS = {
NAVBAR: "/navbar?populate=link&populate=navbarButton",
CATEGORIES: "/categories",
ARTICLES: "/articles",
};
47 changes: 38 additions & 9 deletions src/types/CommonTypes.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
// strapi image type
export interface ImageType {
url: string;
alt: string;
width?: number;
height?: number;
id: string;
documentId: string;
name: string;
alternativeText: string;
caption: string;
width: number;
height: number;
}

export interface NavbarDataType {
link: NavbarLinkType[];
navbarButton: ButtonType;
export interface NavbarType {
link: LinkType[];
navbarButton: ButtonType[];
}

export interface NavbarLinkType {
export interface LinkType {
id: string;
linkText: string;
linkUrl?: string | null;
linkUrl: string;
}

export interface ButtonType {
Expand All @@ -25,6 +30,10 @@ export interface ApiResponse<T> {
data: T[];
}

export interface ApiResponseSingle<T> {
data: T;
}

export interface Category {
id: string;
documentId: string;
Expand All @@ -34,6 +43,26 @@ export interface Category {
subcategories: Subcategory[];
}

export interface SubcategoryType {
id: string;
documentId: string;
name: string;
subtitle: string;
slug: string;
articles: Article[];
}

export interface Article {
id: string;
documentId: string;
title: string;
slug: string;
description: string;
category: string;
subcategory: string;
thumbnailImage: ImageType;
}

export interface Subcategory {
id: string;
name: string;
Expand Down