UNPKG

@hhgtech/hhg-components

Version:
348 lines (341 loc) 14 kB
import { a as __awaiter } from './tslib.es6-00ab44b2.js'; import { useRef, useEffect, useState, useCallback, useMemo } from 'react'; import { getCookie } from './miscCookieHelper.js'; import { u as useInitialMount } from './useUniqueId-38cdf062.js'; import './index-fe4471f4.js'; import { u as useTranslations } from './index-09d9e570.js'; import { L as LOCALE } from './Locale-dc1237b9.js'; function normalizeAndHash(string) { const utf8 = new TextEncoder().encode(string.trim().toLowerCase()); return crypto.subtle.digest('SHA-256', utf8).then((hashBuffer) => { const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray .map((bytes) => bytes.toString(16).padStart(2, '0')) .join(''); return hashHex; }); } const FbDataLayerStoreKey = 'fbDataLayer_userInfo'; const IPStoreKey = 'fbClientIp'; const useFbDataLayer = (userInfo) => { const savedIpRef = useRef(''); useEffect(() => { (() => __awaiter(void 0, void 0, void 0, function* () { var _a, _b, _c, _d, _e; if (!savedIpRef.current) { let userIp = yield fetch('https://api.ipify.org').then((res) => res.text()); if (!userIp) { userIp = yield fetch('https://icanhazip.com').then((res) => res.text()); } savedIpRef.current = userIp; } (_b = (_a = window.localStorage) === null || _a === void 0 ? void 0 : _a.setItem) === null || _b === void 0 ? void 0 : _b.call(_a, IPStoreKey, JSON.stringify({ client_ip_address: ((_c = savedIpRef.current) === null || _c === void 0 ? void 0 : _c.replace('\n', '')) || '', client_user_agent: navigator.userAgent || '', })); if (userInfo === null || userInfo === void 0 ? void 0 : userInfo.id) { const [em, ph, db, ge, ct, fn] = yield Promise.all([ userInfo.email ? normalizeAndHash(userInfo.email) : null, userInfo.phone ? normalizeAndHash(userInfo.phone) : null, userInfo.birthday ? normalizeAndHash(userInfo.birthday.split('-').join('')) : null, userInfo.gender ? 'm' : 'f', userInfo.city_name ? normalizeAndHash(userInfo.city_name).then((n) => n.replace(/\s/g, '')) : null, userInfo.name ? normalizeAndHash(userInfo.name) : null, ]); ({ fbc: getCookie('_fbc') || '', fbp: getCookie('_fbp') || '', }); const localData = { user_id: userInfo.id, }; if (fn) { localData['fn'] = fn; } if (em) { localData['em'] = em; } if (ph) { localData['ph'] = ph; } if (db) { localData['db'] = db; } if (ct) { localData['ct'] = ct; } (_e = (_d = window.localStorage) === null || _d === void 0 ? void 0 : _d.setItem) === null || _e === void 0 ? void 0 : _e.call(_d, FbDataLayerStoreKey, JSON.stringify(localData)); // ;(async function waitFbq() { // // check for the generic script // // easiest check to prevent race condition // if (window.fbq) { // window.fbq('trackCustom', 'FB Conversion', { // action_source: 'website', // event_source_url: window.location.href, // user_data: [userData], // }) // } else { // timeout = setTimeout(waitFbq, 1000) // } // })() } }))(); return () => { }; }, [userInfo]); }; /** src: https://www.benmvp.com/blog/8-helpful-custom-react-hooks/ * know the PREVIOUS + DIFFERENT value of props or state. */ const usePrevious = (value) => { // use refs to keep track of both the previous & // current values const prevRef = useRef(); const curRef = useRef(value); const isInitialMount = useInitialMount(); // after the initial render, if the value passed in // differs from the `curRef`, then we know that the // value we're tracking actually changed. we can // update the refs. otherwise if the `curRef` & // value are the same, something else caused the // re-render and we should *not* update `prevRef`. if (!isInitialMount && curRef.current !== value) { prevRef.current = curRef.current; curRef.current = value; } return prevRef.current; }; /** src: https://www.benmvp.com/blog/8-helpful-custom-react-hooks/ * delay State update till next animation frame. Similar to debounce but shorter */ const useRafState = (initialState) => { // this is the actual state const [state, setState] = useState(initialState); // keep track of the `requestAnimationFrame` request ID // across renders and successive calls to `useRafState` const requestId = useRef(0); // the actual state setter we'll return. // using `useCallback` so that it's memoized // just like `setState` const setRafState = useCallback((value) => { // cancel active request before making next one. // this is debouncing. cancelAnimationFrame(requestId.current); // create new request to set state on animation frame requestId.current = requestAnimationFrame(() => { setState(value); }); }, []); // cancel any active request when component unmounts useEffect(() => { return () => cancelAnimationFrame(requestId.current); }); return [state, setRafState]; }; const PREGNANCY_SLUG = { 'vi-VN': 'mang-thai', 'id-ID': 'kehamilan', 'ms-MY': 'kehamilan', 'km-KH': 'ពពោះ', 'en-PH': 'pregnancy', 'tl-PH': 'pregnancy', 'th-TH': 'การตั้งครรภ์', 'my-MM': 'pregnancy', 'zh-TW': 'pregnancy', 'hi-IN': 'pregnancy', 'zh-SG': 'pregnancy', }; // NOTE: this is temporary mapping on 13/02/2023, can be outdated due to changes from content team in the future const MAPPED_CATEGORY_SLUGS = { [LOCALE.Vietnam]: { sexualWellness: 'suc-khoe-tinh-duc', health: 'suc-khoe', healthyEating: 'an-uong-lanh-manh', skinHealth: 'da-lieu', healthyHabit: 'thoi-quen-lanh-manh', drug: 'thuoc', womensHealth: 'suc-khoe-phu-nu', fitness: 'the-duc-the-thao', pregnancy: 'mang-thai', parenting: 'nuoi-day-con', diabetes: 'tieu-duong-dai-thao-duong', healthyMind: 'tam-ly-tam-than', }, [LOCALE.Indonesia]: { pregnancy: 'kehamilan', parenting: 'parenting', health: 'sehat', diabetes: 'diabetes', womensHealth: 'wanita', drug: 'obat-suplemen', sexualWellness: '', healthyEating: '', skinHealth: '', }, [LOCALE.Malaysia]: { pregnancy: 'kehamilan', parenting: 'keibubapaan', health: 'kesihatan', diabetes: 'kencing-manis', womensHealth: 'kesihatan-wanita', drug: 'ubat', sexualWellness: '', healthyEating: '', skinHealth: '', }, [LOCALE.Cambodia]: { pregnancy: '%e1%9e%96%e1%9e%96%e1%9f%84%e1%9f%87', parenting: '%e1%9e%85%e1%9e%b7%e1%9e%89%e1%9f%92%e1%9e%85%e1%9e%b9%e1%9e%98%e1%9e%80%e1%9e%bc%e1%9e%93', health: '%e1%9e%9f%e1%9e%bb%e1%9e%81%e1%9e%97%e1%9e%b6%e1%9e%96%e1%9e%91%e1%9e%bc%e1%9e%91%e1%9f%85', diabetes: '%e1%9e%87%e1%9f%86%e1%9e%84%e1%9e%ba%e1%9e%91%e1%9e%b9%e1%9e%80%e1%9e%93%e1%9f%84%e1%9e%98%e1%9e%95%e1%9f%92%e1%9e%a2%e1%9f%82%e1%9e%98', womensHealth: '%e1%9e%9f%e1%9e%bb%e1%9e%81%e1%9e%97%e1%9e%b6%e1%9e%96%e1%9e%9f%e1%9f%92%e1%9e%8f%e1%9f%92%e1%9e%9a%e1%9e%b8', drug: '%e1%9e%b1%e1%9e%9f%e1%9e%90%e1%9e%93%e1%9e%b7%e1%9e%84%e1%9e%a2%e1%9e%b6%e1%9e%a0%e1%9e%b6%e1%9e%9a%e1%9e%94%e1%9f%86%e1%9e%94%e1%9f%89%e1%9e%93', sexualWellness: '', healthyEating: '', skinHealth: '', }, [LOCALE.PhilippinesEnglish]: { pregnancy: 'pregnancy', parenting: 'parenting', health: 'health', diabetes: 'diabetes', womensHealth: 'womens-health', drug: 'drugs-supplements', sexualWellness: '', healthyEating: '', skinHealth: '', }, [LOCALE.PhilippinesTagalog]: { pregnancy: 'pagbubuntis', parenting: 'pagiging-magulang', health: 'kalusugan', diabetes: 'diabetes-fil', womensHealth: 'kalusugan-kababaihan', drug: 'drugs-at-supplements', sexualWellness: '', healthyEating: '', skinHealth: '', }, [LOCALE.Thailand]: { pregnancy: '%e0%b8%81%e0%b8%b2%e0%b8%a3%e0%b8%95%e0%b8%b1%e0%b9%89%e0%b8%87%e0%b8%84%e0%b8%a3%e0%b8%a3%e0%b8%a0%e0%b9%8c', parenting: '%e0%b8%9e%e0%b9%88%e0%b8%ad%e0%b9%81%e0%b8%a1%e0%b9%88%e0%b9%80%e0%b8%a5%e0%b8%b5%e0%b9%89%e0%b8%a2%e0%b8%87%e0%b8%a5%e0%b8%b9%e0%b8%81', health: '%e0%b8%aa%e0%b8%b8%e0%b8%82%e0%b8%a0%e0%b8%b2%e0%b8%9e', diabetes: '%e0%b9%82%e0%b8%a3%e0%b8%84%e0%b9%80%e0%b8%9a%e0%b8%b2%e0%b8%ab%e0%b8%a7%e0%b8%b2%e0%b8%99', womensHealth: '%e0%b8%aa%e0%b8%b8%e0%b8%82%e0%b8%a0%e0%b8%b2%e0%b8%9e%e0%b8%ab%e0%b8%8d%e0%b8%b4%e0%b8%87', drug: '%e0%b8%a2%e0%b8%b2%e0%b9%81%e0%b8%a5%e0%b8%b0%e0%b8%ad%e0%b8%b2%e0%b8%ab%e0%b8%b2%e0%b8%a3%e0%b9%80%e0%b8%aa%e0%b8%a3%e0%b8%b4%e0%b8%a1', sexualWellness: '', healthyEating: '', skinHealth: '', }, [LOCALE.Myanmar]: { pregnancy: 'pregnancy', parenting: 'parenting', health: 'health', diabetes: 'diabetes', womensHealth: 'womens-health', drug: 'drugs-az', sexualWellness: '', healthyEating: '', skinHealth: '', }, [LOCALE.Taiwan]: { pregnancy: 'pregnancy', parenting: 'parenting', health: 'health', diabetes: 'diabetes', womensHealth: 'womens-health', drug: 'drugs-supplement', sexualWellness: '', healthyEating: '', skinHealth: '', }, // TODO: Update label [LOCALE.Singapore]: { pregnancy: 'pregnancy', parenting: 'parenting', health: 'health', diabetes: 'diabetes', womensHealth: 'womens-health', drug: 'drugs-supplement', sexualWellness: '', healthyEating: '', skinHealth: '', }, [LOCALE.India]: { pregnancy: 'pregnancy', parenting: 'parenting', health: 'health', diabetes: 'diabetes', womensHealth: 'womens-health', diabetesEn: 'en-diabetes', drug: 'dawaai', sexualWellness: '', healthyEating: '', skinHealth: '', }, }; function getCategoryFromURL(url, categories) { const urlParts = url.split('/'); for (const key in categories) { const keyword = categories[key]; if (urlParts.includes(keyword)) { return key; } } return null; // Return null if no matching key is found } const useCategory = (asPath) => { const { locale } = useTranslations(); const isPregnancy = useMemo(() => decodeURI(asPath.replace(/\//gi, '')).includes(PREGNANCY_SLUG[locale]), []); const isParenting = useMemo(() => { var _a; return decodeURI(asPath.replace(/\//gi, '')).includes((_a = MAPPED_CATEGORY_SLUGS[locale]) === null || _a === void 0 ? void 0 : _a.parenting); }, []); const type = useMemo(() => { return getCategoryFromURL(asPath, MAPPED_CATEGORY_SLUGS[locale]); }, [asPath, locale]); return { isPregnancy, isParenting, type }; }; function usePhoneValidator() { const [isReady, setReady] = useState(false); useEffect(() => { const loadUtils = () => __awaiter(this, void 0, void 0, function* () { if (typeof window === 'undefined') return; if (!window.intlTelInputUtils) { try { yield import('intl-tel-input/build/js/utils'); } catch (e) { console.error('Failed to load intl-tel-input utils', e); return; } } const utils = window.intlTelInputUtils; if (utils && typeof utils.isValidNumber === 'function') { setReady(true); } }); loadUtils(); }, []); const validator = useMemo(() => { if (!isReady) return null; return (value, countryCode) => { try { const utils = window.intlTelInputUtils; if (!utils || typeof utils.isValidNumber !== 'function') return true; return utils.isValidNumber(value, countryCode); } catch (e) { console.warn('Phone validation error:', e); return true; } }; }, [isReady]); return validator; } export { MAPPED_CATEGORY_SLUGS as M, PREGNANCY_SLUG as P, usePrevious as a, useRafState as b, useCategory as c, usePhoneValidator as d, useFbDataLayer as u };