oliveyoung-restock-notification-popup
v1.0.2
Published
모바일 중심의 재입고 알림 신청 Bottom Sheet 웹컴포넌트
Downloads
1
Maintainers
Readme
🛒 올리브영 재입고 알림 Bottom Sheet
모바일 중심의 재입고 알림 신청 Bottom Sheet 웹컴포넌트
프레임워크에 독립적이며, JSP, Next.js v12/v14 등 모든 환경에서 사용 가능한 네이티브 웹컴포넌트입니다.
✨ 주요 특징
- 📱 모바일 우선 설계: Bottom Sheet 형태로 하단에서 슬라이드업
- 💻 반응형 지원: PC에서는 중앙 모달로 자동 전환
- 🎭 부드러운 애니메이션: 슬라이드 업/다운 효과
- 👆 스와이프 지원: 모바일에서 드래그로 닫기
- ✅ 완전한 폼 기능: 휴대폰/이메일 입력, 유효성 검사, 자동 포맷팅
- 🔄 상태 관리: 로딩/성공/에러 상태 처리
- 🎨 스타일 격리: Shadow DOM으로 CSS 충돌 방지
- 🌐 프레임워크 독립적: Vanilla JS, React, Vue, Angular 모두 지원
📦 설치
npm install oliveyoung-restock-notification-popup🚀 빠른 시작
1. 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에서 올바른 사용법:
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>
);
}또는 커스텀 훅 사용 (권장):
// 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 환경에서 사용
<%@ 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() | 팝업을 숨깁니다 |
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 } |
document.addEventListener("restock-notification-success", (e) => {
console.log("신청 데이터:", e.detail);
// { productId: '12345', phone: '010-1234-5678', email: '[email protected]', agree: true }
});
document.addEventListener("restock-notification-error", (e) => {
console.error("에러:", e.detail.error);
});📱 반응형 디자인
모바일 (768px 미만)
- 🔥 Bottom Sheet 스타일
- 📱 화면 하단에서 슬라이드업
- 👆 스와이프 다운으로 닫기
- 🎯 큰 터치 버튼
PC/태블릿 (768px 이상)
- 💻 중앙 모달 스타일
- ⚡ 페이드인/아웃 애니메이션
- 🖱️ 기존 데스크톱 UX
🔌 API 연동
서버에서 다음과 같은 형태의 API를 제공해야 합니다:
요청 (Request)
POST /api/restock-notifications
Content-Type: application/json
{
"productId": "12345",
"phone": "010-1234-5678",
"email": "[email protected]",
"agree": true
}응답 (Response)
성공시:
{
"success": true,
"message": "재입고 알림이 등록되었습니다.",
"notificationId": "abc123"
}실패시:
{
"success": false,
"message": "이미 등록된 상품입니다."
}🎨 커스터마이징
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 사용
<script src="https://unpkg.com/oliveyoung-restock-notification-popup"></script>ES6 모듈
import "oliveyoung-restock-notification-popup";CommonJS
require("oliveyoung-restock-notification-popup");직접 파일 포함
# dist 폴더를 프로젝트에 복사
cp -r node_modules/oliveyoung-restock-notification-popup/dist ./public/libs/<script src="./public/libs/restock-notification-popup.js"></script>🧪 데모
- 📱 테스트 페이지: GitHub Pages 데모
- 🔗 NPM 패키지: npmjs.com
- 💾 GitHub 저장소: GitHub
🤝 기여하기
- 저장소를 Fork 합니다
- 기능 브랜치를 만듭니다 (
git checkout -b feature/amazing-feature) - 변경 사항을 커밋합니다 (
git commit -m 'Add amazing feature') - 브랜치에 푸시합니다 (
git push origin feature/amazing-feature) - Pull Request를 생성합니다
📄 라이선스
MIT © oy-daegyun
📞 문의
- GitHub Issues: Issues
- NPM: oliveyoung-restock-notification-popup
