UNPKG

@hhgtech/hhg-components

Version:
1,142 lines (1,123 loc) • 237 kB
import { _ as __rest, a as __awaiter } from './tslib.es6-ea4dfe68.js'; import React__default, { createContext, useMemo, useEffect, useRef, useState, useContext, useCallback, forwardRef, useImperativeHandle, memo } from 'react'; import { createStyles, Box, Button as Button$1, Input as Input$1, clsx, Autocomplete, Checkbox as Checkbox$1, Radio as Radio$1, Select as Select$1, TextInput, NumberInput as NumberInput$1, Portal, Transition, Overlay } from '@mantine/core'; import dayjs from 'dayjs'; import debounce from 'lodash/debounce'; import { createFormContext, useForm } from '@mantine/form'; import { B as BEARER_TOKEN_COOKIE } from './index-235eabf2.js'; import { getCookie, setCookie } from './miscCookieHelper.js'; import { u as useTranslations } from './index-9d21b711.js'; import { T as TranslationsContext } from './translationsContext-3a9e3453.js'; import { M as MediaQueries, b as getWrapperDomWithSelector, a as getPopupWrapperDom } from './utils-cb7242c7.js'; import { T as Text } from './index-9f5659e8.js'; import { S as Select, d as Checkbox, I as Input, R as Radio, P as Phone, N as NumberInput, O as OTP } from './index-5d405c0d.js'; import { D as DatePicker } from './index-afb403a9.js'; import { B as Button } from './index-c68a0fa7.js'; import './index.styles-770020ac.js'; import { useClickOutside } from '@mantine/hooks'; import './useMantineLocale-0c6bea99.js'; import { C as COMMON_DATE_TRANSLATE_KEY } from './index-90813715.js'; import './index-ebe66e27.js'; import { Z as ZINDEX_SSO, I as ISO_FORMAT } from './index-5e947517.js'; import './other-4ccb5568.js'; import './index-c2190f6e.js'; import { M as MAPPED_LOCALE } from './utils-9b07a6ba.js'; import { DateInput } from '@mantine/dates'; import { u as usePlacesAutocomplete, G as GOOGLE_API_KEY } from './usePlacesAutocomplete-b017462a.js'; import { H as Heading$1 } from './index-dcc517ff.js'; import { t as translationsMap$1 } from './translationsProvider-03c8b1ac.js'; import { L as LOCALE } from './Locale-f270bd9d.js'; import { v1 } from 'uuid'; import { parsePhoneNumber } from 'react-phone-number-input'; import styled from '@emotion/styled'; import { theme } from './miscTheme.js'; import { css } from '@emotion/react'; import { T as TogetherComponentGlobalContext } from './utils-40e61585.js'; import { i as isVideo } from './index-a7fca99f.js'; import { D as DrawerComponent } from './index-aebc10a7.js'; import { u as useScreenSize } from './useScreenSize-981e5b51.js'; import { createPortal } from 'react-dom'; import { B as Button$2 } from './index-6351bdee.js'; import { I as InputDate } from './InputDate-13f91afd.js'; import { C as Close } from './Close-ee386937.js'; import './constantsIsProduction.js'; import './normalizeLink-593b397a.js'; import './constantsDomainLocales.js'; import '@hhgtech/icons/other'; import '@mantine/carousel'; import 'classnames'; import './useUniqueId-4305c9aa.js'; import './constantsSite.js'; import '@hhgtech/icons/core'; import '@mantine/notifications'; import 'date-fns/locale'; import './constantsRiskScreener.js'; import './i18n-values/en-PH.js'; import './i18n-values/hi-IN.js'; import './i18n-values/id-ID.js'; import './i18n-values/km-KH.js'; import './i18n-values/ms-MY.js'; import './i18n-values/my-MM.js'; import './i18n-values/th-TH.js'; import './i18n-values/tl-PH.js'; import './i18n-values/vi-VN.js'; import './i18n-values/vi-VN_MB.js'; import './i18n-values/zh-TW.js'; import './index-963a1701.js'; import 'slugify'; import 'string-format'; import './togetherApiPaths.js'; import './constants-f4091ce6.js'; import 'vaul'; const LeadGenComponentContext = createContext({}); const CAMPAIGN_TARGET_TYPE = { LINKS: 1, TAGS: 2 }; let LEAD_API = 'https://dev.leadgen.hellobacsi.com/'; const LEAD_DEVICE_TYPE = { MOBILE: 1, DESKTOP: 2, }; let LEAD_CLASS = ''; if (LEAD_API.includes('localhost')) { LEAD_API = 'https://dev.leadgen.hellobacsi.com/'; } if (location.hostname.includes('marrybaby.vn')) { LEAD_CLASS = 'pink'; } // var LEAD_CURRENT_URL = location.href.toLowerCase(); let LEAD_CURRENT_URL = 'https://' + location.hostname + location.pathname + location.search; LEAD_CURRENT_URL = LEAD_CURRENT_URL.toLowerCase(); // TODO: set inital object if exists if (sessionStorage.getItem('insider_object')) { window.insider_object = JSON.parse(sessionStorage.getItem('insider_object')); } const docLang = document.documentElement.lang; // TODO: country code const LEAD_LOCALE_DATA$1 = { 'vi-VN': { popupLang: 'vi', countryCode: 'vn', countryCodeNumber: 84, }, 'id-ID': { popupLang: 'id', countryCode: 'id', countryCodeNumber: 62, }, 'th-TH': { popupLang: 'th', countryCode: 'th', countryCodeNumber: 66, }, 'ms-MY': { popupLang: 'ms', countryCode: 'my', countryCodeNumber: 60, }, 'zh-TW': { popupLang: 'zh', countryCode: 'tw', countryCodeNumber: 886, }, 'km-KH': { popupLang: 'km', countryCode: 'kh', countryCodeNumber: 855, }, 'my-MM': { popupLang: 'my', countryCode: 'mm', countryCodeNumber: 95, }, 'hi-IN': { popupLang: 'hi', countryCode: 'in', countryCodeNumber: 91, }, }; const LEAD_LOCALE = LEAD_LOCALE_DATA$1[docLang] || LEAD_LOCALE_DATA$1['vi-VN']; function LEAD_RESET_VAR() { // LEAD_CURRENT_URL = location.href.toLowerCase(); LEAD_CURRENT_URL = 'https://' + location.hostname + location.pathname + location.search; } const LEAD_TIMEZONE_DATA = { 1: 'Asia/Ho_Chi_Minh', 10: 'Asia/Ho_Chi_Minh', 11: 'Asia/Ho_Chi_Minh', 12: 'Asia/Ho_Chi_Minh', 2: 'Asia/Jakarta', 3: 'Asia/Bangkok', 4: 'Asia/Phnom_Penh', 5: 'Asia/Kuala_Lumpur', 6: 'Asia/Taipei', 7: 'Asia/Yangon', 8: 'Asia/Kolkata', 9: 'Asia/Manila', // Philippines / Filipinos Site }; const LEADGEN_ACTIONS = { SHOW: 'SHOW', SCROLL: 'SCROLL', TIME: 'TIME', }; const LEADGEN_LAYOUT = { LightBoxA: 'LightBoxA', LightBoxB: 'LightBoxB', SkinA: 'SkinA', SkinB: 'SkinB', Floating: 'Floating', Tab: 'Tab', InlineA: 'InlineA', InlineB: 'InlineB', CenterTab: 'CenterTab', Sidebar: 'Sidebar', Fullscreen: 'Fullscreen', Slider: 'Slider', }; const LEADGEN_BLOCK = { TextBlock: 'TextBlock', NumberBlock: 'NumberBlock', DateBlock: 'DateBlock', EmailBlock: 'EmailBlock', PhoneBlock: 'PhoneBlock', PhoneOtpBlock: 'PhoneOtpBlock', WhatsappOtpBlock: 'WhatsappOtpBlock', ZaloOtpBlock: 'ZaloOtpBlock', LocationBlock: 'LocationBlock', LinkButtonBlock: 'LinkButtonBlock', RadioBlock: 'RadioBlock', DropdownBlock: 'DropdownBlock', CheckboxBlock: 'CheckboxBlock', TncBlock: 'TncBlock', TitleBlock: 'TitleBlock', SubtitleBlock: 'SubtitleBlock', }; const LEADGEN_BLOCK_INPUT = [ LEADGEN_BLOCK.TextBlock, LEADGEN_BLOCK.NumberBlock, LEADGEN_BLOCK.DateBlock, LEADGEN_BLOCK.EmailBlock, LEADGEN_BLOCK.PhoneBlock, LEADGEN_BLOCK.PhoneOtpBlock, LEADGEN_BLOCK.WhatsappOtpBlock, LEADGEN_BLOCK.ZaloOtpBlock, LEADGEN_BLOCK.LocationBlock, LEADGEN_BLOCK.RadioBlock, LEADGEN_BLOCK.DropdownBlock, LEADGEN_BLOCK.CheckboxBlock, LEADGEN_BLOCK.TncBlock, ]; const leadGenFieldNamePhone = (listBlockAdded) => { return listBlockAdded .filter(({ name }) => [ LEADGEN_BLOCK.PhoneBlock, LEADGEN_BLOCK.PhoneOtpBlock, LEADGEN_BLOCK.WhatsappOtpBlock, LEADGEN_BLOCK.ZaloOtpBlock, ].includes(name)) .map(({ data }) => data.value); }; const SSO_MAP_LEAD = ['name', 'email', 'birthday', 'phone', 'gender']; const LEAD_LOCALE_DATA = { 'vi-VN': { popupLang: 'vi', countryCode: 'vn', countryCodeNumber: 84, }, 'id-ID': { popupLang: 'id', countryCode: 'id', countryCodeNumber: 62, }, 'th-TH': { popupLang: 'th', countryCode: 'th', countryCodeNumber: 66, }, 'ms-MY': { popupLang: 'ms', countryCode: 'my', countryCodeNumber: 60, }, 'zh-TW': { popupLang: 'zh', countryCode: 'tw', countryCodeNumber: 886, }, 'km-KH': { popupLang: 'km', countryCode: 'kh', countryCodeNumber: 855, }, 'my-MM': { popupLang: 'my', countryCode: 'mm', countryCodeNumber: 95, }, 'hi-IN': { popupLang: 'hi', countryCode: 'in', countryCodeNumber: 91, }, }; const mappingSSOToLead = (userInfoProps) => { var _a, _b; try { const { id, area_code } = userInfoProps; if (!userInfoProps || !id) { return; } const user = {}; for (const ssoKey of SSO_MAP_LEAD) { if (ssoKey in userInfoProps && typeof (userInfoProps === null || userInfoProps === void 0 ? void 0 : userInfoProps[ssoKey]) !== 'undefined') { const initValue = userInfoProps[ssoKey]; if (ssoKey === 'birthday') { const dob = dayjs(initValue, 'YYYY-MM-DD', true); if (dob.isValid()) { user.birthday = dob.toDate(); } } else if (ssoKey === 'gender') { user.gender = initValue.toString(); } else if (ssoKey === 'phone' && typeof area_code !== 'undefined') { user.phone = area_code + initValue; } else { user[ssoKey] = initValue; } } } if (((_a = user === null || user === void 0 ? void 0 : user.email) === null || _a === void 0 ? void 0 : _a.includes('@hhg.com')) || ((_b = user === null || user === void 0 ? void 0 : user.email) === null || _b === void 0 ? void 0 : _b.includes('@facebook.com'))) { delete user.email; } return Object.values(user).length ? user : undefined; } catch (error) { return; } }; const formatCampaignDetail = (campaign) => { if (!campaign) { return {}; } try { const { extra_fields, thank_you_image } = campaign || {}; const { textBlocks: exTextBlocks, imageBlocks: exImageBlocks, listBlockAdded: exListBlockAdded, listBlockThankyou: exListBlockThankyou, actionBlocks: exActionBlocks, } = extra_fields; const textBlocks = JSON.parse(exTextBlocks); const imageBlocks = JSON.parse(exImageBlocks); const listBlockAdded = JSON.parse(exListBlockAdded); const listBlockThankyou = JSON.parse(exListBlockThankyou); const actionBlocks = JSON.parse(exActionBlocks); const ThankYouBlock = { image: { src: thank_you_image }, }; listBlockThankyou.forEach((block) => { const { name, data } = block || {}; const { value: htmlText, align, newtab, url } = data || {}; switch (name) { case LEADGEN_BLOCK.TitleBlock: { ThankYouBlock.title = { htmlText, align }; } case LEADGEN_BLOCK.SubtitleBlock: { ThankYouBlock.description = { htmlText, align }; } case LEADGEN_BLOCK.LinkButtonBlock: { ThankYouBlock.button = { htmlText, newtab, url }; } } }); return Object.assign(Object.assign({}, campaign), { extra_fields: Object.assign(Object.assign({}, extra_fields), { textBlocks, imageBlocks, listBlockAdded, listBlockThankyou, actionBlocks }), ThankYouBlock }); } catch (error) { return {}; } }; class Store { constructor() { this.apiSsoUrl = 'https://staging-id.hellobacsi.com/'; this.apiLeadUrl = 'https://dev.leadgen.hellobacsi.com/'; this.apiSubotUrl = 'https://staging-service-subot.hellohealthgroup.com/'; } } const leadStore = new Store(); const METHOD = { GET: 'get', POST: 'POST', }; const LEADGEN_ERROR_CODE = { UNAUTHORIZED: 'UNAUTHORIZED', }; const LEADGEN_API_PATH = { V2_CAMPAIGN: 'api/v2/campaign', V2_SUBSCRIPTION_LEAD: 'api/v2/subscription-box', V2_SUBSCRIPTION_INFO: 'api/campaign/get-title', }; const SSO_API_PATH = { USER_UPDATE: 'api/user/update', }; const ssoApi = { call(_a) { var { url, data } = _a, config = __rest(_a, ["url", "data"]); const token = getCookie(BEARER_TOKEN_COOKIE); config.body = JSON.stringify(data); config.headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }; if (!token) { return Promise.reject({ code: LEADGEN_ERROR_CODE.UNAUTHORIZED, _data: '', }); } return fetch(`${leadStore.apiSsoUrl}${url}`, config) .then((res) => res.json()) .catch(() => ({})); }, }; const leadApi = { call(_a) { var { url, data = undefined } = _a, config = __rest(_a, ["url", "data"]); config.body = JSON.stringify(data); config.headers = { 'Content-Type': 'application/json', }; return fetch(`${leadStore.apiLeadUrl}${url}`, config) .then((res) => res.json()) .catch(() => ({})); }, }; const subotApi = { call(_a) { var { url, data } = _a, config = __rest(_a, ["url", "data"]); config.body = JSON.stringify(data); config.headers = { 'Content-Type': 'application/json', }; return fetch(`${leadStore.apiSubotUrl}${url}`, config) .then((res) => res.json()) .catch(() => ({})); }, }; const campaignGetById = (id) => { return leadApi.call({ url: `api/internal/campaign/${id}`, method: 'get', }); }; const validateEmailOrPhoneOnLeadGen = ({ campaign_id, email, phone, }) => { let phoneToSend = phone; // Remove the '0' part. Logic from Back to check between Subot and Lead with different format if (phoneToSend && phoneToSend.startsWith('0')) { phoneToSend = phoneToSend.substring(1); } return leadApi.call({ url: 'api/subot-campaign/check', method: 'post', data: { campaign_id, email, phone: phoneToSend, }, }); }; const validateEmailOrPhoneOnSubot = ({ bot_id, email, phone, }) => { let phoneToSend = phone; // Remove the '0' part. Logic from Back to check between Subot and Lead with different format if (phoneToSend && phoneToSend.startsWith('0')) { phoneToSend = phoneToSend.substring(1); } return subotApi.call({ url: 'frontend/api/subot-campaign/check', method: 'post', data: { bot_id, email, phone: phoneToSend, }, }); }; const validatePhoneNumberOnLeadGen = ({ campaign_id, phone, }) => { return leadApi.call({ url: 'api/collection/log/check-phone-with-campaign', method: 'post', data: { campaign_id, phone, }, }); }; const LEAD_OTP_API = { whatsapp: 'api/sms/whatsapp_otp', phone: 'api/sms/otp', zalo: 'api/sms/zalo_otp', }; const sendSMSOtpLead = ({ phone, type, }) => { return leadApi.call({ url: LEAD_OTP_API[type], method: 'post', data: { // The type Whatsapp/Zalo do not remove the '+' phone_number: type === 'phone' ? phone.replace('+', '') : phone, }, }); }; const LEAD_VERIFY_OTP_API = { whatsapp: 'api/sms/whatsapp_verify', phone: 'api/sms/verify', zalo: 'api/sms/zalo_verify', }; const verifyOtpLead = ({ phone, otp, type, }) => { return leadApi.call({ url: LEAD_VERIFY_OTP_API[type], method: 'post', data: { // The type Whatsapp/Zalo do not remove the '+' otp_code: otp, phone_number: type === 'phone' ? phone.replace('+', '') : phone, }, }); }; const getCampaignByCode = (campaign_code) => { return leadApi.call({ url: `${LEADGEN_API_PATH.V2_CAMPAIGN}/${campaign_code}`, method: METHOD.GET, }); }; const getSubscriptionBoxInfo = ({ category, site, }) => { return leadApi.call({ url: `${LEADGEN_API_PATH.V2_SUBSCRIPTION_INFO}?category=${category}&site=${site}`, method: METHOD.GET, }); }; const postSubscriptionBoxLead = ({ data }) => { return leadApi.call({ url: LEADGEN_API_PATH.V2_SUBSCRIPTION_LEAD, method: METHOD.POST, data, }); }; const postUserInfoFromLeadGen = ({ name }) => { return ssoApi.call({ url: SSO_API_PATH.USER_UPDATE, method: METHOD.POST, data: { name }, }); }; const campaignPostImpression = ({ code, action, title_article, ga_client_id, cookie_id, extra, url, referrer, }) => { return leadApi.call({ url: `api/campaign/${code}/impression`, method: METHOD.POST, data: { action, title_article, cookie_id, ga_client_id, url, extra, referrer, }, }); }; const Service = { campaignGetById, getCampaignByCode, getSubscriptionBoxInfo, postSubscriptionBoxLead, postUserInfoFromLeadGen, campaignPostImpression, validateEmailOrPhoneOnSubot, validateEmailOrPhoneOnLeadGen, validatePhoneNumberOnLeadGen, sendSMSOtpLead, verifyOtpLead, }; const checkUsedEmailOrPhone = (campaignId, campaign_subot_id, data) => __awaiter(void 0, void 0, void 0, function* () { const key = 'email' in data ? 'email' : 'phone'; const value = 'email' in data ? data.email : data.phone; const errorMsg = 'email' in data ? 'validator.emailUsed' : 'validator.phoneUsed'; /** Check on Leadgen Tool */ const resLeadGen = yield Service.validateEmailOrPhoneOnLeadGen({ campaign_id: [campaignId], [key]: value, // Can be email or phone }); if (resLeadGen._errorCode === 'SubmitLeadWithBotId_ERR_001' || resLeadGen._errorCode === 'SubmitLeadWithBotId_ERR_002') { return errorMsg; } /** Check on Subot */ if (campaign_subot_id.length) { const resSubot = yield Service.validateEmailOrPhoneOnSubot({ bot_id: campaign_subot_id, [key]: value, // Can be email or phone }); if (resSubot._errorCode === 'CheckSuBotLeadTool_ERR_001') { return errorMsg; } } }); const checkUsedPhoneOnly = (campaignId, phone) => __awaiter(void 0, void 0, void 0, function* () { var _a; const resLeadGen = yield Service.validatePhoneNumberOnLeadGen({ campaign_id: campaignId, phone, }); if (((_a = resLeadGen === null || resLeadGen === void 0 ? void 0 : resLeadGen._messages) === null || _a === void 0 ? void 0 : _a[0]) === 'Phone was exist') { return 'validator.phoneUsed'; } }); const validatedCache = { email: {}, phone: {}, phoneOnly: {}, }; const checkUsedEmailOrPhoneWithCache = (campaignId, campaign_subot_id, data) => __awaiter(void 0, void 0, void 0, function* () { const key = 'email' in data ? 'email' : 'phone'; const value = 'email' in data ? data.email : data.phone; const errorMsg = 'email' in data ? 'validator.emailUsed' : 'validator.phoneUsed'; if (validatedCache[key][value]) { if (validatedCache[key][value].value) { return errorMsg; } else if (!validatedCache[key][value].value && validatedCache[key][value].expire > Date.now()) { return ''; } } const res = yield checkUsedEmailOrPhone(campaignId, campaign_subot_id, data); if (res) { validatedCache[key][value] = { value: true, }; } else { validatedCache[key][value] = { value: false, expire: Date.now() + 1000 * 60, }; } return res; }); const checkUsedPhoneOnlyWithCache = (campaignId, phone) => __awaiter(void 0, void 0, void 0, function* () { if (validatedCache.phoneOnly[phone]) { if (validatedCache.phoneOnly[phone].value) { return 'validator.phoneUsed'; } else if (!validatedCache.phoneOnly[phone].value && validatedCache.phoneOnly[phone].expire > Date.now()) { return ''; } } const res = yield checkUsedPhoneOnly(campaignId, phone); if (res) { validatedCache.phoneOnly[phone] = { value: true, }; } else { validatedCache.phoneOnly[phone] = { value: false, expire: Date.now() + 1000 * 60, }; } return res; }); const clearCacheUsedEmailOrPhone = () => { validatedCache.email = {}; validatedCache.phone = {}; validatedCache.phoneOnly = {}; }; // You can give context variables any name const [LeadFormProvider$1, useLeadFormContext$1, useLeadForm$1] = createFormContext(); const useLeadFormConfig$1 = ({ listBlockAdded = [], validatingPhoneRef, validatingEmailRef, campaignId, campaign_subot_id = [], userInfo, }) => { const { t } = useTranslations(); const initialValues = useMemo(() => mappingSSOToLead(userInfo), [userInfo === null || userInfo === void 0 ? void 0 : userInfo.id]); useEffect(() => { if (!window.intlTelInputUtils) { require('intl-tel-input/build/js/utils'); } }, []); const validateObj = useMemo(() => { const InputBlocks = [ 'TextBlock', 'NumberBlock', 'EmailBlock', 'PhoneBlock', 'DateBlock', 'CheckboxBlock', 'RadioBlock', 'DropdownBlock', 'PhoneOtpBlock', 'WhatsappOtpBlock', 'ZaloOtpBlock', 'LocationBlock', 'TncBlock', ]; // ALL are required and can skip if not touched yet const withSharedCheck = (name, cb, // eslint-disable-next-line @typescript-eslint/no-explicit-any block) => { return (value) => { var _a; const isBLockRequired = (_a = block === null || block === void 0 ? void 0 : block.data) === null || _a === void 0 ? void 0 : _a.required; if (!formRef.current.isTouched(name)) return; if (typeof value === 'undefined' || value === '' || (Array.isArray(value) && value.length === 0)) { return isBLockRequired ? t('validator.required') : cb === null || cb === void 0 ? void 0 : cb(value); } return cb === null || cb === void 0 ? void 0 : cb(value); }; }; return listBlockAdded .filter((b) => InputBlocks.includes(b.name)) .reduce((r, b) => { var _a; const isRequired = (_a = b.data.required) !== null && _a !== void 0 ? _a : true; if (b.name === 'NumberBlock') { return Object.assign(Object.assign({}, r), { [b.data.value]: withSharedCheck(b.data.value, (value) => { if (value && isNaN(Number(value))) { return t('validator.number'); } }, b) }); } else if (b.name === 'EmailBlock') { return Object.assign(Object.assign({}, r), { [b.data.value]: withSharedCheck(b.data.value, (value) => { if (value && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) { return t('validator.email'); } if (!value) return; validatingEmailRef.current = true; setTimeout(() => { formRef.current.setFieldError(b.data.value, 'Validating...'); checkUsedEmailOrPhoneWithCache(campaignId, campaign_subot_id, { email: value, }) .then((tKey) => { if (tKey) { formRef.current.setFieldError(b.data.value, t(tKey)); } else { formRef.current.clearFieldError(b.data.value); } validatingEmailRef.current = false; }) .catch((e) => { console.error(e); formRef.current.setFieldError(b.data.value, e.message || 'Something went wrong'); validatingEmailRef.current = false; }); }, 200); }, b) }); } else if (b.name === 'PhoneBlock' || b.name === 'PhoneOtpBlock' || b.name === 'ZaloOtpBlock' || b.name === 'WhatsappOtpBlock') { return Object.assign(Object.assign({}, r), { [b.data.value]: withSharedCheck(b.data.value, (value) => { if (value && window.intlTelInputUtils && !window.intlTelInputUtils.isValidNumber(String(value), LEAD_LOCALE.countryCode)) { return t('validator.phone'); } if (!value) return; validatingPhoneRef.current = true; setTimeout(() => { formRef.current.setFieldError(b.data.value, 'Validating...'); if (b.data.singleSubmission) { checkUsedPhoneOnlyWithCache(campaignId, value) .then((tKey) => { if (tKey) { formRef.current.setFieldError(b.data.value, t(tKey)); } else { formRef.current.clearFieldError(b.data.value); } validatingPhoneRef.current = false; }) .catch((err) => { console.error(err); formRef.current.setFieldError(b.data.value, err.message || 'Something went wrong'); validatingPhoneRef.current = false; }); } else { checkUsedEmailOrPhoneWithCache(campaignId, campaign_subot_id, { phone: value, }) .then((tKey) => { if (tKey) { formRef.current.setFieldError(b.data.value, t(tKey)); } else { formRef.current.clearFieldError(b.data.value); } validatingPhoneRef.current = false; }) .catch((e) => { console.error(e); formRef.current.setFieldError(b.data.value, e.message || 'Something went wrong'); validatingPhoneRef.current = false; }); } }, 200); }, b) }); } else if (b.name === 'DateBlock') { return Object.assign(Object.assign({}, r), { [b.data.value]: withSharedCheck(b.data.value, (value) => { if (value && isNaN(Date.parse(value))) { return t('validator.date'); } }, b) }); } else if (b.name === 'TncBlock') { return Object.assign(Object.assign({}, r), { [`TNC-` + b.id]: withSharedCheck('TNC-' + b.id, (value) => { if (isRequired && !value) { return t('validator.required'); } }, b) }); } else { return Object.assign(Object.assign({}, r), { [b.data.value]: withSharedCheck(b.data.value, undefined, b) }); } }, {}); }, [listBlockAdded.map((b) => b.name).join(',')]); const form = useLeadForm$1({ validateInputOnChange: true, clearInputErrorOnChange: true, validate: validateObj, initialValues, }); const formRef = useRef(form); formRef.current = form; return { form, validateObj }; }; const Component = ({ campaign, onClose: onCloseProp, onOtherSubmit, onSubmit, showThankyou, setShowThankyou, locale, children, showEmpty, setShowEmpty, userInfo, }) => { var _a, _b; const extraFields = campaign.extra_fields; const campaignId = campaign.id; const campaign_subot_id = campaign.bot_id || []; const listBlockAdded = JSON.parse(extraFields.listBlockAdded); const actionBlocks = JSON.parse(extraFields.actionBlocks); const textBlocks = JSON.parse(extraFields.textBlocks); const heading = ((_b = (_a = textBlocks === null || textBlocks === void 0 ? void 0 : textBlocks.titleBlock) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.value) || ''; const description = textBlocks.subtitleBlock.data.value; const validatingPhoneRef = useRef(false); const validatingEmailRef = useRef(false); const leadFormConfig = useLeadFormConfig$1({ listBlockAdded, validatingPhoneRef, validatingEmailRef, campaignId, campaign_subot_id, userInfo, }); const [showOtpPhone, setShowOtpPhone] = useState(null); const [formRef, setFormRef] = useState(null); const onClose = () => { if (showOtpPhone) { setShowOtpPhone(null); } else { onCloseProp === null || onCloseProp === void 0 ? void 0 : onCloseProp(); } }; useEffect(() => { clearCacheUsedEmailOrPhone(); }, []); return campaign ? (React__default.createElement(LeadGenComponentContext.Provider, { value: { campaignId, campaign_subot_id, heading, description, listBlockAdded, textBlocks, actionBlocks, leadFormConfig, validatingEmailRef, validatingPhoneRef, formRef: { current: formRef }, setFormRef, locale, onClose, onOtherSubmit, showOtpPhone, setShowOtpPhone, onSubmit, showThankyou, setShowThankyou, showEmpty, setShowEmpty, } }, children)) : null; }; const Description = (_a) => { var rest = __rest(_a, []); const { description } = useContext(LeadGenComponentContext); return description ? (React__default.createElement(Text, Object.assign({ size: "p3" }, rest), description)) : null; }; const LeadGenContext$1 = createContext({}); var useStyles$2 = createStyles(() => { return { control: {}, }; }); const libraries$1 = ['places']; const LocationBlock = ({ name, placeholder, locale, required = true, }) => { var _a; const form = useLeadFormContext$1(); const [searchValue, setSearchValue] = useState(''); const [address, setAddress] = useState(''); const { predictions } = usePlacesAutocomplete(searchValue, '', locale === 'tl-PH' ? 'en' : (_a = locale === null || locale === void 0 ? void 0 : locale.split('-')) === null || _a === void 0 ? void 0 : _a[0]); const [LoadScript, setLoadScript] = useState(null); const [ready, setReady] = useState(false); const randRef = useRef(Math.random().toString(36).substring(7)); const options = useMemo(() => { const _opts = predictions.map((p) => { return { value: p.description, label: p.description, }; }); const isExist = _opts.find((o) => o.value === address); if (!address || isExist) { return _opts; } return [{ value: address, label: address }].concat(_opts); }, [predictions, address]); useEffect(() => { var _a, _b, _c; // only load extra google script when not yet loaded if (!((_c = (_b = (_a = window === null || window === void 0 ? void 0 : window.google) === null || _a === void 0 ? void 0 : _a.maps) === null || _b === void 0 ? void 0 : _b.places) === null || _c === void 0 ? void 0 : _c.AutocompleteService)) { import('@react-google-maps/api').then((m) => { setLoadScript(() => m.LoadScript); setTimeout(() => { setReady(true); }, 200); }); } else { setReady(true); } }, []); if (!ready) return (React__default.createElement("div", { style: { height: 73, } })); return (React__default.createElement(React__default.Fragment, null, LoadScript && (React__default.createElement(LoadScript, { googleMapsApiKey: GOOGLE_API_KEY, libraries: libraries$1, loadingElement: React__default.createElement(React__default.Fragment, null) })), React__default.createElement("div", { style: { display: 'none' }, "data-extra": true, "data-name": name, "data-control": 'text' }), React__default.createElement(Select, Object.assign({ className: "lead-modal__form-control", label: placeholder, placeholder: placeholder, withAsterisk: required, name: name, data: options, searchValue: searchValue, onSearchChange: (query) => { setSearchValue(query); }, filter: () => true, clearable: true, searchable: true, onChange: (val) => setAddress(val || ''), icon: React__default.createElement("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none" }, React__default.createElement("path", { d: "M10 9.792q.605 0 1.032-.427.426-.428.426-1.032 0-.603-.426-1.031A1.4 1.4 0 0 0 10 6.875q-.604 0-1.032.427a1.4 1.4 0 0 0-.426 1.031q0 .604.426 1.032.428.426 1.032.427m0 8.083q-.145 0-.292-.042a.7.7 0 0 1-.27-.145Q6.478 15 5.01 12.708 3.54 10.418 3.54 8.5q0-3.021 1.949-4.823T10 1.875t4.51 1.802q1.95 1.802 1.949 4.823 0 1.917-1.468 4.208-1.47 2.292-4.427 4.98a.7.7 0 0 1-.271.145 1 1 0 0 1-.292.042", fill: "#8C8C8C" })), autoComplete: 'no-auto-complete-' + randRef.current, rightSection: React__default.createElement(React__default.Fragment, null) }, form.getInputProps(name))))); }; const SubtitleBlock$1 = ({ children, align, }) => (React__default.createElement("p", { className: `lead-modal__description ${'le-text-align-' + (align || '')} ${LEAD_CLASS}` }, children)); const TitleBlock$1 = ({ children, align, }) => (React__default.createElement("h2", { className: `lead-modal__title ${'le-text-align-' + (align || '')} ${LEAD_CLASS}` }, children)); const Fields = ({ listBlockAdded, popupId, locale, onClose, onOtherSubmit, styles, classNames, popoverProps, }) => { const { primaryColor } = useContext(LeadGenContext$1); const { classes, cx } = useStyles$2(undefined, { name: 'LeadGen__Field', styles, classNames, }); const form = useLeadFormContext$1(); return (React__default.createElement(React__default.Fragment, null, listBlockAdded.map((b, index) => { var _a; const { name = '', data = {} } = b || {}; const { placeholder, value, align, listQuestion, isSendMailChimp = false, newtab, url, } = data; const required = (_a = data.required) !== null && _a !== void 0 ? _a : true; switch (name) { case 'TitleBlock': return (React__default.createElement(TitleBlock$1, { key: index, align: align }, value)); case 'SubtitleBlock': return (React__default.createElement(SubtitleBlock$1, { key: index, align: align }, value)); case 'TextBlock': return (React__default.createElement(Input, Object.assign({ key: index, withAsterisk: required, spellCheck: false, type: "text", placeholder: placeholder, className: cx('leadgen-control', classes.control), // onChangeRaw={(e) => inputOnChange('text', e)} label: placeholder, "data-control": "text", name: value }, form.getInputProps(value)))); case 'NumberBlock': return (React__default.createElement(NumberInput, Object.assign({ key: index, withAsterisk: required, spellCheck: false, type: "number", placeholder: placeholder, className: cx('leadgen-control', classes.control), // onChange={(e) => inputOnChange('number', e)} label: placeholder, "data-control": "number", name: value }, form.getInputProps(value)))); case 'EmailBlock': return (React__default.createElement(Input, Object.assign({ key: index, withAsterisk: required, spellCheck: false, // type="email" placeholder: placeholder, className: cx('leadgen-control', classes.control), label: placeholder, "data-control": "email", name: value }, form.getInputProps(value)))); case 'PhoneOtpBlock': case 'WhatsappOtpBlock': case 'ZaloOtpBlock': case 'PhoneBlock': { const id = popupId + '-' + value + '-' + index; return (React__default.createElement(Input.Wrapper, Object.assign({ size: "md", withAsterisk: required, key: index, label: placeholder, // error={errorField.phone} className: cx('leadgen-control', classes.control), labelProps: { htmlFor: id, } }, form.getInputProps(value)), React__default.createElement(Phone, { name: value, spellCheck: false, type: "tel", placeholder: placeholder, value: form.getInputProps(value).value, onChange: (v) => { form.setFieldValue(value, v); }, // onBlur={(e) => inputOnBlur('tel', e)} id: id, defaultCountry: (locale ? MAPPED_LOCALE[locale] || 'VN' : 'VN'), "data-control": "tel" }))); } case 'LocationBlock': { return (React__default.createElement(LocationBlock, { key: index, name: value, placeholder: placeholder, locale: locale, required: required })); } case 'DateBlock': return (React__default.createElement(React__default.Fragment, null, React__default.createElement(DatePicker, Object.assign({ withAsterisk: required, key: index, type: "default", name: value, placeholder: placeholder, className: cx('leadgen-control', classes.control), label: placeholder, "data-control": "date", popoverProps: popoverProps }, form.getInputProps(value))), React__default.createElement("input", { type: "hidden", name: value, "data-control": "date" }))); case 'LinkButtonBlock': return (React__default.createElement("div", { key: index }, React__default.createElement("a", { target: newtab ? 'blank' : 'parrent', href: url, style: { textDecoration: 'none' } }, React__default.createElement(Button, { type: "button", size: "md", color: primaryColor, className: `lead-modal__btn ${LEAD_CLASS}`, onClick: () => { onClose === null || onClose === void 0 ? void 0 : onClose(); onOtherSubmit === null || onOtherSubmit === void 0 ? void 0 : onOtherSubmit(); } }, value)))); case 'CheckboxBlock': return (React__default.createElement(React__default.Fragment, null, isSendMailChimp && (React__default.createElement("div", { style: { display: 'none', }, "data-name": value + '-mailchimp' })), React__default.createElement(Checkbox.Group, Object.assign({ withAsterisk: required, className: cx('leadgen-control', classes.control), key: index, label: placeholder, size: "md", sx: { display: 'flex', flexDirection: 'column', gap: 8, } }, form.getInputProps(value)), listQuestion.map((l, _index) => (React__default.createElement(Checkbox, { name: value, key: _index, value: l.value, label: l.placeholder, "data-control": "checkbox" })))))); case 'RadioBlock': return (React__default.createElement(React__default.Fragment, null, isSendMailChimp && (React__default.createElement(Input, { type: "hidden", name: value + '-mailchimp', value: isSendMailChimp })), React__default.createElement(Radio.Group, Object.assign({ withAsterisk: required, className: cx('leadgen-control', classes.control), key: index, label: placeholder, size: "md" }, form.getInputProps(value)), listQuestion.map((l, _index) => (React__default.createElement(Radio, { name: value, key: _index, value: l.value, label: l.placeholder, "data-control": "radio" })))))); case 'DropdownBlock': return (React__default.createElement(React__default.Fragment, null, React__default.createElement("div", { style: { display: 'none' }, "data-extra": true, "data-name": value, "data-control": 'dropdown' }), React__default.createElement(Select, Object.assign({ key: index, className: cx('leadgen-control', classes.control), label: placeholder, withAsterisk: required, name: value, data: listQuestion.map((l) => ({ value: l.value, label: l.placeholder, })) }, form.getInputProps(value))))); case 'TncBlock': const tncInputProps = form.getInputProps('TNC-' + b.id); return (React__default.createElement(React__default.Fragment, null, React__default.createElement(Checkbox, Object.assign({ name: 'TNC-' + b.id, key: b.id, label: React__default.createElement("p", { className: "lead-modal__tnc-link", dangerouslySetInnerHTML: { __html: data.valueHTML } }), className: "tnc-block", "data-control": "checkbox" }, tncInputProps, { error: tncInputProps.error ? tncInputProps.error : undefined })))); } return null; }))); }; var useStyles$1 = createStyles((theme) => { return { root: {}, header: {}, heading: {}, description: {}, term: { a: { color: theme.fn.primaryColor(), }, }, controlList: {}, control: {}, submitBtn: {}, submitBtnWrapper: {}, }; }); const Heading = (_a) => { var rest = __rest(_a, []); const { heading } = useContext(LeadGenComponentContext); return heading ? (React__default.createElement(Text, Object.assign({ size: "h3" }, rest), heading)) : null; }; const FormComponent = ({ styles, className, classNames, fillInfo, popoverProps, submitProps, }) => { var _a; const { primaryColor } = useContext(LeadGenContext$1); const { listBlockAdded, leadFormConfig: { form, validateObj }, validatingEmailRef, validatingPhoneRef, formRef, setFormRef, onClose, onOtherSubmit, actionBlocks, locale, setShowOtpPhone, onSubmit, } = useContext(LeadGenComponentContext); const { classes, cx } = useStyles$1(undefined, { name: 'LeadGen__FormComponent', styles, classNames, }); const [isSubmitLoading, setIsSubmitLoading] = useState(false); const popUpSubmitText = actionBlocks.submitBlock.data.value; const middlewareOnSubmit = (e) => { e.preventDefault(); // mark all as touched to allow validation form.setTouched(Object.keys(validateObj).reduce((acc, cur) => { acc[cur] = true; return acc; }, {})); if (validatingEmailRef.current || validatingPhoneRef.current) { return; } setTimeout(() => { form.onSubmit((v) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j; if (Object.keys(form.errors).length) return; let newShowOtpPhone = null; if (listBlockAdded.findIndex((x) => x.name === 'PhoneOtpBlock') > -1) { // not submit yet, open otp const fieldName = (_b = (_a = listBlockAdded.find((x) => x.name === 'PhoneOtpBlock')) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.value; if ((_c = v[fieldName]) === null || _c === void 0 ? void 0 : _c.startsWith('+')) { newShowOtpPhone = { phone: v[fieldName], type: 'phone', }; } } if (listBlockAdded.findIndex((x) => x.name === 'WhatsappOtpBlock') > -1) { // not submit yet, open otp const fieldName = (_e = (_d = listBlockAdded.find((x) => x.name === 'WhatsappOtpBlock')) === null || _d === void 0 ? void 0 : _d.data) === null || _e === void 0 ? void 0 : _e.value; if ((_f = v[fieldName]) === null || _f === void 0 ? void 0 : _f.startsWith('+')) { newShowOtpPhone = { phone: v[fieldName], type: 'whatsapp', }; } } if (listBlockAdded.findIndex((x) => x.name === 'ZaloOtpBlock') > -1) { // not submit yet, open otp const fieldName = (_h = (_g = listBlockAdded.find((x) => x.name === 'ZaloOtpBlock')) === null || _g === void 0 ? void 0 : _g.data) === null || _h === void 0 ? void 0 : _h.value; if ((_j = v[fieldName]) === null || _j === void 0 ? void 0 : _j.startsWith('+')) { newShowOtpPhone = { phone: v[fieldName], type: 'zalo', }; } } if (newShowOtpPhone) { setIsSubmitLoading(true); Service.sendSMSOtpLead(newShowOtpPhone) .then((res) => { var _a; const respMessage = (_a = res === null || res === void 0 ? void 0 : res._messages) === null || _a === void 0 ? void 0 : _a[0]; if (respMessage === 'This phone number was verified') { onSubmit === null || onSubmit === void 0 ? void 0 : onSubmit(formRef.current, v); return; } setShowOtpPhone(newShowOtpPhone); }) .finally(() => { setIsSubmitLoading(false); }); return; } onSubmit === null || onSubmit === void 0 ? void 0 : onSubmit(formRef.current, v); })(e); }, 100); }; useEffect(() => { form === null || form === void 0 ? void 0 : form.setValues(fillInfo); }, [fillInfo]); return (React__default.createElement(LeadFormProvider$1, { form: form }, React__default.createElement(Box, { component: "form", ref: (el) => el && setFormRef(el), className: cx(className, classes.root), onSubmit: middlewareOnSubmit, styles: styles }, React__default.createElement("div", { className: classes.header }, React__default.createElement(Heading, { className: classes.heading }), React__default.createElement(Description, { className: classes.description })),