From 638c592d2dc3bb77c8b9da36ea6c84afc5505df0 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Wed, 16 Jul 2025 09:23:59 +0700 Subject: (andri) fix layout popup bottom --- src/lib/home/components/PopupBannerPromotion.jsx | 28 +++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/lib/home/components/PopupBannerPromotion.jsx b/src/lib/home/components/PopupBannerPromotion.jsx index 347617d6..6700030a 100644 --- a/src/lib/home/components/PopupBannerPromotion.jsx +++ b/src/lib/home/components/PopupBannerPromotion.jsx @@ -22,6 +22,28 @@ const PagePopupInformation = () => { const [isSnapping, setIsSnapping] = useState(false); // 🔥 Penanda kapan transisi diaktifkan + const [containerLeft, setContainerLeft] = useState(0); + + const updateContainerLeft = () => { + const container = document.querySelector('.container'); + if (container) { + const left = container.getBoundingClientRect().left; + setContainerLeft(left); + } + }; + + useEffect(() => { + updateContainerLeft(); + + window.addEventListener('resize', updateContainerLeft); + window.addEventListener('scroll', updateContainerLeft); + + return () => { + window.removeEventListener('resize', updateContainerLeft); + window.removeEventListener('scroll', updateContainerLeft); + }; + }, []); + useEffect(() => { const getData = async () => { try { @@ -158,7 +180,11 @@ const PagePopupInformation = () => { const banner = data[0]; return ( -
+
Date: Wed, 16 Jul 2025 10:23:17 +0700 Subject: (andri) fix --- src/lib/home/components/PopupBannerPromotion.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/home/components/PopupBannerPromotion.jsx b/src/lib/home/components/PopupBannerPromotion.jsx index 6700030a..1463840a 100644 --- a/src/lib/home/components/PopupBannerPromotion.jsx +++ b/src/lib/home/components/PopupBannerPromotion.jsx @@ -180,16 +180,16 @@ const PagePopupInformation = () => { const banner = data[0]; return ( -
Date: Thu, 17 Jul 2025 08:49:25 +0700 Subject: (andri) rev button close popup bottom & fix layout mobile --- src/lib/home/components/PopupBannerPromotion.jsx | 134 ++++++++++++++++------- 1 file changed, 94 insertions(+), 40 deletions(-) diff --git a/src/lib/home/components/PopupBannerPromotion.jsx b/src/lib/home/components/PopupBannerPromotion.jsx index 1463840a..1ef166f2 100644 --- a/src/lib/home/components/PopupBannerPromotion.jsx +++ b/src/lib/home/components/PopupBannerPromotion.jsx @@ -4,6 +4,7 @@ import Image from 'next/image'; import Link from 'next/link'; import { getAuth } from '~/libs/auth'; import { X } from 'lucide-react'; +import useDevice from '@/core/hooks/useDevice'; const PagePopupInformation = () => { const router = useRouter(); @@ -19,6 +20,7 @@ const PagePopupInformation = () => { const dragStartPos = useRef({ x: 0, y: 0 }); const isDragging = useRef(false); const isTouching = useRef(false); + const { isDesktop } = useDevice(); const [isSnapping, setIsSnapping] = useState(false); // 🔥 Penanda kapan transisi diaktifkan @@ -80,8 +82,9 @@ const PagePopupInformation = () => { const popupHeight = popupRef.current?.offsetHeight || 0; const maxX = window.innerWidth - popupWidth - 20; const maxY = window.innerHeight - popupHeight - 20; + const minX = -containerLeft; - newX = Math.max(0, Math.min(newX, maxX)); + newX = Math.max(minX, Math.min(newX, maxX)); newY = Math.max(0, Math.min(newY, maxY)); setPosition({ x: newX, y: newY }); @@ -137,8 +140,9 @@ const PagePopupInformation = () => { const popupHeight = popupRef.current?.offsetHeight || 0; const maxX = window.innerWidth - popupWidth - 20; const maxY = window.innerHeight - popupHeight - 20; + const minX = -containerLeft; - newX = Math.max(0, Math.min(newX, maxX)); + newX = Math.max(minX, Math.min(newX, maxX)); newY = Math.max(0, Math.min(newY, maxY)); setPosition({ x: newX, y: newY }); @@ -179,61 +183,111 @@ const PagePopupInformation = () => { const banner = data[0]; - return ( -
+ if (isDesktop) { + // ✅ RENDER UNTUK DESKTOP + return (
-
-
+ { + if (isDragging.current) { + e.preventDefault(); + isDragging.current = false; + } else { + setActive(false); + } + }} + draggable="false" > - { - if (isDragging.current) { - e.preventDefault(); - isDragging.current = false; - } else { - setActive(false); - } - }} + {banner.name - {banner.name - -
+ /> +
+ ); + } + + // ✅ RENDER UNTUK MOBILE + return ( +
+
+ { + if (isDragging.current) { + e.preventDefault(); + isDragging.current = false; + } else { + setActive(false); + } + }} + draggable="false" + > + {banner.name + + + +
); + }; export default PagePopupInformation; -- cgit v1.2.3 From 5002ab911b779f3b3ed9b40dcda0f175269e8872 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Thu, 17 Jul 2025 09:44:17 +0700 Subject: (andri) fix --- src/lib/home/components/PopupBannerPromotion.jsx | 339 +++++++++-------------- 1 file changed, 131 insertions(+), 208 deletions(-) diff --git a/src/lib/home/components/PopupBannerPromotion.jsx b/src/lib/home/components/PopupBannerPromotion.jsx index 1ef166f2..eff2ba59 100644 --- a/src/lib/home/components/PopupBannerPromotion.jsx +++ b/src/lib/home/components/PopupBannerPromotion.jsx @@ -2,14 +2,15 @@ import { useRouter } from 'next/router'; import { useEffect, useState, useRef } from 'react'; import Image from 'next/image'; import Link from 'next/link'; -import { getAuth } from '~/libs/auth'; import { X } from 'lucide-react'; +import { getAuth } from '~/libs/auth'; import useDevice from '@/core/hooks/useDevice'; const PagePopupInformation = () => { const router = useRouter(); const isHomePage = router.pathname === '/'; const auth = getAuth(); + const { isDesktop } = useDevice(); const [active, setActive] = useState(false); const [data, setData] = useState(null); @@ -20,26 +21,43 @@ const PagePopupInformation = () => { const dragStartPos = useRef({ x: 0, y: 0 }); const isDragging = useRef(false); const isTouching = useRef(false); - const { isDesktop } = useDevice(); + const [isSnapping, setIsSnapping] = useState(false); + const [containerLeft, setContainerLeft] = useState(0); - const [isSnapping, setIsSnapping] = useState(false); // 🔥 Penanda kapan transisi diaktifkan + useEffect(() => { + if (isHomePage && !auth) { + setActive(true); + fetchData(); + } + }, [isHomePage, auth]); - const [containerLeft, setContainerLeft] = useState(0); + const fetchData = async () => { + try { + const res = await fetch(`/api/hero-banner?type=dragable-banner`); + const { data } = await res.json(); + if (Array.isArray(data) && data[0]?.image) { + setData(data[0]); + } else { + setActive(false); + } + } catch (error) { + console.error('Failed to fetch popup banner:', error); + } finally { + setLoading(false); + } + }; const updateContainerLeft = () => { const container = document.querySelector('.container'); if (container) { - const left = container.getBoundingClientRect().left; - setContainerLeft(left); + setContainerLeft(container.getBoundingClientRect().left); } }; useEffect(() => { updateContainerLeft(); - window.addEventListener('resize', updateContainerLeft); window.addEventListener('scroll', updateContainerLeft); - return () => { window.removeEventListener('resize', updateContainerLeft); window.removeEventListener('scroll', updateContainerLeft); @@ -47,100 +65,31 @@ const PagePopupInformation = () => { }, []); useEffect(() => { - const getData = async () => { - try { - const res = await fetch(`/api/hero-banner?type=dragable-banner`); - const { data } = await res.json(); - if (Array.isArray(data) && data.length > 0 && data[0]?.image) { - setData(data); - } else { - setActive(false); - } - } catch (error) { - console.error('Failed to fetch popup banner:', error); - } - setLoading(false); - }; - - if (isHomePage && !auth) { - setActive(true); - getData(); + if (isDesktop && containerLeft) { + const popupWidth = popupRef.current?.offsetWidth || 85; + setPosition({ + x: containerLeft - popupWidth - 20, + y: window.innerHeight - 130, + }); } - }, [isHomePage, auth]); - - useEffect(() => { - const handleGlobalTouchMove = (e) => { - if (isTouching.current) { - e.preventDefault(); - isDragging.current = true; - setIsSnapping(false); // 🔥 Matikan transisi saat drag - - let newX = e.touches[0].clientX - dragStartPos.current.x; - let newY = e.touches[0].clientY - dragStartPos.current.y; - - const popupWidth = popupRef.current?.offsetWidth || 0; - const popupHeight = popupRef.current?.offsetHeight || 0; - const maxX = window.innerWidth - popupWidth - 20; - const maxY = window.innerHeight - popupHeight - 20; - const minX = -containerLeft; - - newX = Math.max(minX, Math.min(newX, maxX)); - newY = Math.max(0, Math.min(newY, maxY)); - - setPosition({ x: newX, y: newY }); - } - }; - - const handleGlobalTouchEnd = () => { - if (isDragging.current) { - const popupWidth = popupRef.current?.offsetWidth || 0; - const screenMiddle = window.innerWidth / 2; + }, [isDesktop, containerLeft]); - setIsSnapping(true); // 🔥 Aktifkan transisi saat snap - - if (position.x + popupWidth / 2 < screenMiddle) { - // Snap ke kiri - setPosition({ x: 20, y: position.y }); - } else { - // Snap ke kanan - setPosition({ x: window.innerWidth - popupWidth - 20, y: position.y }); - } - } - - isTouching.current = false; - isDragging.current = false; - }; - - window.addEventListener('touchmove', handleGlobalTouchMove, { passive: false }); - window.addEventListener('touchend', handleGlobalTouchEnd); - - return () => { - window.removeEventListener('touchmove', handleGlobalTouchMove); - window.removeEventListener('touchend', handleGlobalTouchEnd); - }; - }, [position]); - - const handleMouseDown = (e) => { - e.preventDefault(); - dragStartPos.current = { x: e.clientX - position.x, y: e.clientY - position.y }; + const startDrag = (clientX, clientY) => { + dragStartPos.current = { x: clientX - position.x, y: clientY - position.y }; isDragging.current = false; - setIsSnapping(false); // 🔥 Matikan transisi saat drag - - window.addEventListener('mousemove', handleMouseMove); - window.addEventListener('mouseup', handleMouseUp); + setIsSnapping(false); }; - const handleMouseMove = (e) => { + const moveDrag = (clientX, clientY) => { isDragging.current = true; - - let newX = e.clientX - dragStartPos.current.x; - let newY = e.clientY - dragStartPos.current.y; - - const popupWidth = popupRef.current?.offsetWidth || 0; - const popupHeight = popupRef.current?.offsetHeight || 0; + const popupWidth = popupRef.current?.offsetWidth || 85; + const popupHeight = popupRef.current?.offsetHeight || 85; const maxX = window.innerWidth - popupWidth - 20; const maxY = window.innerHeight - popupHeight - 20; - const minX = -containerLeft; + const minX = isDesktop ? containerLeft - popupWidth - 20 : 0; + + let newX = clientX - dragStartPos.current.x; + let newY = clientY - dragStartPos.current.y; newX = Math.max(minX, Math.min(newX, maxX)); newY = Math.max(0, Math.min(newY, maxY)); @@ -148,146 +97,120 @@ const PagePopupInformation = () => { setPosition({ x: newX, y: newY }); }; - const handleMouseUp = () => { + const endDrag = () => { if (isDragging.current) { - const popupWidth = popupRef.current?.offsetWidth || 0; + const popupWidth = popupRef.current?.offsetWidth || 85; const screenMiddle = window.innerWidth / 2; - setIsSnapping(true); // 🔥 Aktifkan transisi saat snap - - if (position.x + popupWidth / 2 < screenMiddle) { - // Snap ke kiri - setPosition({ x: 20, y: position.y }); - } else { - // Snap ke kanan - setPosition({ x: window.innerWidth - popupWidth - 20, y: position.y }); - } + setIsSnapping(true); + setPosition(pos => ({ + x: pos.x + popupWidth / 2 < screenMiddle ? 20 : window.innerWidth - popupWidth - 20, + y: pos.y, + })); } + isDragging.current = false; + isTouching.current = false; + }; + + const handleMouseDown = e => { + e.preventDefault(); + startDrag(e.clientX, e.clientY); + window.addEventListener('mousemove', handleMouseMove); + window.addEventListener('mouseup', handleMouseUp); + }; + + const handleMouseMove = e => moveDrag(e.clientX, e.clientY); + const handleMouseUp = () => { + endDrag(); window.removeEventListener('mousemove', handleMouseMove); window.removeEventListener('mouseup', handleMouseUp); - - isDragging.current = false; }; - const handleTouchStart = (e) => { + const handleTouchStart = e => { if (e.touches.length === 1) { - dragStartPos.current = { x: e.touches[0].clientX - position.x, y: e.touches[0].clientY - position.y }; - isDragging.current = false; isTouching.current = true; - setIsSnapping(false); // 🔥 Matikan transisi saat drag + startDrag(e.touches[0].clientX, e.touches[0].clientY); } }; - if (!active || !data || loading || !Array.isArray(data) || !data[0]?.image) return null; + useEffect(() => { + const handleTouchMove = e => { + if (isTouching.current) { + e.preventDefault(); + moveDrag(e.touches[0].clientX, e.touches[0].clientY); + } + }; - const banner = data[0]; + const handleTouchEnd = () => endDrag(); - if (isDesktop) { - // ✅ RENDER UNTUK DESKTOP - return ( -
-
- { - if (isDragging.current) { - e.preventDefault(); - isDragging.current = false; - } else { - setActive(false); - } - }} - draggable="false" - > - {banner.name - + window.addEventListener('touchmove', handleTouchMove, { passive: false }); + window.addEventListener('touchend', handleTouchEnd); + return () => { + window.removeEventListener('touchmove', handleTouchMove); + window.removeEventListener('touchend', handleTouchEnd); + }; + }, []); - -
-
- ); - } + if (!active || !data || loading) return null; - // ✅ RENDER UNTUK MOBILE - return ( -
-
+ { + if (isDragging.current) { + e.preventDefault(); + isDragging.current = false; + } else { + setActive(false); + } }} - onMouseDown={handleMouseDown} - onTouchStart={handleTouchStart} + draggable="false" > - { - if (isDragging.current) { - e.preventDefault(); - isDragging.current = false; - } else { - setActive(false); - } - }} + {data.name - {banner.name - + /> + - -
+
); + if (isDesktop) { + return ( +
+ {popupContent} +
+ ); + } + + return ( +
+ {popupContent} +
+ ); }; export default PagePopupInformation; -- cgit v1.2.3 From 126a61f234218ec4553bdcf2ab0c19cfeff5a921 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Thu, 17 Jul 2025 15:55:10 +0700 Subject: (andri) fix popup --- src/lib/home/components/PopupBannerPromotion.jsx | 53 ++++++++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/src/lib/home/components/PopupBannerPromotion.jsx b/src/lib/home/components/PopupBannerPromotion.jsx index eff2ba59..1392a246 100644 --- a/src/lib/home/components/PopupBannerPromotion.jsx +++ b/src/lib/home/components/PopupBannerPromotion.jsx @@ -47,6 +47,27 @@ const PagePopupInformation = () => { } }; + useEffect(() => { + const handleResizeOrZoom = () => { + if (!popupRef.current) return; + + const popupWidth = popupRef.current.offsetWidth || 85; + const popupHeight = popupRef.current.offsetHeight || 85; + + setPosition({ + x: 20, + y: window.innerHeight - popupHeight - 20, + }); + }; + + window.addEventListener('resize', handleResizeOrZoom); + + return () => { + window.removeEventListener('resize', handleResizeOrZoom); + }; + }, []); + + const updateContainerLeft = () => { const container = document.querySelector('.container'); if (container) { @@ -85,8 +106,11 @@ const PagePopupInformation = () => { const popupWidth = popupRef.current?.offsetWidth || 85; const popupHeight = popupRef.current?.offsetHeight || 85; const maxX = window.innerWidth - popupWidth - 20; - const maxY = window.innerHeight - popupHeight - 20; - const minX = isDesktop ? containerLeft - popupWidth - 20 : 0; + + const bottomPadding = 80; // batas bawah minimal + const maxY = window.innerHeight - popupHeight - bottomPadding; + + const minX = 0; let newX = clientX - dragStartPos.current.x; let newY = clientY - dragStartPos.current.y; @@ -99,19 +123,30 @@ const PagePopupInformation = () => { const endDrag = () => { if (isDragging.current) { - const popupWidth = popupRef.current?.offsetWidth || 85; - const screenMiddle = window.innerWidth / 2; - setIsSnapping(true); - setPosition(pos => ({ - x: pos.x + popupWidth / 2 < screenMiddle ? 20 : window.innerWidth - popupWidth - 20, - y: pos.y, - })); + + if (isDesktop) { + const popupWidth = popupRef.current?.offsetWidth || 85; + setPosition({ + x: containerLeft - popupWidth - 20, + y: window.innerHeight - 130, + }); + } else { + const popupWidth = popupRef.current?.offsetWidth || 85; + const screenMiddle = window.innerWidth / 2; + + setPosition(pos => ({ + x: pos.x + popupWidth / 2 < screenMiddle ? 20 : window.innerWidth - popupWidth - 20, + y: pos.y, + })); + } } isDragging.current = false; isTouching.current = false; }; + + const handleMouseDown = e => { e.preventDefault(); startDrag(e.clientX, e.clientY); -- cgit v1.2.3 From 7494d68e936833d3958563a99a5fe977f24d7536 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Thu, 17 Jul 2025 16:19:40 +0700 Subject: (andri) fix padding drag popup --- src/lib/home/components/PopupBannerPromotion.jsx | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/lib/home/components/PopupBannerPromotion.jsx b/src/lib/home/components/PopupBannerPromotion.jsx index 1392a246..538f35e6 100644 --- a/src/lib/home/components/PopupBannerPromotion.jsx +++ b/src/lib/home/components/PopupBannerPromotion.jsx @@ -5,6 +5,7 @@ import Link from 'next/link'; import { X } from 'lucide-react'; import { getAuth } from '~/libs/auth'; import useDevice from '@/core/hooks/useDevice'; +import { createPortal } from 'react-dom'; const PagePopupInformation = () => { const router = useRouter(); @@ -23,6 +24,12 @@ const PagePopupInformation = () => { const isTouching = useRef(false); const [isSnapping, setIsSnapping] = useState(false); const [containerLeft, setContainerLeft] = useState(0); + + const [isClient, setIsClient] = useState(false); + + useEffect(() => { + setIsClient(true); + }, []); useEffect(() => { if (isHomePage && !auth) { @@ -106,17 +113,18 @@ const PagePopupInformation = () => { const popupWidth = popupRef.current?.offsetWidth || 85; const popupHeight = popupRef.current?.offsetHeight || 85; const maxX = window.innerWidth - popupWidth - 20; - - const bottomPadding = 80; // batas bawah minimal + + const topPadding = isDesktop ? 0 : 130; + const bottomPadding = isDesktop ? 0 : 80; const maxY = window.innerHeight - popupHeight - bottomPadding; - + const minX = 0; let newX = clientX - dragStartPos.current.x; let newY = clientY - dragStartPos.current.y; newX = Math.max(minX, Math.min(newX, maxX)); - newY = Math.max(0, Math.min(newY, maxY)); + newY = Math.max(topPadding, Math.min(newY, maxY)); setPosition({ x: newX, y: newY }); }; @@ -233,11 +241,12 @@ const PagePopupInformation = () => {
); - if (isDesktop) { - return ( + if (isDesktop && isClient) { + return createPortal(
{popupContent} -
+
, + document.body ); } -- cgit v1.2.3