diff --git a/src/Pages/Dashboard.tsx b/src/Pages/Dashboard.tsx index 2f67d1d..9fb4149 100644 --- a/src/Pages/Dashboard.tsx +++ b/src/Pages/Dashboard.tsx @@ -277,8 +277,6 @@ const Dashboard: React.FC = () => { } }; - console.log("AXIOS BASE URL:", API_BASE_URL); - fetchDashboardData(); }, [api]); diff --git a/src/Pages/Landing.tsx b/src/Pages/Landing.tsx index 59d4be3..b83d4fe 100644 --- a/src/Pages/Landing.tsx +++ b/src/Pages/Landing.tsx @@ -3,7 +3,7 @@ import team from "../assets/teamwokr.jpg"; import bghero1 from "../assets/hero1.png"; import Footer from "../Layout/Footer"; import Faq from "../Layout/Faq"; -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; type Internship = { @@ -33,6 +33,11 @@ const Landing = () => { const [feedbacks, setFeedbacks] = useState([]); const [activeIndex, setActiveIndex] = useState(0); + // Smooth fade animation + const [displayIndex, setDisplayIndex] = useState(0); + const [fadeIn, setFadeIn] = useState(true); + const FADE_MS = 450; + const handleSearch = (e: React.FormEvent) => { e.preventDefault(); if (search.trim()) { @@ -40,8 +45,22 @@ const Landing = () => { } }; - const getFeedbackImageUrl = (path: string) => - `${import.meta.env.VITE_API_BASE_URL}${path}`; + // helper url image + const getFeedbackImageUrl = (path: string) => { + if (!path) return ""; + if (/^https?:\/\//i.test(path)) return path; + return `${import.meta.env.VITE_API_BASE_URL}${path}`; + }; + + const currentFeedback = useMemo(() => { + if (feedbacks.length === 0) return null; + return feedbacks[displayIndex]; + }, [feedbacks, displayIndex]); + + const currentImgUrl = useMemo(() => { + if (!currentFeedback) return ""; + return getFeedbackImageUrl(currentFeedback.image_path); + }, [currentFeedback]); useEffect(() => { // Fetch internships @@ -58,23 +77,60 @@ const Landing = () => { fetch(`${import.meta.env.VITE_API_BASE_URL}/feedback-api/get`) .then((res) => res.json()) .then((data) => { - setFeedbacks(data.data as Feedback[]); + const arr = data.data as Feedback[]; + setFeedbacks(arr); setActiveIndex(0); + setDisplayIndex(0); + setFadeIn(true); }) .catch((err) => console.error("Error fetching feedback:", err)); }, []); - // Auto slide testimonial + // Auto slide target index useEffect(() => { if (feedbacks.length === 0) return; const intervalId = setInterval(() => { setActiveIndex((prev) => (prev + 1) % feedbacks.length); - }, 5000); // 5 detik + }, 5000); return () => clearInterval(intervalId); }, [feedbacks.length]); + // ✅ Animasi fade 2-phase: fade-out -> switch content -> fade-in + useEffect(() => { + if (feedbacks.length === 0) return; + if (activeIndex === displayIndex) return; + + // 1) fade-out konten lama + setFadeIn(false); + + // 2) setelah fade-out selesai, ganti konten, lalu fade-in + const t = setTimeout(() => { + setDisplayIndex(activeIndex); + + // next frame biar browser apply dom update + requestAnimationFrame(() => { + setFadeIn(true); + }); + }, FADE_MS); + + return () => clearTimeout(t); + }, [activeIndex, displayIndex, feedbacks.length]); + + // preload gambar slide berikutnya biar next slide lebih cepat + useEffect(() => { + if (feedbacks.length === 0) return; + + const next = feedbacks[(activeIndex + 1) % feedbacks.length]; + const nextUrl = getFeedbackImageUrl(next.image_path); + if (!nextUrl) return; + + const img = new Image(); + img.decoding = "async"; + img.src = nextUrl; + }, [activeIndex, feedbacks]); + return (
@@ -97,8 +153,8 @@ const Landing = () => { Tingkatkan keahlian, perluas kesempatan

- Asah keterampilanmu dan jadilah mahasiswa yang siap bersaing di - dunia industri + Asah keterampilanmu dan jadilah mahasiswa yang siap bersaing di dunia + industri

@@ -118,9 +174,7 @@ const Landing = () => { viewBox="0 0 24 24" onClick={() => { if (search.trim()) - navigate( - `/internships?search=${encodeURIComponent(search)}` - ); + navigate(`/internships?search=${encodeURIComponent(search)}`); }} > { Life at Humic Engineering

- Raih pengalaman internship yang bernilai dengan berkontribusi - langsung dalam pengembangan solusi teknologi kami. Kembangkan - kompetensi Anda melalui keterlibatan nyata dalam proyek IT serta - bimbingan langsung dari para expert di bidang Software engineering - dan IoT. + Raih pengalaman internship yang bernilai dengan berkontribusi langsung + dalam pengembangan solusi teknologi kami. Kembangkan kompetensi Anda + melalui keterlibatan nyata dalam proyek IT serta bimbingan langsung + dari para expert di bidang Software engineering dan IoT.

@@ -156,30 +209,35 @@ const Landing = () => {
{/* Hero 3 Section */} - {feedbacks.length > 0 && ( + {feedbacks.length > 0 && currentFeedback && (
- {/* LEFT: big + small image */} -
- {feedbacks[activeIndex].nama} - - {feedbacks.length > 1 && ( + {/* LEFT: image */} +
+
{feedbacks[(activeIndex - )} +
- {/* RIGHT: text + thumbnails */} -
+ {/* RIGHT: text */} +

Kata mereka tentang Humic Engineering @@ -188,44 +246,24 @@ const Landing = () => {

+ />

- {feedbacks[activeIndex].nama},{" "} + {currentFeedback.nama},{" "} - {feedbacks[activeIndex].posisi} · Humic Internship Batch{" "} - {feedbacks[activeIndex].batch}{" "} - {feedbacks[activeIndex].tahun} + {currentFeedback.posisi} · Humic Internship Batch{" "} + {currentFeedback.batch} {currentFeedback.tahun}

- {feedbacks[activeIndex].universitas} + {currentFeedback.universitas}

-
- {feedbacks.map((fb, index) => ( - - ))} -
+
@@ -255,22 +293,17 @@ const Landing = () => { } }} > - {/* Background image */}
- {/* Gradient overlay */}
- {/* Text content */}
{ if (response.status === 200) { document.cookie = `token=${response.data.data.token}; path=/;`; - navigate("/internships-list"); + navigate("/dashboard"); } else { setErrorMsg(response.data.message || "Login failed"); }