UNPKG

@hhgtech/hhg-components

Version:
1,035 lines (995 loc) • 57.7 kB
import React__default, { createContext, forwardRef, useContext, useImperativeHandle, useState, useRef, useEffect, useMemo, Fragment } from 'react'; import { Box, Input, Grid, Title, Container, Flex, rem, Stack, AspectRatio } from '@mantine/core'; import { P as Phone, I as Input$1, R as Radio, O as OTP, d as Checkbox } from './index-bd44bcb2.js'; import '@mantine/dates'; import { L as LOCALE_SPECS } from './index-8c40504a.js'; import './index-fe4471f4.js'; import { C as CommonGAssets } from './index-7adf994c.js'; import './index-3f09210d.js'; import { T as Text } from './index-0b67696c.js'; import { B as Button } from './index-2d25b0f0.js'; import './index-17c85f76.js'; import './index.styles-3adef5f6.js'; import './translationsContext-18f7b7e0.js'; import { useInterval, useCounter } from '@mantine/hooks'; import { M as MediaQueries, a as getPopupWrapperDom } from './utils-538169b3.js'; import './index-04505e35.js'; import { M as MAPPED_LOCALE, h as hiddenEmailChar } from './utils-2d973164.js'; export { M as MAPPED_LOCALE } from './utils-2d973164.js'; import { createFormContext, yupResolver } from '@mantine/form'; import styled from '@emotion/styled'; import { _ as __rest, a as __awaiter } from './tslib.es6-00ab44b2.js'; import { u as useTranslations } from './index-09d9e570.js'; import * as yup from 'yup'; import { D as DatePicker } from './index-0861b084.js'; import { A as AddressInput } from './index-48d7f133.js'; import { V as Visible } from './Visible-95cdc6e2.js'; import { H as Heading } from './index-e348d0b2.js'; import { createPortal } from 'react-dom'; import { theme } from './miscTheme.js'; import { u as useScreenSize } from './index-50aea2c8.js'; import { L as LogoIcon } from './logoIcon-b515c32f.js'; import { I as Icon } from './index-a22d54f1.js'; import throttle from 'lodash/throttle'; import { T as Text$1 } from './index-546ca9b5.js'; import { B as Button$1 } from './index-67429eb2.js'; import { format } from 'date-fns'; import flattenChildren from 'react-keyed-flatten-children'; import '@hhgtech/icons/other'; import '@mantine/carousel'; import './shared-b07d1eb2.js'; import 'classnames'; import 'uuid'; import './useUniqueId-38cdf062.js'; import './constantsSite.js'; import './Locale-dc1237b9.js'; import '@emotion/react'; import '@hhgtech/icons/core'; import 'date-fns/locale'; import './constantsDomainLocales.js'; import './constantsRiskScreener.js'; import './constantsIsProduction.js'; import 'dayjs'; import '@mantine/notifications'; import './WhatsApp-6a0c0a12.js'; import './Spinner-589f30ad.js'; // define shared context const OnboardingContext = createContext({ currentStep: 0, setCurrentStep: () => false, setMaxStep: () => false, nextStep: () => false, prevStep: () => false, isMarryBaby: false, siteType: 'helloSites', sharedData: {}, setSharedData: () => false, }); const [FormProvider, useFormContext, useForm] = createFormContext(); const StyledDynamicForm = styled(Box) ` .phone-input { width: 100%; margin-bottom: 32px; ${MediaQueries.mbDown} { margin-bottom: 16px; } .PhoneInput { margin-bottom: 16px; } .PhoneInputCountry { border-radius: 4px 0 0 4px; } .PhoneInputInput { border-radius: 0 4px 4px 0; } } `; const DynamicForm = (_a) => { var { inputOrder = ['phone'], withSimilac = false, customTerms = '', formContext } = _a, rest = __rest(_a, ["inputOrder", "withSimilac", "customTerms", "formContext"]); const { t } = useTranslations(); const form = formContext || useFormContext(); const Phone$1 = (_a) => { var { label, name = 'phone' } = _a, phoneProps = __rest(_a, ["label", "name"]); return (React__default.createElement(Input.Wrapper, { className: withSimilac ? 'input-control' : 'phone-input', withAsterisk: true, label: label || withSimilac ? (React__default.createElement(Text, { size: "s4", weight: "semiBold", as: "span" }, label || t('onboarding.similac.input.phone'))) : undefined }, React__default.createElement(Phone, Object.assign({ defaultCountry: MAPPED_LOCALE[process.env.UNIFY_LOCALE] || 'VN' }, form.getInputProps(name), phoneProps)), React__default.createElement(Input.Error, { size: "md" }, form.errors.phone))); }; const FullName = (_a) => { var { label, name = 'name' } = _a, rest = __rest(_a, ["label", "name"]); return (React__default.createElement(Input$1, Object.assign({ label: React__default.createElement(Text, { size: "s4", weight: "semiBold", as: "span" }, label || t('onboarding.formEmail.yourName')), withAsterisk: true }, form.getInputProps(name), rest))); }; const Email = (_a) => { var { label, name = 'email' } = _a, rest = __rest(_a, ["label", "name"]); return (React__default.createElement(Input$1, Object.assign({ label: React__default.createElement(Text, { size: "s4", weight: "semiBold", as: "span" }, label || t('onboarding.formEmail.yourEmail')), withAsterisk: true }, form.getInputProps(name), rest))); }; const Dob = (_a) => { var { label, name = 'dob' } = _a, rest = __rest(_a, ["label", "name"]); return (React__default.createElement(DatePicker, Object.assign({ label: React__default.createElement(Text, { size: "s4", weight: "semiBold", as: "span" }, label || t('onboarding.formEmail.yourBirthday')), placeholder: "DD/MM/YYYY" }, form.getInputProps(name), rest))); }; const Gender = (_a) => { var { label, name = 'gender' } = _a, radioProps = __rest(_a, ["label", "name"]); return (React__default.createElement(Radio.Group, Object.assign({ className: "radio-group", label: React__default.createElement(Text, { size: "s4", weight: "semiBold", as: "span" }, label || t('tools.selectGender')) }, form.getInputProps(name), radioProps), React__default.createElement(Radio, { value: "0", label: t('onboarding.formEmail.genderMale') }), React__default.createElement(Radio, { value: "1", label: t('onboarding.formEmail.genderFemale') }))); }; const Otp = ({ name = 'otp' }) => (React__default.createElement("div", { className: "otp-input" }, React__default.createElement(OTP, Object.assign({ enterKeyHint: undefined, nonce: undefined }, form.getInputProps(name))), React__default.createElement(Input.Error, null, form.errors.otp))); const Password = ({ label, name = 'password' }) => (React__default.createElement(Input$1.Password, Object.assign({ label: React__default.createElement(Text, { size: "s4", weight: "semiBold", as: "span" }, label || t('onboarding.updatePassword.password')), withAsterisk: true, rightSection: React__default.createElement(Visible, null) }, form.getInputProps(name)))); const Term = ({ name = 'term', className = '' }) => customTerms ? (React__default.createElement("div", { style: { marginBottom: 16 }, className: className }, React__default.createElement(Checkbox, Object.assign({ label: React__default.createElement(Text, { size: "p4", as: "span", sx: { a: { color: '#2d87f3', fontWeight: 'bold', letterSpacing: 0, }, } }, customTerms) }, form.getInputProps(name, { type: 'checkbox' }), { error: null })), React__default.createElement(Input.Error, { size: "md" }, form.getInputProps('term', { type: 'checkbox' }).error))) : null; const Address = (_a) => { var { label, className = '', name = 'address' } = _a, rest = __rest(_a, ["label", "className", "name"]); return (React__default.createElement(AddressInput, Object.assign({ className: `${className} input-control`, label: React__default.createElement(Text, { size: "s4", weight: "semiBold", as: "span" }, label || t('onboarding.similac.input.address')) }, form.getInputProps(name), rest))); }; const ConfirmPassword = ({ label, name = 'confirmPassword', }) => (React__default.createElement(Input$1.Password, Object.assign({ label: React__default.createElement(Text, { size: "s4", weight: "semiBold", as: "span" }, label || t('onboarding.updatePassword.confirmPassword')), withAsterisk: true, rightSection: React__default.createElement(Visible, null) }, form.getInputProps(name)))); const elements = { phone: Phone$1, full_name: FullName, email: Email, dob: Dob, gender: Gender, otp: Otp, password: Password, confirm_password: ConfirmPassword, term: Term, address: Address, }; const content = inputOrder.map((part) => { var _a; const curProps = typeof part === 'string' ? { inputType: part } : part; return (_a = elements[curProps.inputType]) === null || _a === void 0 ? void 0 : _a.call(elements, curProps); }); return React__default.createElement(StyledDynamicForm, Object.assign({}, rest), content); }; const frisoOnboardingSchema = (t) => yup.object().shape({ phone: yup.string().required(t('onboarding.updatePhone.error')).default(''), name: yup.string().required(t('onboarding.errorMessage.requiredName')), email: yup .string() .required(t('onboarding.errorMessage.requiredEmail')) .email(t('onboarding.errorMessage.invalidEmail')) .default(''), address: yup.mixed().required(t('onboarding.similac.address.error')), term: yup.bool().oneOf([true], t('validation.error.requiredField')), }); const FrisoOnboardingForm = (_a, ref) => { var { inputOrder, onSubmit: _onSubmit, validateSchema, defaultValues, isActive, customTerms, customFormTexts } = _a, rest = __rest(_a, ["inputOrder", "onSubmit", "validateSchema", "defaultValues", "isActive", "customTerms", "customFormTexts"]); const { nextStep, setSharedData, sharedData } = useContext(OnboardingContext); const { t } = useTranslations(); const form = useForm({ initialValues: { term: false, phone: (sharedData === null || sharedData === void 0 ? void 0 : sharedData.phone) || (defaultValues === null || defaultValues === void 0 ? void 0 : defaultValues.phone) || '', email: (sharedData === null || sharedData === void 0 ? void 0 : sharedData.email) || (defaultValues === null || defaultValues === void 0 ? void 0 : defaultValues.email) || '', name: (sharedData === null || sharedData === void 0 ? void 0 : sharedData.name) || (defaultValues === null || defaultValues === void 0 ? void 0 : defaultValues.name) || '', }, validate: validateSchema || yupResolver(frisoOnboardingSchema(t)), }); const onSubmit = (values) => __awaiter(void 0, void 0, void 0, function* () { try { yield (_onSubmit === null || _onSubmit === void 0 ? void 0 : _onSubmit(values)); setSharedData((d) => (Object.assign(Object.assign({}, d), { phone: values.phone, email: values.email, name: values.name }))); nextStep(); } catch (err) { console.error(err); } }); const onError = (fieldErrors) => { console.log(fieldErrors); }; const handleSubmitForm = () => { var _a; return (_a = form.onSubmit(onSubmit, onError)) === null || _a === void 0 ? void 0 : _a(); }; useImperativeHandle(ref, () => ({ submitForm: handleSubmitForm, })); return (React__default.createElement(Box, Object.assign({ "data-active": isActive }, rest), React__default.createElement(Box, { sx: (theme) => ({ display: 'flex', flexDirection: 'column', gap: '16px', [theme.fn.largerThan('md')]: { gap: '24px', }, }) }, React__default.createElement(Box, { sx: { textAlign: 'center' } }, React__default.createElement(Heading, { tag: "h4", as: "h2" }, customFormTexts === null || customFormTexts === void 0 ? void 0 : customFormTexts.heading), React__default.createElement(Text, { size: "p3" }, customFormTexts === null || customFormTexts === void 0 ? void 0 : customFormTexts.description)), React__default.createElement(FormProvider, { form: form }, React__default.createElement("form", { className: "friso-form", style: { width: '100%', }, onSubmit: form.onSubmit(onSubmit, onError) }, React__default.createElement(Box, { sx: { '.friso-form': { display: 'flex', flexWrap: 'wrap', gap: '8px', '.input-control': { width: '100%', marginBottom: 0, }, '.phone-input': { marginBottom: '0 !important', '.PhoneInput': { marginBottom: '0 !important', }, }, }, } }, React__default.createElement(DynamicForm, { inputOrder: inputOrder, customTerms: customTerms, className: "friso-form" }))))))); }; var FrisoOnboardingForm$1 = forwardRef(FrisoOnboardingForm); const StyledOnboardingModal = styled.div ` position: fixed; inset: 0; z-index: 1000; background: white; overflow-y: auto; `; const StyledContainer = styled.div ` height: 100%; ${MediaQueries.lgPcUp} { display: table; width: 100%; height: calc(100% - 25px); } `; const StyledContent = styled.div ` padding: 16px; ${MediaQueries.mbUp} { padding: 48px 24px 24px; } &[data-similac='true'][data-has-banner='true'] { ${MediaQueries.mbDown} { background: white; border-top-left-radius: 1rem; border-top-right-radius: 1rem; margin-top: -1rem; } } `; const StyledBannerCol = styled.div ` width: 640px; padding: 16px 16px 0 16px; display: none; ${MediaQueries.mbUp} { width: 640px; display: table-cell; } `; const StyledBannerInner = styled.div ` background-color: ${theme.colors.primary50}; border-radius: 12px; height: 100%; display: flex; flex-direction: column; justify-content: space-between; &[data-is-marry-baby='true'] { background-color: ${theme.mbColors.tonePink}; } `; const StyledIntro = styled.div ` margin-top: 40px; padding: 24px 40px; `; const StyledBannerImgWrapper = styled.div ` width: 100%; display: block; img { width: 100%; height: auto; } &.similac { min-width: 1px; img { width: 100%; height: 100%; object-fit: contain; } ${MediaQueries.mbUp} { position: sticky; top: 0; height: 100vh; } } `; const OnboardingModal = (_a) => { var { children, withSimilac, banner, withPortal } = _a, rest = __rest(_a, ["children", "withSimilac", "banner", "withPortal"]); const { isMobile } = useScreenSize(); const { isMarryBaby } = useContext(OnboardingContext); const { t } = useTranslations(); if (withPortal && typeof window === 'undefined') return null; const MainContent = (React__default.createElement(StyledOnboardingModal, Object.assign({}, rest), React__default.createElement(StyledContainer, null, React__default.createElement(Grid, { sx: { [MediaQueries.mbDown]: { margin: 0, }, '.mantine-Grid-col': { [MediaQueries.mbDown]: { padding: 0, }, }, } }, React__default.createElement(Grid.Col, { span: (typeof banner === 'object' || withSimilac) && !isMobile ? 6 : 12, order: withSimilac ? 2 : 1, orderMd: withSimilac ? 1 : 2, sx: { zIndex: withSimilac ? 99 : undefined, } }, React__default.createElement(StyledContent, { "data-similac": withSimilac, "data-has-banner": typeof banner === 'object' }, children)), banner && typeof banner === 'object' && !withSimilac && (React__default.createElement(Grid.Col, { span: !isMobile ? 6 : 12, order: 1, orderMd: 2 }, React__default.createElement(StyledBannerCol, null, React__default.createElement(StyledBannerInner, { "data-is-marry-baby": isMarryBaby }, React__default.createElement(StyledIntro, null, banner.heading && (React__default.createElement(Title, { order: 1, mb: 24 }, banner.heading)), banner.description && (React__default.createElement(Text, { size: "p1", color: theme.colors.gray800 }, t('onboarding.welcomeScreen.content')))), React__default.createElement(StyledBannerImgWrapper, null, banner.imgSrc ? (React__default.createElement("img", { src: banner.imgSrc, loading: "lazy" })) : banner.imgComponent ? (banner.imgComponent) : null))))), banner && typeof banner === 'object' && withSimilac && (banner.imgSrc || banner.imgComponent) && (React__default.createElement(Grid.Col, { span: 'auto', order: 1, orderMd: 2 }, React__default.createElement(StyledBannerImgWrapper, { className: "similac" }, banner.imgSrc ? (React__default.createElement("img", { src: banner.imgSrc, loading: "lazy" })) : banner.imgComponent ? (banner.imgComponent) : null))))))); if (withPortal) { return createPortal(MainContent, getPopupWrapperDom()); } return MainContent; }; const StyledFormInner$1 = styled.div ` margin-top: 70px; display: flex; flex-direction: column; align-items: center; justify-content: center; &.similac { margin-top: 16px; } `; const StyledOnboarding$1 = styled(Container) ` &.hhg-comp-onboarding-container.hhg-comp-onboarding-container { display: flex; flex-direction: column; align-items: center; height: 100%; width: 100%; max-width: 520px; } .header { margin-bottom: 32px; text-align: center; ${MediaQueries.mbDown} { margin-bottom: 16px; } } .input-control { width: 100%; } .radio-group, .input-control { margin-bottom: 16px; } .form { width: 100%; } /* .form-error { margin-top: 32px; font-size: 14px; } .field-error { margin-top: 10px; font-size: 14px; } */ .form-button { width: 100%; } `; const StyledThumb$1 = styled.img ` margin-bottom: 38px; `; const Onboarding$1 = (_a) => { var _b; var { heading, description, children, className, imgSrc, hiddenLogo = false } = _a, rest = __rest(_a, ["heading", "description", "children", "className", "imgSrc", "hiddenLogo"]); const { isMarryBaby, siteType } = useContext(OnboardingContext); return (React__default.createElement(StyledOnboarding$1, Object.assign({}, rest, { className: `hhg-comp-onboarding-container ${className}`, size: "sm" }), !hiddenLogo && (React__default.createElement(LogoIcon, { type: isMarryBaby ? siteType : (((_b = LOCALE_SPECS[process.env.UNIFY_LOCALE]) === null || _b === void 0 ? void 0 : _b.LOGO_TYPE) || 'hellobacsi') })), React__default.createElement(StyledFormInner$1, { className: hiddenLogo ? 'similac' : '' }, imgSrc && React__default.createElement(StyledThumb$1, { src: imgSrc, loading: "lazy" }), (heading || description) && (React__default.createElement("div", { className: "header" }, heading && React__default.createElement(Title, { order: 3 }, heading), description && (React__default.createElement(Text, { size: "p3", mt: 8, color: theme.colors.gray600 }, description)))), children))); }; const StyledOnboardingForm$2 = styled(Onboarding$1) ` .phone-input { width: 100%; margin-bottom: 32px; ${MediaQueries.mbDown} { margin-bottom: 16px; } .PhoneInput { margin-bottom: 16px; } .PhoneInputCountry { border-radius: 4px 0 0 4px; } .PhoneInputInput { border-radius: 0 4px 4px 0; } } &:not([data-active='true']) { display: none !important; } `; const onboardingSchema = (t) => yup.object().shape({ phone: yup.string().required(t('onboarding.updatePhone.error')).default(''), }); const DefaultOnboardingForm = ({ onClose, onSubmit: _onSubmit, canSkip = true, customFormTexts, isActive, submitProps, submitLabel, skipProps, isWhatsApp, }) => { const { t } = useTranslations(); const { sharedData, setSharedData, nextStep } = useContext(OnboardingContext); const form = useForm({ initialValues: { phone: (sharedData === null || sharedData === void 0 ? void 0 : sharedData.phone) || '', }, validate: yupResolver(onboardingSchema(t)), }); const onSubmit = (values) => __awaiter(void 0, void 0, void 0, function* () { try { setSharedData((p) => (Object.assign(Object.assign({}, p), { phone: values.phone }))); const error = yield (_onSubmit === null || _onSubmit === void 0 ? void 0 : _onSubmit(values.phone)); !error && nextStep(); } catch (err) { console.error(err); } }); const onError = (fieldErrors) => { console.log(fieldErrors); }; return (React__default.createElement(StyledOnboardingForm$2, { heading: (customFormTexts === null || customFormTexts === void 0 ? void 0 : customFormTexts.heading) || t('onboarding.updatePhone.heading'), description: (customFormTexts === null || customFormTexts === void 0 ? void 0 : customFormTexts.description) || (isWhatsApp ? t('onboarding.updateWhatsapp.description') : t('onboarding.updatePhone.description')), "data-active": isActive }, React__default.createElement(FormProvider, { form: form }, React__default.createElement("form", { onSubmit: form.onSubmit(onSubmit, onError) }, React__default.createElement(DynamicForm, { inputOrder: ['phone'] }), React__default.createElement(Button, Object.assign({ variant: "primary", fullWidth: true, size: "lg" }, (isWhatsApp && { leftIcon: React__default.createElement(Icon.WhatsApp, { size: 18, useCurrentColor: true }), }), submitProps, { type: "submit", "data-event-category": isWhatsApp ? 'OTP' : 'Sign Up', "data-event-action": isWhatsApp ? 'Whatsapp - Fill phone and continue Click' : 'Update Phone Number', "data-event-label": typeof window !== 'undefined' ? window.location.href : '', className: "pointer-event-child-none" }), submitLabel || (isWhatsApp ? t('onboarding.updateWhatsapp.submitLabel') : t('onboarding.button.continue'))), canSkip && (React__default.createElement(Button, Object.assign({ variant: "ghost", fullWidth: true, size: "lg" }, (isWhatsApp && { dataEventCategory: 'OTP', dataEventAction: 'Whatsapp - Skip fill phone Click', dataEventLabel: typeof window !== 'undefined' ? window.location.href : '', }), skipProps, { onClick: onClose, type: "button" }), t('onboarding.button.skip'))))))); }; const StyledOtpForm = styled(Onboarding$1) ` .otp-input { margin-bottom: 36px; ${MediaQueries.mbDown} { margin-bottom: 20px; } .otpContainer { margin-bottom: 16px; } } .resend { display: flex; gap: 6px; margin-bottom: 32px; ${MediaQueries.mbDown} { margin-bottom: 16px; } a { text-decoration: underline; cursor: pointer; } } .phone-description { margin-left: 2px; margin-top: 2px; } .otp-description-edit-icon { cursor: pointer; vertical-align: bottom; /* height: 100%; */ margin-bottom: 3px; margin-left: 3px; } `; // export const StyledOtpForm = styled(Container)` // &.hhg-comp-onboarding-container.hhg-comp-onboarding-container { // display: flex; // flex-direction: column; // align-items: center; // height: 100%; // width: 100%; // text-align: center; // max-width: 520px; // } // .header { // margin-top: 70px; // display: flex; // flex-direction: column; // align-items: center; // justify-content: center; // gap: 8px; // margin-bottom: 32px; // ${MediaQueries.mbDown} { // margin-bottom: 16px; // } // } // .otpContainer { // margin-bottom: 36px; // ${MediaQueries.mbDown} { // margin-bottom: 20px; // } // } // .resend { // display: flex; // gap: 6px; // margin-bottom: 32px; // ${MediaQueries.mbDown} { // margin-bottom: 16px; // } // a { // text-decoration: underline; // cursor: pointer; // } // } // ` const otpSchema = (t) => yup.object().shape({ otp: yup .string() .required(t('onboarding.otpForm.error')) .length(6, t('onboarding.otpForm.error')) .default(''), }); const EmailOtpForm = ({ onSubmit: _onSubmit, email: emailProp, onResendCode, otpError, onClose, loading, // onBack, canSkip: canSkipInit, }) => { const { sharedData: { email: emailContext, retryEmailCount }, setSharedData, prevStep, siteType, isMarryBaby, nextStep, } = useContext(OnboardingContext); const email = emailProp || emailContext || ''; const [seconds, setSeconds] = useState(30); const interval = useInterval(() => setSeconds((s) => s - 1), 1000); const [canSkip, handlers] = useCounter(0, { min: 0, max: 3 }); const preventClickRef = useRef(true); const { t } = useTranslations(); useEffect(() => { interval.start(); return interval.stop; }, []); useEffect(() => { if (seconds === 0) { interval.stop(); preventClickRef.current = false; } }, [seconds]); const form = useForm({ initialValues: { otp: '', }, validate: yupResolver(otpSchema(t)), }); useEffect(() => { if (otpError) form.setFieldError('otp', otpError); }, [otpError]); const onSubmit = (values) => __awaiter(void 0, void 0, void 0, function* () { try { handlers.increment(); const error = yield (_onSubmit === null || _onSubmit === void 0 ? void 0 : _onSubmit(values.otp)); !error && nextStep(); } catch (err) { console.error(err); } }); const onError = (fieldErrors) => { console.log(fieldErrors); }; const throttleResendCode = useMemo(() => { return throttle(() => { if (preventClickRef.current) return; handlers.increment(); setSeconds(30); onResendCode === null || onResendCode === void 0 ? void 0 : onResendCode(email); interval.start(); preventClickRef.current = true; }, 1000, { trailing: false }); }, [email, onResendCode, interval]); const onBack = () => { if (retryEmailCount >= 2) return; setSharedData((d) => (Object.assign(Object.assign({}, d), { retryEmailCount: d.retryEmailCount + 1 }))); prevStep(); }; const outOfEdit = retryEmailCount >= 2; return (React__default.createElement(StyledOtpForm, { heading: t('onboarding.otpForm.heading'), description: React__default.createElement(React__default.Fragment, null, React__default.createElement("span", { dangerouslySetInnerHTML: { __html: t('onboarding.otpForm.descriptionEmail', { email: `<b style="color:${theme.colors.gray800}">${hiddenEmailChar(email)}</b>`, }), } }), !outOfEdit && (React__default.createElement("svg", { onClick: onBack, width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "otp-description-edit-icon" }, React__default.createElement("path", { d: "M12.7812 1.33337C12.2987 1.33337 11.8162 1.51712 11.4479 1.88546L10.6667 2.66671L13.3333 5.33337L14.1146 4.55212C14.8506 3.81612 14.8506 2.62212 14.1146 1.88546C13.7463 1.51712 13.2638 1.33337 12.7812 1.33337ZM9.66667 3.66671L2 11.3334V14H4.66667L12.3333 6.33337L9.66667 3.66671Z", fill: "#ADB3BC" })))) }, React__default.createElement(FormProvider, { form: form }, React__default.createElement("form", { onSubmit: form.onSubmit(onSubmit, onError) }, React__default.createElement(DynamicForm, { inputOrder: ['otp'] }), React__default.createElement("div", { className: "resend" }, React__default.createElement(Text$1, { size: "p4", color: theme.colors.gray400 }, t('onboarding.otpForm.notReceiveOTP')), React__default.createElement(Text$1, { as: "a", size: "p4", color: isMarryBaby ? theme.mbColors.pink : theme.colors.primaryBase, onClick: throttleResendCode }, seconds === 0 ? t('onboarding.otpForm.resendCode') : t('onboarding.otpForm.resendCodeWithSeconds', { seconds }))), React__default.createElement(Button$1, { theme: siteType, color: "primary", isBlock: true, size: "lg", type: "submit", isLoading: loading, disabled: loading, "data-event-category": "Sign Up", "data-event-action": "Confirm Phone Number", "data-event-label": typeof window !== 'undefined' ? window.location.href : '', className: "pointer-event-child-none" }, t('onboarding.button.continue')), canSkipInit && canSkip >= 3 && (React__default.createElement(Button$1, { theme: siteType, color: "ghost", isBlock: true, size: "lg", onClick: onClose, type: "button" }, t('onboarding.button.skip'))))))); }; const PhoneOtpForm = ({ onSubmit: _onSubmit, phone: phoneProp, onResendCode, otpError, onClose, loading, // onBack, canSkip: canSkipInit, isWhatsApp, }) => { const { sharedData: { phone: phoneContext, retryPhoneCount }, setSharedData, prevStep, siteType, isMarryBaby, nextStep, } = useContext(OnboardingContext); const phone = phoneProp || phoneContext || ''; const [seconds, setSeconds] = useState(30); const interval = useInterval(() => setSeconds((s) => s - 1), 1000); const [canSkip, handlers] = useCounter(0, { min: 0, max: 3 }); const preventClickRef = useRef(true); const { t } = useTranslations(); useEffect(() => { interval.start(); return interval.stop; }, []); useEffect(() => { if (seconds === 0) { interval.stop(); preventClickRef.current = false; } }, [seconds]); const form = useForm({ initialValues: { otp: '', }, validate: yupResolver(otpSchema(t)), }); useEffect(() => { if (otpError) form.setFieldError('otp', otpError); }, [otpError]); const onSubmit = (values) => __awaiter(void 0, void 0, void 0, function* () { try { handlers.increment(); const error = yield (_onSubmit === null || _onSubmit === void 0 ? void 0 : _onSubmit(values.otp)); !error && nextStep(); } catch (err) { console.error(err); } }); const onError = (fieldErrors) => { console.log(fieldErrors); }; const throttleResendCode = useMemo(() => { return throttle(() => { if (preventClickRef.current) return; handlers.increment(); setSeconds(30); onResendCode === null || onResendCode === void 0 ? void 0 : onResendCode(phone); interval.start(); preventClickRef.current = true; }, 1000, { trailing: false }); }, [phone, onResendCode, interval]); const onBack = () => { if (retryPhoneCount >= 2) return; setSharedData((d) => (Object.assign(Object.assign({}, d), { retryPhoneCount: d.retryPhoneCount + 1 }))); prevStep(); }; const outOfEdit = retryPhoneCount >= 2; const phoneEleStr = `<b style="color:${theme.colors.gray800}">${phone .slice(0, -3) .replace(/./g, 'x') .concat(phone.slice(-3))}</b>`; return (React__default.createElement(StyledOtpForm, { heading: isWhatsApp ? (React__default.createElement(Flex, { align: 'center', justify: 'center', gap: rem(8) }, React__default.createElement("img", { style: { width: rem(24) }, loading: "lazy", src: CommonGAssets.getAssetPath('whatsapp.svg'), alt: "whatsapp" }), React__default.createElement("span", null, t('onboarding.otpWhatsapps.heading')))) : (t('onboarding.otpForm.heading')), description: React__default.createElement(React__default.Fragment, null, React__default.createElement("span", { dangerouslySetInnerHTML: { __html: t(isWhatsApp ? 'onboarding.otpWhatsapps.description' : 'onboarding.otpForm.description', { phone: phoneEleStr, }), } }), !outOfEdit && (React__default.createElement("svg", { onClick: onBack, width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "otp-description-edit-icon" }, React__default.createElement("path", { d: "M12.7812 1.33337C12.2987 1.33337 11.8162 1.51712 11.4479 1.88546L10.6667 2.66671L13.3333 5.33337L14.1146 4.55212C14.8506 3.81612 14.8506 2.62212 14.1146 1.88546C13.7463 1.51712 13.2638 1.33337 12.7812 1.33337ZM9.66667 3.66671L2 11.3334V14H4.66667L12.3333 6.33337L9.66667 3.66671Z", fill: "#ADB3BC" })))) }, React__default.createElement(FormProvider, { form: form }, React__default.createElement("form", { onSubmit: form.onSubmit(onSubmit, onError) }, React__default.createElement(DynamicForm, { inputOrder: ['otp'] }), React__default.createElement("div", { className: "resend" }, React__default.createElement(Text, { size: "p4", color: theme.colors.gray400 }, t('onboarding.otpForm.notReceiveOTP')), React__default.createElement(Text, { as: "a", size: "p4", color: isMarryBaby ? theme.mbColors.pink : theme.colors.primaryBase, onClick: throttleResendCode }, seconds === 0 ? t('onboarding.otpForm.resendCode') : t('onboarding.otpForm.resendCodeWithSeconds', { seconds }))), React__default.createElement(Button$1, { theme: siteType, color: "primary", isBlock: true, size: "lg", type: "submit", isLoading: loading, disabled: loading, "data-event-category": isWhatsApp ? 'OTP' : 'Sign Up', "data-event-action": isWhatsApp ? 'Whatsapp - OTP verified Click' : 'Confirm Phone Number', "data-event-label": typeof window !== 'undefined' ? window.location.href : '', className: "pointer-event-child-none" }, t('onboarding.button.continue')), canSkipInit && canSkip >= 3 && (React__default.createElement(Button$1, { theme: siteType, color: "ghost", isBlock: true, size: "lg", onClick: onClose, type: "button" }, t('onboarding.button.skip'))))))); }; const onboardingEmailSchema = (t) => yup.object().shape({ email: yup .string() .required(t('onboarding.errorMessage.requiredEmail')) .email(t('onboarding.errorMessage.invalidEmail')) .default(''), name: yup.string().required(t('onboarding.errorMessage.requiredName')), }); const StyledFormInner = styled.div ` margin-top: 70px; display: flex; flex-direction: column; align-items: center; justify-content: center; &.similac { margin-top: 16px; } `; const StyledOnboarding = styled(Container) ` &.hhg-comp-onboarding-container.hhg-comp-onboarding-container { display: flex; flex-direction: column; align-items: center; height: 100%; width: 100%; max-width: 520px; } .header { margin-bottom: 32px; text-align: center; ${MediaQueries.mbDown} { margin-bottom: 16px; } } .input-control { width: 100%; } .radio-group, .input-control { margin-bottom: 16px; } .form { width: 100%; } /* .form-error { margin-top: 32px; font-size: 14px; } .field-error { margin-top: 10px; font-size: 14px; } */ .form-button { width: 100%; } `; const StyledThumb = styled.img ` margin-bottom: 38px; `; const OnboardingUI = (_a) => { var _b; var { heading, description, children, className, imgSrc, hiddenLogo = false } = _a, rest = __rest(_a, ["heading", "description", "children", "className", "imgSrc", "hiddenLogo"]); const { isMarryBaby, siteType } = useContext(OnboardingContext); return (React__default.createElement(StyledOnboarding, Object.assign({}, rest, { className: `hhg-comp-onboarding-container ${className}`, size: "sm" }), !hiddenLogo && (React__default.createElement(LogoIcon, { type: isMarryBaby ? siteType : (((_b = LOCALE_SPECS[process.env.UNIFY_LOCALE]) === null || _b === void 0 ? void 0 : _b.LOGO_TYPE) || 'hellobacsi') })), React__default.createElement(StyledFormInner, { className: hiddenLogo ? 'similac' : '' }, imgSrc && React__default.createElement(StyledThumb, { src: imgSrc, loading: "lazy" }), React__default.createElement("div", { className: "header" }, React__default.createElement(Title, { order: 3 }, heading), React__default.createElement(Text, { size: "p3", mt: 8, color: theme.colors.gray600 }, description)), children))); }; const PersonalInfoForm = ({ onClose, onSubmit, canSkip, loading, errorMessage, initialData, }) => { const { t, locale } = useTranslations(); const { siteType, isMarryBaby, setSharedData, nextStep } = useContext(OnboardingContext); const form = useForm({ validate: yupResolver(onboardingEmailSchema(t)), }); const onError = (fieldErrors) => { console.log({ fieldErrors }); }; useEffect(() => { form.setValues(Object.assign(Object.assign({ gender: '0' }, initialData), ((initialData === null || initialData === void 0 ? void 0 : initialData.birthday) && { birthday: new Date(initialData.birthday), }))); }, [initialData]); useEffect(() => { if (errorMessage) form.setFieldError('email', errorMessage); }, [errorMessage]); return (React__default.createElement(OnboardingUI, { heading: t('onboarding.formEmail.heading'), description: t('onboarding.formEmail.description', { site: isMarryBaby ? 'Marry Baby' : LOCALE_SPECS[locale].SITE_NAME_FORMATTED, }) }, React__default.createElement(FormProvider, { form: form }, React__default.createElement("form", { className: "form", onSubmit: form.onSubmit((values) => __awaiter(void 0, void 0, void 0, function* () { setSharedData((d) => (Object.assign(Object.assign({}, d), values))); const error = yield (onSubmit === null || onSubmit === void 0 ? void 0 : onSubmit(Object.assign(Object.assign({}, values), { birthday: values.birthday && format(values.birthday, 'yyyy-MM-dd') }))); !error && nextStep(); }), onError) }, React__default.createElement(DynamicForm, { inputOrder: ['full_name', 'email', 'dob', 'gender'] }), React__default.createElement(Button$1, { color: "primary", isBlock: true, size: "lg", type: "submit", theme: siteType, isLoading: loading, disabled: loading }, t('onboarding.button.continue')), canSkip && (React__default.createElement(Button$1, { theme: siteType, color: "ghost", isBlock: true, size: "lg", onClick: onClose, type: "button" }, t('onboarding.button.skip'))))))); }; const OnboardingProvider = ({ children, siteType, setSharedData: _setSharedData, }) => { const [currentStep, setCurrentStep] = useState(0); const [maxStep, setMaxStep] = useState(0); const [sharedData, setSharedData] = useState({}); const nextStep = () => currentStep + 1 <= maxStep && setCurrentStep(currentStep + 1); const prevStep = () => currentStep - 1 >= 0 && setCurrentStep(currentStep - 1); useEffect(() => { _setSharedData === null || _setSharedData === void 0 ? void 0 : _setSharedData(sharedData); }, [sharedData, _setSharedData]); return (React__default.createElement(OnboardingContext.Provider, { value: { currentStep, setCurrentStep, setMaxStep, nextStep, prevStep, siteType, isMarryBaby: siteType === 'marryBaby', sharedData, setSharedData, } }, children)); }; const ResultScreen = (_a) => { var { onClose } = _a, rest = __rest(_a, ["onClose"]); const { t } = useTranslations(); const { siteType } = useContext(OnboardingContext); return (React__default.createElement(OnboardingUI, Object.assign({}, rest), React__default.createElement(Button$1, { theme: siteType, size: "lg", onClick: onClose, className: "form-button" }, t('onboarding.button.continue')))); }; const StyledOnboardingForm$1 = styled(Onboarding$1) ` .phone-input { width: 100%; margin-bottom: 32px; ${MediaQueries.mbDown} { margin-bottom: 16px; } .PhoneInput { margin-bottom: 16px; } .PhoneInputCountry { border-radius: 4px 0 0 4px; } .PhoneInputInput { border-radius: 0 4px 4px 0; } } &:not([data-active='true']) { display: none !important; } `; const similacOnboardingSchema = (t, optionalTerm) => yup.object().shape({ phone: yup.string().required(t('onboarding.updatePhone.error')).default(''), name: yup.string().required(t('onboarding.errorMessage.requiredName')), email: yup .string() .required(t('onboarding.errorMessage.requiredEmail')) .email(t('onboarding.errorMessage.invalidEmail')) .default(''), address: yup.mixed().required(t('onboarding.similac.address.error')), term: optionalTerm ? yup.bool() : yup.bool().oneOf([true], t('validation.error.requiredField')), }); const SimilacOnboardingForm = (_a) => { var { onClose, onSubmit: _onSubmit, canSkip = true, customFormTexts, customTerms, defaultValues, isActive } = _a, rest = __rest(_a, ["onClose", "onSubmit", "canSkip", "customFormTexts", "customTerms", "defaultValues", "isActive"]); const { t } = useTranslations(); const { nextStep, setSharedData, sharedData } = useContext(OnboardingContext); const { isMobile } = useScreenSize(); const form = useForm({ initialValues: { term: false, phone: (sharedData === null || sharedData === void 0 ? void 0 : sharedData.phone) || (defaultValues === null || defaultValues === void 0 ? void 0 : defaultValues.phone) || '', email: (sharedData === null || sharedData === void 0 ? void 0 : sharedData.email) || (defaultValues === null || defaultValues === void 0 ? void 0 : defaultValues.email) || '', name: (sharedData === null || sharedData === void 0 ? void 0 : sharedData.name) || (defaultValues === null || defaultValues === void 0 ? void 0 : defaultValues.name) || '', }, validate: yupResolver(similacOnboardingSchema(t, !customTerms)), }); const onSubmit = (values) => __awaiter(void 0, void 0, void 0, function* () { try { yield (_onSubmit === null || _onSubmit === void 0 ? void 0 : _onSubmit(values)); setSharedData((d) => (Object.assign(Object.assign({}, d), { phone: values.phone, email: values.email, name: values.name }))); nextStep(); } catch (err) { console.error(err); } }); const onError = (fieldErrors) => { console.log(fieldErrors); }; const inputOrder = (defaultValues === null || defaultValues === void 0 ? void 0 : defaultValues.email) ? ['full_name', 'phone', 'address', 'term'] : ['full_name', 'email', 'phone', 'address', 'term']; return (React__default.createElement(StyledOnboardingForm$1, Object.assign({ heading: (customFormTexts === null || customFormTexts === void 0 ? void 0 : customFormTexts.heading) || t('onboarding.updatePhone.heading'), description: (customFormTexts === null || customFormTexts === void 0 ? void 0 : customFormTexts.description) || t('onboarding.updatePhone.description'), hiddenLogo: isMobile, "data-active": isActive }, rest), React__default.createElement(FormProvider, { form: form }, React__default.createElement("form", { style: { width: '100%', }, onSubmit: form.onSubmit(onSubmit, onError) }, React__default.createElement(DynamicForm, { inputOrder: inputOrder, withSimilac: true, customTerms: customTerms }), React__default.createElement(Button, { fullWidth: true, size: "lg", type: "submit", "data-event-category": "Sign Up", "data-event-action": "Update Phone Number", "data-event-label": typeof window !== 'undefined' ? window.location.href : '', className: "pointer-event-child-none" }, t('onboarding.button.continue')), canSkip && (React__default.createElement(Button, { variant: "ghost", fullWidth: true, size: "lg", onClick: onClose, type: "button" }, t('onboarding.button.skip'))))))); }; const OnboardingStepRenderer = ({ children, onStepChange }) => { const { currentStep, setMaxStep } = useContext(OnboardingContext); const childrenCount = React__default.Children.count(children); useEffect(() => { onStepChange === null || onStepChange === void 0 ? void 0 : onStepChange(currentStep); }, [currentStep]); useEffect(() => { setMaxStep(childrenCount - 1); }, [childrenCount]); return (React__default.createElement(React__default.Fragment, null, flattenChildren(children).map((element, idx) => { const active = idx === currentStep; return (React__default.createElement(Fragment, { key: idx }, !React__default.isValidElement(element) ? active ? element : null : element.props.alwaysRender || active ? React__default.cloneElement(element, { isActive: idx === currentStep, stepIndex: idx, }) : null)); }))); }; const StyledOnboardingForm = styled(Onboarding$1) ` .phone-input { width: 100%; margin-bottom: 32px; ${MediaQueries.mbDown} { margin-bottom: 16px; } .PhoneInput { margin-bottom: 16px; } .PhoneInputCountry { border-radius: 4px 0 0 4px; } .PhoneInputInput { border-radius: 0 4px 4px 0; } } &:not([data-active='true']) { display: none !important; } `; const ThankYouStepRenderer = (_a) => { var { onClose, thanksPageInfo, isActive } = _a, rest = __rest(_a, ["onClose", "thanksPageInfo", "isActive"]); const { t } = useTranslations(); const { isMobile } = useScreenSize(); return (React__default.createElement(StyledOnboardingForm, Object.assign({ heading: '', description: '', hiddenLogo: isMobile, "data-active": isActive }, rest), React__default.createElement(Container, { fluid: true }, React__default.createElement(Stack, { align: "center", spacing: 8, w: "100%", ta: "center" }, React__default.createElement(AspectRatio, { ratio: 1, w: { base: 120, md: 160 } }, React__default.createElement("svg", { width: "160", height: "160", viewBox: "0 0 160 160", fill: "none" }, React__default.createElement("mask", { id: "mask0_4580_96805", maskUnits: "userSpaceOnUse", x: "0", y: "0", width: "160", height: "160" }, React__default.createElement("circle", { cx: "80", cy: "80", r: "80", fill: "url(#paint0_radial_4580_96805)" })), React__default.createElement("g", { mask: "url(#mask0_4580_96805)", fill: "#E0F8EE" }, React__default.createElement("path", { d: "m71.594.46 5.382 37.677c.035 0 .106 0 .141-.035l5.242 36.901 5.207-36.936h.07l5.207-37.043A81 81 0 0 0 80.002 0c-2.85 0-5.664.141-8.408.46m59.556 18.08a79.7 79.7 0 0 0-17.977-11.336L97.87 41.068c.035 0 .07.036.07.036L82.46 75.286z" }), React__default.createElement("path", { d: "M46.439 64.833 82.11 75.321h-.14l.352.106h.035l.035-.035.035.035h-.035l.035.035h.035l.14.071-.105-.07 35.849 10.523c0 .035 0 .035-.035.07l39.789 11.76a81.6 81.6 0 0 0 1.9-17.48c0-1.66-.071-3.355-.141-4.98h-40.035v.071l-37.362.035v-.035l.176-.035-.14.07.316-.106h-.176l72.858-21.717a81 81 0 0 0-9.885-19.35L82.639 75.285h-.14l.07-.07-.106.07.035-.212-.07.141v