UNPKG

@hhgtech/hhg-components

Version:
1,015 lines (991 loc) 277 kB
import React__default, { createContext, useContext, useRef, useState, useEffect, useCallback, useMemo, forwardRef, useImperativeHandle, memo } from 'react'; import { d as NodeType, E as ELEMENT_CONTROL_INPUT_TYPE, f as NodeActionType, c as NodePosition, e as NodeFinalTypes, g as NodeMultipleOptions, N as NodeIntentType, F as FULL_KEY_ADDRESS, C as COMMON_DATE_TRANSLATE_KEY } from './index-90813715.js'; import { a as __awaiter, _ as __rest } from './tslib.es6-ea4dfe68.js'; import { f as basePath, G as GA_TOKEN_COOKIE, A as API_DATE_FORMAT, I as ISO_FORMAT, g as SSO_URL } from './index-5e947517.js'; import Cookies from 'js-cookie'; import fd from 'fastdom'; import fastdomPromised from 'fastdom/extensions/fastdom-promised'; import { G as GlobalData, c as callApi, u as locale, T as TogetherComponentGlobalContext } from './utils-40e61585.js'; import formatString from 'string-format'; import { a as getUserIdFromCookie, b as getSubotCookieId, c as getUserInfoFromCookie, d as getWindowId, o as overrideParamsByQuery, e as checkUntilFinished, g as getHelloSitesUrl, f as checkMobile, h as clickAndOpenInNewTab, i as formatUrlWithEncrypedGa, T as TIME_RESET_RESEND_OTP, j as isFakeEmail, s as ssoIntents, k as getHhgIdFromCookie } from './index-8b24c2ec.js'; export { T as TIME_RESET_RESEND_OTP, f as checkMobile, e as checkUntilFinished, h as clickAndOpenInNewTab, i as formatUrlWithEncrypedGa, g as getHelloSitesUrl, k as getHhgIdFromCookie, b as getSubotCookieId, a as getUserIdFromCookie, c as getUserInfoFromCookie, d as getWindowId, j as isFakeEmail, o as overrideParamsByQuery, s as ssoIntents } from './index-8b24c2ec.js'; import dayjs from 'dayjs'; import { MAP_DOMAIN_BY_LOCALE } from './constantsDomainLocales.js'; import cn from 'classnames'; import { C as Container$w } from './index-3a8ea352.js'; import { L as Loading } from './index-07d56b7b.js'; import { motion } from 'framer-motion'; import styled from '@emotion/styled'; import { M as MediaQueries } from './utils-cb7242c7.js'; import { B as Button } from './index-c68a0fa7.js'; import { Remarkable } from 'remarkable'; import { ArrowRight } from '@hhgtech/icons/other'; import { useInView } from 'react-intersection-observer'; import { Box, Textarea } from '@mantine/core'; import { C as CommonGAssets } from './index-ebe66e27.js'; import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'; import { d as LEAD_TOKEN_COOKIE } from './constants-f4091ce6.js'; import { v4 } from 'uuid'; import { T as Text } from './index-9f5659e8.js'; import { theme } from './miscTheme.js'; import { isProduction } from './constantsIsProduction.js'; import { S as Select } from './index-5d405c0d.js'; import '@mantine/dates'; import './useMantineLocale-0c6bea99.js'; import './index.styles-770020ac.js'; import './translationsContext-3a9e3453.js'; import '@mantine/hooks'; import './other-4ccb5568.js'; import './index-c2190f6e.js'; import isEmpty from 'lodash/isEmpty'; import { Controller, useForm } from 'react-hook-form'; import PhoneInputBase, { getCountryCallingCode, isPossiblePhoneNumber, parsePhoneNumber } from 'react-phone-number-input'; import { LoadScript } from '@react-google-maps/api'; import { u as usePlacesAutocomplete, G as GOOGLE_API_KEY, a as GOOGLE_API_LANGUAGE } from './usePlacesAutocomplete-b017462a.js'; import { setDefaultClass } from './miscDefaultClassWrapper.js'; import { L as LOCALE } from './Locale-f270bd9d.js'; import { I as InputDate } from './InputDate-13f91afd.js'; import { B as Button$1 } from './index-6351bdee.js'; import { D as Dropdown } from './index-a2183fa7.js'; import { u as useSSOV2Store, I as IS_SSOV2_ENABLED } from './store-994a3f4d.js'; import { g as getURLwithSSOTracking } from './utils-757f12af.js'; import 'date-fns/locale'; import './constantsSite.js'; import './constantsRiskScreener.js'; import './index-963a1701.js'; import './miscCookieHelper.js'; import 'slugify'; import './togetherApiPaths.js'; import './index-5d841202.js'; import './WhatsApp-f7a93c46.js'; import './Spinner-2d43eb3a.js'; import './index-9d21b711.js'; import './useScreenSize-981e5b51.js'; import '@mantine/carousel'; import './useUniqueId-4305c9aa.js'; import '@hhgtech/icons/core'; import '@mantine/notifications'; import '@emotion/react'; import 'zustand'; import './index-235eabf2.js'; import './normalizeLink-593b397a.js'; import './healthTools-84f2ddc1.js'; // extend fastdom const fastdom = fd.extend(fastdomPromised); const PATHS$1 = { POST_VERIFY_SMS_OTP: 'sms/update-phone', POST_SEND_OTP: 'sms/otp', POST_SEND_OTP_WHATSAPP: 'whatsapp/otp', POST_VERIFY_OTP: 'sms/verify', POST_VERIFY_OTP_WHATSAPP: 'sms/verify-whatsapp', GET_LANDING_PAGE_FIRST_NODE: 'landing_page/bot', GET_LANDING_PAGE_NEXT_NODE: 'landing_page/messages', POST_LANDING_PAGE_IMPRESSION: 'landing_page/impressions', POST_LANDING_PAGE_CLICK: 'landing_page/clicks', GET_INLINE_FIRST_NODE: 'bots', GET_INLINE_MESSAGE: 'inline/messages', GET_INLINE_IMPRESSION: 'inline/impressions', GET_INLINE_CLICK: 'inline/clicks', GET_SUBOT_LOG: 'log/bot/{botId}/{cookieId}/{accountId}?type={type}', POST_SUBOT_CREATE_LOG: 'log/bot', FETCH_URL_DATA: 'preview', GET_VOUCHER_QUANTITY: 'vouchers/total_quantity?search={search}&client_id={clientId}', }; const TIMEOUT = 30 * 60 * 1000; const WAITING_FIRST_RESP = 'waitingTheFirstResponse'; const CachedSystem = { // eslint-disable-next-line @typescript-eslint/no-explicit-any cached: {}, clearCached: (prefix) => { console.log(CachedSystem.cached); Object.keys(CachedSystem.cached) .filter((k) => k.startsWith(prefix)) .forEach((key) => { console.log(key); CachedSystem.cached[key] = undefined; }); }, withCached: (key, fnResponse) => __awaiter(void 0, void 0, void 0, function* () { if (CachedSystem.cached[key] === WAITING_FIRST_RESP) { return new Promise((resolve) => { const startDate = new Date().getTime(); const intervalId = setInterval(() => { const currentDate = new Date().getTime(); if (currentDate - startDate > 3000) { clearInterval(intervalId); } if (typeof CachedSystem.cached[key] === 'object') { resolve(CachedSystem.cached[key]); clearInterval(intervalId); } }, 100); }); } if (typeof CachedSystem.cached[key] === 'object') { return CachedSystem.cached[key]; } CachedSystem.cached[key] = 'waitingTheFirstResponse'; try { const result = yield fnResponse(); CachedSystem.cached[key] = result; setTimeout(() => { CachedSystem.cached[key] = undefined; }, TIMEOUT); return result; } catch (err) { CachedSystem.cached[key] = undefined; return Promise.reject(err); } }), }; const getSubotApiPath = (path, params) => { const { subotApiUrl } = GlobalData === null || GlobalData === void 0 ? void 0 : GlobalData.env; const apiUrl = subotApiUrl.endsWith('frontend/api/') ? subotApiUrl : subotApiUrl + 'frontend/api/'; return apiUrl + formatString(path, Object.assign({}, params)); }; /** inline message */ const subotInlineMessage = (data) => __awaiter(void 0, void 0, void 0, function* () { try { return yield callApi(getSubotApiPath(PATHS$1.GET_INLINE_MESSAGE), 'POST', { data, }); } catch (error) { } }); const computeExtraSettingsForBot = (data) => { var _a; if ((data === null || data === void 0 ? void 0 : data._status) === 1 && ((_a = data === null || data === void 0 ? void 0 : data._data) === null || _a === void 0 ? void 0 : _a.extra_settings)) { try { const extraSettingsObj = JSON.parse(data._data.extra_settings); if (typeof extraSettingsObj === 'object') { data._data.extra_settings = extraSettingsObj; } else { data._data.extra_settings = { sync_data_friso_campaign: false, }; } } catch (err) { data._data.extra_settings = { sync_data_friso_campaign: false, }; } } return data; }; /** inline first node */ const subotInlineFirstNode = (id) => __awaiter(void 0, void 0, void 0, function* () { try { const data = yield CachedSystem.withCached('SubotInlineFirstNode/' + id, () => __awaiter(void 0, void 0, void 0, function* () { const response = yield callApi(getSubotApiPath(PATHS$1.GET_INLINE_FIRST_NODE) + `/${id}`, 'GET'); computeExtraSettingsForBot(response); return response; })); return data; } catch (error) { return null; } }); /** inline click */ const subotInlineClick = (data) => __awaiter(void 0, void 0, void 0, function* () { try { return yield callApi(getSubotApiPath(PATHS$1.GET_INLINE_CLICK), 'POST', { data, }); } catch (error) { } }); /** inline impression */ const subotInlineImpression = (data) => __awaiter(void 0, void 0, void 0, function* () { try { return yield callApi(getSubotApiPath(PATHS$1.GET_INLINE_IMPRESSION), 'POST', { data, }); } catch (error) { } }); const calcAge = (value) => { const birthDate = dayjs(value); const today = dayjs(); return { birthDate, today, age: today.diff(birthDate, 'year'), }; }; /** * Temporary hard the range of age from 1 -> 6 for Durgo Campaign at this time * Ticket: https://hhgdev.atlassian.net/browse/HTO-1327 */ const validateAge = (value, errMsg, conditions) => { const { birthDate, today } = calcAge(value); if (!conditions || !conditions.length) { return true; } const diff = today.diff(birthDate, 'M') / 12; /** * No body in future can validate */ if (diff < 0 || (diff === 0 && today.date() < birthDate.date())) { return errMsg; } /** * from, to * if from === null then compare 0 - to * if to === null then compare from - infinity */ let isValid = false; if (Array.isArray(conditions)) { for (const cond of conditions) { const { from, to } = cond || {}; if (!from && !to) { break; } if ((from <= diff && diff <= to) || (from <= diff && to === null) || (from === null && to <= diff)) { isValid = true; break; } } } if (typeof localStorage !== 'undefined' && localStorage.getItem('hhg_debug') === 'true') { console.log('Log __DOB__ : ', { conditions, isValid, diff }); } return isValid || errMsg; }; const getDynamicScore = (node) => { try { return node.dynamic_score || {}; } catch (err) { return {}; } }; const getCurrentTotalDynamicScore = (listNodes, activeId, nextActionId, _formSubmitMeta) => { const dynamicScoreHash = getDynamicScore(listNodes[0]); // const isDynamicScoreMode = Object.keys(dynamicScoreHash).length > 0 if (!activeId) { return {}; } const currentIdx = listNodes.findIndex((n) => n.id == activeId); // console.log('[LogDynamicScore] currentIdx', currentIdx) // console.log('[LogDynamicScore] listNodes', listNodes) // console.log('[LogDynamicScore] activeId', activeId) const current_total_dynamic_score = listNodes.reduce((totalScore, _node, idx) => { var _a, _b; if (idx > currentIdx) { return totalScore; } const node = _node; // 1. Chưa chọn action nào trước đó. Chọn Action mới. Không có "node._message" // 2. Đã chọn một action trước đó rồi giờ edit lại. Có "node._message" // 3. Nếu có truyền "nextActionId" tính luôn cả action tiếp theo chuẩn bị chọn // Giả lập object _message sau khi đã chọn. const nodeMessage = nextActionId && node.id === activeId ? { action_id: nextActionId } : node._message; let acc = 0; // Calculate normal action score const currentSelectedAction = (_a = node.actions) === null || _a === void 0 ? void 0 : _a.find((act) => act.id === (nodeMessage === null || nodeMessage === void 0 ? void 0 : nodeMessage.action_id)); acc = acc + ((currentSelectedAction === null || currentSelectedAction === void 0 ? void 0 : currentSelectedAction.score) || 0); // Calculate dynamic action score. const isNodeWithDynamicScore = typeof dynamicScoreHash[node.id] !== 'undefined'; const formSubmitMeta = nextActionId && node.id === activeId ? _formSubmitMeta : nodeMessage === null || nodeMessage === void 0 ? void 0 : nodeMessage.form_submit_meta; if (isNodeWithDynamicScore && node.type === NodeType.FORM && formSubmitMeta) { // debugger // NodeId hiện tại có trong object "dynamic_score" // Lấy ra action // Kết hợp với action id đã chọn const actionIdsDynamicScore = dynamicScoreHash[node.id].action_ids.map((i) => i.id); const actionVarsDynamicScore = dynamicScoreHash[node.id].action_ids.map((i) => i.variableName); const formula = dynamicScoreHash[node.id].formula; const foundActions = (_b = node.actions) === null || _b === void 0 ? void 0 : _b.filter((act) => actionIdsDynamicScore.includes(act.id)); const foundFormMetas = formSubmitMeta.filter((f) => foundActions.find((a) => a.key === f.key) && (f.control === ELEMENT_CONTROL_INPUT_TYPE[NodeActionType.USER_SUBMIT_NUMBER] || f.control === ELEMENT_CONTROL_INPUT_TYPE[NodeActionType.USER_SUBMIT_DOB])); const formulaWithVariable = actionVarsDynamicScore .map((variableName, idx) => { const variableMapToActionId = actionIdsDynamicScore[idx]; const variableMapToAction = foundActions.find((act) => act.id === variableMapToActionId); const formValue = foundFormMetas.find((f) => (variableMapToAction === null || variableMapToAction === void 0 ? void 0 : variableMapToAction.key) === f.key && (f.control === ELEMENT_CONTROL_INPUT_TYPE[NodeActionType.USER_SUBMIT_NUMBER] || f.control === ELEMENT_CONTROL_INPUT_TYPE[NodeActionType.USER_SUBMIT_DOB])); if (!formValue) return ''; if (formValue.control === ELEMENT_CONTROL_INPUT_TYPE[NodeActionType.USER_SUBMIT_DOB]) { const { age } = calcAge(dayjs(formValue.value).toDate()); return `var ${variableName} = ${age};`; } return `var ${variableName} = ${formValue.value};`; }) .join(''); try { const computedValue = new Function(`${formulaWithVariable} return ${formula}`)(); if (!isNaN(computedValue)) { acc = acc + Math.round(computedValue); } } catch (err) { } } return totalScore + acc; }, 0); return { current_total_dynamic_score }; }; const replaceTextWithVariables = (label, listNodes) => { const dynamicScoreHash = getDynamicScore(listNodes[0]); try { const listFormNodes = listNodes.filter((node) => node.type === NodeType.FORM); /** Apply for dynamic score */ Object.keys(dynamicScoreHash).forEach((nodeId) => { var _a, _b, _c; const foundNode = listFormNodes.find((node) => node.id === nodeId); const actionIdsDynamicScore = dynamicScoreHash[nodeId].action_ids.map((i) => i.id); const actionVarsDynamicScore = dynamicScoreHash[nodeId].action_ids.map((i) => i.variableName); const formula = dynamicScoreHash[nodeId].formula; const foundActions = (_a = foundNode === null || foundNode === void 0 ? void 0 : foundNode.actions) === null || _a === void 0 ? void 0 : _a.filter((act) => actionIdsDynamicScore.includes(act.id)); const foundFormMetas = (_c = (_b = foundNode === null || foundNode === void 0 ? void 0 : foundNode._message) === null || _b === void 0 ? void 0 : _b.form_submit_meta) === null || _c === void 0 ? void 0 : _c.filter((f) => foundActions.find((a) => a.key === f.key) && (f.control === ELEMENT_CONTROL_INPUT_TYPE[NodeActionType.USER_SUBMIT_NUMBER] || f.control === ELEMENT_CONTROL_INPUT_TYPE[NodeActionType.USER_SUBMIT_DOB])); if (dynamicScoreHash[nodeId].formula && dynamicScoreHash[nodeId].formula_result_name && (foundFormMetas === null || foundFormMetas === void 0 ? void 0 : foundFormMetas.length)) { const formulaWithVariable = actionVarsDynamicScore .map((variableName, idx) => { const variableMapToActionId = actionIdsDynamicScore[idx]; const variableMapToAction = foundActions.find((act) => act.id === variableMapToActionId); const formValue = foundFormMetas.find((f) => (variableMapToAction === null || variableMapToAction === void 0 ? void 0 : variableMapToAction.key) === f.key && (f.control === ELEMENT_CONTROL_INPUT_TYPE[NodeActionType.USER_SUBMIT_NUMBER] || f.control === ELEMENT_CONTROL_INPUT_TYPE[NodeActionType.USER_SUBMIT_DOB])); if (!formValue) return ''; return `var ${variableName} = ${formValue.value};`; }) .join(''); const computedValue = new Function(`${formulaWithVariable} return ${formula}`)(); const formKey = dynamicScoreHash[nodeId].formula_result_name; if (!isNaN(computedValue) && label.includes(`{{var:${formKey}}}`)) { const regex = new RegExp(`{{var:${formKey}}}`, 'g'); label = label.replace(regex, String(Math.floor(computedValue * 100) / 100)); } } }); /** Apply for normal field in form */ listFormNodes.map((formNode) => { var _a, _b; (_b = (_a = formNode._message) === null || _a === void 0 ? void 0 : _a.form_submit_meta) === null || _b === void 0 ? void 0 : _b.map((formMeta) => { const formKey = formMeta.key; const formValue = formMeta.value; const regex = new RegExp(`{{var:${formKey}}}`, 'g'); label = label.replace(regex, formValue); }); }); } catch (err) { console.log('[replaceTextWithVariables]', err); } return label; }; const KEY_OF_TEXT_CHOICE_WITH_OTHER_FIELD = 'other'; const STATE_SUBOT_INLINE_KEY = 'stateInlineSSO'; /** Clone from this package https://github.com/sindresorhus/hex-rgb/blob/main/index.js */ /* eslint-disable no-redeclare */ /** Convert HEX color to RGBA. @param hex - The color in HEX format. Leading `#` is optional. @example ``` import hexRgb from 'hex-rgb'; hexRgb('4183c4'); //=> {red: 65, green: 131, blue: 196, alpha: 1} hexRgb('#4183c4'); //=> {red: 65, green: 131, blue: 196, alpha: 1} hexRgb('#fff'); //=> {red: 255, green: 255, blue: 255, alpha: 1} hexRgb('#22222299'); //=> {red: 34, green: 34, blue: 34, alpha: 0.6} hexRgb('#0006'); //=> {red: 0, green: 0, blue: 0, alpha: 0.4} hexRgb('#cd2222cc'); //=> {red: 205, green: 34, blue: 34, alpha: 0.8} hexRgb('#cd2222cc', {format: 'array'}); //=> [205, 34, 34, 0.8] hexRgb('#cd2222cc', {format: 'css'}); //=> 'rgb(205 34 34 / 80%)' hexRgb('#000', {format: 'css'}); //=> 'rgb(0 0 0)' hexRgb('#22222299', {alpha: 1}); //=> {red: 34, green: 34, blue: 34, alpha: 1} hexRgb('#fff', {alpha: 0.5}); //=> {red: 255, green: 255, blue: 255, alpha: 0.5} ``` */ const hexCharacters = 'a-f\\d'; const match3or4Hex = `#?[${hexCharacters}]{3}[${hexCharacters}]?`; const match6or8Hex = `#?[${hexCharacters}]{6}([${hexCharacters}]{2})?`; const nonHexChars = new RegExp(`[^#${hexCharacters}]`, 'gi'); const validHexSize = new RegExp(`^${match3or4Hex}$|^${match6or8Hex}$`, 'i'); function hexRgb(hex, options) { if (typeof hex !== 'string' || nonHexChars.test(hex) || !validHexSize.test(hex)) { throw new TypeError('Expected a valid hex string'); } hex = hex.replace(/^#/, ''); let alphaFromHex = 1; if (hex.length === 8) { alphaFromHex = Number.parseInt(hex.slice(6, 8), 16) / 255; hex = hex.slice(0, 6); } if (hex.length === 4) { alphaFromHex = Number.parseInt(hex.slice(3, 4).repeat(2), 16) / 255; hex = hex.slice(0, 3); } if (hex.length === 3) { hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; } const number = Number.parseInt(hex, 16); const red = number >> 16; const green = (number >> 8) & 255; const blue = number & 255; const alpha = typeof options.alpha === 'number' ? options.alpha : alphaFromHex; return [red, green, blue, alpha]; } const getPreviousStateFromStorage = (botId, { getParams }) => { try { if (!getUserIdFromCookie()) return null; const json = JSON.parse(localStorage.getItem(STATE_SUBOT_INLINE_KEY) || ''); const timeToExist = 30 * 60 * 1000; // 30 minutes if ((json === null || json === void 0 ? void 0 : json.botId) === botId && json.listNodes && json.activeId && json.createdAt + timeToExist > Date.now()) { localStorage.removeItem(STATE_SUBOT_INLINE_KEY); const isSSOAtLast = json.listNodes.slice(-1)[0].position === NodePosition.SSO; if (isSSOAtLast) { return { listNodes: json.listNodes, activeId: json.activeId, params: Object.assign(Object.assign(Object.assign({}, getParams()), json.params), { account_id: getUserIdFromCookie() || null, cookie_id: getSubotCookieId(json.params.cookie_id) }), }; } } return null; } catch (err) { return null; } }; const getSubotInlineLogs = (botItem) => __awaiter(void 0, void 0, void 0, function* () { var _a, _b; try { if (!botItem) return null; const response = yield callApi(getSubotApiPath(PATHS$1.GET_SUBOT_LOG, { botId: botItem.id, cookieId: getSubotCookieId(), accountId: getUserIdFromCookie() || '', type: 'inline', }), 'GET'); if (!((_a = response === null || response === void 0 ? void 0 : response._data) === null || _a === void 0 ? void 0 : _a.data) || ((_b = response === null || response === void 0 ? void 0 : response._data) === null || _b === void 0 ? void 0 : _b.type) !== 'inline') return null; const subotLogsJson = JSON.parse(response._data.data); const nodesLogs = subotLogsJson.nodes; const isInprogress = response._data.status === 'in_progress'; const isComplete = response._data.status === 'complete'; if (isInprogress || isComplete) { return { nodes: [botItem, ...nodesLogs], activeId: subotLogsJson.activeId, params: Object.assign(Object.assign({}, subotLogsJson.params), { account_id: getUserIdFromCookie() || subotLogsJson.params.account_id || null }), }; } return null; } catch (err) { return null; } }); const getExtraLogsWithCarePath = () => { try { // eslint-disable-next-line @typescript-eslint/no-explicit-any const nextInstance = window.next; const pageProps = nextInstance.router.components['/[...slug]'].props.pageProps; const isCarePath = pageProps.template === 'services-connection'; if (!isCarePath) return {}; return { project_id: 'care-path', user_funnel: pageProps.spotlight.additionalSlugActive || '', audience_name: pageProps.spotlight.groupIdActive || '', }; } catch (err) { return {}; } }; const extractUnifiedAnswers = (nodes) => { // console.log('nodes', nodes) const subotNodesMessage = nodes.filter((n) => n.name === 'Unified Questions'); const finalUnifiedAnswers = subotNodesMessage.reduce((result, nodeMessage) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w; if (nodeMessage.actions && ((_a = nodeMessage._message) === null || _a === void 0 ? void 0 : _a.action_id) && ((_b = nodeMessage._message) === null || _b === void 0 ? void 0 : _b.action_value)) { const key = nodeMessage._message.action_value; // submit if (nodeMessage.type === NodeType.FORM) { const addressControl = ['address', 'province', 'district', 'commune']; const formMetaExceptAddress = (((_c = nodeMessage._message) === null || _c === void 0 ? void 0 : _c.form_submit_meta) || []).filter((formMeta) => !addressControl.includes(formMeta.control)); /** For address field */ const formAddressMultipleFieldMap = (((_d = nodeMessage._message) === null || _d === void 0 ? void 0 : _d.form_submit_meta) || []) .filter((formMeta) => addressControl.includes(formMeta.control)) .reduce((result, formMetaItem) => { result[formMetaItem.control] = formMetaItem; return result; }, {}); const address = [ (_e = formAddressMultipleFieldMap.address) === null || _e === void 0 ? void 0 : _e.value, (_f = formAddressMultipleFieldMap.commune) === null || _f === void 0 ? void 0 : _f.value, (_g = formAddressMultipleFieldMap.district) === null || _g === void 0 ? void 0 : _g.value, (_h = formAddressMultipleFieldMap.province) === null || _h === void 0 ? void 0 : _h.value, ] .filter(Boolean) .join(', '); if (address && formAddressMultipleFieldMap.address) { result.push({ attribute: formAddressMultipleFieldMap.address.key, value: address, label_question: ((_k = (_j = nodeMessage.intents) === null || _j === void 0 ? void 0 : _j[0]) === null || _k === void 0 ? void 0 : _k.label) || '', }); } else { formMetaExceptAddress.forEach((formNormalMeta) => { var _a, _b; result.push({ attribute: formNormalMeta.key, value: formNormalMeta.value, label_question: ((_b = (_a = nodeMessage.intents) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.label) || '', }); }); } } if (nodeMessage.type === NodeType.TEXT) { if (nodeMessage.is_multi_select) { const actionIds = Object.keys(nodeMessage._message.selected_actions || {}); const actionLabel = nodeMessage.actions .filter((act) => act.label && actionIds.includes(act.id)) .map((act) => act.label); actionIds.length && result.push({ attribute: nodeMessage.actions[0].key || '', value: actionLabel, label_question: ((_m = (_l = nodeMessage.intents) === null || _l === void 0 ? void 0 : _l[0]) === null || _m === void 0 ? void 0 : _m.label) || '', }); } else { const actionId = nodeMessage._message.action_id; const action = nodeMessage.actions.find((a) => a.id === actionId); const actionLabel = action === null || action === void 0 ? void 0 : action.label; // Select "Other, please provide more detail" -> There is an input below the option is stored in form_submit_meta const otherText = (_q = (_p = (_o = nodeMessage._message) === null || _o === void 0 ? void 0 : _o.form_submit_meta) === null || _p === void 0 ? void 0 : _p.find((f) => f.key === KEY_OF_TEXT_CHOICE_WITH_OTHER_FIELD)) === null || _q === void 0 ? void 0 : _q.value; const isSelectedOther = (action === null || action === void 0 ? void 0 : action.type) === NodeActionType.USER_CHOICE_TEXT_BY_INPUT; if (actionLabel && actionId) { result.push({ attribute: key, value: isSelectedOther && otherText ? otherText : actionLabel, label_question: ((_s = (_r = nodeMessage.intents) === null || _r === void 0 ? void 0 : _r[0]) === null || _s === void 0 ? void 0 : _s.label) || '', }); } } } if (nodeMessage.type === NodeType.POLL) { const nodeId = nodeMessage.id; const actionIds = ((_u = (_t = nodeMessage._message) === null || _t === void 0 ? void 0 : _t.current_polls) === null || _u === void 0 ? void 0 : _u[nodeId]) || []; const actionLabel = nodeMessage.actions .filter((act) => act.label && actionIds.includes(act.id)) .map((act) => act.label); actionIds.length && result.push({ attribute: nodeMessage.actions[0].key || '', value: actionLabel, label_question: ((_w = (_v = nodeMessage.intents) === null || _v === void 0 ? void 0 : _v[0]) === null || _w === void 0 ? void 0 : _w.label) || '', }); } } return result; }, []); // console.log('finalUnifiedAnswers', finalUnifiedAnswers) return finalUnifiedAnswers; }; const extractVoucherAnswers = (nodes, botItem) => { var _a; try { if (((_a = botItem.extra_settings) === null || _a === void 0 ? void 0 : _a.subot_type) !== 'ACUVUE') { return; } let voucherProduct = ''; // Select let voucherColor = ''; // Select let voucherSize = ''; // Dropdown let voucherLocation = ''; // Dropdown let phone = ''; const anotherFields = {}; let emailSubmitted = getUserInfoFromCookie().email; const nodesWithMessage = (nodes || []); nodesWithMessage.forEach((nodeMessage) => { var _a, _b, _c, _d, _e, _f, _g, _h; const submitMessage = nodeMessage._message; if (!submitMessage) return; const selectedAction = (_a = nodeMessage.actions) === null || _a === void 0 ? void 0 : _a.find((act) => act.id === submitMessage.action_id); if (submitMessage.action_value === 'voucher_product') { voucherProduct = (selectedAction === null || selectedAction === void 0 ? void 0 : selectedAction.label) || ''; } else if (submitMessage.action_value === 'voucher_color') { voucherColor = (selectedAction === null || selectedAction === void 0 ? void 0 : selectedAction.label) || ''; } if (nodeMessage.type === NodeType.FORM) { const logicFind = (key) => (formMeta) => { return formMeta.key === key; }; const formMetaVoucherSize = (_b = submitMessage.form_submit_meta) === null || _b === void 0 ? void 0 : _b.find(logicFind('voucher_size')); const formMetaVoucherLocation = (_c = submitMessage.form_submit_meta) === null || _c === void 0 ? void 0 : _c.find(logicFind('voucher_location')); const formMetaVoucherProduct = (_d = submitMessage.form_submit_meta) === null || _d === void 0 ? void 0 : _d.find(logicFind('voucher_product')); const formMetaVoucherColor = (_e = submitMessage.form_submit_meta) === null || _e === void 0 ? void 0 : _e.find(logicFind('voucher_color')); const formMetaEmail = (_f = submitMessage.form_submit_meta) === null || _f === void 0 ? void 0 : _f.find((formMeta) => { return formMeta.control === 'email'; }); const formMetaPhone = (_g = submitMessage.form_submit_meta) === null || _g === void 0 ? void 0 : _g.find((formMeta) => { return formMeta.control === 'tel'; }); if (formMetaVoucherSize) { voucherSize = formMetaVoucherSize.value; } if (formMetaVoucherLocation) { voucherLocation = formMetaVoucherLocation.value; } if (formMetaVoucherProduct) { voucherProduct = formMetaVoucherProduct.value; } if (formMetaVoucherColor) { voucherColor = formMetaVoucherColor.value; } if (formMetaEmail) { emailSubmitted = formMetaEmail.value; } if (formMetaPhone) { phone = formMetaPhone.value; } (_h = submitMessage.form_submit_meta) === null || _h === void 0 ? void 0 : _h.filter((formMeta) => { return ![ 'voucher_size', 'voucher_location', 'voucher_product', 'voucher_color', 'email', 'tel', ].includes(formMeta.control); }).forEach((formMeta) => { anotherFields[formMeta.key] = formMeta.value; }); } }); /** Doc: https://docs.google.com/spreadsheets/d/1WxA84tyzTyUQyloFdmzV7_Cffz7XYIc3ZJ2mVYQNgs4/edit#gid=0 */ /** https://docs.google.com/spreadsheets/d/1WxA84tyzTyUQyloFdmzV7_Cffz7XYIc3ZJ2mVYQNgs4/edit?gid=1287925107#gid=1287925107 */ if (emailSubmitted) { return Object.assign(Object.assign({}, anotherFields), { email: emailSubmitted, voucherName: voucherProduct === 'ACUVUE® OASYS (1-DAY) WITH HYDRALUXE®' ? voucherProduct : voucherProduct && voucherColor && voucherSize ? `${voucherProduct}|${voucherColor}|${voucherSize}` : 'N/A', voucher_product: voucherProduct || 'N/A', voucher_location: voucherLocation, voucher_size: voucherSize || 'N/A', voucher_color: voucherColor || 'N/A', phone }); } } catch (err) { console.log('ExtractVoucherAnswer', err); } }; const saveSubotInlineLogs = ({ nodes, activeId, params, accountIdFromLogs, }) => __awaiter(void 0, void 0, void 0, function* () { try { let statusFlowBot = 'in_progress'; const lastNode = nodes[nodes.length - 1]; // Saving data with status COMPLETE when chatbot go to final node if ((lastNode === null || lastNode === void 0 ? void 0 : lastNode.type) && NodeFinalTypes.includes(lastNode.type)) { statusFlowBot = 'complete'; } /** Remove the first node and push it later in data fetching step to make sure data is latest */ const dataNodes = nodes.slice(1); const data = { activeId, params, nodes: dataNodes, tracking: Object.assign(Object.assign({}, getExtraLogsWithCarePath()), { full_url: window.location.href }), unifiedAnswers: extractUnifiedAnswers(dataNodes), voucherAnswers: extractVoucherAnswers(dataNodes, nodes[0]), }; console.log('data.voucherAnswers', data.voucherAnswers); const payload = { cookie_id: getSubotCookieId(), account_id: accountIdFromLogs || getUserIdFromCookie() || null, bot_id: nodes[0].id, flow_uuid: nodes[0].flow_uuid, data: JSON.stringify(data), status: statusFlowBot, type: 'inline', market: MAP_DOMAIN_BY_LOCALE[locale], }; yield callApi(getSubotApiPath(PATHS$1.POST_SUBOT_CREATE_LOG), 'POST', { data: payload, }); } catch (err) { // } }); const getColorWithOpacity = (color, opacity) => { try { const [r, g, b] = hexRgb(color, { format: 'array' }); return `rgba(${r}, ${g}, ${b}, ${opacity})`; } catch (err) { return undefined; } }; const detectToSkipNodeStart = (botItem, currentActiveId, currentListNodes) => { if (!(botItem === null || botItem === void 0 ? void 0 : botItem.subot_field_type)) { return [currentActiveId, currentListNodes]; } const foundNode = currentListNodes.find((nodeItem) => nodeItem.id == currentActiveId); const isActiveAtFirstNode = foundNode && foundNode.hasOwnProperty('first_node'); if (isActiveAtFirstNode && currentListNodes.length > 1) { return [currentListNodes[1].id, currentListNodes]; } return [currentActiveId, currentListNodes]; }; const SubotInlineContext = createContext({ activeId: '', params: {}, listNodes: [], loading: true, getParams: () => ({}), onNext: () => null, onPrev: () => null, onSubmit: () => null, onStartOver: () => null, onChange: () => null, isShowFooter: false, setIsShowFooter: () => null, setLoading: () => null, userInfo: null, }); const SubotInlineProvider = ({ children, articleLink, subotId, isFullContainer, bgColor: _bgColor, primaryColor: _primaryColor, textColor, textButtonColor, bgContentColor, bgImgFullContainer, isDisabledAnimationOnMobile, onCloseMobile, userInfo, }) => { const { formatMessage: f, action: { pushNotifications }, } = useContext(TogetherComponentGlobalContext); const ref = useRef(null); // const { formatMessage: f } = useIntl() const refAccountIdFromLogs = useRef(null); const [loading, setLoading] = useState(true); const [activeId, setActiveId] = useState(''); const [listNodes, setListNodes] = useState([]); const [isShowFooter, setIsShowFooter] = useState(false); const [params, setParams] = useState({}); useEffect(() => { const bgColor = _bgColor || '#e3f2ff'; const primaryColor = _primaryColor || '#2d87f3'; const startTime = new Date().getTime(); const intervalId = setInterval(() => { const element = ref.current; const endTime = new Date().getTime(); if (element) { fastdom.mutate(() => { element.style.setProperty('--subot-inline-bg-color', bgColor); element.style.setProperty('--subot-inline-primary-color', primaryColor); element.style.setProperty('--subot-inline-primary-color-hover', getColorWithOpacity(primaryColor, 0.9) || primaryColor); element.style.setProperty('--subot-inline-primary-color-100', getColorWithOpacity(primaryColor, 0.1) || '#e3f2ff'); element.style.setProperty('--subot-inline-primary-color-300', getColorWithOpacity(primaryColor, 0.3) || '#bcdeff'); if (textColor) { element.style.setProperty('--subot-inline-text-color', textColor); } if (textButtonColor) { element.style.setProperty('--subot-inline-text-button-color', textButtonColor); } if (bgContentColor) { element.style.setProperty('--subot-inline-bg-content-color', bgContentColor); } }); clearInterval(intervalId); } if (endTime - startTime > 3 * 60 * 1000) { clearInterval(intervalId); } }, 100); return () => { clearInterval(intervalId); }; }, [_bgColor, _primaryColor, textColor, textButtonColor, bgContentColor]); /** Get Params */ const getParams = useCallback(() => { const gaData = window.gaData; const url = window.location.origin + basePath + ((GlobalData === null || GlobalData === void 0 ? void 0 : GlobalData.locale) === 'tl-PH' ? articleLink.replace('fil/', '') : articleLink); const params = { bot_id: subotId, account_id: getUserIdFromCookie() || null, action_id: '', action_value: '', cookie_id: getSubotCookieId(), current_score: 0, current_keys: [], current_selected: [], form_submit_meta: [], gtm_id: gaData ? Object.keys(gaData)[0] : '', ga_client_id: Cookies.get('_ga') || '', is_new: false, mode: 'inline', node_id: '', selected_actions: {}, title_url: document.title || '', // url, // Keep this commnent line to test on local url: url .replace('http://localhost:6006', 'https://discover.hellobacsi.com') // Storybook .replace('http://localhost', 'https://discover.hellobacsi.com') .replace('dev.', 'discover.') .replace('staging.hellohealthgroup.com', 'discover.hellodoctor.com.ph') // Stagign .replace('https://hellohealthgroup.com', 'https://hellodoctor.com.ph'), window_id: getWindowId(), }; return overrideParamsByQuery(params, GlobalData === null || GlobalData === void 0 ? void 0 : GlobalData.router.query); }, []); const elementScrollIntoView = useCallback(() => { var _a; (_a = ref.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'center', }); }, []); const getFirstNode = useCallback((params, useSubotLog = true) => __awaiter(void 0, void 0, void 0, function* () { var _a; if (!params || !params.url || !params.bot_id) { return; } let newActiveId = ''; let nodes = []; setLoading(true); const resFirst = yield subotInlineFirstNode(params.bot_id); if ((resFirst === null || resFirst === void 0 ? void 0 : resFirst._status) === 1) { newActiveId = resFirst === null || resFirst === void 0 ? void 0 : resFirst._data.id.toString(); nodes.push(resFirst === null || resFirst === void 0 ? void 0 : resFirst._data, resFirst === null || resFirst === void 0 ? void 0 : resFirst._data.first_node); } const subotLogs = useSubotLog ? yield getSubotInlineLogs(nodes[0]) : null; if (subotLogs) { nodes = subotLogs.nodes; newActiveId = subotLogs.activeId; refAccountIdFromLogs.current = ((_a = subotLogs.params) === null || _a === void 0 ? void 0 : _a.account_id) || 0; } /** [Subot Inline] Show result page after redirect from SSO */ const previousState = getPreviousStateFromStorage(params.bot_id, { getParams, }); if (previousState && previousState.params.action_id && previousState.params.action_value) { const resResultInline = yield subotInlineMessage(previousState.params); if ((resResultInline === null || resResultInline === void 0 ? void 0 : resResultInline._status) === 1 && (resResultInline === null || resResultInline === void 0 ? void 0 : resResultInline._data.node)) { newActiveId = resResultInline === null || resResultInline === void 0 ? void 0 : resResultInline._data.node.id; nodes = previousState.listNodes; nodes[nodes.length - 1] = resResultInline === null || resResultInline === void 0 ? void 0 : resResultInline._data.node; saveSubotInlineLogs({ nodes, activeId: newActiveId, params: previousState.params, accountIdFromLogs: refAccountIdFromLogs.current, }); setTimeout(() => { elementScrollIntoView(); }, 100); } } const newParams = (previousState === null || previousState === void 0 ? void 0 : previousState.params) || (subotLogs === null || subotLogs === void 0 ? void 0 : subotLogs.params) || params; const [computedActiveId, computedNodes] = detectToSkipNodeStart(nodes[0], newActiveId, nodes); setLoading(false); setActiveId(computedActiveId); setListNodes(computedNodes); setParams(Object.assign(Object.assign({}, params), newParams)); }), []); const onSubmit = useCallback((nextNode, message) => { // Bot Event Submission const botEvtSubmissionBtnEl = document.querySelector(`.si-revamp-event-submission[data-bot-id="${subotId}"]`); if (botEvtSubmissionBtnEl) { botEvtSubmissionBtnEl.click(); } let newActiveId = activeId; let newListNodes = [...listNodes]; if (message === null || message === void 0 ? void 0 : message.node_id) { const updateNodeIndex = newListNodes.findIndex(({ id }) => id == message.node_id); if (updateNodeIndex !== -1) { newListNodes[updateNodeIndex]._message = Object.assign(Object.assign({}, newListNodes[updateNodeIndex]._message), message); newListNodes = [...newListNodes.slice(0, updateNodeIndex + 1)]; } } setLoading(true); if (nextNode) { const nextNodeFindIndex = newListNodes.findIndex(({ id }) => id == (nextNode === null || nextNode === void 0 ? void 0 : nextNode.id)); if (nextNodeFindIndex === -1) { newListNodes = [...newListNodes, Object.assign({}, nextNode)]; } else { const tmpNode = Object.assign(Object.assign(Object.assign({}, newListNodes[nextNodeFindIndex]), nextNode), { _message: Object.assign(Object.assign({}, newListNodes[nextNodeFindIndex]._message), nextNode === null || nextNode === void 0 ? void 0 : nextNode._message) }); newListNodes = [ ...newListNodes.slice(0, nextNodeFindIndex), Object.assign({}, tmpNode), ...newListNodes.slice(nextNodeFindIndex + 1), ]; } newActiveId = nextNode.id; } setTimeout(() => { setListNodes(newListNodes); setActiveId(newActiveId); setLoading(false); saveSubotInlineLogs({ nodes: newListNodes, activeId: newActiveId, params, accountIdFromLogs: refAccountIdFromLogs.current, }); }, 250); }, [listNodes, activeId]); const onNext = useCallback((messageParams) => __awaiter(void 0, void 0, void 0, function* () { if (messageParams === null || messageParams === void 0 ? void 0 : messageParams.node_id) { const newMessage = Object.assign(Object.assign({}, messageParams), getCurrentTotalDynamicScore(listNodes, activeId, messageParams.action_id)); const res = yield subotInlineMessage(newMessage); setLoading(false); if ((res === null || res === void 0 ? void 0 : res._status) === 1) { const _b = res === null || res === void 0 ? void 0 : res._data, { node } = _b, restData = __rest(_b, ["node"]); const nextNode = Object.assign(Object.assign({}, node), { _message: Object.assign(Object.assign({}, restData), { node_id: node.id }) }); const foundIdxOfNextNode = listNodes.findIndex((nodeItem) => nodeItem.id === nextNode.id); const isFound = foundIdxOfNextNode !== -1; if (isFound) { // onSubmi