// ============================================================ // SECTION 6 — Testimoni (Klaro-style scrapbook) // • Centerpiece headline "Cerita Mereka Cobain Yojea" // • Polaroid testimonial cards pop up in sequence around it, // each at a random scattered position with slight rotation. // • Below: a horizontal quote marquee that pauses on hover. // ============================================================ // Privacy mask for testimonial handles: keep the leading "@" (if any) // and the FIRST TWO letters, replace every remaining character with "*". // e.g. "@bliani" → "@bl****", "tamara" → "ta****" function maskName(raw) { const at = raw.startsWith('@') ? '@' : ''; const body = at ? raw.slice(1) : raw; if (!body) return raw; const visible = body.slice(0, 2); return at + visible + '*'.repeat(Math.max(0, body.length - visible.length)); } function Section6() { // ─── Responsive: tighter ring + fewer slots on mobile so cards never // hang off the edge. Headline + cards stay inside the stage box. const [isMobile, setIsMobile] = React.useState(false); React.useEffect(() => { const mq = window.matchMedia('(max-width: 700px)'); const update = () => setIsMobile(mq.matches); update(); if (mq.addEventListener) mq.addEventListener('change', update); else mq.addListener(update); return () => { if (mq.removeEventListener) mq.removeEventListener('change', update); else mq.removeListener(update); }; }, []); // Each "card" is now a mini text testimonial (no photo). // Variants give the floating ring visual rhythm. const CARDS = [ { name: '@betaraniarda', city: 'Pelanggan Yojea', q: 'Nyeri haid berkurang drastis.', tone: 'cream' }, { name: '@putriwifebrianti_',city: 'Pelanggan Yojea', q: 'Tanggal haid jadi konsisten.', tone: 'ink' }, { name: '@chikytacm', city: 'Pengguna IUD', q: 'Kram pre-haid berkurang banyak.', tone: 'white' }, { name: '@cicikeu', city: 'Pelanggan Yojea', q: '3 bulan telat, akhirnya haid.', tone: 'orange' }, { name: '@jeanette_lesi', city: 'Pelanggan Yojea', q: 'Keputihan auto berkurang.', tone: 'cream' }, { name: '@sugema_utami08', city: 'Pelanggan Yojea', q: 'Siklus haid jadi teratur.', tone: 'white' }, { name: '@levi', city: 'Pelanggan Yojea', q: '2x minum, langsung dapet.', tone: 'ink' }, { name: '@bliani', city: 'Post-melahirkan', q: 'Kram pasca lahiran ilang.', tone: 'cream' }, { name: '@tamara', city: 'Pelanggan Yojea', q: '1 box langsung kerasa.', tone: 'orange' }, { name: '@hash.ry', city: 'Pelanggan Yojea', q: '2 tahun gak haid, akhirnya haid.', tone: 'white' }, { name: '@karinauio', city: 'Pelanggan Yojea', q: 'Sakit 3 hari jadi sehari.', tone: 'ink' }, { name: '@yayuk2810', city: 'Pelanggan Yojea', q: 'Badan ringan selama haid.', tone: 'cream' }, ]; // Cards arranged in a CIRCLE around the central headline. // 12 slots evenly spaced at 30° intervals, offset 15° so none land on // pure cardinal axes (no card directly above/below headline). // Top-half cards sit BEHIND the headline and are slightly smaller, so // the ring feels layered around the text instead of in front of it. let SLOTS; if (isMobile) { // ─── Mobile: tidy scatter (no circle) ─── // Cards float in top & bottom bands that frame the headline. They // never overlap the centered title and stay inside the screen edges // (anchored by center, so x≈25/75% keeps wide cards within bounds). const MOBILE_SLOTS = [ { x: 50, y: 9, rot: -2, isBehind: true, scale: 0.72 }, { x: 25, y: 17, rot: -5, isBehind: true, scale: 0.80 }, { x: 75, y: 19, rot: 5, isBehind: true, scale: 0.82 }, { x: 24, y: 82, rot: 4, isBehind: false, scale: 0.90 }, { x: 76, y: 79, rot: -4, isBehind: false, scale: 0.86 }, { x: 50, y: 91, rot: 2, isBehind: false, scale: 0.80 }, ]; SLOTS = MOBILE_SLOTS.map((s, i) => ({ ...s, z: s.isBehind ? 0 : 3 + (i % 3), // headline sits at z-index 2 })); } else { // ─── Desktop/tablet: cards arranged in an elliptical ring ─── const RADIUS_X = 40; // % of stage width (horizontal radius) const RADIUS_Y = 36; // % of stage height (vertical radius) const SLOT_COUNT = 12; SLOTS = Array.from({ length: SLOT_COUNT }, (_, i) => { const angle = i * (360 / SLOT_COUNT) + 15; const a = (angle * Math.PI) / 180; const x = 50 + Math.cos(a) * RADIUS_X; const y = 50 + Math.sin(a) * RADIUS_Y; const isBehind = y < 50; // upper half sits behind headline const baseScale = isBehind ? 0.62 + (i % 3) * 0.04 // smaller in the back : 0.92 + (i % 3) * 0.05; return { x, y, isBehind, rot: (i % 2 === 0 ? -1 : 1) * (5 + (i % 4) * 2), scale: baseScale, z: isBehind ? 0 : 3 + (i % 3), // headline sits at z-index 2 }; }); } // ─── Sequence engine ─────────────────────────────────────── // Each slot independently cycles: hidden → showing → visible // → leaving → hidden. Tuned to keep ~8-10 cards on screen at // any moment but with constant pop-in/out motion so the ring // feels alive (the user perceives orbiting motion). const CYCLE_MS = 3600; // total time per slot cycle const STAGGER = 260; // delay between adjacent slots const [tick, setTick] = React.useState(0); React.useEffect(() => { const id = setInterval(() => setTick(t => t + 1), 200); return () => clearInterval(id); }, []); // For each slot, compute: which card is shown + lifecycle phase. function phaseFor(slotIdx, now) { const offset = slotIdx * STAGGER; const local = (now - offset + SLOTS.length * 9999 * CYCLE_MS) % CYCLE_MS; const cycleN = Math.floor((now - offset) / CYCLE_MS); // cycle-stable card pick: deterministic rotation through CARDS const cardIdx = ((cycleN % CARDS.length) + slotIdx * 2) % CARDS.length; let phase = 'hidden'; if (local < 380) phase = 'showing'; // pop in 380ms else if (local < 2900) phase = 'visible'; // stay else if (local < 3300) phase = 'leaving'; // pop out else phase = 'hidden'; return { phase, cardIdx }; } // ─── Marquee data ────────────────────────────────────────── const QUOTES = [ { q: 'Hari pertama mens nyerinya udah berkurang, siangnya bisa beraktivitas. Rutin minum 1x sehari ngaruh banget.', name: '@betaraniarda', city: 'Pelanggan Yojea' }, { q: 'Rasanya lebih mild dan manis daripada jamu biasa. Perut juga jadi lebih adem, keputihan jadi lebih bening.', name: '@na.ttto', city: 'Pelanggan Yojea' }, { q: 'Tipe yang tanggal haidnya maju mundur, abis minum ini bulan keduanya tanggalnya sama. Ga peres emang ngaruh.', name: '@putriwifebrianti_', city: 'Pelanggan Yojea' }, { q: 'Sebelum menjelang haid tuh kramnya masyaAllah. Setelah Yojea berkurang banyak. Aku telat banget tau ini.', name: '@chikytacm', city: 'Pengguna IUD' }, { q: 'Udah 3 bulan gak haid. Coba konsumsi tiap hari, udah haid kaget banget — tanpa sakit perut sama sekali.', name: '@cicikeu', city: 'Pelanggan Yojea' }, { q: 'Keputihan dulu hampir tiap aktivitas pasti banyak, sekarang udah berkurang. Aktivitas waktu mens jadi nyaman.', name: '@jeanette_lesi', city: 'Pelanggan Yojea' }, { q: 'Siklus haid jadi bener-bener teratur dan rasa nyeri udah mendingan banget. Aku ga suka jamu, Yojea ga pait.', name: '@sugema_utami08', city: 'Pelanggan Yojea' }, { q: 'Keputihan udah berkurang padahal cuma habis 1 box langsung berasa ngefeknya. Mungkin perlu 1 box lagi nih.', name: '@tamara', city: 'Pelanggan Yojea' }, { q: 'Udah keram perut tapi ga dapet-dapet, abis minum Yojea, lusanya dapet. Baru 2-3x minum padahal, udah works.', name: '@levi', city: 'Pelanggan Yojea' }, { q: 'Setelah melahirkan, setiap haid perut aku sakit banget. Setelah Yojea, kram berkurang, badan lebih rileks.', name: '@bliani', city: 'Post-melahirkan' }, { q: 'Yang paling kerasa soal mengurangi keputihan. Apalagi kalau aku lagi banyak kegiatan, berkurang after konsumsi.', name: '@aditamutiara', city: 'Pelanggan Yojea' }, { q: 'MasyaAllah kaa, tadi banget aku haid lagi setelah 2 tahun ga haid.', name: '@hash.ry', city: 'Pelanggan Yojea' }, { q: 'Biasanya 3 hari aku sakit terus, konsumsi ini alhamdulillah cuma sehari aja sakitnya.', name: '@karinauio', city: 'Pelanggan Yojea' }, { q: 'Haid ku lancar, ga datang flek lagi. Aku haid di tanggal 29 dan ini sudah hari terakhir.', name: '@chillaxavier', city: 'Pelanggan Yojea' }, { q: 'Tidak lagi sakit perut, nyeri pundak dan pinggang berkurang jauh. Haid lebih lancar, badan terasa ringan.', name: '@yayuk2810', city: 'Pelanggan Yojea' }, { q: 'Minum Yojea 2 kali aja udah ngerasain banget ga gatal, terus bener-bener ga ada lagi itu keputihannya.', name: '@jundina_w', city: 'Pelanggan Yojea' }, ]; // ─── Video marquee data ─────────────────────────────────── // Real YouTube Shorts testimonials from the Yojea channel. // Labels rotate through benefit themes for visual rhythm. const VIDEOS = [ { id: 'nvicrgtPf0s', handle: '@yojea.id', label: 'Nyeri haid berkurang' }, { id: 'KoGgIDYmcZs', handle: '@yojea.id', label: 'Kram pre-haid lega' }, { id: 'lw1s6mH1dNs', handle: '@yojea.id', label: 'Badan lebih ringan' }, { id: 'TeHqIbrHnoY', handle: '@yojea.id', label: 'Akhirnya haid lagi' }, { id: 'PQX6VNCwNio', handle: '@yojea.id', label: 'Cerita pelanggan Yojea' }, { id: 'p258dXfYOow', handle: '@yojea.id', label: 'Ritual harian Yojea' }, { id: 'Ima-os67lQM', handle: '@yojea.id', label: 'Nyeri haid berkurang' }, { id: 'RCwawx3iYBo', handle: '@yojea.id', label: 'Siklus jadi teratur' }, { id: 'mxGes6gDo_4', handle: '@yojea.id', label: 'Keputihan berkurang' }, { id: 'PlqvFbZt9C8', handle: '@yojea.id', label: 'Kram pre-haid lega' }, { id: 'AvemvpCQrmk', handle: '@yojea.id', label: 'Badan lebih ringan' }, { id: 'lXBV1MNOPSA', handle: '@yojea.id', label: 'Akhirnya haid lagi' }, { id: 'JM8IfYTHW3Q', handle: '@yojea.id', label: 'Cerita pelanggan Yojea' }, { id: '1BSNPkcXVJ4', handle: '@yojea.id', label: 'Ritual harian Yojea' }, { id: 'KDI1_T6_aeY', handle: '@yojea.id', label: 'Nyeri haid berkurang' }, { id: 'JKqYOXeVuf4', handle: '@yojea.id', label: 'Siklus jadi teratur' }, { id: 'E9SE7SBPQQg', handle: '@yojea.id', label: 'Keputihan berkurang' }, { id: 'lddEnvNlgEg', handle: '@yojea.id', label: 'Cerita pelanggan Yojea' }, ]; // Now expressed in same units as phaseFor (tick × 200ms) const now = tick * 200; return (
Testimoni · Ribuan wanita Indonesia
{/* ─── Centerpiece stage: headline + popup cards ─── */}

Cerita Mereka
Cobain Yojea.

{/* Floating mini testimonial cards (no photo) */}
{/* ─── Marquee #1 — quote pills, scroll left ─── */}
{[...QUOTES, ...QUOTES].map((q, i) => (
★★★★★ "{q.q}" — {maskName(q.name)}
))}
{/* ─── Marquee #2 — square text cards, scroll right ─── */}
{[...QUOTES, ...QUOTES].map((q, i) => (
★★★★★

"{q.q}"

{q.name.charAt(0)}
{maskName(q.name)}
))}
{/* ─── Marquee #3 — "Dengarkan cerita mereka" video carousel ─── */}
Video Testimoni

Dengarkan cerita mereka

{[...VIDEOS, ...VIDEOS].map((v, i) => (
{v.label}
▶ Shorts
{v.handle} {v.label}
))}
Explore Testimoni Yojea
4.9/5
Rating rata-rata
6
Bahan premium
54+
Tahun warisan resep
); } Object.assign(window, { Section6 });