diff --git a/public/images/blogPage/blogCard1.png b/public/images/blogPage/blogCard1.png new file mode 100644 index 000000000..86038db41 Binary files /dev/null and b/public/images/blogPage/blogCard1.png differ diff --git a/public/images/blogPage/blogCard2.png b/public/images/blogPage/blogCard2.png new file mode 100644 index 000000000..dd3dee213 Binary files /dev/null and b/public/images/blogPage/blogCard2.png differ diff --git a/public/images/blogPage/blogCard3.png b/public/images/blogPage/blogCard3.png new file mode 100644 index 000000000..08c44879d Binary files /dev/null and b/public/images/blogPage/blogCard3.png differ diff --git a/public/images/blogPage/blogCard4.png b/public/images/blogPage/blogCard4.png new file mode 100644 index 000000000..5f30b1cb4 Binary files /dev/null and b/public/images/blogPage/blogCard4.png differ diff --git a/public/images/blogPage/blogCard5.png b/public/images/blogPage/blogCard5.png new file mode 100644 index 000000000..49bfc18c9 Binary files /dev/null and b/public/images/blogPage/blogCard5.png differ diff --git a/public/images/blogPage/blogCard6.png b/public/images/blogPage/blogCard6.png new file mode 100644 index 000000000..522c64f5a Binary files /dev/null and b/public/images/blogPage/blogCard6.png differ diff --git a/public/images/blogPage/blogHero.png b/public/images/blogPage/blogHero.png new file mode 100644 index 000000000..a613b50d3 Binary files /dev/null and b/public/images/blogPage/blogHero.png differ diff --git a/public/images/blogPage/blogHero1.png b/public/images/blogPage/blogHero1.png new file mode 100644 index 000000000..942d337f3 Binary files /dev/null and b/public/images/blogPage/blogHero1.png differ diff --git a/public/images/blogPage/utils/index.tsx b/public/images/blogPage/utils/index.tsx new file mode 100644 index 000000000..32ad46d04 --- /dev/null +++ b/public/images/blogPage/utils/index.tsx @@ -0,0 +1,7 @@ +export { default as blogCard1 } from "../../blogPage/blogCard1.png"; +export { default as blogCard3 } from "../../blogPage/blogCard3.png"; +export { default as blogCard2 } from "../../blogPage/blogCard2.png"; +export { default as blogCard4 } from "../../blogPage/blogCard4.png"; +export { default as blogCard5 } from "../../blogPage/blogCard5.png"; +export { default as blogCard6 } from "../../blogPage/blogCard1.png"; +export { default as blogHero } from "../../blogPage/blogHero.png"; diff --git a/src/app/(landing-routes)/blog/[id]/BlogDetailsPage.tsx b/src/app/(landing-routes)/blog/[id]/BlogDetailsPage.tsx new file mode 100644 index 000000000..e498834b8 --- /dev/null +++ b/src/app/(landing-routes)/blog/[id]/BlogDetailsPage.tsx @@ -0,0 +1,16 @@ +"use client"; + +import RelatedArticle from "./RelatedArticle"; + +const BlogDetailsPage = () => { + return ( +
+
+ Blog Details Section + +
+
+ ); +}; + +export default BlogDetailsPage; diff --git a/src/app/(landing-routes)/blog/[id]/RelatedArticle.tsx b/src/app/(landing-routes)/blog/[id]/RelatedArticle.tsx new file mode 100644 index 000000000..dbfffdb90 --- /dev/null +++ b/src/app/(landing-routes)/blog/[id]/RelatedArticle.tsx @@ -0,0 +1,102 @@ +import { useEffect, useState } from "react"; + +import BlogCard from "~/components/blog/BlogCard"; + +export type New = { + id: number; + thumbnailUrl: string; +}; + +const newsTypes = [ + { + id: 0, + name: "Business", + color: "#F97316", + title: "The Power of Networking: How to Build Meaningful Connections", + date: "July 12, 2024", + timeRead: "5 min read", + }, + { + id: 1, + name: "Lifestyle", + color: "#7F0682", + title: "The Power of Networking: How to Build Meaningful Connections", + date: "July 12, 2024", + timeRead: "5 min read", + }, + { + id: 2, + name: "World News", + color: "#EAB308", + title: "The Power of Networking: How to Build Meaningful Connections", + date: "July 12, 2024", + timeRead: "5 min read", + }, +]; + +const RelatedArticle = () => { + const [news, setNews] = useState([]); + const [loading, setLoading] = useState(false); + const [errors, setError] = useState(); + useEffect(() => { + const getData = async () => { + try { + setLoading(true); + const response = await fetch( + "https://jsonplaceholder.typicode.com/photos", + ); + if (!response.ok) { + throw new Error("Something went wrong"); + } + const data = await response.json(); + setNews(data.slice(0, 3)); + } catch (error) { + if (error instanceof Error) { + setError(error.message); + } else { + setError("An unknown error occurred"); + } + } finally { + setLoading(false); + } + }; + getData(); + }, []); + + if (errors) { + return ( +

+ {errors} +

+ ); + } + + return ( +
+

+ Related Articles +

+ + {loading ? ( +
+

+ Loading... +

+
+ ) : ( +
+ {news.map((article, index) => ( +
+ +
+ ))} +
+ )} +
+ ); +}; + +export default RelatedArticle; diff --git a/src/app/(landing-routes)/blog/[id]/page.tsx b/src/app/(landing-routes)/blog/[id]/page.tsx new file mode 100644 index 000000000..f2bff7647 --- /dev/null +++ b/src/app/(landing-routes)/blog/[id]/page.tsx @@ -0,0 +1,11 @@ +import BlogDetailsPage from "./BlogDetailsPage"; + +const page = () => { + return ( +
+ +
+ ); +}; + +export default page; diff --git a/src/app/(landing-routes)/blog/latest/data/dummy-article-data.ts b/src/app/(landing-routes)/blog/latest/data/dummy-article-data.ts new file mode 100644 index 000000000..4be19afe3 --- /dev/null +++ b/src/app/(landing-routes)/blog/latest/data/dummy-article-data.ts @@ -0,0 +1,72 @@ +interface ArtileDataProperties { + title: string; + content: string; + author: string; + tag: string; + avatar: string; + minsRead: string; + datePublished: string; + thumbnail: string; +} + +export const articlesData: ArtileDataProperties[] = [ + { + title: "5 Mistakes That Kill Your Start-up Before It Takes Off", + content: + "We often hear about the ENIAC, hailed as the first computer, but its story is just one thread in a rich tapestry woven by brilliant", + author: "Nora Nora", + minsRead: "7 mins Read", + datePublished: "July 12, 2024", + avatar: "/images/latest-articles/avatar.png", + tag: "BUSINESS", + thumbnail: "/images/latest-articles/post-1.png", + }, + + { + title: "5 Mistakes That Kill Your Start-up Before It Takes Off", + content: + "We often hear about the ENIAC, hailed as the first computer, but its story is just one thread in a rich tapestry woven by brilliant", + author: "Nora Nora", + minsRead: "7 mins Read", + datePublished: "July 12, 2024", + avatar: "/images/latest-articles/avatar.png", + tag: "BUSINESS", + thumbnail: "/images/latest-articles/post-2.png", + }, + + { + title: "5 Mistakes That Kill Your Start-up Before It Takes Off", + content: + "We often hear about the ENIAC, hailed as the first computer, but its story is just one thread in a rich tapestry woven by brilliant", + author: "Nora Nora", + minsRead: "7 mins Read", + datePublished: "July 12, 2024", + avatar: "/images/latest-articles/avatar.png", + tag: "BUSINESS", + thumbnail: "/images/latest-articles/post-3.png", + }, + + { + title: "5 Mistakes That Kill Your Start-up Before It Takes Off", + content: + "We often hear about the ENIAC, hailed as the first computer, but its story is just one thread in a rich tapestry woven by brilliant", + author: "Nora Nora", + minsRead: "7 mins Read", + datePublished: "July 12, 2024", + avatar: "/images/latest-articles/avatar.png", + tag: "BUSINESS", + thumbnail: "/images/latest-articles/post-4.png", + }, + + { + title: "5 Mistakes That Kill Your Start-up Before It Takes Off", + content: + "We often hear about the ENIAC, hailed as the first computer, but its story is just one thread in a rich tapestry woven by brilliant", + author: "Nora Nora", + minsRead: "7 mins Read", + datePublished: "July 12, 2024", + avatar: "/images/latest-articles/avatar.png", + tag: "BUSINESS", + thumbnail: "/images/latest-articles/post-5.png", + }, +]; diff --git a/src/app/(landing-routes)/blog/latest/errorboundry.tsx b/src/app/(landing-routes)/blog/latest/errorboundry.tsx new file mode 100644 index 000000000..f7c7dbf31 --- /dev/null +++ b/src/app/(landing-routes)/blog/latest/errorboundry.tsx @@ -0,0 +1,39 @@ +import { Component, ReactNode } from "react"; + +interface ErrorBoundaryProperties { + children: ReactNode; +} + +interface ErrorBoundaryState { + hasError: boolean; +} + +class ErrorBoundary extends Component< + ErrorBoundaryProperties, + ErrorBoundaryState +> { + constructor(properties: ErrorBoundaryProperties) { + super(properties); + this.state = { hasError: false }; + } + + // static getDerivedStateFromError(_: Error): ErrorBoundaryState { + // return { hasError: true }; + // } + + // componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { + // // Log the error to an error reporting service or console + // // console.error("Uncaught error:", error, errorInfo); + // } + + render() { + if (this.state.hasError) { + // Render any custom fallback UI + return

Something went wrong.

; + } + + return this.props.children; + } +} + +export default ErrorBoundary; diff --git a/src/app/(landing-routes)/blog/latest/page.tsx b/src/app/(landing-routes)/blog/latest/page.tsx new file mode 100644 index 000000000..6298a8314 --- /dev/null +++ b/src/app/(landing-routes)/blog/latest/page.tsx @@ -0,0 +1,66 @@ +import BlogCard from "~/components/common/blogCard/BlogCard"; +import CustomButton from "~/components/common/common-button/common-button"; +import { articlesData } from "./data/dummy-article-data"; + +const LatestArticlesPage = () => { + const isTesting: boolean = process.env.NEXT_PUBLIC_TESTING === "true"; + + return ( + <> +
+

+ Latest Articles +

+
+ {!isTesting && + articlesData.map((data, index) => { + const { + author, + avatar, + content, + datePublished, + minsRead, + tag, + thumbnail, + title, + } = data; + + return ( +
+ +
+ ); + })} +
+ +
+
+ + Load more + +
+
+
+ + ); +}; + +export default LatestArticlesPage; diff --git a/src/app/(landing-routes)/blog/page.test.tsx b/src/app/(landing-routes)/blog/page.test.tsx index dea52ad56..b770fe26d 100644 --- a/src/app/(landing-routes)/blog/page.test.tsx +++ b/src/app/(landing-routes)/blog/page.test.tsx @@ -1,5 +1,5 @@ import { render } from "~/test/utils"; -import Page from "./page"; +import Page from "./comments/page"; describe("page tests", () => { it("should render correctly", () => { diff --git a/src/app/(landing-routes)/blog/page.tsx b/src/app/(landing-routes)/blog/page.tsx index 72a9725f6..b837755e0 100644 --- a/src/app/(landing-routes)/blog/page.tsx +++ b/src/app/(landing-routes)/blog/page.tsx @@ -1,5 +1,100 @@ -const BlogPage = () => { - return
BlogPage
; +import CustomButton from "~/components/common/common-button/common-button"; +import BlogCard from "~/components/layouts/BlogCards"; +import { + blogCard1, + blogCard2, + blogCard3, + blogCard4, + blogCard5, + blogCard6, +} from "../../../../public/images/blogPage/utils"; +import HeroSection from "../../../components/extDynamicPages/blogCollection/BlogPageHero"; + +const BlogHome = () => { + const blogPosts = [ + { + title: "The Power of Networking: How to Build Meaningful Connections", + date: "Jul 12, 2024", + readTime: "5", + category: "Business", + image: blogCard1, + labelClassName: "bg-primary", + }, + { + title: "The Global Impact of Climate Change: A Look at the Evidence", + date: "Jul 12, 2024", + readTime: "5", + category: "World News", + image: blogCard2, + labelClassName: "bg-warning", + }, + { + title: "5 Easy and Delicious Recipes for Busy Weeknights", + date: "Jul 12, 2024", + readTime: "5", + category: "Food", + image: blogCard3, + labelClassName: "bg-success", + }, + { + title: "5 Simple Habits to Improve Your Mental Wellbeing", + date: "Jul 12, 2024", + readTime: "5", + category: "Lifestyle", + image: blogCard4, + labelClassName: "bg-primary", + }, + { + title: "The Ultimate Guide to Dressing Stylishly with Fewer Clothes", + date: "Jul 12, 2024", + readTime: "5", + category: "Fashion", + image: blogCard5, + labelClassName: "bg-success", + }, + { + title: "The Future of Travel: What Will the World Look Like in 2030?", + date: "Jul 12, 2024", + readTime: "5", + category: "World News", + image: blogCard6, + labelClassName: "bg-warning", + }, + ]; + + return ( +
+ +
+

+ Recent Blog Posts +

+
+ {blogPosts.map((post, index) => ( + + ))} +
+
+
+ + Show More Articles + +
+
+ ); }; -export default BlogPage; +export default BlogHome; diff --git a/src/components/common/blogCard/BlogCard.tsx b/src/components/common/blogCard/BlogCard.tsx new file mode 100644 index 000000000..e28c40195 --- /dev/null +++ b/src/components/common/blogCard/BlogCard.tsx @@ -0,0 +1,98 @@ +"use client"; + +import clsx from "clsx"; +import Image from "next/image"; +import Link from "next/link"; +import { useEffect, useState } from "react"; + +import { Card, CardDescription, CardHeader, CardTitle } from "../../ui/card"; + +interface blogCardProperties { + tag: string; + date: string; + link: string; + title: string; + authorPfP: string; + blogImage: string; + authorName: string; + description: string; + timeOfReading: number; +} + +const BlogCard = (properties: blogCardProperties) => { + const [leading, setLeading] = useState(false); + + useEffect(() => { + if (window.innerWidth > 768) { + setLeading(true); + } + }, []); + + return ( +
+ + +
+ · +

+ {properties.tag} +

+
+ + {properties.title} + + + {properties.description} + +
+
+ {"author"} +

+ {properties.authorName} +

+
+
+

{properties.timeOfReading} mins Read

+

·

+

{properties.date}

+
+
+
+ + author + +
+
+ ); +}; + +export default BlogCard; diff --git a/src/components/common/blogCard/blogCard.test.tsx b/src/components/common/blogCard/blogCard.test.tsx new file mode 100644 index 000000000..921c909a8 --- /dev/null +++ b/src/components/common/blogCard/blogCard.test.tsx @@ -0,0 +1,52 @@ +import { render, screen } from "@testing-library/react"; + +import "@testing-library/jest-dom"; + +import { vi } from "vitest"; + +import BlogCard from "./BlogCard"; + +const setScreenSize = (width: number) => { + window.innerWidth = width; + window.dispatchEvent(new Event("resize")); +}; + +describe("blog Card Template", () => { + const properties = { + tag: "Business", + title: "5 Mistakes That kill your start-up before it takes off", + description: + " We often hear about the ENIAC, hailed as the first computer, but its story is just one thread in a rich tapestry woven by brilliant", + authorName: "Rahul Sharma", + date: "2022-02-02", + link: "", + authorPfP: "", + blogImage: "", + timeOfReading: 7, + }; + + describe("responsiveComponent", () => { + beforeEach(() => { + vi.resetModules(); + }); + + it("renders correctly on mobile screens", () => { + expect.assertions(2); + setScreenSize(375); + render(); + const mobileElement = screen.getByTestId("mobile-element"); + expect(mobileElement).toBeInTheDocument(); + expect(mobileElement).toBeVisible(); + }); + }); + + describe("page tests", () => { + it("navbar renders", () => { + expect.assertions(1); + + const view = render(); + + expect(view.baseElement).toBeInTheDocument(); + }); + }); +}); diff --git a/src/components/extDynamicPages/blogCollection/BlogPageHero.tsx b/src/components/extDynamicPages/blogCollection/BlogPageHero.tsx new file mode 100644 index 000000000..ebca20b47 --- /dev/null +++ b/src/components/extDynamicPages/blogCollection/BlogPageHero.tsx @@ -0,0 +1,35 @@ +import Image from "next/image"; + +import CustomButton from "~/components/common/common-button/common-button"; +import { blogHero } from "../../../../public/images/blogPage/utils"; + +const HeroSection: React.FC = () => { + return ( +
+
+ Hero Background +
+
+

+ Unlock Industry Insights: Get Essential Tips & Boilerplate Hacks +

+
+ + Read More + +
+
+ ); +}; + +export default HeroSection; diff --git a/src/components/layouts/BlogCards/index.tsx b/src/components/layouts/BlogCards/index.tsx new file mode 100644 index 000000000..4e085dd2c --- /dev/null +++ b/src/components/layouts/BlogCards/index.tsx @@ -0,0 +1,53 @@ +import Image, { StaticImageData } from "next/image"; + +import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card"; + +interface BlogCardProperties { + title: string; + date: string; + readTime: string; + category: string; + image: StaticImageData; + labelClassName: string; +} + +const BlogCard: React.FC = ({ + title, + date, + readTime, + category, + image, + labelClassName, +}) => { + return ( + +
+ {title} + + {category} + +
+ + {title} + + +
+ {date} + {readTime} mins read +
+
+
+ ); +}; + +export default BlogCard; diff --git a/src/components/layouts/index.tsx b/src/components/layouts/index.tsx new file mode 100644 index 000000000..e9b87fe93 --- /dev/null +++ b/src/components/layouts/index.tsx @@ -0,0 +1,20 @@ +import React from "react"; + +import Footer from "./Footer"; +import Navbar from "./Navbar"; + +interface IProperties { + children: React.ReactNode; +} + +const index: React.FC = ({ children }) => { + return ( +
+ +
{children}
+
+ ); +}; + +export default index;