pango-zma-experience-wheel
v1.8.7
Published
A lightweight, reusable React component for integrating the Pango ZMA Experience Wheel into your application. 🎉
Readme
[Beta] PZEWheel
A lightweight, reusable React component for integrating the Pango ZMA Experience Wheel into your application. 🎉
Features
- 🌟 Easy integration with any React project
- ⚡ Fast setup with minimal configuration
- 🛠 Supports
WidgetandOverlayandNonemodes - 💬 Supports
authorize,followOA,startSpin,spinResult,viewGift,viewWidget,closeWidget,initSuccessevents callback - 📦 Published as ESM, CJS, and TypeScript-ready
Before Integration
- Contact PangoCDP guide setup (integrate batch voucher/qr campaign/digital gift,.. and customUI,...) and get
pzeKey
Prerequisites
- Node.js >= 18.x
- React >= 18.0.0
- React Router DOM >= 6.0.0
- Vite >= 3 (ZMA Required Vite 5.x)
Usage
Basic Example
1. pzeWheel.page.tsx
import { PZEWheel } from 'pango-zma-experience-wheel';
import React from 'react';
import PZEWheelHandler from './pzeWheel.handler';
interface IPZEWheelPage {
}
const PZEWheelPage: React.FC = ({ }: IPZEWheelPage) => {
// handle logic show defaultMode
const defaultMode = "Overlay";
return (
<div
id="pzeWheel"
className="relative z-[60]"
>
<PZEWheel
pzeKey='pango_key'
pzeEnv='production'
pzeVersion='latest'
userAppId='your_userAppId'
defaultMode={defaultMode}
/>
<PZEWheelHandler />
</div>
);
};
export default PZEWheelPage;2. pzeWheel.handler.tsx
import { PZEWheelStore, PzeWheelType } from 'pango-zma-experience-wheel';
import React, { useEffect, useRef } from 'react';
import { getRecoil, setRecoil } from 'recoil-nexus';
import { followOA } from 'zmp-sdk/apis';
import { useIngestLog } from '~/hooks/useIngestLog';
import useShareUserInfo from '~/hooks/useShareUserInfo';
import { userInfoAtom } from '~/recoil/userInfo';
interface IPZEWheelHandler {
}
const PZEWheelHandlerComponent: React.FC = ({ }: IPZEWheelHandler) => {
const initializedRef = useRef(false);
const { handleActionShareUserInfo } = useShareUserInfo();
const { ingestLog } = useIngestLog()
const handlePopupError = (error: any, atoms: any) => {
console.error(error);
if (error?.code == -203) {
atoms.pzeWheelPopupError({
title: "Oops! Đã có lỗi xảy ra",
subTitle: "Bạn từ chối quá nhiều lần, vui lòng tắt và mở lại ứng dụng"
});
return;
}
atoms.pzeWheelPopupRequiredOpen();
}
useEffect(() => {
if (initializedRef.current) {
return;
}
initializedRef.current = true;
PZEWheelStore().then((atoms: PzeWheelType) => {
if (!atoms.pzeWheelStore) {
return;
}
// handle get current userInfo
const userInfo = getRecoil(userInfoAtom);
// handle updatepzeWheelFollowedOA
atoms.updatepzeWheelFollowedOA(userInfo?.followedOA);
// handle updatepzeWheelUserInfo
atoms.updatepzeWheelUserInfo({
userName: userInfo.userName == "Guest" ? "" : userInfo.userName,
userPhone: userInfo.userPhone,
userAvatar: "https://storage.googleapis.com/pangocdp-images/p-act/public/a446a8794d04498386b34dd833fb7eef.png",
cdpaid: userInfoUpdate.cdpaid,
});
const handlers = {
"zmp": {
"authorize": async () => {
try {
// handle call api zmp
const userInfoUpdate: any = await handleActionShareUserInfo(true, true);
if (userInfoUpdate.userPhone && userInfoUpdate.userName) {
atoms.updatepzeWheelUserInfo({
userName: userInfoUpdate.userName,
userPhone: userInfoUpdate.userPhone,
userAvatar: userInfoUpdate.userAvatar || "https://storage.googleapis.com/pangocdp-images/p-act/public/a446a8794d04498386b34dd833fb7eef.png",
cdpaid: userInfoUpdate.cdpaid,
});
return;
} else {
atoms.pzeWheelPopupRequiredOpen();
return;
}
} catch (error: any) {
handlePopupError(error, atoms);
return;
}
},
"followOA": async () => {
try {
// handle followedOA will skip call zmp
if (getRecoil(userInfoAtom)?.followedOA) {
atoms.updatepzeWheelFollowedOA(true);
return;
}
const oaId = atoms.pzeWheelStore.get(atoms.pzeCallback)?.data?.oaId;
if (!oaId) {
return;
}
await followOA({
id: oaId,
success: async () => {
// handle update current userInfo
const userInfoUpdate = { ...userInfo, followedOA: true }
setRecoil(userInfoAtom, userInfoUpdate)
// example: push event log follow-oa
await ingestLog(
'follow-oa',
{ userEvent: true },
userInfoUpdate
)
// handle updatepzeWheelFollowedOA
atoms.updatepzeWheelFollowedOA(true);
},
fail: (error: any) => {
handlePopupError(error, atoms);
return;
}
})
} catch (error: any) {
handlePopupError(error, atoms);
return;
}
}
},
"wheel": {
"startSpin": () => {
// example: push event log start-spin
},
"spinResult": () => {
const result = atoms.pzeWheelStore.get(atoms.pzeCallback)?.data || {};
console.log(result);
// example push event log: receive-gift-success or receive-gift-fail
// + result.errorCode => receive-gift-fail
// + !result.errorCode => receive-gift-success
},
"viewGift": () => {
// example: reload loadGiftWallet
},
"viewWidget": async () => {
// example: push event log click-widget
},
"closeWidget": async () => {
// example: push event log close-flow
},
"initSuccess": async () => {
// example: push event log open-flow
// ingestLog(
// 'open-flow',
// {
// userEvent: false,
// "pze": "wheel",
// ...eventData
// },
// userInfo)
},
},
default: () => {
console.warn(`Unknown message type: ${atoms.pzeWheelStore.get(atoms.pzeCallback)?.type}`);
},
};
const unsub = atoms.pzeWheelStore.sub(atoms.pzeCallback, (res) => {
const callbackData = atoms.pzeWheelStore.get(atoms.pzeCallback);
console.log("💬 ", callbackData)
const type = callbackData?.type;
const action = callbackData?.data?.action;
if (!type || !action) {
return;
}
(handlers?.[type]?.[action] || handlers.default)();
});
return () => unsub?.();
});
}, []);
return null;
};
const PZEWheelHandler = React.memo(PZEWheelHandlerComponent);
export default PZEWheelHandler;