fix: convert landing events/testimonials to client components

Server-side fetch fails during Nix build due to SSL cert issues in
the sandbox. Converted to client components with useEffect+fetch
so data loads at runtime instead of build time.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
maulanasdqn
2026-04-10 15:34:37 +07:00
co-authored by Claude Opus 4.6
parent 8fff0df753
commit e61c003e07
2 changed files with 38 additions and 30 deletions
+25 -15
View File
@@ -1,5 +1,8 @@
'use client';
import { buttonVariants } from '@components'; import { buttonVariants } from '@components';
import { cn } from '@utils'; import { cn } from '@utils';
import { useEffect, useState } from 'react';
import { HiCalendar, HiClock, HiLocationMarker } from 'react-icons/hi'; import { HiCalendar, HiClock, HiLocationMarker } from 'react-icons/hi';
interface ApiEvent { interface ApiEvent {
@@ -47,28 +50,35 @@ const getEventStatus = (endDate: string) => {
return end > now ? 'upcoming' : 'past'; return end > now ? 'upcoming' : 'past';
}; };
async function fetchEvents(): Promise<ApiEvent[]> { export default function EventsPage() {
const res = await fetch( const [events, setEvents] = useState<ApiEvent[]>([]);
'https://api.imphnen.dev/v1/landing/cms/events', const [loading, setLoading] = useState(true);
{ next: { revalidate: 60 } }
);
if (!res.ok) { useEffect(() => {
return []; fetch('https://api.imphnen.dev/v1/landing/cms/events')
} .then((res) => res.json())
.then((json: ApiResponse) => {
const json: ApiResponse = await res.json(); setEvents(json.data?.filter((e) => !e.is_deleted) || []);
return json.data.filter((e) => !e.is_deleted); })
} .catch(() => setEvents([]))
.finally(() => setLoading(false));
export default async function EventsPage() { }, []);
const events = await fetchEvents();
const sortedEvents = [...events].sort( const sortedEvents = [...events].sort(
(a, b) => (a, b) =>
new Date(b.start_date).getTime() - new Date(a.start_date).getTime() new Date(b.start_date).getTime() - new Date(a.start_date).getTime()
); );
if (loading) {
return (
<section className="min-h-screen bg-background container py-10">
<div className="flex justify-center items-center py-20">
<div className="w-8 h-8 border-3 border-gray-200 border-t-primary-500 rounded-full animate-spin" />
</div>
</section>
);
}
if (sortedEvents.length === 0) { if (sortedEvents.length === 0) {
return ( return (
<section className="min-h-screen bg-background container py-10"> <section className="min-h-screen bg-background container py-10">
@@ -1,5 +1,8 @@
'use client';
import { Button } from '@components'; import { Button } from '@components';
import Link from 'next/link'; import Link from 'next/link';
import { useEffect, useState } from 'react';
import { BsChatLeftQuote } from 'react-icons/bs'; import { BsChatLeftQuote } from 'react-icons/bs';
import { FaQuoteLeft } from 'react-icons/fa'; import { FaQuoteLeft } from 'react-icons/fa';
@@ -36,22 +39,17 @@ function getInitial(name: string) {
return name.charAt(0).toUpperCase(); return name.charAt(0).toUpperCase();
} }
async function fetchTestimonials() { export default function Page() {
const res = await fetch( const [testimonials, setTestimonials] = useState<ApiTestimonial[]>([]);
'https://api.imphnen.dev/v1/landing/cms/testimonials',
{ next: { revalidate: 60 } }
);
if (!res.ok) { useEffect(() => {
return []; fetch('https://api.imphnen.dev/v1/landing/cms/testimonials')
} .then((res) => res.json())
.then((json: ApiResponse) => {
const json: ApiResponse = await res.json(); setTestimonials(json.data?.filter((t: ApiTestimonial) => !t.is_deleted) || []);
return json.data.filter((t) => !t.is_deleted); })
} .catch(() => setTestimonials([]));
}, []);
export default async function Page() {
const testimonials = await fetchTestimonials();
return ( return (
<div className="min-h-screen"> <div className="min-h-screen">