UNPKG

oliveyoung-restock-notification-popup

Version:

모바일 중심의 재입고 알림 신청 Bottom Sheet 웹컴포넌트

401 lines (311 loc) 11.1 kB
# 🛒 올리브영 재입고 알림 Bottom Sheet [![npm version](https://badge.fury.io/js/oliveyoung-restock-notification-popup.svg)](https://www.npmjs.com/package/oliveyoung-restock-notification-popup) [![GitHub](https://img.shields.io/github/license/oy-daegyun/oliveyoung-mall-restock-noti-pop)](https://github.com/oy-daegyun/oliveyoung-mall-restock-noti-pop) **모바일 중심의 재입고 알림 신청 Bottom Sheet 웹컴포넌트** 프레임워크에 독립적이며, JSP, Next.js v12/v14 등 모든 환경에서 사용 가능한 네이티브 웹컴포넌트입니다. ## ✨ **주요 특징** - 📱 **모바일 우선 설계**: Bottom Sheet 형태로 하단에서 슬라이드업 - 💻 **반응형 지원**: PC에서는 중앙 모달로 자동 전환 - 🎭 **부드러운 애니메이션**: 슬라이드 업/다운 효과 - 👆 **스와이프 지원**: 모바일에서 드래그로 닫기 - ✅ **완전한 폼 기능**: 휴대폰/이메일 입력, 유효성 검사, 자동 포맷팅 - 🔄 **상태 관리**: 로딩/성공/에러 상태 처리 - 🎨 **스타일 격리**: Shadow DOM으로 CSS 충돌 방지 - 🌐 **프레임워크 독립적**: Vanilla JS, React, Vue, Angular 모두 지원 ## 📦 **설치** ```bash npm install oliveyoung-restock-notification-popup ``` ## 🚀 **빠른 시작** ### 1. HTML에서 직접 사용 ```html <!DOCTYPE html> <html> <head> <script src="https://unpkg.com/oliveyoung-restock-notification-popup"></script> </head> <body> <restock-notification-popup product-id="12345" product-name="올리브영 베스트 크림" product-price="29,000원" api-endpoint="/api/restock-notifications" > </restock-notification-popup> <button onclick="showPopup()">재입고 알림 신청</button> <script> function showPopup() { document.querySelector("restock-notification-popup").show(); } // 성공 이벤트 리스너 document.addEventListener("restock-notification-success", (e) => { console.log("신청 완료:", e.detail); alert("재입고 알림이 등록되었습니다!"); }); </script> </body> </html> ``` ### 2. React/Next.js에서 사용 **⚠️ Next.js에서 올바른 사용법:** ```jsx import { useEffect, useRef, useState } from "react"; export default function ProductPage() { const popupRef = useRef(null); const [isComponentLoaded, setIsComponentLoaded] = useState(false); useEffect(() => { // 웹컴포넌트 동적 로드 (Next.js SSR 고려) const loadComponent = async () => { if (typeof window !== "undefined") { await import("oliveyoung-restock-notification-popup"); setIsComponentLoaded(true); } }; loadComponent(); }, []); const showPopup = () => { if (isComponentLoaded && popupRef.current) { popupRef.current.show(); } }; const handleSuccess = (e) => { console.log("성공:", e.detail); // 성공 처리 로직 }; useEffect(() => { if (isComponentLoaded && popupRef.current) { // 이벤트 리스너 등록 const popup = popupRef.current; popup.addEventListener("restock-notification-success", handleSuccess); return () => { popup.removeEventListener( "restock-notification-success", handleSuccess ); }; } }, [isComponentLoaded]); return ( <div> <button onClick={showPopup}>재입고 알림 신청</button> {/* 컴포넌트 로드 후에만 렌더링 */} {isComponentLoaded && ( <restock-notification-popup ref={popupRef} product-id="12345" product-name="올리브영 베스트 크림" product-price="29,000원" api-endpoint="/api/restock-notifications" /> )} </div> ); } ``` **또는 커스텀 훅 사용 (권장):** ```jsx // hooks/useRestockPopup.js import { useEffect, useRef, useState } from "react"; export function useRestockPopup() { const popupRef = useRef(null); const [isLoaded, setIsLoaded] = useState(false); useEffect(() => { const loadComponent = async () => { if (typeof window !== "undefined") { await import("oliveyoung-restock-notification-popup"); setIsLoaded(true); } }; loadComponent(); }, []); const showPopup = () => { if (isLoaded && popupRef.current) { popupRef.current.show(); } }; const hidePopup = () => { if (isLoaded && popupRef.current) { popupRef.current.hide(); } }; return { popupRef, isLoaded, showPopup, hidePopup }; } // ProductPage.js에서 사용 import { useRestockPopup } from "../hooks/useRestockPopup"; export default function ProductPage() { const { popupRef, isLoaded, showPopup } = useRestockPopup(); return ( <div> <button onClick={showPopup}>재입고 알림 신청</button> {isLoaded && ( <restock-notification-popup ref={popupRef} product-id="12345" product-name="올리브영 베스트 크림" product-price="29,000원" api-endpoint="/api/restock-notifications" /> )} </div> ); } ``` ### 3. JSP 환경에서 사용 ```jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html> <html> <head> <script src="/node_modules/oliveyoung-restock-notification-popup/dist/restock-notification-popup.js"></script> </head> <body> <div class="product-detail"> <h1>${product.name}</h1> <p class="price">${product.price}원</p> <c:if test="${product.soldOut}"> <button onclick="showRestockPopup()">재입고 알림 신청</button> </c:if> </div> <restock-notification-popup product-id="${product.id}" product-name="${product.name}" product-price="${product.price}원" product-image="${product.imageUrl}" api-endpoint="/api/restock-notifications"> </restock-notification-popup> <script> function showRestockPopup() { document.querySelector('restock-notification-popup').show(); } document.addEventListener('restock-notification-success', function(e) { alert('재입고 알림 신청이 완료되었습니다!'); }); </script> </body> </html> ``` ## 📋 **API 문서** ### **속성 (Attributes)** | 속성 | 타입 | 필수 | 기본값 | 설명 | | --------------- | ------ | ---- | ------ | -------------------------- | | `product-id` | string | ✅ | - | 상품 ID | | `product-name` | string | ✅ | - | 상품명 | | `product-price` | string | ✅ | - | 상품 가격 | | `product-image` | string | ❌ | - | 상품 이미지 URL | | `api-endpoint` | string | ✅ | - | 재입고 알림 API 엔드포인트 | ### **메서드 (Methods)** | 메서드 | 설명 | | -------- | ----------------- | | `show()` | 팝업을 표시합니다 | | `hide()` | 팝업을 숨깁니다 | ```javascript const popup = document.querySelector("restock-notification-popup"); popup.show(); // 팝업 열기 popup.hide(); // 팝업 닫기 ``` ### **이벤트 (Events)** | 이벤트 | 설명 | 데이터 | | ------------------------------ | ---------------- | ------------------------------------ | | `restock-notification-show` | 팝업이 표시될 때 | - | | `restock-notification-hide` | 팝업이 숨겨질 때 | - | | `restock-notification-success` | 신청 성공시 | `{ productId, phone, email, agree }` | | `restock-notification-error` | 신청 실패시 | `{ error, data }` | ```javascript document.addEventListener("restock-notification-success", (e) => { console.log("신청 데이터:", e.detail); // { productId: '12345', phone: '010-1234-5678', email: 'user@example.com', agree: true } }); document.addEventListener("restock-notification-error", (e) => { console.error("에러:", e.detail.error); }); ``` ## 📱 **반응형 디자인** ### **모바일 (768px 미만)** - 🔥 Bottom Sheet 스타일 - 📱 화면 하단에서 슬라이드업 - 👆 스와이프 다운으로 닫기 - 🎯 큰 터치 버튼 ### **PC/태블릿 (768px 이상)** - 💻 중앙 모달 스타일 - ⚡ 페이드인/아웃 애니메이션 - 🖱️ 기존 데스크톱 UX ## 🔌 **API 연동** 서버에서 다음과 같은 형태의 API를 제공해야 합니다: ### **요청 (Request)** ```http POST /api/restock-notifications Content-Type: application/json { "productId": "12345", "phone": "010-1234-5678", "email": "user@example.com", "agree": true } ``` ### **응답 (Response)** **성공시:** ```json { "success": true, "message": "재입고 알림이 등록되었습니다.", "notificationId": "abc123" } ``` **실패시:** ```json { "success": false, "message": "이미 등록된 상품입니다." } ``` ## 🎨 **커스터마이징** CSS 변수를 사용하여 스타일을 커스터마이징할 수 있습니다: ```css restock-notification-popup { --primary-color: #28a745; --border-radius: 12px; --overlay-color: rgba(0, 0, 0, 0.4); } ``` ## 🌐 **브라우저 지원** - ✅ Chrome 60+ - ✅ Firefox 63+ - ✅ Safari 13+ - ✅ Edge 79+ - ❌ IE (웹컴포넌트 미지원) ## 📖 **다양한 환경에서의 설치 방법** ### **CDN 사용** ```html <script src="https://unpkg.com/oliveyoung-restock-notification-popup"></script> ``` ### **ES6 모듈** ```javascript import "oliveyoung-restock-notification-popup"; ``` ### **CommonJS** ```javascript require("oliveyoung-restock-notification-popup"); ``` ### **직접 파일 포함** ```bash # dist 폴더를 프로젝트에 복사 cp -r node_modules/oliveyoung-restock-notification-popup/dist ./public/libs/ ``` ```html <script src="./public/libs/restock-notification-popup.js"></script> ``` ## 🧪 **데모** - 📱 **테스트 페이지**: [GitHub Pages 데모](https://oy-daegyun.github.io/oliveyoung-mall-restock-noti-pop) - 🔗 **NPM 패키지**: [npmjs.com](https://www.npmjs.com/package/oliveyoung-restock-notification-popup) - 💾 **GitHub 저장소**: [GitHub](https://github.com/oy-daegyun/oliveyoung-mall-restock-noti-pop) ## 🤝 **기여하기** 1. 저장소를 Fork 합니다 2. 기능 브랜치를 만듭니다 (`git checkout -b feature/amazing-feature`) 3. 변경 사항을 커밋합니다 (`git commit -m 'Add amazing feature'`) 4. 브랜치에 푸시합니다 (`git push origin feature/amazing-feature`) 5. Pull Request를 생성합니다 ## 📄 **라이선스** MIT © [oy-daegyun](https://github.com/oy-daegyun) ## 📞 **문의** - GitHub Issues: [Issues](https://github.com/oy-daegyun/oliveyoung-mall-restock-noti-pop/issues) - NPM: [oliveyoung-restock-notification-popup](https://www.npmjs.com/package/oliveyoung-restock-notification-popup)