Skip to content

feat: add testimonial section #48

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

Merged
Merged
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
10,509 changes: 10,509 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"@typescript-eslint/eslint-plugin": "^8.0.1",
"@typescript-eslint/parser": "^8.0.1",
"@vitejs/plugin-react": "^4.3.3",
"daisyui": "^5.0.3",
"eslint": "^8",
"eslint-config-next": "14.2.5",
"eslint-config-prettier": "^9.1.0",
Expand Down
1 change: 1 addition & 0 deletions src/app/[locale]/globals.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@plugin "daisyui";

@layer base {
:root {
Expand Down
7 changes: 7 additions & 0 deletions src/app/[locale]/testimonial/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { TestimonialPage } from "@/features/testimonial";

const Testimony = () => {
return <TestimonialPage />;
};

export default Testimony;
3 changes: 2 additions & 1 deletion src/components/layout/Navbar/Navbar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const messages = {
navbar: {
"link-1": "About Us",
"link-2": "Events",
"link-3": "Donate",
"link-3": "Testimonial",
"link-4": "Donate",
},
},
Announcement: {
Expand Down
4 changes: 4 additions & 0 deletions src/components/layout/Navbar/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export const LINKS: NavLinkProps<ValidPathnames>[] = [
},
{
id: "3",
href: "/testimonial",
},
{
id: "4",
href: "/support-us",
},
];
2 changes: 1 addition & 1 deletion src/features/home/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ export const testimonialData: TestimonialType[] = [
},
{
id: 7,
name: "Faldi",
name: "Faldiansyah",
role: "Ex Software Engineer Intern",
quote:
"Banyak hal yang bisa kita ambil dalam komunitas ini, selain untuk belajar kita juga mendapatkan banyak jaringan. Bersama dengan teman-teman dan mentor yang saling memotivasi untuk kemajuan kedepan.",
Expand Down
130 changes: 130 additions & 0 deletions src/features/testimonial/TestimonialPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"use client";
import React, { useState, useEffect, useRef } from "react";
import { useTranslations } from "next-intl";
import { testimonialData } from "../home/constants";
import { Card, CardContent, CardHeader } from "@/components/ui/Card";
import Image from "next/image";
import Link from "next/link";
import { Dialog, DialogTrigger } from "@/components/ui/Dialog";
import DetailTestimoni from "../home/components/DetailTestimoni";

const TestimonialPage = () => {
const t = useTranslations("TestimonialPage");
const [visibleCount, setVisibleCount] = useState(0); // 0 dulu biar shimmer
const [isLoading, setIsLoading] = useState(true);
const observerRef = useRef<IntersectionObserver | null>(null);

// jumlah data awal sesuai ukuran layar
const getInitialVisibleCount = () => {
if (window.innerWidth >= 1024) return 6;
if (window.innerWidth >= 768) return 4;
return 2;
};

// shimmer tampilkan data awal
useEffect(() => {
const initialCount = getInitialVisibleCount();
setTimeout(() => {
setVisibleCount(initialCount);
setIsLoading(false);
}, 1000);
}, []);

// lazy load buat scroll
useEffect(() => {
observerRef.current = new IntersectionObserver(
(entries) => {
const entry = entries[0];
if (entry.isIntersecting) {
setIsLoading(true);
setTimeout(() => {
setVisibleCount((prevCount) => {
const cols = getInitialVisibleCount();
return Math.min(prevCount + cols, testimonialData.length);
});
setIsLoading(false);
}, 1000);
}
},
{ threshold: 1 }
);

const loadMoreTrigger = document.getElementById("loadMoreTrigger");
if (loadMoreTrigger) {
observerRef.current?.observe(loadMoreTrigger);
}

return () => {
if (observerRef.current) observerRef.current?.disconnect();
};
}, [visibleCount]);

return (
<>
<div className="container mx-auto px-5 pt-24 pb-28">
<div className="w-full">
<h1 className="text-hmc-base-blue text-xl sm:text-3xl font-semibold">{t("title")}</h1>
<p className="text-gray-500 text-xs sm:text-base">{t("description")}</p>
</div>
<div className="mt-6">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{isLoading
? Array(getInitialVisibleCount()) // shimmer jumlah sesuai grid
.fill(null)
.map((_, index) => <ShimmerCard key={index} />)
: testimonialData.slice(0, visibleCount).map((data) => (
<Card key={data.id}>
<CardHeader>
<div className="flex justify-center w-full">
<div className="space-y-4">
<Image
src={data.avatar_url}
alt={data.name}
width={140}
height={140}
loading="lazy"
className="w-28 md:w-32 lg:w-36 rounded-full object-cover border-4"
/>
</div>
</div>
</CardHeader>
<CardContent>
<div className="flex flex-col items-center gap-1">
<h3 className="font-semibold">{data.name}</h3>
<p className="text-center text-slate-400 dark:bg-slate-400 text-sm">
{`${data.role} at `}
<Link className="font-semibold" href={data.company_url} target="_blank">
{data.company_name}
</Link>
</p>
<Image
className="mt-4 self-start"
src="/assets/icons/ic_qoute.svg"
height={24}
width={24}
alt="qoute"
/>
<Dialog>
<DialogTrigger asChild>
<p className="cursor-pointer text-slate-400 dark:text-slate-400 text-sm leading-6 pt-3 line-clamp-4">
{data.quote}
</p>
</DialogTrigger>
<DetailTestimoni data={data} />
</Dialog>
</div>
</CardContent>
</Card>
))}
</div>
</div>

{visibleCount < testimonialData.length && <div id="loadMoreTrigger" className="h-10"></div>}
</div>
</>
);
};

const ShimmerCard = () => <div className="bg-gray-200 dark:bg-gray-700 animate-pulse rounded-lg p-4 h-96"></div>;

export default TestimonialPage;
1 change: 1 addition & 0 deletions src/features/testimonial/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as TestimonialPage } from "./TestimonialPage";
4 changes: 4 additions & 0 deletions src/lib/navigation/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ export const pathnames: Pathnames<Locales> = {
en: "/events",
id: "/events",
},
"/testimonial": {
en: "/testimonial",
id: "/testimonial",
},
"/support-us": {
en: "/support-us",
id: "/support-us",
Expand Down
10 changes: 8 additions & 2 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
"navbar": {
"link-1": "About Us",
"link-2": "Events",
"link-3": "Donate"
"link-3": "Testimonial",
"link-4": "Donate"
},
"breadcrumb": {
"link-1": "About Us",
"link-2": "Events",
"link-3": "Donate"
"link-3": "Testimonial",
"link-4": "Donate"
}
},
"LocaleLayout": {
Expand Down Expand Up @@ -149,5 +151,9 @@
},
"Announcement": {
"pdd-2024": "🚀 Hi there! Our annual tech conference Palu Developer Day is around the corner! Check it out!"
},
"TestimonialPage": {
"title": "Testimonial",
"description": "Some friends and alumni who feel the benefits from Hammercode"
}
}
10 changes: 8 additions & 2 deletions src/locales/id.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
"navbar": {
"link-1": "Tentang Kami",
"link-2": "Acara",
"link-3": "Donasi"
"link-3": "Testimoni",
"link-4": "Donasi"
},
"breadcrumb": {
"link-1": "Tentang Kami",
"link-2": "Acara",
"link-3": "Donasi"
"link-3": "Testimoni",
"link-4": "Donasi"
}
},
"LocaleLayout": {
Expand Down Expand Up @@ -149,5 +151,9 @@
},
"Announcement": {
"pdd-2024": "🚀 Halo! Acara tahunan teknologi Palu Developer Day sudah dekat! Klik di sini!"
},
"TestimonialPage": {
"title": "Testimoni",
"description": "Berbagai testimonial yang dapat membantu kami memahami manfaat Hammercode"
}
}
Loading