& {\n value: ESteps,\n info?: string,\n}\n\nexport const guideSteps: TGuideSteps[] = [\n {\n value: ESteps.address,\n title: 'Проверка адреса',\n description: 'Убедитесь, что в вашем доме есть техническая возможность подключить тариф.',\n Icon: Location,\n isActive: false,\n },\n {\n value: ESteps.equipments,\n title: 'Выбор роутера',\n description: 'Выберите один, если хотите получить от своего тарифа максимум скорости и управлять настройками Wi-Fi через приложение. ',\n Icon: Game,\n isActive: false,\n },\n {\n value: ESteps.equipmentsCottage,\n title: 'Выбор оборудования',\n description: 'Без него услуги не будут работать, и мы не сможем вам их подключить. Оборудование нужно, чтобы преобразовать оптический ' +\n 'сигнал в электрический и передать его по кабелю Ethernet.',\n Icon: House,\n isActive: false,\n },\n {\n value: ESteps.tariffInfo,\n title: 'Выбор подписок',\n description: 'Подписки уже входят в цену тарифа, каждый месяц их можно менять.',\n Icon: VideoPlay,\n isActive: false,\n },\n {\n value: ESteps.contacts,\n title: 'Ввод данных',\n description: 'Укажите свои ФИО и номер телефона, чтобы мы смогли оформить вашу ' +\n 'заявку на подключение. Договор оформляем только на лицо старше 18 лет.',\n Icon: ProfileCircle,\n isActive: false,\n info: ` \n Дома должен быть владелец — тот, на чьё имя оформлен договор. Или его представитель старше 18 лет.
\n У представителя должна быть доверенность, которую можно написать от руки.
\n \n Что обязательно нужно указать в доверенности:\n
\n \n - - ФИО клиента и его представителя
\n - - паспортные данные владельца и его адрес
\n - - дату подписания доверенности
\n - - подтверждение, что клиент передает представителю право представлять его перед третьими лицами
\n
\n Также понадобится паспорт представителя и копия паспорта того, на чьё имя будет оформлен договор.
\n `,\n },\n {\n value: ESteps.timeSlots,\n title: 'Выбор даты подключения',\n description: 'Выберите день и время, когда инженер приедет, привезёт оборудование, всё установит и настроит.',\n Icon: CalendarSecond,\n isActive: false,\n info: `\n На все работы инженеру понадобится около 60 минут.
\n \n Как подготовиться в визиту инженера:\n
\n \n - - Держите под рукой свой паспорт или доверенность на того, кто будет встречать инженера вместо вас.
\n - - Вспомните логин и пароль от Госуслуг, чтобы быстро ввести их и заключить онлайн-договор.
\n - - Убедитесь, что на вашей карте хватает денег для оплаты услуг.
\n - - Выберите и подготовьте место для роутера или ТВ-приставки.
\n
\n `,\n },\n {\n value: ESteps.equipmentsTv,\n title: 'Выбор ТВ приставки',\n description: 'Добавьте её, чтобы смотреть ТВ-каналы и подписки из своего тарифа. Если у вас Smart TV, приставку можно не брать.',\n Icon: MovixHelper,\n isActive: false,\n },\n {\n value: ESteps.final,\n title: 'Отслеживание заявки',\n description: 'После оплаты получите смс с ссылкой на свой личный кабинет. ' +\n 'Там вы сможете следить за статусом своей заявки, изменить её или отменить.',\n Icon: CloseBox,\n isActive: false,\n },\n {\n value: ESteps.subscriptions,\n title: 'Выбор подписок',\n description: 'Подписки уже входят в цену тарифа, каждый месяц их можно менять.',\n Icon: VideoPlay,\n isActive: false,\n },\n];\n","import { isTruthy } from '@r1-frontend/shared/guards';\n\nimport { EShopCategory } from '~/src/api/content/shop/getShopItems';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { ESteps } from '~/src/features/full-buy/types';\nimport { TState } from '~/src/store';\n\nimport { guideSteps } from './data';\n\nexport const getGuideData = (state: TState) =>{\n const { flow, stepIndex, selectedTariff } = state.fullBuy;\n\n const isSalePackageId = !!((selectedTariff && 'salePackageId' in selectedTariff));\n const tariff = selectCurrentTariff(state);\n const currentStep = flow?.steps[stepIndex];\n\n const hasEquipmentInTariff = tariff?.additionalProducts.some(product => product.category === 'router' && product.required);\n const hasRequiredTvBox = tariff?.additionalProducts.find(el => el.category === EShopCategory.Decoders && el.required);\n // @todo replace to a selector. Simplify condition by `!!tariff?.subscriptions Summary?.length && !!tariff?.sale Package Links?.length;`\n const hasSubscriptions = (tariff?.subscriptionsSummary && tariff?.subscriptionsSummary?.length > 0) && (tariff?.salePackageLinks && tariff?.salePackageLinks?.length > 0);\n\n if (!flow) {\n return undefined;\n }\n\n return flow.steps\n .map((step) =>{\n const findStep = guideSteps.find(item => item.value === step);\n\n if (isSalePackageId && findStep?.value === ESteps.tariffInfo) {\n return null;\n }\n\n if (!hasSubscriptions && findStep?.value === ESteps.subscriptions) {\n return null;\n }\n if ((tariff?.isMono || hasRequiredTvBox) && findStep?.value === ESteps.equipmentsTv) {\n return null;\n }\n if (hasEquipmentInTariff && findStep?.value === ESteps.equipments) {\n return null;\n }\n if (findStep) {\n const { value, ...mappedItem } = { ...findStep, isActive: currentStep === findStep.value }; // eslint-disable-line\n return { ...mappedItem };\n }\n return null;\n })\n .filter(isTruthy);\n};\n","import React, { useMemo } from 'react';\nimport { useSelector } from 'react-redux';\n\nimport { Guide } from '@r1-frontend/ui-react/components/Guide';\nimport HtmlContentFromApi from '@r1-frontend/ui-react/components/HtmlContentFromApi';\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport { Paragraph4 } from '@r1-frontend/ui-react/components/typography/paragraph';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\n\nimport OpenChat from '~/src/components/OpenChatLink';\nimport { BasePopupRightAlign, TheScrollbar } from '~/src/features/full-buy/popups/BasePopupRightAlign';\nimport { getGuideData } from '~/src/features/full-buy/store/selectors/getGuideData/getGuideData';\n\ninterface IGuideFullBuy {\n isOpen: boolean,\n onClose: () => void,\n}\n\nexport const GuideFullBuy = ({ isOpen, onClose }: IGuideFullBuy): JSX.Element => {\n const guideData = useSelector(getGuideData);\n\n const createDescriptionElements = useMemo(()=>{\n return guideData?.map((item)=> {\n if (item?.info) {\n return { ...item, info: {item.info} };\n } else {\n return item;\n }\n });\n }, [guideData]);\n\n if (!createDescriptionElements) {\n return <>>;\n }\n\n return (\n \n Подключение тарифа: шаги
\n \n \n Если на каком-либо шаге появятся сложности, напишите в чат. Поможем разобраться.\n \n \n \n \n );\n};\n","import { batch } from 'react-redux';\n\nimport { setPrevStep, setStep } from '~/src/features/full-buy/store/actions';\nimport { TDispatch, TGetState } from '~/src/store';\n\nexport const goToPrevStep = () => (dispatch: TDispatch, getState: TGetState) => {\n const state = getState().fullBuy;\n\n const {\n stepIndex,\n flow,\n } = state;\n\n if (!flow) {\n return;\n }\n\n const newIndex = stepIndex - 1;\n\n if (newIndex >= 0) {\n batch(() => {\n dispatch(setPrevStep(stepIndex));\n dispatch(setStep(newIndex));\n });\n }\n};\n","import React, { useMemo } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\n\nimport { TSvgProps } from '@r1-frontend/ui-react/components/svg/createSvg';\nimport SteppableProgressBar from '@r1-frontend/ui-react/organisms/SteppableProgressBar';\n\nimport { MEGABIT_AVAIL_CODES_LIST, MEGABIT_SPEED } from '~/src/features/full-buy/consts';\nimport isOneLineAddressScreen from '~/src/features/full-buy/helpers/ab/isOneLineAddressScreen';\nimport { goToPrevStep } from '~/src/features/full-buy/store/actions/goToPrevStep';\nimport { isHaveSelectedProducts } from '~/src/features/full-buy/store/selectors/products/isHaveSelectedProducts';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { ESteps } from '~/src/features/full-buy/types';\nimport { TState } from '~/src/store';\n\ntype TGetProgressTitlesArgument = {\n step: ESteps,\n hasProducts: boolean,\n canConnectAfterCheckedAddress: boolean,\n isEdit: boolean,\n hasError: boolean,\n isAddressVerificationOnFirstStep: boolean,\n}\n\nconst getProgressTitles = ({\n step,\n hasProducts,\n canConnectAfterCheckedAddress,\n isEdit,\n hasError,\n isAddressVerificationOnFirstStep,\n}: TGetProgressTitlesArgument): { title: string, imgName?: string, hasPrevBtn?: boolean } => {\n switch (step) {\n case ESteps.tariffInfo: {\n return {\n title: 'Что входит в стоимость тарифа',\n };\n }\n case ESteps.subscriptions: {\n return {\n title: 'Выбор подписок',\n hasPrevBtn: true,\n };\n }\n case ESteps.equipments: {\n return {\n title: hasProducts ? 'Уже пакуем роутер...' : 'Выбор роутера',\n imgName: hasProducts ? 'box-packing.gif' : '',\n hasPrevBtn: true,\n };\n }\n case ESteps.equipmentsTv: {\n return {\n title: 'Выбор приставки',\n hasPrevBtn: true,\n };\n }\n case ESteps.equipmentsCottage: {\n return {\n title: 'Выбор оборудования',\n hasPrevBtn: true,\n };\n }\n case ESteps.address: {\n return {\n title: (canConnectAfterCheckedAddress && !isEdit) ? 'Уже прокладываем маршрут...' : 'Проверка адреса',\n imgName: (canConnectAfterCheckedAddress && !isEdit) ? 'dog-walking.gif' : '',\n hasPrevBtn: !isAddressVerificationOnFirstStep,\n };\n }\n case ESteps.contacts: {\n return {\n title: 'Ввод данных',\n hasPrevBtn: true,\n };\n }\n case ESteps.agreementCreated: {\n return {\n title: 'Осталось совсем чуть-чуть...',\n };\n }\n case ESteps.timeSlots: {\n return {\n title: 'Остался последний шаг',\n };\n }\n case ESteps.final: {\n return {\n title: hasError ? 'Получили вашу заявку, но есть нюанс' : 'Вы молодец! Заявка отправлена.',\n imgName: 'lightblue-paper-airplane.gif',\n };\n }\n default: {\n const unknownAction: never = step;\n return {\n title: '',\n } || unknownAction;\n }\n }\n};\n\ninterface IProgressBarWithBackBtnContainer {\n Icon?: (props: TSvgProps) => JSX.Element,\n onClickInfoIcon?: () => void,\n}\n\nconst ProgressBarWithBackBtnContainer = ({\n Icon,\n onClickInfoIcon,\n}: IProgressBarWithBackBtnContainer): JSX.Element | null => {\n const {\n fullBuy: { stepIndex, flow, agreement: agreementData },\n contactAddress: { isEdit, verifiedAddressData: { gigabitAvail, isHouseConnected } },\n hasProducts,\n selectedTariff,\n selectedAddress,\n isAddressVerificationOnFirstStep,\n } = useSelector((state: TState) => ({\n fullBuy: state.fullBuy,\n hasProducts: isHaveSelectedProducts(state),\n contactAddress: state.contactAddress,\n selectedTariff: selectCurrentTariff(state),\n selectedAddress: state.fullBuy.selectedAddress,\n isAddressVerificationOnFirstStep: state.fullBuy._addressVerificationOnFirstStep,\n }));\n\n const isOneLineAddressFormScreen = isOneLineAddressScreen();\n\n const dispatch = useDispatch();\n\n const { speed: tariffSpeed } = selectedTariff || {};\n\n const canConnectAfterCheckedAddress = useMemo(() => {\n const _gigabitMayConnect = MEGABIT_AVAIL_CODES_LIST.includes(gigabitAvail);\n\n const _requiredGigaSpeed = !!tariffSpeed && (tariffSpeed > MEGABIT_SPEED);\n\n const _shouldConnect = _requiredGigaSpeed\n ? (isHouseConnected && _gigabitMayConnect)\n : isHouseConnected;\n\n return isOneLineAddressFormScreen\n ? Boolean(selectedAddress?.isConnectionAvailable)\n : (_shouldConnect && !isEdit);\n }, [isHouseConnected, gigabitAvail, tariffSpeed, selectedAddress]);\n\n const onClickHandler = () => {\n dispatch(goToPrevStep());\n };\n\n if (!flow) {\n return null;\n }\n\n const progress = (stepIndex + 1) / flow.steps.length;\n const currentStep = flow.steps[stepIndex];\n\n const dynamicProps = getProgressTitles({\n step: currentStep,\n hasProducts,\n canConnectAfterCheckedAddress,\n isEdit: isOneLineAddressFormScreen ? !selectedAddress : isEdit,\n hasError: agreementData.hasError,\n isAddressVerificationOnFirstStep,\n });\n\n const props = {\n progress: progress,\n imgPath: '/static/images/full-buy/for-progress-bar',\n onClick: dynamicProps.hasPrevBtn ? onClickHandler : undefined,\n Icon: Icon,\n onClickInfoIcon: onClickInfoIcon,\n\n ...dynamicProps,\n };\n\n return ;\n};\nexport default ProgressBarWithBackBtnContainer;\n","import styled from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\n\nexport const RequestContent = styled.div`\n margin-top: 32px;\n position: sticky;\n flex-direction: column;\n width: 100%;\n top: 120px;\n \n &:empty {\n display: none;\n }\n`;\n\nexport const LeftSide = styled.div`\n flex: 1;\n flex-direction: column;\n display: contents;\n\n @media (max-width: ${wideBreakpoints.laptop}) {\n flex: 0 1 auto;\n display: flex;\n width: 100%;\n }\n`;\n","import React, { ReactNode, useMemo, useState } from 'react';\nimport { shallowEqual, useSelector } from 'react-redux';\nimport { useRouter } from 'next/router';\n\nimport { UnifiedAddressFormCtx } from '@r1-frontend/unified-address-form';\n\nimport { InfoCircleFlip } from '@r1-frontend/ui-react/components/svg/main';\nimport { FullWidthListContainer } from '@r1-frontend/ui-react/experimental/containers';\n\nimport { useAnalytics } from '~/src/features/full-buy/analytics/context';\nimport { Banner } from '~/src/features/full-buy/Banner';\nimport { TiketContainer } from '~/src/features/full-buy/containers/agregate/TiketContainer';\nimport { TiketContainerFinal } from '~/src/features/full-buy/containers/agregate/TiketContainerFinal';\nimport GoToNextStepButton from '~/src/features/full-buy/containers/GoToNextStepButton';\nimport { GuideFullBuy } from '~/src/features/full-buy/containers/GuideFullBuy';\nimport ProgressBarWithBackBtnContainer from '~/src/features/full-buy/containers/ProgressBarWithBackBtn';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { ESteps } from '~/src/features/full-buy/types';\nimport { TState } from '~/src/store';\n\nimport { DoubleColumnLayout } from '~/src/features/full-buy/containers/pages/styled';\nimport * as ST from './styled';\n\ninterface IMainLayout {\n children: ReactNode,\n showFinalTicket?: boolean,\n className?: string,\n isHide?: boolean,\n}\n\nexport const MainLayout = ({ children, isHide = false, showFinalTicket = false, className }: IMainLayout) => {\n const router = useRouter();\n const analytics = useAnalytics();\n\n const [isOpenGuide, setIsOpenGuide] = useState(false);\n\n const {\n selectedTariff,\n stepIndex,\n flow,\n } = useSelector((state: TState) => ({\n selectedTariff: selectCurrentTariff(state),\n stepIndex: state.fullBuy.stepIndex,\n flow: state.fullBuy.flow,\n }), shallowEqual);\n\n const onCloseGuide = () => {\n setIsOpenGuide(false);\n };\n\n const onOpenGuide = () => {\n setIsOpenGuide(true);\n analytics.clickGuide(step);\n };\n\n const step = flow?.steps[stepIndex];\n\n const isHideGuideIcon = useMemo(() => {\n return (step === ESteps.final) || (!router?.query?.tariffName && step === ESteps.tariffInfo);\n }, [step]);\n\n return (\n \n \n \n \n {children}\n\n \n\n \n \n \n \n {\n showFinalTicket\n ? \n : \n }\n \n \n \n \n \n );\n};\n","import { useState } from 'react';\nimport { useRouter } from 'next/router';\n\nimport Button from '@r1-frontend/ui-react/components/buttons/button';\nimport { ButtonGroup } from '@r1-frontend/ui-react/components/buttons/buttonGroup/ButtonGroup';\nimport DefaultPopup from '@r1-frontend/ui-react/components/popups/defaultPopup';\nimport { InfoCircleFlip } from '@r1-frontend/ui-react/components/svg/main';\nimport ControlElement from '@r1-frontend/ui-react/components/typography/controlElement';\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport { Paragraph4 } from '@r1-frontend/ui-react/components/typography/paragraph';\nimport TextWrapper from '@r1-frontend/ui-react/components/typography/TextWrapper';\nimport { IndentContainer } from '@r1-frontend/ui-react/experimental/containers';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\n\nimport { USER_LOGIN_ROUTE } from '~/src/constants/routes';\nimport { useAnalytics } from '~/src/features/full-buy/analytics/context';\n\nexport const HasAgreementPopup = (): JSX.Element => {\n const analytics = useAnalytics();\n\n const router = useRouter();\n\n const [isOpen, changePopupState] = useState(false);\n\n const goToLk = () => {\n router.push(USER_LOGIN_ROUTE);\n changePopupState(false);\n analytics.address.popupAddressAgreement('click_enter_lk');\n };\n\n const handleClosePopup = () => {\n changePopupState(false);\n analytics.address.popupAddressAgreement('click_create_agreement');\n };\n\n const handleOpenPopup = () => {\n changePopupState(true);\n analytics.address.popupAddressAgreement('view_popup');\n };\n\n return (\n <>\n \n Проверим техническую возможность подключить тариф. Уже подключали Дом.ру?\n \n\n \n \n \n Уже подключали Дом.ру?
\n \n Чтобы не создавать новый договор, вы можете войти в личный кабинет и поменять тариф на более подходящий.\n \n \n\n \n \n \n \n \n \n >\n );\n};\n","import React, { useCallback } from 'react';\n\nimport { doRequest } from '@r1-frontend/do-request';\nimport { ResponseDto } from '@r1-frontend/api-domru/dadata/suggest/dto/ResponseDto';\nimport suggestFio from '@r1-frontend/api-domru/dadata/suggest/fio';\n\nimport { IPersonFormProps, PersonForm as PersonFormComponent } from '@r1-frontend/ui-react/organisms/Forms/PersonForm';\n\n\ntype TProps = Omit;\n\nexport const PersonForm = ({\n fio,\n phone,\n onChangeFio,\n onChangePhone,\n isNeedToBlockInvalidFio = false,\n actionButtonProps,\n}: TProps): JSX.Element => {\n const onLoadSuggestions = useCallback(async(value) => {\n const resp = await doRequest.dadataProxy(\n suggestFio(value),\n );\n\n return resp.isSuccess\n ? resp.payload?.suggestions.map(suggestion => suggestion.value)\n : [];\n }, []);\n\n return (\n \n );\n};\n","import styled from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\nexport const EditableContactsForm = styled.div`\n position: relative;\n flex-direction: column;\n align-items: flex-start;\n row-gap: 12px;\n width: 100%;\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n align-items: stretch;\n }\n`;\n\nexport const NoWrapText = styled.span`\n display: contents;\n white-space: nowrap;\n`;\n\nexport const BoldText = styled.span`\n display: contents;\n ${FONTS.H5};\n`;\n\nexport const BlockWrap = styled.div`\n display: grid;\n flex-wrap: nowrap;\n align-items: flex-start;\n grid-template-columns: 524px min-content;\n column-gap: 12px;\n width: 100%;\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n grid-template-columns: 1fr;\n row-gap: 24px;\n } \n`;\n\nexport const BlockTitle = styled.div`\n ${FONTS.S};\n color: ${COLORS.TextPrimary};\n`;\n","import { memo, useState } from 'react';\nimport { useSelector } from 'react-redux';\nimport { useRouter } from 'next/router';\n\nimport { selectAddressParamsMemoize } from '@r1-frontend/entities/ContactAddress/selectors/selectAddressParams';\n\nimport { EResultPopupStatus } from '@r1-frontend/ui-react/components/popups/popupResult'; // TODO заменить на объединение строк\nimport { useResultPopup } from '@r1-frontend/ui-react/components/popups/useResultPopup';\n\nimport { PersonForm } from '~/src/features/full-buy/components/uiReactComponents/PersonForm';\nimport {\n isGigabitCanConnected,\n isGigaSpeedRequired,\n isTariffCanConnected,\n submitRequest,\n} from '~/src/features/full-buy/functions';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { TState } from '~/src/store';\nimport { selectCsrf } from '~/src/store/selectors/auth/selectCsrf';\n\nimport * as ST from './styled';\n\n/**\n * Форма для отправки заявки на подключение\n */\nconst RequestForm = (): JSX.Element => {\n const csrf = useSelector(selectCsrf);\n const router = useRouter();\n const onClickClose = () => router.push('/');\n const [PopupResult, showResult] = useResultPopup(onClickClose);\n const [fio, setFio] = useState('');\n const [phone, setPhone] = useState('');\n\n const {\n tariffPackage,\n products,\n unifiedSelectedAddress,\n addressParams,\n isHouseConnected,\n gigabitAvail,\n } = useSelector((state: TState) => ({\n tariffPackage: selectCurrentTariff(state),\n products: state.fullBuy.products,\n unifiedSelectedAddress: state.fullBuy.selectedAddress,\n addressParams: selectAddressParamsMemoize(state),\n isHouseConnected: state.contactAddress.verifiedAddressData.isHouseConnected,\n gigabitAvail: state.contactAddress.verifiedAddressData.gigabitAvail,\n }));\n\n const { isMono, speed, sale_package_id, tariff_name, additionalProducts } = tariffPackage || {};\n\n const gigabitMayConnect = isGigabitCanConnected(gigabitAvail);\n const requiredGigaSpeed = isGigaSpeedRequired(speed || 0);\n const shouldConnect = isTariffCanConnected(isHouseConnected, requiredGigaSpeed, gigabitMayConnect);\n\n const onSubmitRequest = async() => {\n const resp = await submitRequest({\n isMono: !!isMono,\n fio,\n phone,\n csrf,\n sale_package_id,\n tariff_name,\n additionalProducts: additionalProducts || [],\n products: products || [],\n address: unifiedSelectedAddress?.address.value,\n street: addressParams?.street?.label,\n house: addressParams?.house?.label,\n flat: addressParams?.flat,\n shouldConnect,\n });\n\n const { ok, message } = resp;\n\n showResult({\n type: ok ? EResultPopupStatus.SUCCESS : EResultPopupStatus.ERROR,\n title: ok ? 'Заявка на подключение отправлена' : 'Произошла ошибка',\n text: ok ? 'Мы свяжемся с вами в ближайшее время' : message,\n });\n };\n\n return (\n \n \n \n \n \n \n );\n};\n\nexport default memo(RequestForm);\n","import React, { useContext } from 'react';\n\nimport { AddressInput } from '@r1-frontend/unified-address-form';\n\nimport { FullBuyContext, TFullBuyContextProperties } from '~/src/features/full-buy/analytics/context';\n\nexport const OneLineAddressInput = () => {\n const { isVillage } = useContext(FullBuyContext);\n\n return (\n \n );\n};\n","import styled from 'styled-components';\n\nimport BaseAlert from '@r1-frontend/ui-react/components/Alert';\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\nexport const MsgContent = styled.div`\n width: 100%;\n`;\n\nexport const Text = styled.div`\n flex: 1;\n width: 100%;\n ${FONTS.S};\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n ${FONTS.XS};\n }\n`;\n\nexport const NoWrapText = styled.span`\n display: contents;\n white-space: nowrap;\n`;\n\nexport const BoldText = styled.span`\n display: contents;\n ${FONTS.H5};\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n ${FONTS.H6};\n }\n`;\n\nexport const Alert = styled(BaseAlert)`\n flex-direction: column;\n gap: 10px;\n width: 100%;\n align-items: baseline;\n overflow: visible;\n`;\n","import styled from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { RounderContainer } from '@r1-frontend/ui-react/experimental/containers';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\n\nexport const Block = styled.div`\n display: block;\n`;\n\nexport const GrayBlock = styled(RounderContainer)`\n width: 100%;\n display: flex;\n flex-direction: column;\n gap: 16px;\n\n background-color: ${COLORS.BgSurface};\n padding: 24px;\n \n @media (min-width: ${wideBreakpoints.mobile}) {\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n }\n`;\n","// @ts-nocheck\nimport React, { useContext, useEffect, useMemo } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport styled from 'styled-components';\n\nimport { ResultMessage } from '@r1-frontend/unified-address-form';\nimport { flush } from '@r1-frontend/unified-address-form/actions';\nimport { useCtxDispatch } from '@r1-frontend/unified-address-form/hooks';\n\nimport Button from '@r1-frontend/ui-react/components/buttons/button';\nimport { ButtonGroup } from '@r1-frontend/ui-react/components/buttons/buttonGroup/ButtonGroup';\nimport { PolicyNote } from '@r1-frontend/ui-react/components/PolicyNote';\nimport { Location } from '@r1-frontend/ui-react/components/svg/location';\nimport { InfoCircle } from '@r1-frontend/ui-react/components/svg/main';\nimport { Paragraph4 } from '@r1-frontend/ui-react/components/typography/paragraph';\nimport { IndentContainer, ListContainer, RounderContainer } from '@r1-frontend/ui-react/experimental/containers';\nimport ListItemWithIcon from '@r1-frontend/ui-react/organisms/ListItemWithIcon';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\n\nimport { POLICY_PAGE_LINK } from '~/src/constants';\nimport RequestForm from '~/src/features/full-buy/AddressCheckMessage/RequestForm';\nimport { FullBuyContext, TFullBuyContextProperties, useAnalytics } from '~/src/features/full-buy/analytics/context';\nimport { OneLineAddressInput } from '~/src/features/full-buy/components/OneLineAddressInput/OneLineAddressInput';\nimport isFullBuyVillage from '~/src/features/full-buy/helpers/ab/isFullBuyVillage';\nimport { setAddress } from '~/src/features/full-buy/store/actions';\nimport { ETariffFilters } from '~/src/features/full-buy/store/initialState';\nimport { TState } from '~/src/store';\n\nimport * as FullBuyST from '~/src/features/full-buy/AddressCheckMessage/styled';\nimport * as S from './styled';\n\nconst SPEED_OF_INTERNET_100 = 100;\n\nconst UnifiedAddressForm = ({ ...props }): JSX.Element => {\n const analytics = useAnalytics();\n const dispatch = useDispatch();\n const { isVillage } = useContext(FullBuyContext);\n\n const checkingResult = useSelector((state: TState) => state.fullBuy?.selectedAddress?.checkingResult);\n const addressFormDispatch = useCtxDispatch();\n const buttonText = useMemo(() => 'Проверить адрес', []);\n\n useEffect(() => {\n window.scrollTo(0, 0);\n }, [checkingResult]);\n\n\n const handleChangeAddress = () => {\n analytics.address.changeAddressClicked();\n dispatch(setAddress(undefined));\n addressFormDispatch(flush());\n };\n\n const goToMainPageWithRestrictions = () => {\n // @todo remove ignore, write type\n // @ts-ignore\n const restrictions = checkingResult.availableSpeed.max;\n\n if (restrictions === SPEED_OF_INTERNET_100) {\n analytics.address.only100Clicked();\n } else {\n analytics.address.lessThan1000Clicked();\n }\n\n location.href = `/full-buy?filters=${restrictions === SPEED_OF_INTERNET_100 ? ETariffFilters.SPEED100 : ETariffFilters.SPEED_LESS_1000}${isVillage ? '&filters=cottage' : ''}`;\n };\n\n const goToMainPageInViewOfCompatibilities = () => {\n location.href = '/full-buy' + (isVillage ? '' : '?filters=cottage');\n };\n\n // main component with the address input form and the own store\n if (!checkingResult) {\n return \n \n \n \n \n \n \n \n \n \n ;\n }\n\n // situation when checking was fail or connection unavailable\n if (checkingResult && checkingResult.isConnectionAvailable === false) {\n return \n \n \n \n \n\n \n \n \n \n ;\n }\n\n // connection available\n return \n \n {checkingResult.isCompatible && (\n \n )}\n\n {(!checkingResult.isTariffAvailableForActivation && checkingResult.isCompatible) && (\n \n \n \n )}\n\n {!checkingResult.isCompatible && (\n <>\n \n \n \n \n {isFullBuyVillage() && (\n \n \n \n )}\n >\n )}\n\n \n \n \n \n \n ;\n};\n\nexport default styled(UnifiedAddressForm)`\n ${RounderContainer} {\n background-color: ${COLORS.BgSurface};\n width: 100%;\n display: block;\n\n overflow: visible;\n }\n`;\n","import React from 'react';\nimport { useSelector } from 'react-redux';\n\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport TextWrapper from '@r1-frontend/ui-react/components/typography/TextWrapper';\n\nimport { MainLayout } from '~/src/features/full-buy/containers/MainLayout/MainLayout';\nimport { HasAgreementPopup } from '~/src/features/full-buy/containers/pages/Address/HasAgreementPopup';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\n\nimport UnifiedAddressForm from './UnifiedAddressForm';\n\nconst OneLineAddress = (): JSX.Element => {\n const selectedTariff = useSelector(selectCurrentTariff);\n const { title = '' } = selectedTariff || {};\n\n return \n \n {`Проверьте, доступен ли тариф «${title}» по вашему адресу`}
\n \n \n\n \n ;\n};\n\nexport default OneLineAddress;\n","import styled, { css } from 'styled-components';\n\nimport { BaseButton } from '@r1-frontend/ui-react/components/buttons/baseButton';\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\nexport const FullBuy = styled.div`\n display: block;\n width: 100%;\n padding-top: 60px;\n\n @media (max-width: ${wideBreakpoints.sDesktop}) {\n padding-top: 69px;\n }\n\n @media (max-width: ${wideBreakpoints.laptop}) {\n padding-top: 24px;\n }\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n padding-top: 40px;\n }\n`;\n\nexport const FullBuyByPage = styled.div<{ isNotNeedGap?: boolean }>`\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n padding-top: 40px;\n ${({ isNotNeedGap = false }) => !isNotNeedGap && css`\n row-gap: 40px;\n `}\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n padding-top: 10px;\n }\n`;\n\nexport const StageWrap = styled.section`\n display: flex;\n flex-direction: column;\n row-gap: 16px;\n align-items: flex-start;\n`;\n\nexport const LeftSide = styled.div`\n flex: 1;\n flex-direction: column;\n gap: 32px;\n\n @media (max-width: ${wideBreakpoints.laptop}) {\n flex: 0 1 auto;\n display: flex;\n width: 100%;\n }\n\n @media (max-width: 1350px) {\n flex-direction: column;\n }\n`;\n\nexport const RightSide = styled.div<{ isLastStage?: boolean, isOnTimeslots?: boolean }>`\n z-index: 1;\n flex: 0 1 auto;\n display: flex;\n flex-direction: column;\n padding-top: ${p => p.isLastStage ? '78px' : p.isOnTimeslots ? '82px' : '48px'};\n\n @media (max-width: ${wideBreakpoints.laptop}) {\n width: 100%;\n max-width: 100%;\n ${p => p.isLastStage ? 'padding-top: 0px' : ''};\n }\n`;\n\nexport const Title = styled.div`\n margin-top: 24px;\n width: 100%;\n padding: 0 16px;\n ${FONTS.XS};\n color: ${COLORS.TextPrimary};\n\n @media (min-width: ${wideBreakpoints.mobile}) {\n padding: 0;\n }\n`;\n\n/**\n * @deprecated use the @r1-frontend/ui-react/typography/heading H3\n */\nexport const BlockTitle = styled.div`\n ${FONTS.H3};\n color: ${COLORS.TextPrimary};\n margin-bottom: 16px;\n\n @media (max-width: ${wideBreakpoints.laptop}) {\n ${FONTS.H4};\n }\n \n @media (max-width: ${wideBreakpoints.mobile}) {\n ${FONTS.H4};\n }\n`;\n\nexport const TextWrap = styled.div`\n flex: 1;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n`;\n\n/**\n * @deprecated use the @r1-frontend/ui-react/typography/heading H3 or H4...\n */\nexport const Text = styled.div`\n ${FONTS.H3};\n color: ${COLORS.TextPrimary};\n\n @media (max-width: ${wideBreakpoints.laptop}) {\n ${FONTS.H4};\n }\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n ${FONTS.H5};\n }\n`;\n\nexport const Button = styled(BaseButton)`\n @media (max-width: ${wideBreakpoints.mobile}) {\n width: 100% !important;\n }\n`;\n","import styled from 'styled-components';\n\nexport const Block = styled.div`\n width: 100%;\n\n * {\n width: 100%;\n }\n`;\n\nexport const FlexBlock = styled.div`\n width: auto;\n display: flex;\n gap: 16px;\n`;\n","import React from 'react';\nimport Skeleton, { SkeletonTheme } from 'react-loading-skeleton';\n\nimport 'react-loading-skeleton/dist/skeleton.css';\n\nimport { DoubleColumnLayout } from '~/src/components/DoubleColumnLayout';\nimport { StageTitle } from '~/src/features/full-buy/StageTitle';\n\nimport * as ST from '../styled';\n\nimport * as S from './styled';\n\nconst TariffInfoPageSkeleton = ({ title }: { title: string }): JSX.Element => {\n return (\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n );\n};\n\nexport default TariffInfoPageSkeleton;\n","import { useEffect } from 'react';\n\nimport { dataLayerPush } from '@r1-frontend/analytics/dataLayerPush';\n\nimport { EVENTS } from '@r1-frontend/shared/constants/analytics';\n\n/**\n * Хук для отправки referrer в GA метрику,\n * в label пишется путь без домена.\n * Использовать на конечной странице.\n */\nexport const useSendReferrerToGA = (category: string, action: string) => {\n const sendReferrer = () => {\n const {\n document: { referrer = '/' },\n location: { origin },\n } = window;\n const withoutOrigin = referrer.replace(origin, '');\n\n dataLayerPush({\n event: EVENTS.UAevent,\n category,\n action,\n label: withoutOrigin,\n });\n };\n\n useEffect(() => {\n sendReferrer();\n }, []);\n};\n","import styled from 'styled-components';\n\nimport InteractiveLoader from '~/src/components/InteractiveLoader';\n\nexport const SInteractiveLoader = styled(InteractiveLoader)`\n flex: 1;\n`;\n","import { RefObject, useEffect, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { isClientSide } from '@r1-frontend/shared/helpers/ssr';\nimport { useMatchMedia } from '@r1-frontend/shared/hooks/useMatchMedia';\n\nimport { agreementCreationStatuses } from '~/src/features/full-buy/consts';\nimport { MainLayout } from '~/src/features/full-buy/containers/MainLayout/MainLayout';\n\nimport * as ST from './styles';\n\ninterface IProps {\n parent?: RefObject,\n}\n\nconst Loader = ({ parent }: IProps) => {\n const [root, setRoot] = useState(null);\n const isMobile = useMatchMedia(`(max-width: ${wideBreakpoints.mobile})`);\n\n useEffect(() => {\n if (isClientSide()) {\n const portal = parent ? parent.current : document.getElementById('loader-portal');\n if (portal) {\n if (isMobile) {\n portal.style.minHeight = '70vh';\n } else {\n portal.style.minHeight = 'auto';\n }\n setRoot(portal);\n }\n }\n }, [isMobile, parent]);\n\n return root\n ? createPortal(\n (\n \n \n \n ),\n root,\n )\n : null;\n};\n\nexport default Loader;\n","import React, { useMemo } from 'react';\n\nimport { EAvailableSpeed, EVerificationStatus } from '@r1-frontend/entities/ContactAddress/initialState';\n\nimport { TAlertIcon } from '@r1-frontend/ui-react/components/Alert';\nimport { TAlertTypes } from '@r1-frontend/ui-react/components/Alert/TAlertTypes';\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { InfoCircle, TickCircle } from '@r1-frontend/ui-react/components/svg/main';\nimport { Paragraph4 } from '@r1-frontend/ui-react/components/typography/paragraph';\nimport { useMatchMediaByWidth } from '@r1-frontend/shared/hooks/useMatchMedia';\n\nimport RequestForm from './RequestForm';\n\nimport * as ST from './styled';\n\ntype TResultTypes = 'notConnected' | 'canConnected' | 'gigabitError' | 'checkError' | 'flatError';\n\ninterface IResult {\n getText: (args: { tariffName?: string, availableSpeed: EAvailableSpeed }) => JSX.Element,\n hasCallRequest: boolean,\n messageType: TAlertTypes,\n icon: TAlertIcon,\n}\n\nconst results: Record = {\n canConnected: {\n getText: ({ tariffName = '' }) => <>По вашему адресу можно подключить тариф «{tariffName}»>,\n hasCallRequest: false,\n messageType: 'success',\n icon: () => ,\n },\n notConnected: {\n getText: () => <>Ваш дом пока не подключён к Дом.ру. Можем сообщить вам, когда подключим.\n Чтобы мы смогли дозвониться — проверьте, что у вас отключен автоответчик и антиспам приложения.>,\n hasCallRequest: true,\n messageType: 'error',\n icon: () => ,\n },\n gigabitError: {\n getText: ({ availableSpeed }) => {\n if (availableSpeed === EAvailableSpeed.between100and1000) {\n return <>\n Пока в вашем доме можно подключить только тарифы со скоростью меньше 1000 Мбит/с.\n >;\n } else {\n return <>\n Пока в вашем доме можно подключить только тариф с максимальной скоростью 100 Мбит/с.\n >;\n }\n },\n hasCallRequest: false,\n messageType: 'info',\n icon: () => ,\n },\n checkError: {\n getText: () => <>Не смогли проверить ваш адрес. Пожалуйста, оставьте ваши ФИО и номер телефона — мы позвоним вам и всё проверим.\n Чтобы мы смогли дозвониться — проверьте, что у вас отключен автоответчик и антиспам приложения.>,\n hasCallRequest: true,\n messageType: 'error',\n icon: () => ,\n },\n flatError: {\n getText: () => <>Этот тариф недоступен по вашему адресу. Оставьте свои контакты — мы перезвоним и подберём другой вариант.\n Чтобы мы смогли дозвониться — проверьте, что у вас отключен автоответчик и антиспам приложения.>,\n hasCallRequest: true,\n messageType: 'error',\n icon: () => ,\n },\n};\n\nexport interface IAddressCheckMessageProps {\n tariffName: string | undefined,\n gigabitMayConnect: boolean,\n requiredGigaSpeed: boolean,\n isNotFlatAddress?: boolean,\n isHouseConnected: boolean,\n addressStatus: EVerificationStatus,\n availableSpeed: EAvailableSpeed,\n}\n\n/**\n * Выводит сообщение с результатом проверки адреса или null, если адрес ещё не проверялся\n */\nexport const AddressCheckMessage = ({\n tariffName,\n gigabitMayConnect,\n requiredGigaSpeed,\n isNotFlatAddress,\n isHouseConnected,\n addressStatus,\n availableSpeed,\n}: IAddressCheckMessageProps): JSX.Element | null => {\n const isGigabitError = requiredGigaSpeed && !gigabitMayConnect;\n const isTariffCanConnect = isHouseConnected && !isGigabitError;\n const isMobile = useMatchMediaByWidth(wideBreakpoints.mobile);\n const resultType = useMemo(() => {\n switch (true) {\n // Проверка адреса не прошла\n case (addressStatus === EVerificationStatus.error):\n return 'checkError';\n // Проверка адреса не прошла\n case (isNotFlatAddress):\n return 'flatError';\n // Тариф можно подключить\n case (isTariffCanConnect):\n return 'canConnected';\n // Дом не подключен\n case (![EVerificationStatus.notVerified, EVerificationStatus.verifying].includes(addressStatus) && !isHouseConnected):\n return 'notConnected';\n // Нет гигабитной сети\n case (isGigabitError):\n return 'gigabitError';\n default:\n return 'checkError';\n }\n }, [isTariffCanConnect, isGigabitError, isHouseConnected, addressStatus]);\n\n const result = results[resultType];\n\n // Адрес ещё не проверяли\n if (addressStatus === EVerificationStatus.notVerified || addressStatus === EVerificationStatus.verifying) {\n return null;\n }\n\n return (\n \n \n {result.getText({ tariffName, availableSpeed: availableSpeed })}\n \n {result.hasCallRequest &&\n \n }\n \n );\n};\n","import styled from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { BorderRadius } from '@r1-frontend/ui-react/tokens/borderRadius';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\nexport const EditableForm = styled.div`\n position: relative;\n flex-direction: column;\n align-items: flex-start;\n row-gap: 24px;\n width: 100%;\n border-radius: ${BorderRadius.componentRadius};\n background-color: ${COLORS.BgSurface};\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n align-items: stretch;\n }\n`;\n\nexport const NoWrapText = styled.span`\n display: contents;\n white-space: nowrap;\n`;\n\nexport const BoldText = styled.span`\n display: contents;\n ${FONTS.H5};\n`;\n\nexport const BlockWrap = styled.div`\n width: 100%;\n flex-direction: column;\n`;\n","import { memo } from 'react';\n\nimport { BaseButton, btnTypes } from '@r1-frontend/ui-react/components/buttons/baseButton';\nimport { PolicyNote } from '@r1-frontend/ui-react/components/PolicyNote';\nimport { IndentContainer } from '@r1-frontend/ui-react/experimental/containers';\nimport { IAddress } from '@r1-frontend/shared/types/IAddress';\n\nimport AddressInputFields from '~/src/components/AddressInputFields';\nimport { POLICY_PAGE_LINK } from '~/src/constants';\nimport { useAnalytics } from '~/src/features/full-buy/analytics/context';\n\nimport * as ST from './styled';\n\nexport type TField = {\n value: string,\n isValid: boolean,\n clearInput: () => void,\n}\n\nexport type TContactDetailsProps = {\n isConfirmButtonActive: boolean,\n defaultAddress?: IAddress | null,\n showConfirmButton?: boolean,\n withSatelliteFilter?: boolean,\n}\n\nexport type TContactDetailsCallbacks = {\n onFillAddress: (address: IAddress) => void,\n onConfirmBtnClick: () => void,\n}\n\nconst EditableForm = ({\n isConfirmButtonActive,\n onFillAddress,\n onConfirmBtnClick,\n defaultAddress,\n showConfirmButton = true,\n withSatelliteFilter,\n}: TContactDetailsProps & TContactDetailsCallbacks): JSX.Element => {\n const analytics = useAnalytics();\n\n return (\n \n \n analytics.send(action)}\n defaultAddress={defaultAddress}\n withSatelliteFilter={withSatelliteFilter}\n />\n \n \n \n \n {showConfirmButton &&\n \n }\n \n );\n};\n\nexport default memo(EditableForm);\n","import styled from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport Throbber from '@r1-frontend/ui-react/components/loaders/Throbber';\nimport { StyledMenu } from '@r1-frontend/ui-react/components/select/dropdown';\nimport { BorderRadius } from '@r1-frontend/ui-react/tokens/borderRadius';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\nimport { ResultMessage } from '~/src/features/full-buy/ResultMessage';\n\nexport const AddressWrapper = styled.div`\n position: relative;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n padding: 24px;\n border-radius: ${BorderRadius.OuterBlockRadius};\n background-color: ${COLORS.BgSurface};\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n padding: 16px;\n }\n \n ${StyledMenu} {\n z-index: 198 !important;\n }\n`;\n\nexport const SelectOtherTariff = styled.div`\n position: relative;\n flex-wrap: nowrap;\n flex-direction: column;\n row-gap: 16px;\n width: 100%;\n margin-top: 20px;\n padding: 24px 0 24px 24px;\n border-radius: ${BorderRadius.componentRadius};\n background-color: ${COLORS.BgSurface};\n`;\n\nexport const SResultMessage = styled(ResultMessage)`\n align-items: center;\n padding-right: 24px;\n fill: ${COLORS.Error};\n\n & > div:first-child {\n flex: 0 0 40px;\n align-self: flex-start;\n width: 40px;\n height: 40px;\n margin-right: 16px;\n background-color: ${COLORS.BgMain};\n border-radius: 20px;\n }\n`;\n\nexport const NoWrapText = styled.span`\n display: contents;\n white-space: nowrap;\n`;\n\nexport const BoldText = styled.span`\n display: contents;\n ${FONTS.H5};\n`;\n\nexport const STrobber = styled(Throbber)`\n position: absolute;\n top: 0;\n width: 100%;\n height: 100%;\n`;\n","import React, { memo, useCallback } from 'react';\nimport { shallowEqual, useDispatch, useSelector } from 'react-redux';\n\nimport { ERequestStatus } from '@r1-frontend/api-domru/api-request/v1/user/request-by-connection';\nimport { checkAddress } from '@r1-frontend/entities/ContactAddress/actions/checkAddress';\nimport { fillAddressAction } from '@r1-frontend/entities/ContactAddress/actions/fillAddress';\nimport { setAddressEdit } from '@r1-frontend/entities/ContactAddress/actions/setAddressEdit';\nimport { isAddressFilled } from '@r1-frontend/entities/ContactAddress/selectors/isAddressFilled';\nimport { EVerificationStatus } from '@r1-frontend/entities/ContactDetail/initialState';\n\nimport { IAddress } from '@r1-frontend/shared/types/IAddress';\n\nimport { TState } from '~/src/store';\n\nimport { ConfirmedForm } from './ConfirmedForm';\nimport EditableForm from './EditableForm';\nimport { useStorageAddress } from './useStorageAddress';\n\nimport * as ST from './styled';\n\nexport type TField = {\n value: string,\n isValid: boolean,\n clearInput: () => void,\n}\n\nexport interface IResp {\n ok: boolean,\n message: string,\n status: ERequestStatus,\n id: number | undefined,\n}\n\ninterface IProps {\n showConfirmButton?: boolean,\n showConfirmForm?: boolean,\n addressBlockRef?: React.RefObject,\n}\n\nconst ContactAddress = ({ showConfirmButton = true, showConfirmForm = true, addressBlockRef }: IProps): JSX.Element => {\n const dispatch = useDispatch();\n\n const {\n isConfirmButtonActive,\n verifiedAddress,\n addressStatus,\n isEdit,\n } = useSelector((state: TState) => ({\n isConfirmButtonActive: isAddressFilled(state),\n verifiedAddress: state.contactAddress.verifiedAddressData.address,\n addressStatus: state.contactAddress.verifiedAddressData.status,\n editedAddress: state.contactAddress.editedAddressData,\n isEdit: state.contactAddress.isEdit,\n }), shallowEqual);\n\n useStorageAddress();\n\n const onEdit = useCallback(() => {\n dispatch(setAddressEdit(true));\n }, [dispatch]);\n\n const onFillAddress = useCallback((address: IAddress) => {\n dispatch(fillAddressAction(address));\n }, [dispatch]);\n\n const checkAddressData = () => {\n dispatch(checkAddress());\n dispatch(setAddressEdit(false));\n };\n\n return (\n \n {isEdit &&\n \n }\n\n {!isEdit && showConfirmForm &&\n \n }\n {(addressStatus === EVerificationStatus.verifying) &&\n \n }\n \n );\n};\n\nexport default memo(ContactAddress);\n","import React, { useEffect, useMemo, useState } from 'react';\nimport { batch, shallowEqual, useDispatch, useSelector } from 'react-redux';\n\nimport { EAvailableSpeed } from '@r1-frontend/entities/ContactAddress/initialState';\nimport { EVerificationStatus } from '@r1-frontend/entities/ContactDetail/initialState';\n\nimport Button from '@r1-frontend/ui-react/components/buttons/button';\nimport { ButtonGroup } from '@r1-frontend/ui-react/components/buttons/buttonGroup/ButtonGroup';\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport TextWrapper from '@r1-frontend/ui-react/components/typography/TextWrapper';\n\nimport { AddressCheckMessage } from '~/src/features/full-buy/AddressCheckMessage';\nimport { useAnalytics } from '~/src/features/full-buy/analytics/context';\nimport { GIGABIT_SPEED, MEGABIT_SPEED } from '~/src/features/full-buy/consts';\nimport ContactAddress from '~/src/features/full-buy/ContactAddress';\nimport { MainLayout } from '~/src/features/full-buy/containers/MainLayout/MainLayout';\nimport { setDisplayTariffLineState, setTariffFilters, setTariffLineAlias } from '~/src/features/full-buy/store/actions';\nimport { ETariffFilters } from '~/src/features/full-buy/store/initialState';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { selectFilteredTariffs } from '~/src/features/full-buy/store/selectors/selectFilteredTariffs';\nimport { TState } from '~/src/store';\n\nimport { HasAgreementPopup } from './HasAgreementPopup';\n\ntype TAdditionalTariffs = 'only100' | 'less1000';\n\nexport const Address = (): JSX.Element => {\n const analytics = useAnalytics();\n\n const {\n selectedTariff,\n addressStatus,\n isEdit,\n verifiedAddressData: {\n isHouseConnected,\n isHouseCottage,\n availableSpeed,\n },\n } = useSelector((state: TState) => ({\n selectedTariff: selectCurrentTariff(state),\n filteredTariffs: selectFilteredTariffs(state),\n addressStatus: state.contactAddress.verifiedAddressData.status,\n isEdit: state.contactAddress.isEdit,\n\n verifiedAddressData: state.contactAddress.verifiedAddressData,\n }), shallowEqual);\n\n useEffect(() => {\n window.scrollTo(0, 0);\n }, [isEdit]);\n\n const dispatch = useDispatch();\n\n const [displayAdditionalTariffLine, setDisplayAdditionalTariffLine] = useState(false);\n\n const { title = '', speed: tariffSpeed = null } = selectedTariff || {};\n\n const tariffSpeedAcrossEnum = useMemo(() => {\n if (tariffSpeed === null) {\n return null;\n }\n\n if (tariffSpeed >= GIGABIT_SPEED) {\n return EAvailableSpeed.more1000;\n }\n\n if (tariffSpeed > MEGABIT_SPEED) {\n return EAvailableSpeed.between100and1000;\n }\n\n return EAvailableSpeed.lessOrEqual100;\n }, [tariffSpeed]);\n\n const shouldConnect = isHouseConnected && (\n (Number(tariffSpeedAcrossEnum) > EAvailableSpeed.lessOrEqual100 && Number(tariffSpeedAcrossEnum) <= availableSpeed) ||\n (Number(tariffSpeedAcrossEnum) === EAvailableSpeed.lessOrEqual100)\n );\n\n const addressIsVerified = addressStatus === EVerificationStatus.verified;\n\n useEffect(() => {\n if (addressStatus === EVerificationStatus.verified) {\n const allowedSpeed = availableSpeed === EAvailableSpeed.lessOrEqual100 ? 'only100' : 'less1000';\n if (!isHouseConnected) {\n analytics.address.verificationFailed('Ваш дом пока не подключён к Дом.ру');\n return;\n }\n\n if (Number(tariffSpeedAcrossEnum) > availableSpeed) {\n analytics.address.verificationFailed(`Ваш дом пока не подключен к такой скорости (${allowedSpeed})`);\n return;\n }\n\n analytics.address.verificationSuccess();\n }\n\n if (addressStatus === EVerificationStatus.error) {\n analytics.address.verificationFailed('Не смогли проверить ваш адрес');\n }\n }, [addressStatus]);\n\n useEffect(() => {\n if (!tariffSpeed || !addressIsVerified || !isHouseConnected) {\n return;\n }\n\n if (!shouldConnect) {\n setDisplayAdditionalTariffLine(availableSpeed === EAvailableSpeed.lessOrEqual100 ? 'only100' : 'less1000');\n batch(() => {\n dispatch(setTariffFilters([availableSpeed === EAvailableSpeed.lessOrEqual100 ? ETariffFilters.SPEED100 : ETariffFilters.SPEED_LESS_1000]));\n dispatch(setTariffLineAlias(''));\n dispatch(setDisplayTariffLineState(true));\n });\n }\n }, [dispatch, tariffSpeed, addressIsVerified, shouldConnect]);\n\n useEffect(() => {\n if (displayAdditionalTariffLine && isEdit) {\n setDisplayAdditionalTariffLine(false);\n }\n }, [displayAdditionalTariffLine, isEdit]);\n\n const goToSpeed100Tariffs = () => {\n if (availableSpeed === EAvailableSpeed.lessOrEqual100) {\n analytics.address.only100Clicked();\n } else {\n analytics.address.lessThan1000Clicked();\n }\n\n location.href = `/full-buy?filters=${availableSpeed === EAvailableSpeed.lessOrEqual100 ? ETariffFilters.SPEED100 : ETariffFilters.SPEED_LESS_1000}`;\n };\n\n return (\n \n {isEdit &&\n \n {`Проверьте, доступен ли тариф «${title}» по вашему адресу`}
\n \n \n }\n\n {!isEdit &&\n EAvailableSpeed.lessOrEqual100}\n requiredGigaSpeed={Number(tariffSpeedAcrossEnum) > EAvailableSpeed.lessOrEqual100}\n availableSpeed={availableSpeed}\n isHouseConnected={isHouseConnected}\n tariffName={title}\n isNotFlatAddress={isHouseCottage}\n addressStatus={addressStatus}\n />\n }\n {/* Альтернативные тарифы */}\n {displayAdditionalTariffLine &&\n \n \n \n }\n {selectedTariff &&\n \n }\n \n );\n};\n","import styled from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\nexport const EditableContactsForm = styled.div`\n position: relative;\n flex-direction: column;\n align-items: flex-start;\n row-gap: 12px;\n width: 100%;\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n align-items: stretch;\n }\n`;\n\nexport const NoWrapText = styled.span`\n display: contents;\n white-space: nowrap;\n`;\n\nexport const BoldText = styled.span`\n display: contents;\n ${FONTS.H5};\n`;\n\nexport const BlockWrap = styled.div`\n display: grid;\n flex-wrap: nowrap;\n align-items: flex-start;\n grid-template-columns: 524px min-content;\n column-gap: 12px;\n width: 100%;\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n grid-template-columns: 1fr;\n row-gap: 24px;\n } \n`;\n\nexport const BlockTitle = styled.div`\n ${FONTS.S};\n color: ${COLORS.TextPrimary};\n`;\n","import { memo } from 'react';\n\nimport { PersonForm } from '~/src/features/full-buy/components/uiReactComponents/PersonForm';\n\nimport * as ST from './styled';\n\nexport type TField = {\n value: string,\n isValid: boolean,\n clearInput: () => void,\n}\n\nexport type TContactDetailsProps = {\n title: string,\n fio: string,\n phone: string,\n isConfirmButtonActive?: boolean,\n btnText?: string,\n hideBtn?: boolean,\n}\n\nexport type TContactDetailsCallbacks = {\n onFillFio: (fio: string) => void,\n onFillPhone: (phone: string) => void,\n onClick?: () => void,\n}\n\nconst EditableContactsForm = ({\n title,\n fio,\n phone,\n isConfirmButtonActive,\n btnText,\n hideBtn,\n onFillFio,\n onFillPhone,\n onClick,\n}: TContactDetailsProps & TContactDetailsCallbacks): JSX.Element => {\n return (\n \n {title && {title}}\n \n \n \n \n );\n};\n\nexport default memo(EditableContactsForm);\n","import styled from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport Throbber from '@r1-frontend/ui-react/components/loaders/Throbber';\nimport { BorderRadius } from '@r1-frontend/ui-react/tokens/borderRadius';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\n\nexport const StyledThrobber = styled(Throbber)`\n position: fixed;\n width: 100%;\n height: 100%;\n top: 0;\n background-color: rgba(0,0,0,0.1);\n`;\n\nexport const ContactPerson = styled.div`\n position: relative;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n padding: 24px;\n border-radius: ${BorderRadius.OuterBlockRadius};\n background-color: ${COLORS.BgSurface};\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n padding: 16px;\n }\n`;\n","import React, { useEffect, useMemo, useState } from 'react';\nimport { batch, shallowEqual, useDispatch, useSelector } from 'react-redux';\n\nimport { doRequest } from '@r1-frontend/do-request';\nimport { selectTimeSlot } from '@r1-frontend/api-domru/full-buy/v1/sale-agent/select-time-slot';\nimport { ResponseDto } from '@r1-frontend/api-domru/full-buy/v1/sale-agent/select-time-slot/dto/ResponseDto';\nimport { saleAgentTimeSlots } from '@r1-frontend/api-domru/full-buy/v1/sale-agent/time-slots';\nimport { RequestDto } from '@r1-frontend/api-domru/full-buy/v1/sale-agent/time-slots/dto/RequestDto';\nimport {\n ResponseDto as GetTimeSlotsResponseDto,\n} from '@r1-frontend/api-domru/full-buy/v1/sale-agent/time-slots/dto/ResponseDto';\n\nimport DateOfServiceEngineerVisitWrapper, {\n ESaleAgentClientName,\n TReturnType,\n} from '@r1-frontend/service-engineer-visit';\n\nimport Alert from '@r1-frontend/ui-react/components/Alert';\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { Danger } from '@r1-frontend/ui-react/components/svg/main';\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport { Paragraph4 } from '@r1-frontend/ui-react/components/typography/paragraph';\nimport { useMatchMediaByWidth } from '@r1-frontend/shared/hooks/useMatchMedia';\n\nimport { useAnalytics } from '~/src/features/full-buy/analytics/context';\nimport CallbackContacts from '~/src/features/full-buy/CallbackContacts';\nimport { MainLayout } from '~/src/features/full-buy/containers/MainLayout/MainLayout';\nimport { isConnectionCostByVisitShown } from '~/src/features/full-buy/helpers/ab/isConnectionCostHidden';\nimport selectTimeSubText from '~/src/features/full-buy/helpers/selectTimeSubText';\nimport { setIsLoadingShown, setSlot } from '~/src/features/full-buy/store/actions';\nimport { goToNextStep } from '~/src/features/full-buy/store/actions/goToNextStep';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport TariffInclude from '~/src/features/full-buy/TariffInclude';\nimport { TState } from '~/src/store';\nimport { selectDomain } from '~/src/store/selectors/domain';\n\nimport * as S from '~/src/features/full-buy/containers/pages/styled';\n\nconst TIME_SLOT_YK_ERROR = 'Предварительное согласование с УК/ТСЖ';\n\nenum ESlotsContainerState {\n SHOW_SLOTS = 1,\n HIDE_SLOTS = 2,\n SLOTS_EMPTY = 3\n}\n\ntype TSlotResult = {\n state: ESlotsContainerState,\n result: TReturnType | null,\n errorMsg: string,\n}\n\nexport const EngineerRequest = (): JSX.Element | null => {\n const analytics = useAnalytics();\n const dispatch = useDispatch();\n\n const isLaptop = useMatchMediaByWidth(wideBreakpoints.laptop);\n const [failureResponseFromSelectSlot, setFailureResponseFromSelectSlot] = useState(false);\n const [slotResult, setSlotResult] = useState({ state: ESlotsContainerState.SHOW_SLOTS, result: null, errorMsg: '' });\n\n const [isTimeSlotLoading, setIsTimeSlotLoading] = useState(true);\n\n const {\n products,\n agreementId,\n domain,\n providerId,\n slot,\n selectedTariff,\n } = useSelector((state: TState) => ({\n products: state.fullBuy.products,\n agreementId: state.fullBuy.agreement.agreementId,\n domain: selectDomain(state),\n providerId: state.city.provider.providerId,\n slot: state.fullBuy.slot,\n selectedTariff: selectCurrentTariff(state),\n }), shallowEqual);\n\n const dateTime = slot?.date;\n\n const hasEquipment = useMemo(() => !!products?.some(el => el.quantity > 0), []);\n\n useEffect(() => {\n dispatch(setIsLoadingShown(isTimeSlotLoading));\n }, [isTimeSlotLoading]);\n\n useEffect(() => {\n if (slotResult.result !== null && slotResult.result.date && slotResult.result.hour && agreementId) {\n (async(slot: TReturnType, agreement: number) => {\n const requestData = {\n agreementId: agreement,\n dateFrom: `${slot.date} ${slot.hour}`,\n saleAgentClientName: ESaleAgentClientName.FULL_BUY_SITE,\n info: slot.comment,\n };\n\n const resp = await doRequest.fullBuy(\n selectTimeSlot(providerId, requestData),\n );\n\n if (resp.isSuccess) {\n batch(() => {\n dispatch(setSlot(slot));\n dispatch(goToNextStep());\n });\n\n analytics.timeSlots.success();\n } else {\n setFailureResponseFromSelectSlot(true);\n\n analytics.timeSlots.failed(resp.error.message, domain);\n }\n })(slotResult.result, agreementId);\n }\n }, [domain, agreementId, slotResult]);\n\n const handleConfirm = (result: TReturnType | null, errorMsg?: string) => {\n setSlotResult(prevState => ({\n ...prevState,\n state: result === null ? ESlotsContainerState.SLOTS_EMPTY : ESlotsContainerState.SHOW_SLOTS,\n result,\n errorMsg: errorMsg || '',\n }));\n };\n\n const onUpdate = () => {\n setIsTimeSlotLoading(false);\n };\n\n const getTimeSlots = (providerId: number, body: RequestDto) => {\n return doRequest.fullBuy(saleAgentTimeSlots(providerId, body));\n };\n\n if (!agreementId) {\n throw new Error('FullBuy Error. Required agreementId in this page!');\n }\n\n return (\n \n \n Визит инженера
\n {(slotResult.state === ESlotsContainerState.SHOW_SLOTS && !failureResponseFromSelectSlot) && (\n <>\n {isConnectionCostByVisitShown(!selectedTariff?.isCottage)\n ? <>\n \n Стоимость подключения составляет {selectedTariff?.connectionPrice.final} рублей. В эту сумму входят\n визит инженера, доставка и настройка оборудования, качественные материалы и прокладка восьмижильного\n кабеля длиной до 5 метров без ущерба для ремонта. Инженер поможет с настройкой услуг, онлайн\n оплатой, продемонстрирует работу услуг и ответит на ваши вопросы.\n \n \n Мы можем вам позвонить и уточнить детали. Убедитесь, что у вас отключен автоответчик\n и антиспам приложения.\n \n >\n : \n {!hasEquipment && <>Инженер проложит кабель, подключит и настроит услуги.{'\\n'}>}\n {selectTimeSubText(hasEquipment, false)}{'\\n'}\n Мы можем вам позвонить и уточнить детали. Убедитесь, что у вас отключен автоответчик и антиспам\n приложения.\n \n }\n >\n )}\n\n {slotResult.state === ESlotsContainerState.SLOTS_EMPTY &&\n \n \n {slotResult.errorMsg.includes(TIME_SLOT_YK_ERROR)\n ? <>Мы свяжемся с вами в течение дня и поможем выбрать дату и время визита инженера.>\n : <>Не удалось подтвердить время и дату. Мы свяжемся с вами в течение дня и поможем\n выбрать их заново.\n Чтобы мы смогли дозвониться — проверьте, что у вас отключен автоответчик и антиспам\n приложения.>\n }\n \n \n }\n {failureResponseFromSelectSlot && (\n \n \n Не удалось подтвердить дату. Мы свяжемся с вами в течение дня и поможем выбрать её заново.\n Чтобы мы смогли дозвониться — проверьте, что у вас отключен автоответчик и антиспам приложения.\n \n \n )}\n\n {(slotResult.state === ESlotsContainerState.SHOW_SLOTS && !failureResponseFromSelectSlot) &&\n analytics.timeSlots.start()}\n contractId={agreementId}\n clientName={ESaleAgentClientName.FULL_BUY_SITE}\n withComment={true}\n gaCategory={analytics.category}\n domain={domain}\n onUpdateLoading={onUpdate}\n />\n }\n {(slotResult.state === ESlotsContainerState.SLOTS_EMPTY || failureResponseFromSelectSlot) && !isLaptop &&\n <>\n \n Если остались вопросы
\n \n >\n }\n \n \n );\n};\n","import React, { useState } from 'react';\nimport { batch, useDispatch, useSelector } from 'react-redux';\n\nimport { fillFioAction } from '@r1-frontend/entities/ContactDetail/actions/fillFio';\nimport { fillPhoneAction } from '@r1-frontend/entities/ContactDetail/actions/fillPhone';\nimport { setConfirmedPhone } from '@r1-frontend/entities/ContactDetail/actions/setConfirmedPhone';\n\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport { Paragraph4 } from '@r1-frontend/ui-react/components/typography/paragraph';\nimport TextWrapper from '@r1-frontend/ui-react/components/typography/TextWrapper';\n\nimport { ConfirmNumberPopup } from '~/src/components/ConfirmNumberPopup';\nimport { useAnalytics } from '~/src/features/full-buy/analytics/context';\nimport EditableContactsForm from '~/src/features/full-buy/ContactPerson/EditableContactsForm';\nimport { MainLayout } from '~/src/features/full-buy/containers/MainLayout/MainLayout';\nimport { goToNextStep } from '~/src/features/full-buy/store/actions/goToNextStep';\nimport { TState } from '~/src/store';\nimport { hidePopup } from '~/src/store/reducers/popups/actions';\nimport { getPopupData } from '~/src/store/reducers/popups/selectors';\n\nimport * as ST from './styled';\n\nconst popupId = 'confirmPopup';\n\nexport const Contacts = (): JSX.Element | null => {\n const analytics = useAnalytics();\n\n const {\n fio,\n phone,\n confirmPopup,\n } = useSelector((state: TState) => ({\n fio: state.contactDetails.editedFio,\n phone: state.contactDetails.editedPhone,\n confirmPopup: getPopupData(state, popupId),\n }));\n\n const dispatch = useDispatch();\n\n const [isFIOEnterStarted, setIsFIOEnterStarted] = useState(false);\n const [isPhoneEnterStarted, setIsPhoneEnterStarted] = useState(false);\n\n const onFillFio = (_person: string) => {\n if (!isFIOEnterStarted) {\n analytics.contacts.startEnterName();\n setIsFIOEnterStarted(true);\n }\n dispatch(fillFioAction(_person));\n };\n\n const onFillPhone = (_phone: string) => {\n if (!isPhoneEnterStarted) {\n analytics.contacts.startEnterPhoneNumber();\n setIsPhoneEnterStarted(true);\n }\n dispatch(fillPhoneAction(_phone));\n };\n\n const onCloseConfirmPopup = () => {\n dispatch(hidePopup(popupId));\n };\n\n const executeFinalAction = () => {\n dispatch(goToNextStep());\n };\n\n const onConfirmPhone = () => {\n batch(() => {\n dispatch(setConfirmedPhone(phone));\n dispatch(hidePopup(popupId));\n });\n executeFinalAction();\n };\n\n return (\n \n \n Введите ваши ФИО и номер телефона
\n \n Они нужны, чтобы оформить заявку на подключение онлайн.\n Вам останется выбрать только дату и время визита инженера.\n \n \n \n \n \n \n \n );\n};\n","import { IRequest } from '@r1-frontend/shared/types/IRequest';\n\n/**\n * Получение конечного идентификатора тарифа по набору подписок.\n *\n * @param salePackageId number\n * @param subscriptions number[]\n * @link https://master.api-tariffs.sandbox.d2c.r-one.io/docs#/Tariffs/TariffsController_getPackageIdBySubscriptions\n */\nconst getPackageIdBySubscriptions = (salePackageId: number, subscriptions: number[]): IRequest => ({\n uri: `v1/tariffs/${salePackageId}/package-id-by-subscriptions`,\n method: 'GET',\n queryParams: {\n subscriptions,\n },\n withProvider: true,\n});\n\nexport default getPackageIdBySubscriptions;\n","import { TResponse } from '@r1-frontend/do-request/core/types';\nimport { captureQueryError } from '@r1-frontend/do-request/error';\n\nimport { IBundlePackage } from '@r1-frontend/shared/types/tariff/bundle/IBundlePackage';\nimport { IInternetPackage } from '@r1-frontend/shared/types/tariff/mono/IInternetPackage';\n\nimport contentRequest from '~/src/api/requests/contentRequest';\nimport { getAccessModeByRights } from '~/src/helpers/accessMode';\n\nexport type TDataResponse = TResponse<{\n bundles: Record,\n mono: IInternetPackage[],\n}, any>;\n\nexport interface IGetCitiesTariffsQueryParams {\n availableAuth?: number, // Фильтр доступа для авторизованных пользователей\n availableNew?: number, // Фильтр доступа для неавторизованных\n selfOrder?: number, // Фильтр доступа для полной покупки (по-умолчанию - false)\n isBackcallAvailable?: number, // Доступно для оформления в обратном звонке (по-умолчанию - не учитывается, 1 да, 0 нет, * не переданный параметр - отсутствие фильрации по параметру)\n ignoreAvailable?: number, // Игонорировать параметр sale у пакетов и available у моно, это нужно чтобы получить все тарифы какие пришли от биллинга (по-умолчанию - 0)\n isLowSpeed?: number, // Если передан этот параметр, то вернутся тарифы со скорость до 100. По умолчанию - 0, чтобы заработало нужно передать 1\n restrictIgnore?: number, // Если передан этот параметр, то вернуться тарифы со скорость до 100 который отключены. По умолчанию - 0, чтобы заработало нужно передать 1\n landingAvailable?: string, // Если передан этот параметр, то вернуться тарифы, которые доступны из лендингов(берется из url query) (по-умолчанию - не учитывается, 1 да)\n}\n\nexport const getCitiesTariffs = async(providerId: number, params?: IGetCitiesTariffsQueryParams): Promise => {\n const url = '/v1/cities/tariffs';\n\n try {\n const response = await contentRequest.get(url, {\n params: {\n providerId,\n accessMode: getAccessModeByRights({}),\n ...(params || {}),\n },\n });\n\n return {\n isSuccess: true,\n payload: response.data,\n };\n } catch (error) {\n return captureQueryError(error);\n }\n};\n","import { IOfferCreateAddress, IOfferCreateItem, IOfferCreateRequestDto } from '@r1-frontend/api-domru/full-buy/v2/agreement/offer-create';\nimport { IAddressProps } from '@r1-frontend/entities/ContactAddress/selectors/selectAddressParams';\n\nimport { isServerSide } from '@r1-frontend/shared/helpers/ssr';\nimport { TSalePackage } from '@r1-frontend/shared/types/tariff/salePackage/TSalePackage';\n\nimport { getCitiesTariffs, IGetCitiesTariffsQueryParams } from '~/src/api/content/cities/tariffs';\nimport { DEALER_UID } from '~/src/constants/sessionStorageKeys';\nimport { getProductsCosts } from '~/src/features/full-buy/functions';\nimport { TUnifiedAddressData } from '~/src/features/full-buy/store/initialState';\n\nimport { IFullBuyTariff, tariffTransformer } from './tariffTransformer';\nimport { TProduct } from './transformShopItem';\n\ninterface IRequestBody {\n fio: string,\n phone: string,\n tariffId: number,\n productsByProps: IOfferCreateItem[],\n summaryCheckInfo: string,\n promoCode: string,\n analytics_id: string,\n}\n\n/**\n * Возвращает true если браузер поддерживает webp\n * Должен использоваться только на стороне браузера\n */\nconst isWebp = async(): Promise => {\n if (isServerSide()) {\n throw new Error('Проверка isWebp(), вызвана на стороне сервера (SSR)!');\n }\n\n return new Promise(resolve => {\n const image = new Image();\n image.onerror = () => resolve(false);\n image.onload = () => resolve(image.width === 1);\n image.src = 'data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA=';\n }).catch(() => false);\n};\n\n// Данные по пакетам тарифов\nexport const fetchTariffPackages = async(providerId: number, queryParams: IGetCitiesTariffsQueryParams, forCottage = false): Promise => {\n const resp = await getCitiesTariffs(providerId, queryParams);\n const retrieveTariffsFunction = forCottage ? getOnlyCottageTariffPackages : getOnlyCityTariffPackages;\n\n if (resp.isSuccess) {\n const { bundles, mono } = resp.payload;\n\n const bundlePackages = Object.values(bundles || {});\n const tariffs = retrieveTariffsFunction([...mono, ...bundlePackages]);\n\n if (!tariffs) {\n return null;\n }\n\n const isSupportsWebp = await isWebp();\n\n // @todo move transformer to the initialization action\n return tariffs?.map(tariff => tariffTransformer(tariff, isSupportsWebp)) || null;\n }\n\n return null;\n};\n\n// Получаем только тарифы для города\nexport const getOnlyCityTariffPackages = (tariffPackages: TSalePackage[] | null): TSalePackage[] | undefined => {\n return tariffPackages?.filter((pack) => {\n const isCottage = 'salePackage2in1' in pack ? pack.salePackage2in1.is_cottage : pack.is_cottage;\n return !isCottage;\n });\n};\n\nexport const getOnlyCottageTariffPackages = (tariffPackages: TSalePackage[] | null): TSalePackage[] | undefined => {\n return tariffPackages?.filter((pack) => {\n return 'salePackage2in1' in pack ? pack.salePackage2in1.is_cottage : pack.is_cottage;\n });\n};\n\ninterface ICheckInfoProps {\n promoPrice: number | null,\n price: number | null,\n products: TProduct[],\n connectPrice: number,\n oncePaymentSum: number,\n monthlyPaymentSum: number,\n}\n\n/**\n * Собирает информацию для комментария при создании договора\n */\nexport const getSummaryCheckInfo = ({\n promoPrice,\n price,\n\n products,\n connectPrice,\n oncePaymentSum,\n monthlyPaymentSum,\n}: ICheckInfoProps) => {\n const showPrice = promoPrice || price;\n const tariff = showPrice ? `, тариф ${showPrice}` : '';\n const productsCost = getProductsCosts(products);\n const oncePaymentEquipment = `, оборудование ${productsCost.once}`;\n const connection = `, подключение ${connectPrice}`;\n const monthlyPaymentEquipment = `, оборудование ${productsCost.monthly}`;\n\n return `Ежемесячно ${monthlyPaymentSum}` +\n tariff +\n monthlyPaymentEquipment +\n '. ' +\n `Разово ${oncePaymentSum}` +\n connection +\n oncePaymentEquipment +\n '. ' +\n `Итого: ${oncePaymentSum + monthlyPaymentSum}`;\n};\n\n// собираем данные для отправки запроса\nexport const createOfferRequestBody = (\n address: IAddressProps | null,\n unifiedAddress: TUnifiedAddressData | undefined,\n {\n fio,\n phone,\n tariffId,\n productsByProps,\n summaryCheckInfo,\n promoCode,\n analytics_id,\n }: IRequestBody,\n): IOfferCreateRequestDto => {\n const dealerUid = window.sessionStorage.getItem(DEALER_UID) ?? undefined;\n\n let addressData: IOfferCreateAddress = { companyId: 0, office: '' };\n\n if (address) {\n addressData = {\n houseId: address.house.value,\n office: address.flat,\n companyId: address.companyId,\n };\n }\n\n if (unifiedAddress) {\n addressData = {\n unifiedHouseId: unifiedAddress.address.unifiedHouseId,\n office: unifiedAddress.address.flat,\n companyId: 0,\n };\n }\n\n const result: IOfferCreateRequestDto = {\n address: addressData,\n personalInformation: {\n clientName: fio,\n clientPhone: phone,\n },\n tariff: {\n tariffId,\n },\n items: productsByProps,\n comment: summaryCheckInfo,\n promocodeName: promoCode,\n analyticsId: analytics_id,\n };\n\n if (dealerUid) {\n result.managerId = Number(dealerUid);\n window.sessionStorage.removeItem(DEALER_UID);\n }\n\n return result;\n};\n","import { createSelector } from 'reselect';\n\nimport { IAddressProps, selectAddressParamsMemoize } from '@r1-frontend/entities/ContactAddress/selectors/selectAddressParams';\nimport { selectIsPhoneConfirmed } from '@r1-frontend/entities/ContactDetail/selectors/selectIsPhoneConfirmed';\n\nimport { IFlow, TUnifiedAddressData } from '~/src/features/full-buy/store/initialState';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { IFullBuyTariff } from '~/src/features/full-buy/store/tariffTransformer';\nimport { TProduct } from '~/src/features/full-buy/store/transformShopItem';\nimport { TState } from '~/src/store';\nimport { selectDomain } from '~/src/store/selectors/domain';\n\nexport interface IDataForAgreement {\n domain: string,\n tariffPackage: IFullBuyTariff | null,\n addressParams: IAddressProps | null,\n isPhoneConfirmed: boolean,\n providerId: number,\n isHouseConnected: boolean,\n gigabitAvail: number,\n fio: string,\n phone: string,\n products: TProduct[],\n promoCode: string,\n flow: IFlow | null,\n selectedSubscriptions: number[],\n unifiedSelectedAddress: TUnifiedAddressData,\n}\n\n/**\n * Селектор выбирает данные для функции создания договора\n */\nexport const selectDataForCreateAgreement = createSelector(\n [\n (state: TState) => state,\n ],\n (state: TState): IDataForAgreement => ({\n domain: selectDomain(state),\n tariffPackage: selectCurrentTariff(state),\n addressParams: selectAddressParamsMemoize(state),\n isPhoneConfirmed: selectIsPhoneConfirmed(state),\n providerId: state.city.provider.providerId,\n isHouseConnected: state.contactAddress.verifiedAddressData.isHouseConnected,\n gigabitAvail: state.contactAddress.verifiedAddressData.gigabitAvail,\n fio: state.contactDetails.editedFio,\n phone: state.contactDetails.confirmedPhone.phone,\n products: state.fullBuy.products,\n promoCode: state.fullBuy.promoCode?.value || '',\n flow: state.fullBuy.flow,\n selectedSubscriptions: state.fullBuy.selectedSubscriptions,\n unifiedSelectedAddress: state.fullBuy.selectedAddress!,\n }),\n);\n","import React, { useEffect } from 'react';\nimport { useDispatch } from 'react-redux';\n\nimport { useAnalytics } from '~/src/features/full-buy/analytics/context';\nimport { createAgreement } from '~/src/features/full-buy/store/actions/createAgreement';\n\n/**\n * Экран диспатчит создание договора\n */\nexport const CreateAgreementScreen = (): JSX.Element => {\n const analytics = useAnalytics();\n const dispatch = useDispatch();\n\n useEffect(() => {\n dispatch(createAgreement(analytics));\n }, []);\n\n return <>>;\n};\n","import { doRequest } from '@r1-frontend/do-request';\nimport getPackageIdBySubscriptionIds\n from '@r1-frontend/api-domru/api-tariffs/v1/tariffs/[salePackageId]/packageIdBySubscriptions';\nimport {\n IOfferCreateResponseDto,\n offerCreate,\n} from '@r1-frontend/api-domru/full-buy/v2/agreement/offer-create';\n\nimport { getGaId } from '@r1-frontend/shared/helpers/getGaId';\n\nimport FullBuyAnalytics from '~/src/features/full-buy/analytics';\nimport {\n calculateTotalPrices,\n getErrorMessage,\n isGigabitCanConnected,\n isGigaSpeedRequired,\n isTariffCanConnected,\n submitRequest,\n} from '~/src/features/full-buy/functions';\nimport { buildProductsForRequest } from '~/src/features/full-buy/helpers';\nimport { setCalculatedSalePackageId, setPromoCode } from '~/src/features/full-buy/store/actions';\nimport { goToNextStep } from '~/src/features/full-buy/store/actions/goToNextStep';\nimport { getAgreementDataString } from '~/src/features/full-buy/store/actions/helpers';\nimport { setStep } from '~/src/features/full-buy/store/actions/setStep';\nimport { createOfferRequestBody, getSummaryCheckInfo } from '~/src/features/full-buy/store/functions';\nimport { selectDataForCreateAgreement } from '~/src/features/full-buy/store/selectors/selectDataForCreateAgreement';\nimport { TDispatch, TGetState } from '~/src/store';\nimport { selectCsrf } from '~/src/store/selectors/auth/selectCsrf';\n\nimport { setAgreementData } from './index';\n\n/**\n * Создание договора\n * TODO Рефакторинг функции, перенести второй запрос, подготовка дынных в отдельную функцию\n */\nexport const createAgreement = (analytics: FullBuyAnalytics) => {\n return async(dispatch: TDispatch, getState: TGetState): Promise => {\n const state = getState();\n const {\n tariffPackage,\n isPhoneConfirmed,\n providerId,\n promoCode,\n isHouseConnected,\n gigabitAvail,\n products,\n fio,\n phone,\n flow,\n selectedSubscriptions,\n\n addressParams,\n unifiedSelectedAddress,\n } = selectDataForCreateAgreement(state);\n const csrf = selectCsrf(state);\n\n if (!tariffPackage || !(addressParams || unifiedSelectedAddress) || !isPhoneConfirmed || !fio || !phone || !flow) {\n throw new Error('FullBuy Error. Required data is not set');\n }\n\n const lastStepKey = flow.steps.length - 1;\n\n let calculatedSalePackageId: number | null = null;\n\n if (selectedSubscriptions && selectedSubscriptions.length > 0) {\n const response = await doRequest.apiTariffs<{\n salePackageId: number,\n }>(getPackageIdBySubscriptionIds(tariffPackage.sale_package_id, selectedSubscriptions));\n\n if (response.isSuccess) {\n calculatedSalePackageId = Number(response.payload.salePackageId);\n dispatch(setCalculatedSalePackageId(calculatedSalePackageId));\n }\n }\n\n const { monthlyPayment, oncePayment } = calculateTotalPrices(\n tariffPackage.promoPrice || tariffPackage.price,\n tariffPackage.connectionPrice.final,\n products,\n );\n\n const summaryCheckInfo = getSummaryCheckInfo({\n promoPrice: tariffPackage.promoPrice,\n price: tariffPackage.price,\n products: products,\n connectPrice: tariffPackage.connectionPrice.final,\n oncePaymentSum: oncePayment,\n monthlyPaymentSum: monthlyPayment,\n });\n const tariffId = calculatedSalePackageId\n ? calculatedSalePackageId\n : tariffPackage.sale_package_id;\n\n const offerRequestBody = createOfferRequestBody(\n addressParams,\n unifiedSelectedAddress,\n {\n fio,\n phone,\n tariffId,\n productsByProps: buildProductsForRequest([...products, ...tariffPackage.additionalProducts]),\n summaryCheckInfo,\n promoCode,\n analytics_id: getGaId(),\n },\n );\n\n const respAgreement = await doRequest.fullBuy(\n offerCreate(providerId, offerRequestBody),\n );\n\n analytics.createAgreement.try();\n\n const agreementDataString = getAgreementDataString(tariffPackage.tariff_name, monthlyPayment, oncePayment);\n\n /* Ошибка при создании договора. Таймслоты пропускаем переходим к финальному шагу */\n if (!respAgreement.isSuccess) {\n const gigabitMayConnect = isGigabitCanConnected(gigabitAvail);\n const requiredGigaSpeed = isGigaSpeedRequired(tariffPackage.speed);\n const shouldConnect = isTariffCanConnected(isHouseConnected, requiredGigaSpeed, gigabitMayConnect);\n\n submitRequest({\n isMono: !!tariffPackage.isMono,\n fio,\n phone,\n csrf,\n sale_package_id: tariffPackage.sale_package_id,\n tariff_name: tariffPackage.tariff_name,\n additionalProducts: tariffPackage.additionalProducts,\n products: products,\n shouldConnect,\n address: unifiedSelectedAddress?.address.value,\n street: addressParams?.street.label,\n house: addressParams?.house.label,\n flat: addressParams?.flat,\n });\n\n dispatch(setAgreementData({\n agreementId: null,\n agreementNumber: null,\n isDouble: false,\n hasError: true,\n errorMessage: getErrorMessage({}),\n }));\n\n // TODO вызывать nextStep - логику пропуска шага таймслотов реализовать в контейнере EngineerRequest\n // Добавить тест на проверку шага\n dispatch(setStep(lastStepKey));\n\n analytics.createAgreement.fail(respAgreement.error?.message, agreementDataString);\n\n if (promoCode) {\n analytics.createAgreement.promocodeActivation(`error | ${promoCode}`);\n }\n\n return;\n }\n\n const { isDouble, fromCache, plbRegistrationSuccessful, promoCodeSuccessful } = respAgreement.payload;\n const agreementNumber = respAgreement.isSuccess ? Number(respAgreement.payload.agreementNumber) : null;\n const agreementId = respAgreement.isSuccess ? Number(respAgreement.payload.agreementId) : null;\n\n /* Создан двойной договор. Таймслоты пропускаем переходим к финальному шагу */\n if (isDouble || fromCache) {\n // TODO рефакторинг, не обрабатывается ситуация если fromCache = true, уточнить flow для fromCache = true\n dispatch(setAgreementData({\n agreementId: null,\n agreementNumber: null,\n isDouble,\n hasError: true,\n errorMessage: getErrorMessage({ isDouble, isFromCache: fromCache }),\n }));\n\n // TODO вызывать nextStep - логику пропуска шага таймслотов реализовать в контейнере EngineerRequest\n dispatch(setStep(lastStepKey));\n\n analytics.createAgreement.double(agreementNumber, agreementDataString);\n return;\n }\n\n if (!agreementId) {\n throw new Error('FullBuy Error. Required agreementId!');\n }\n\n if (!agreementNumber) {\n throw new Error('FullBuy Error. Required agreementNumber!');\n }\n\n /* Договор создан без ошибок, переходим к тайм-слотам */\n dispatch(setAgreementData({\n agreementId,\n agreementNumber,\n isDouble: false,\n hasError: false,\n errorMessage: '',\n }));\n\n // @ts-ignore\n dispatch(goToNextStep());\n\n analytics.createAgreement.success(agreementNumber, agreementDataString);\n\n if (promoCode) {\n // Проверяем, зарегистрирован ли промокод\n if (plbRegistrationSuccessful || promoCodeSuccessful) {\n analytics.createAgreement.promocodeActivation(`success | ${promoCode}`);\n } else {\n // Ошибка\n analytics.createAgreement.promocodeActivation(`error | ${promoCode}`);\n dispatch(setPromoCode({ value: promoCode, hasError: true }));\n }\n }\n\n return;\n };\n};\n","import { actionTypes } from '~/src/features/full-buy/store';\n\nexport const setCalculatedSalePackageId = (salePackageId: number) => ({\n type: actionTypes.SetCalculatedSalePackageId,\n payload: {\n salePackageId,\n },\n});\n","/* Информация о договоре */\nexport const getAgreementDataString = (tariffName: string, itogInMonth: number, itogInOnce: number) =>\n `${tariffName} total amount: ${itogInMonth + itogInOnce} monthly payment: ${itogInMonth} one-time payment: ${itogInOnce}`;\n","export const selectTimeSubText = (isInstallationHardware: boolean, isTimeSelected: boolean): string => {\n const endDot = (isTimeSelected ? '' : '.');\n\n return isInstallationHardware\n ? `Привезёт и подключит оборудование, проложит кабель, проверит и покажет, как всё работает. Поможет оплатить услуги онлайн: на сайте или в мобильном приложении${endDot}`\n : `А ещё покажет, как все работает, ответит на вопросы и поможет оплатить услуги на сайте или в мобильном приложении${endDot}`;\n};\n\nexport default selectTimeSubText;\n","import { actionTypes } from '~/src/features/full-buy/store';\n\nexport const setIsLoadingShown = (flag: boolean) => ({\n type: actionTypes.SET_LOADER_SHOWN_FLAG,\n payload: flag,\n});\n","import { useState } from 'react';\nimport { OrderedList } from 'packages/ui-react/src/components/List/OrderedList';\n\nimport Button from '@r1-frontend/ui-react/components/buttons/button';\nimport { ButtonGroup } from '@r1-frontend/ui-react/components/buttons/buttonGroup/ButtonGroup';\nimport DefaultPopup from '@r1-frontend/ui-react/components/popups/defaultPopup';\nimport { InfoCircleFlip } from '@r1-frontend/ui-react/components/svg/main';\nimport ControlElement from '@r1-frontend/ui-react/components/typography/controlElement';\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport { Paragraph4 } from '@r1-frontend/ui-react/components/typography/paragraph';\nimport TextWrapper from '@r1-frontend/ui-react/components/typography/TextWrapper';\nimport { IndentContainer } from '@r1-frontend/ui-react/experimental/containers';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\n\nexport const RouterChoiceInfo = (): JSX.Element => {\n const [isOpen, changePopupState] = useState(false);\n\n const handleClosePopup = () => {\n changePopupState(false);\n };\n\n const handleOpenPopup = () => {\n changePopupState(true);\n };\n\n return (\n <>\n \n Если хотите получить максимум скорости от своего тарифа. Как выбрать роутер\n \n\n \n \n \n Как выбрать роутер?
\n \n Роутеры, которые мы продаём, отлично подойдут для любого тарифа: они быстрые, надёжные и используют технологию Wi-Fi 6.\n \n \n Главное, на что стоит обратить внимание при выборе роутера:\n \n Площадь покрытия\n Максимальное количество устройств, которые можно одновременно подключить к роутеру\n \n \n \n\n \n \n \n \n \n >\n );\n};\n","import { goToNextStep } from '~/src/features/full-buy/store/actions/goToNextStep';\nimport { goToPrevStep } from '~/src/features/full-buy/store/actions/goToPrevStep';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { TAppThunkDispatch, TGetState } from '~/src/store';\n\n/**\n * Пропускаем шаг выбора роутера, если есть в тарифе\n */\nconst skipEquipmentStep = () => (dispatch: TAppThunkDispatch, getState: TGetState) => {\n const state = getState();\n const selectedTariff = selectCurrentTariff(state);\n const { stepIndex, prevStepIndex } = state.fullBuy;\n\n const isBackward = prevStepIndex > stepIndex;\n\n const hasEquipmentInTariff = selectedTariff?.additionalProducts.some(product => product.category === 'router' && product.required);\n\n if (hasEquipmentInTariff) {\n dispatch(isBackward ? goToPrevStep() : goToNextStep());\n }\n};\n\nexport default skipEquipmentStep;\n","import React, { useEffect } from 'react';\nimport { useDispatch } from 'react-redux';\n\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport TextWrapper from '@r1-frontend/ui-react/components/typography/TextWrapper';\n\nimport { RouterChoiceInfo } from '~/src/features/full-buy/components/RouterChoiceInfo';\nimport { EquipmentList } from '~/src/features/full-buy/containers/EquipmentList';\nimport { MainLayout } from '~/src/features/full-buy/containers/MainLayout/MainLayout';\nimport skipEquipmentStep from '~/src/features/full-buy/store/actions/skipEquipmentStep';\n\nexport const Equipments = (): JSX.Element => {\n const dispatch = useDispatch();\n\n useEffect(() => {\n dispatch(skipEquipmentStep());\n }, []);\n\n return (\n \n \n Рекомендуем выбрать роутер
\n \n \n\n \n \n );\n};\n","import { useState } from 'react';\n\nimport Button from '@r1-frontend/ui-react/components/buttons/button';\nimport { ButtonGroup } from '@r1-frontend/ui-react/components/buttons/buttonGroup/ButtonGroup';\nimport ListItemWithIcon from '@r1-frontend/ui-react/components/List/WithIcon';\nimport DefaultPopup from '@r1-frontend/ui-react/components/popups/defaultPopup';\nimport { InfoCircleFlip } from '@r1-frontend/ui-react/components/svg/main';\nimport { Forward, VideoAdd, VideoVertical, VoiceSquare } from '@r1-frontend/ui-react/components/svg/media';\nimport ControlElement from '@r1-frontend/ui-react/components/typography/controlElement';\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport { Paragraph4 } from '@r1-frontend/ui-react/components/typography/paragraph';\nimport { ListContainer } from '@r1-frontend/ui-react/experimental/containers';\nimport { IndentContainer } from '@r1-frontend/ui-react/experimental/containers';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\n\nexport const DecoderInfo = (): JSX.Element => {\n const [isOpen, changePopupState] = useState(false);\n\n const handleClosePopup = () => {\n changePopupState(false);\n };\n\n const handleOpenPopup = () => {\n changePopupState(true);\n };\n\n return (\n <>\n \n Она нужна, чтобы смотреть ТВ-каналы и подписки из своего тарифа. {' '}\n Все преимущества приставки\n \n\n \n \n \n \n ТВ-приставка Movix — это:
\n\n Тысячи игр и приложений для Android TV\n Цифровое ТВ нового поколения с управлением прямым эфиром\n Кино и сериалы из разных подписок в одном каталоге\n Удобный голосовой поиск и родительский контроль\n \n\n \n \n \n \n \n \n >\n );\n};\n","import React, { useEffect } from 'react';\nimport { useDispatch } from 'react-redux';\n\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport TextWrapper from '@r1-frontend/ui-react/components/typography/TextWrapper';\n\nimport { DecoderInfo } from '~/src/features/full-buy/components/DecoderInfo';\nimport { DecoderList } from '~/src/features/full-buy/containers/DecoderList';\nimport { MainLayout } from '~/src/features/full-buy/containers/MainLayout/MainLayout';\nimport { skipEquipmentTvStep } from '~/src/features/full-buy/store/actions/skipEquipmentTvStep';\n\nexport const EquipmentsTv = (): JSX.Element => {\n const dispatch = useDispatch();\n\n useEffect(() => {\n dispatch(skipEquipmentTvStep());\n }, []);\n\n return (\n \n \n Выберите ТВ-приставку
\n \n \n \n \n );\n};\n","import { EShopCategory } from '~/src/api/content/shop/getShopItems';\nimport { goToNextStep } from '~/src/features/full-buy/store/actions/goToNextStep';\nimport { goToPrevStep } from '~/src/features/full-buy/store/actions/goToPrevStep';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { TAppThunkDispatch, TGetState } from '~/src/store';\n\n/**\n * Пропускаем шаг выбора приставки:\n * для моно-тарифов\n * если есть обязательная приставка в тарифе\n * если а/б тест - не отображать приставку\n */\nexport const skipEquipmentTvStep = () => (dispatch: TAppThunkDispatch, getState: TGetState) => {\n const state = getState();\n const selectedTariff = selectCurrentTariff(state);\n const { stepIndex, prevStepIndex } = state.fullBuy;\n\n const isBackward = prevStepIndex > stepIndex;\n\n const hasRequiredTvBox = selectedTariff?.additionalProducts.find(el => el.category === EShopCategory.Decoders && el.required);\n\n if (selectedTariff?.isMono || hasRequiredTvBox) {\n // пропускаем экран приставок\n dispatch(isBackward ? goToPrevStep() : goToNextStep());\n }\n};\n","import React, { useContext, useMemo } from 'react';\n\nimport { House } from '@r1-frontend/ui-react/components/svg/building';\nimport { Electricity } from '@r1-frontend/ui-react/components/svg/devices';\nimport { CalendarSecond, Clock } from '@r1-frontend/ui-react/components/svg/time';\nimport { Paragraph4 } from '@r1-frontend/ui-react/components/typography/paragraph';\nimport ListItemWithIcon from '@r1-frontend/ui-react/organisms/ListItemWithIcon';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\n\nimport { FullBuyContext, TFullBuyContextProperties } from '~/src/features/full-buy/analytics/context';\nimport InfoBlock from '~/src/features/full-buy/InfoBlock';\n\ninterface IProps {\n date?: string,\n sla?: string,\n isInstallationHardware: boolean,\n}\n\nconst getEngineerText = (isVillage = false) => {\n return isVillage\n ? `Просверлит необходимое отверстие и проложит кабель от оборудования провайдера к вам домой.
\n Если интернет-кабель у вас уже есть — проверит его и заменит при необходимости.
\n Настроит оборудование и покажет, как всё работает.
\n Поможет оплатить услуги через сайт или мобильное приложение «Мой Дом.ру».
\n Если понадобится кабель длиннее 5 метров, за дополнительные метры нужно будет доплатить.\n `\n : `Просверлит отверстие между квартирой и подъездом и проложит кабель.
\n Если интернет-кабель в квартире уже есть — проверит его и заменит при необходимости.
\n Если кабеля потребуется более 5 метров, каждый дополнительный метр оплачивается отдельно.
\n Настроит оборудование и покажет, как всё работает. А ещё поможет оплатить услуги через сайт или мобильное приложение «Мой Дом.ру».\n `;\n};\n\nconst getHowToPrepareText = (isInstallationHardware = false) => {\n let text = '';\n\n if (isInstallationHardware) {\n text += 'Выберите и освободите место для роутера или ТВ-приставки.
';\n }\n\n text += `Держите под рукой паспорт, логин и пароль от Госуслуг для оформления электронного договора.
\n Убедитесь, что ваши телевизор, компьютер или ноутбук исправны.
\n Заранее пополните баланс на карте. Оплатить услуги можно только онлайн на сайте или через мобильное приложение.`;\n\n return text;\n};\n\nconst EmployeeVisit = ({ date, sla, isInstallationHardware }: IProps): JSX.Element => {\n const { isVillage } = useContext(FullBuyContext);\n const engineerText = useMemo(() => getEngineerText(isVillage), [isVillage]);\n const howToPrepareText = useMemo(() => getHowToPrepareText(isInstallationHardware), [isVillage, isInstallationHardware]);\n\n return (\n \n \n }\n />\n }\n />\n \n \n );\n};\n\nexport default EmployeeVisit;\n","import React, { useContext, useMemo } from 'react';\nimport { shallowEqual, useSelector } from 'react-redux';\n\nimport Alert from '@r1-frontend/ui-react/components/Alert';\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { InfoCircle, TickCircle } from '@r1-frontend/ui-react/components/svg/main';\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport { Paragraph4 } from '@r1-frontend/ui-react/components/typography/paragraph';\nimport { useMatchMediaByWidth } from '@r1-frontend/shared/hooks/useMatchMedia';\n\nimport { FullBuyContext, TFullBuyContextProperties } from '~/src/features/full-buy/analytics/context';\nimport CallbackContacts from '~/src/features/full-buy/CallbackContacts';\nimport { MainLayout } from '~/src/features/full-buy/containers/MainLayout/MainLayout';\nimport EmployeeVisit from '~/src/features/full-buy/EmployeeVisit';\nimport { isHaveSelectedProducts } from '~/src/features/full-buy/store/selectors/products/isHaveSelectedProducts';\nimport TariffInclude from '~/src/features/full-buy/TariffInclude';\nimport { TState } from '~/src/store';\n\nimport * as S from '~/src/features/full-buy/containers/pages/styled';\n\nexport const Final = (): JSX.Element => {\n const { isVillage } = useContext(FullBuyContext);\n const isLaptop = useMatchMediaByWidth(wideBreakpoints.laptop);\n\n const {\n agreementData,\n hasProducts,\n slot,\n } = useSelector((state: TState) => ({\n agreementData: state.fullBuy.agreement,\n hasProducts: isHaveSelectedProducts(state),\n slot: state.fullBuy.slot,\n }), shallowEqual);\n\n const dateTime = useMemo(() => {\n const [hour, minutes] = slot?.hour.split(':') || ['00', '00'];\n return `${slot?.date} c ${slot?.hour} по ${String(Number(hour) + 1).padStart(2, '0')}:${minutes}`;\n }, [slot?.date, slot?.hour]);\n\n return (\n \n \n {agreementData.isDouble &&\n \n \n К вашим данным уже привязан другой договор. Скоро позвоним, чтобы во всём разобраться.{'\\n'}\n Чтобы мы смогли дозвониться — проверьте, что у вас отключен автоответчик и антиспам приложения.\n \n \n }\n {agreementData.hasError && !agreementData.isDouble &&\n \n \n Не удалось создать договор. Скоро позвоним, чтобы во всём разобраться.{'\\n'}\n Чтобы мы смогли дозвониться — проверьте, что у вас отключен автоответчик и антиспам приложения.\n \n \n }\n {!agreementData.hasError &&\n <>\n \n \n Ваша заявка создана и подтверждена. Мы не будем беспокоить вас звонками,\n всю информацию вы получите в смс-сообщении.\n \n \n \n >\n }\n {!isLaptop &&\n <>\n \n Если остались вопросы
\n \n >\n }\n \n \n );\n};\n","import { goToNextStep } from '~/src/features/full-buy/store/actions/goToNextStep';\nimport { goToPrevStep } from '~/src/features/full-buy/store/actions/goToPrevStep';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { TAppThunkDispatch, TGetState } from '~/src/store';\n\n/**\n * Пропускаем шаг выбора роутера, если есть в тарифе\n */\nconst skipPrivateSectorEquipmentStep = () => (dispatch: TAppThunkDispatch, getState: TGetState) => {\n const state = getState();\n const selectedTariff = selectCurrentTariff(state);\n\n const { stepIndex, prevStepIndex } = state.fullBuy;\n\n const isBackward = prevStepIndex > stepIndex;\n\n if (!selectedTariff?.isCottage) {\n dispatch(isBackward ? goToPrevStep() : goToNextStep());\n }\n};\n\nexport default skipPrivateSectorEquipmentStep;\n","import React, { useEffect } from 'react';\nimport { useDispatch } from 'react-redux';\n\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport { Paragraph4 } from '@r1-frontend/ui-react/components/typography/paragraph';\nimport TextWrapper from '@r1-frontend/ui-react/components/typography/TextWrapper';\n\nimport { EShopCategory } from '~/src/api/content/shop/getShopItems';\nimport { EquipmentList } from '~/src/features/full-buy/containers/EquipmentList';\nimport { MainLayout } from '~/src/features/full-buy/containers/MainLayout/MainLayout';\nimport skipPrivateSectorEquipmentStep from '~/src/features/full-buy/store/actions/skipPrivateSectorEquipment';\n\nconst PrivateSectorEquipments = (): JSX.Element => {\n const dispatch = useDispatch();\n\n useEffect(() => {\n dispatch(skipPrivateSectorEquipmentStep());\n }, []);\n\n return (\n \n \n Необходимо выбрать оборудование
\n \n Без него услуги не будут работать, и мы не сможем вам их подключить.\n \n \n\n \n \n );\n};\n\nexport default PrivateSectorEquipments;\n","import { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { TState } from '~/src/store';\n\nexport const getSubscriptionsSummary = (state: TState) => {\n const currentTariff = selectCurrentTariff(state);\n\n if (currentTariff?.subscriptionsSummary) {\n const activeSubscriptions = currentTariff.subscriptionsSummary.map((item)=>{\n if (item.alias === currentTariff.alias) {\n return { ...item, active: true };\n }\n return { ...item, active: false };\n });\n\n const currentVariant = currentTariff?.subscriptionsSummary.findIndex(item => item.alias === currentTariff.alias);\n const hasNext = currentTariff.subscriptionsSummary[currentVariant + 1];\n const nextStep = currentTariff.subscriptionsSummary[hasNext ? currentVariant + 1 : currentVariant];\n\n return {\n subscriptionsSummary: activeSubscriptions,\n nextStep: nextStep,\n isLast: !hasNext,\n };\n }\n return null;\n};\n","import { useState } from 'react';\nimport { useSelector } from 'react-redux';\n\nimport Button from '@r1-frontend/ui-react/components/buttons/button';\nimport { ButtonGroup } from '@r1-frontend/ui-react/components/buttons/buttonGroup/ButtonGroup';\nimport DefaultPopup from '@r1-frontend/ui-react/components/popups/defaultPopup';\nimport { InfoCircleFlip } from '@r1-frontend/ui-react/components/svg/main';\nimport ControlElement from '@r1-frontend/ui-react/components/typography/controlElement';\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport { Paragraph4 } from '@r1-frontend/ui-react/components/typography/paragraph';\nimport TextWrapper from '@r1-frontend/ui-react/components/typography/TextWrapper';\nimport { IndentContainer } from '@r1-frontend/ui-react/experimental/containers';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { getPluralize } from '@r1-frontend/shared/helpers/pluralize';\n\nimport { useAnalytics } from '~/src/features/full-buy/analytics/context';\nimport {\n getSubscriptionsSummary,\n} from '~/src/features/full-buy/store/selectors/getSubscriptionsSummary/getSubscriptionsSummary';\n\nexport const WantMoreSubscriptions = () => {\n const analytics = useAnalytics();\n\n const [isOpen, changePopupState] = useState(false);\n const currentTariff = useSelector(getSubscriptionsSummary);\n const handleClosePopup = () => {\n changePopupState(false);\n };\n const handleOpenPopup = () => {\n changePopupState(true);\n analytics.subscriptions.clickMoreSubscriptions();\n };\n const onClick = () => {\n analytics.initializationByTariffLine(String(currentTariff?.nextStep.speed));\n handleClosePopup();\n };\n const getSubscriptionText = (count: number, index: number) => {\n return `${count} ${getPluralize(['подписка', 'подписки', 'подписок'])(count)}${currentTariff?.subscriptionsSummary?.length === index + 1 ? '.' : ','}`;\n };\n\n if (!currentTariff) {\n return null;\n }\n\n return (\n <>\n \n Подписки уже входят в стоимость тарифа. Каждый месяц их можно менять. {' '}\n {!currentTariff.isLast && (\n Хочу больше подписок\n )}\n \n\n \n \n \n Больше подписок
\n \n Чем быстрее интернет, тем больше подписок в тарифе:\n \n \n {currentTariff.subscriptionsSummary.map((item, index) => {\n return (\n \n {item.active\n ? {item.speed} Мбит/с — {getSubscriptionText(item.cnt, index)}\n : <>{item.speed} Мбит/с — {getSubscriptionText(item.cnt, index)}>\n }\n \n );\n })}\n \n \n \n \n \n \n \n \n >\n );\n};\n","import { LazyLoadImage } from 'react-lazy-load-image-component';\nimport styled from 'styled-components';\n\nimport Svg from '@r1-frontend/ui-react/components/svg/Svg';\n\nexport const ImageBlock = styled(LazyLoadImage)<{ src?: string }>`\n width: 100%;\n background-size: cover;\n`;\n\nexport const BenefitsText = styled.div`\n flex-direction: row;\n flex-wrap: nowrap;\n width: 100%;\n gap: 8px;\n\n ${Svg} {\n max-width: 24px;\n width: 100%;\n }\n`;\n","import styled from 'styled-components';\n\nimport Button from '@r1-frontend/ui-react/components/buttons/button';\nimport { ButtonGroup } from '@r1-frontend/ui-react/components/buttons/buttonGroup/ButtonGroup';\nimport HtmlContentFromApi from '@r1-frontend/ui-react/components/HtmlContentFromApi';\nimport DefaultPopup from '@r1-frontend/ui-react/components/popups/defaultPopup';\nimport { TickCircle } from '@r1-frontend/ui-react/components/svg/main';\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport { Paragraph4 } from '@r1-frontend/ui-react/components/typography/paragraph';\nimport { IndentContainer, ListContainer } from '@r1-frontend/ui-react/experimental/containers';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\n\nimport * as ST from './styled';\n\ntype TSubscriptionsPopup = {\n displayImage: string,\n description: string[],\n title: string,\n onClose: () => void,\n isOpen: boolean,\n}\nconst SubscriptionsAdditionalInfoPopup = ({ displayImage, description, isOpen, title, onClose, ...props }: TSubscriptionsPopup) => {\n return (\n \n \n \n {title}
\n \n {description.map((item: string, index: number) =>\n \n \n \n \n {item}\n \n \n )\n }\n \n \n \n \n \n \n );\n};\n\nexport default styled(SubscriptionsAdditionalInfoPopup)`\n ${ListContainer} {\n margin-bottom: 16px;\n }\n`;\n","import { ISubscription } from '~/src/features/full-buy/store/helpers/tariffTransformerHelpers';\nimport { TSubscription } from '~/src/features/full-buy/store/initialState';\n\nexport const selectSubscriptionPopup = (subscription: TSubscription | ISubscription) => {\n if ('fullDescription' in subscription) {\n return {\n displayImage: subscription?.images.desktop || '',\n description: subscription.fullDescriptionList,\n title: subscription?.title || '',\n isOpen: true,\n };\n }\n return {\n displayImage: subscription?.imageForFullBuyWebp || '',\n description: subscription.fullDescriptionList,\n title: subscription?.title || '',\n isOpen: true,\n };\n};\n","import { createSelector } from 'reselect';\n\nimport { ResponseSubscriptionType } from '@r1-frontend/api-domru/api-tariffs/v1/tariffs/[salePackageId]/subscriptions';\n\nimport { TSubscription } from '~/src/features/full-buy/store/initialState';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { TState } from '~/src/store';\n\n/**\n * Получение обязательных и доступных для выбора (не выбранных!)\n */\nexport const getRequiredAndSelectivelySubscriptions = createSelector(\n [\n (state: TState) => state.fullBuy,\n selectCurrentTariff,\n ],\n ({ subscriptions, selectedSubscriptions }, tariff) => {\n if (tariff && subscriptions && tariff.sale_package_id in subscriptions) {\n const needToSelect = Number(tariff?.subscriptionsSummary?.find(s => tariff.speed === s.speed)?.cnt || 1);\n const needToSelectMultiple = needToSelect - 1;\n\n let isOneOfSelected = false;\n\n const sbs = subscriptions[tariff.sale_package_id].items\n .reduce<{ oneOf: TSubscription[], multiple: TSubscription[] }>(\n (acc, cur) => {\n if (cur.type === ResponseSubscriptionType.oneOf) {\n acc.oneOf.push(cur);\n if (selectedSubscriptions.includes(cur.serviceId)) {\n isOneOfSelected = true;\n }\n } else {\n acc.multiple.push(cur);\n }\n\n return acc;\n }, { oneOf: [], multiple: [] },\n );\n\n const leftToSelect = needToSelectMultiple - (isOneOfSelected ? selectedSubscriptions.length - 1 : selectedSubscriptions.length);\n\n return {\n subscriptions: sbs,\n selected: selectedSubscriptions,\n needToSelect: { oneOf: 1, multiple: needToSelectMultiple },\n leftToSelect: { oneOf: isOneOfSelected ? 0 : 1, multiple: leftToSelect },\n tariffName: tariff.tariff_name,\n };\n } else {\n return {\n subscriptions: { oneOf: [], multiple: [] },\n selected: [],\n needToSelect: { oneOf: 0, multiple: 0 },\n leftToSelect: { oneOf: 0, multiple: 0 },\n tariffName: '',\n };\n }\n },\n);\n","import React, { useState } from 'react';\nimport { batch, useDispatch, useSelector } from 'react-redux';\nimport styled from 'styled-components';\n\nimport { ResponseSubscriptionType } from '@r1-frontend/api-domru/api-tariffs/v1/tariffs/[salePackageId]/subscriptions';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport { ListContainer } from '@r1-frontend/ui-react/experimental/containers';\nimport { TvSubscription } from '@r1-frontend/ui-react/organisms/TariffSubscription';\nimport { getPluralize } from '@r1-frontend/shared/helpers/pluralize';\n\nimport { useAnalytics } from '~/src/features/full-buy/analytics/context';\nimport SubscriptionsAdditionalInfoPopup from '~/src/features/full-buy/components/SubscriptionsPopup/SubscriptionsAdditionalInfoPopup';\nimport { selectSubscriptionPopup } from '~/src/features/full-buy/helpers/selectSubscriptionPopup';\nimport { selectSubscription, unSelectSubscription } from '~/src/features/full-buy/store/actions';\nimport {\n getRequiredAndSelectivelySubscriptions,\n} from '~/src/features/full-buy/store/selectors/getRequiredAndSelectivelySubscriptions';\n\nconst subscriptionPlural = getPluralize(['дополнительную подписку', 'дополнительные подписки', 'дополнительных подписок']);\n\nconst initPopupData = {\n displayImage: '',\n title: '',\n description: [],\n isOpen: false,\n};\ntype TSubscriptions = {\n displayImage: string,\n title: string,\n description: string[],\n isOpen: boolean,\n}\n\nconst RequiredAndSelectivelySubscriptionsContainer = ({ className }: { className?: string }): JSX.Element => {\n const analytics = useAnalytics();\n\n const dispatch = useDispatch();\n const { subscriptions, selected, leftToSelect, needToSelect } = useSelector(getRequiredAndSelectivelySubscriptions);\n const [selectedSubscription, setState] = useState(initPopupData);\n const handleToggleMultiple = (id: number, title: string) => () => {\n const state = !selected.includes(id);\n const callback = state\n ? selectSubscription\n : unSelectSubscription;\n\n dispatch(callback(id, title, analytics.subscriptions));\n };\n\n const handleToggleOneOf = (id: number, title: string) => () => {\n const state = !selected.includes(id);\n const callback = state\n ? selectSubscription\n : unSelectSubscription;\n\n const listOfActions = [callback(id, title, analytics.subscriptions)];\n\n if (state) {\n subscriptions.oneOf\n .filter(({ serviceId }) => serviceId !== id)\n .forEach(({ serviceId }) => {\n listOfActions.push(unSelectSubscription(serviceId));\n });\n }\n\n batch(() => {\n listOfActions.forEach(dispatch);\n });\n };\n\n const handleIconClick = (id: number, type: ResponseSubscriptionType) => () => {\n const subscription = subscriptions[type].find(s => s.serviceId === id);\n if (subscription) {\n setState(subscription ? selectSubscriptionPopup(subscription) : initPopupData);\n }\n };\n\n const handleClosePopup = () => {\n setState(initPopupData);\n };\n\n return \n
Выберите одну из основных подписок
\n \n {subscriptions.oneOf.map(subscription => (\n \n {subscription.title}\n \n ))}\n \n\n Выберите {needToSelect.multiple > 1 ? `${needToSelect.multiple} ` : ''}{subscriptionPlural(needToSelect.multiple)}
\n \n {subscriptions.multiple.map(subscription => (\n \n {subscription.title}\n \n ))}\n \n \n ;\n};\n\nexport default styled(RequiredAndSelectivelySubscriptionsContainer)`\n ${ListContainer}:not(:last-child) {\n margin-bottom: 24px;\n }\n\n ${ListContainer} {\n width: 100%;\n flex-wrap: nowrap;\n flex-direction: column;\n }\n\n @media (min-width: ${wideBreakpoints.mobile}) {\n ${ListContainer}:not(:last-child) {\n margin-bottom: 32px;\n }\n\n ${ListContainer} {\n flex-direction: row;\n }\n\n ${TvSubscription} {\n min-height: 100%;\n width: 275px;\n }\n \n ${TvSubscription} img {\n height: auto;\n }\n }\n`;\n","import React, { useState } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport styled from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport NukaCarousel from '@r1-frontend/ui-react/components/NukaCarousel';\nimport { ListContainer } from '@r1-frontend/ui-react/experimental/containers';\nimport { TvSubscription } from '@r1-frontend/ui-react/organisms/TariffSubscription';\nimport { useMatchMediaByWidth } from '@r1-frontend/shared/hooks/useMatchMedia';\n\nimport { useAnalytics } from '~/src/features/full-buy/analytics/context';\nimport SubscriptionsAdditionalInfoPopup from '~/src/features/full-buy/components/SubscriptionsPopup/SubscriptionsAdditionalInfoPopup';\nimport { selectSubscriptionPopup } from '~/src/features/full-buy/helpers/selectSubscriptionPopup';\nimport { selectSubscription, unSelectSubscription } from '~/src/features/full-buy/store/actions';\nimport getSubscriptionsWithConditions from '~/src/features/full-buy/store/selectors/getSubscriptionsWithConditions';\n\nconst initPopupData = {\n displayImage: '',\n title: '',\n description: [],\n isOpen: false,\n};\ntype TSubscriptions = {\n displayImage: string,\n title: string,\n description: string[],\n isOpen: boolean,\n}\nexport const SubscriptionsContainer = ({ className }: { className?: string }): JSX.Element => {\n const analytics = useAnalytics();\n\n const dispatch = useDispatch();\n const isMobile = useMatchMediaByWidth(wideBreakpoints.mobile);\n const { subscriptions, selected, leftToSelect } = useSelector(getSubscriptionsWithConditions);\n const [selectedSubscription, setState] = useState(initPopupData);\n\n const handleToggle = (id: number, title: string) => () => {\n const state = !selected.includes(id);\n const callback = state ? selectSubscription : unSelectSubscription;\n dispatch(callback(id, title, analytics.subscriptions));\n };\n\n const handleIconClick = (id: number) => () => {\n const subscription = subscriptions.find(s => s.serviceId === id);\n if (subscription) {\n setState(subscription ? selectSubscriptionPopup(subscription) : initPopupData);\n }\n };\n\n const handleClosePopup = () => {\n setState(initPopupData);\n };\n\n return \n {isMobile\n ? (\n \n {subscriptions && subscriptions.map(subscription => (\n \n {subscription.title}\n \n ))}\n \n )\n : (\n \n {subscriptions && subscriptions.map(subscription => (\n \n {subscription.title}\n \n ))}\n \n )}\n \n
;\n};\n\nexport default styled(SubscriptionsContainer)`\n @media (min-width: ${wideBreakpoints.mobile}) {\n ${TvSubscription} {\n min-height: 100%;\n }\n }\n \n ${ListContainer} {\n width: 100%;\n }\n`;\n","import React from 'react';\nimport { useSelector } from 'react-redux';\n\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\nimport TextWrapper from '@r1-frontend/ui-react/components/typography/TextWrapper';\nimport { getPluralize } from '@r1-frontend/shared/helpers/pluralize';\n\nimport { WantMoreSubscriptions } from '~/src/features/full-buy/containers/pages/Subscriptions/WantMoreSubscriptions';\nimport { RequiredAndSelectivelySubscriptionsContainer, SubscriptionsContainer } from '~/src/features/full-buy/containers/Subscriptions';\nimport { getRequiredAndSelectivelySubscriptions } from '~/src/features/full-buy/store/selectors/getRequiredAndSelectivelySubscriptions';\n\nimport * as S from '~/src/features/full-buy/containers/pages/styled';\n\nconst subscriptionPlural = getPluralize(['подписку', 'подписки', 'подписок']);\n\nconst CombinedContainerForMainPage = (): JSX.Element | null => {\n const {\n subscriptions,\n needToSelect,\n } = useSelector(getRequiredAndSelectivelySubscriptions);\n\n if (needToSelect.oneOf === 0 && needToSelect.multiple === 0) {\n return null;\n }\n\n return \n {subscriptions.oneOf.length > 0\n ? (\n \n )\n : (\n <>\n \n Выберите {needToSelect.multiple + needToSelect.oneOf} {subscriptionPlural(needToSelect.multiple + needToSelect.oneOf)}
\n \n \n\n \n >\n )\n }\n ;\n};\n\nexport default CombinedContainerForMainPage;\n","import { goToNextStep } from '~/src/features/full-buy/store/actions/goToNextStep';\nimport { goToPrevStep } from '~/src/features/full-buy/store/actions/goToPrevStep';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { TAppThunkDispatch, TGetState } from '~/src/store';\n\nconst skipSubscriptionsStep = () => (dispatch: TAppThunkDispatch, getState: TGetState) => {\n const state = getState();\n const tariff = selectCurrentTariff(state);\n const { stepIndex, prevStepIndex } = state.fullBuy;\n\n const isBackward = prevStepIndex > stepIndex;\n // @todo replace to a selector. Simplify condition by `!!tariff?.subscriptions Summary?.length && !!tariff?.sale Package Links?.length;`\n const hasSubscriptions = (tariff?.subscriptionsSummary && tariff?.subscriptionsSummary?.length > 0) && (tariff?.salePackageLinks && tariff?.salePackageLinks?.length > 0);\n\n if (!hasSubscriptions) {\n dispatch(isBackward ? goToPrevStep() : goToNextStep());\n }\n};\n\nexport default skipSubscriptionsStep;\n","import React, { useEffect } from 'react';\nimport { useDispatch } from 'react-redux';\nimport styled from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { ListContainer } from '@r1-frontend/ui-react/experimental/containers';\nimport { TvSubscription } from '@r1-frontend/ui-react/organisms/TariffSubscription';\n\nimport { MainLayout } from '~/src/features/full-buy/containers/MainLayout/MainLayout';\nimport CombinedContainerForMainPage\n from '~/src/features/full-buy/containers/Subscriptions/CombinedContainerForMainPage';\nimport skipSubscriptionsStep from '~/src/features/full-buy/store/actions/skipSubscriptionsStep';\n\nexport const SubscriptionsPage = ({ className }: { className?: string }): JSX.Element => {\n const dispatch = useDispatch();\n\n useEffect(() => {\n dispatch(skipSubscriptionsStep());\n }, []);\n\n return \n \n \n \n ;\n};\n\nexport default styled(SubscriptionsPage)`\n @media (min-width: ${wideBreakpoints.mobile}) {\n ${TvSubscription} {\n min-height: 100%;\n }\n }\n`;\n","import dynamic from 'next/dynamic';\nimport styled from 'styled-components';\n\nconst SlideCarousel = dynamic(() => import('@r1-frontend/ui-react/components/SlideCarousel'));\n\nexport const CustomSwiper = styled(SlideCarousel)`\n padding-left: 0 !important;\n padding-right: 0 !important;\n\n & section,\n & div {\n outline: none;\n }\n\n & > section > div.slider-frame {\n padding: 10px 0 14px 0 !important;\n }\n`;\n","import React from 'react';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { useMatchMedia } from '@r1-frontend/shared/hooks/useMatchMedia';\n\nimport * as ST from './styled';\n\ninterface IProps {\n children: JSX.Element[],\n slideIndex?: number,\n}\n\n/**\n * Слайдер с фиксом для прокрутки к указанному слайду\n * используется для минифицированных карточек тарифов с выбором тарифа\n */\n// todo: разобраться зачем нужен\nexport const CustomSwiper = ({ slideIndex = 0, children }: IProps): JSX.Element => {\n const isMobile = useMatchMedia(`(max-width: ${wideBreakpoints.mobile})`);\n\n return (\n \n {React.Children.map(children, (child) => child)}\n \n );\n};\n","import styled, { css } from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { BorderRadius } from '@r1-frontend/ui-react/tokens/borderRadius';\nimport { BoxShadow } from '@r1-frontend/ui-react/tokens/boxShadow';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\nconst getGradient = (colors: string[]): string => {\n const [leftColor, rightColor] = colors;\n return `linear-gradient(90deg, ${leftColor} 0%, ${rightColor} 100%)`;\n};\n\nexport const ActiveCardWrapper = styled.div<{ isActive: boolean }>`\n position: relative;\n width: 190px;\n min-height: 180px;\n flex-direction: column;\n flex-wrap: nowrap;\n white-space: pre-wrap;\n text-rendering: geometricPrecision;\n padding: 2px;\n border: ${p => p.isActive ? `3px solid ${COLORS.ButtonPrimary}` : '3px solid transparent'};\n border-radius: 27px;\n transition: all .3s ease;\n user-select: none;\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n width: 148px;\n min-height: 140px;\n border: ${p => p.isActive ? `2px solid ${COLORS.ButtonPrimary}` : '2px solid transparent'};\n border-radius: 19px;\n }\n\n &:hover {\n box-shadow: ${BoxShadow.S};\n }\n`;\n\nexport const ArrowPositioner = styled.div<{ isActive: boolean }>`\n visibility: ${p => p.isActive ? 'initial' : 'hidden'};\n position: absolute;\n width: 100%;\n bottom: -24px;\n justify-content: center;\n`;\n\nexport const TariffCardMinimal = styled.div<{ bg?: string | null, colorText: string | null }>`\n flex-direction: column;\n flex-wrap: nowrap;\n padding: 12px 4px 4px 4px;\n color: ${({ colorText }) => colorText ? colorText : COLORS.TextPrimary};\n background: ${({ bg }) => `${bg}`} 0 0 / cover repeat-y;\n background: image-set(${({ bg }) => `${bg}`} 1x) 0 0 / cover repeat-y;\n background-color: ${({ bg }) => bg};\n border-radius: ${BorderRadius.InnerBlockRadius};\n overflow: hidden;\n z-index: 10;\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n border-radius: ${BorderRadius.componentRadius};\n }\n`;\n\nexport const PromoText = styled.h3<{ colors?: Array, hasBg: boolean }>`\n display: block;\n ${FONTS.H5};\n text-transform: uppercase;\n background: ${({ colors }) => colors?.length ? getGradient(colors) : 'none'};\n color: ${({ colors, hasBg }) => colors?.length ? 'transparent' : hasBg ? 'inherit' : COLORS.TextPrimary};\n padding: 0 12px;\n height: 84px;\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n padding: 0 8px;\n }\n`;\n\nexport const TariffTitle = styled.h3<{ colors?: Array, isSmall?: boolean, hasBg: boolean }>`\n display: block;\n ${({ isSmall }) => isSmall ? css`${FONTS.MediumXXS}` : css`${FONTS.MediumXS}`};\n background: ${({ colors }) => colors?.length ? getGradient(colors) : 'none'};\n color: ${({ colors, hasBg }) => colors?.length ? 'transparent' : hasBg ? 'inherit' : COLORS.TextSecondary};\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n padding: 0 12px;\n margin-bottom: 8px;\n \n @media (max-width: ${wideBreakpoints.mobile}) {\n ${({ isSmall }) => isSmall ? css`${FONTS.XXS} font-size: 8px; line-height: 12px;` : css`${FONTS.XXS}`};\n padding: 0 8px;\n }\n`;\n\nexport const TariffDescription = styled.div<{ colorText: string, bgColor: string, hasBg?: boolean, defaultBg: string }>`\n flex-direction: column;\n min-height: 136px;\n ${FONTS.XS};\n padding: 12px;\n background-color: ${({ bgColor, defaultBg, hasBg }) => bgColor || (hasBg ? 'rgba(255, 255, 255, 0.4)' : defaultBg)};\n border-radius: 22px;\n color: ${({ colorText = COLORS.TextPrimary }) => colorText};\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n padding: 12px 8px;\n min-height: 100px;\n border-radius: 14px;\n\n & > .customSubscriptions{\n margin: 4px -10px 4px !important;\n & > [data-test=\"right-arrow\"] {\n margin-right: 4px;\n }\n & > [data-test=\"left-arrow\"].visible {\n margin-left: 4px;\n }\n }\n }\n`;\n\nexport const PropsBlock = styled.div`\n flex: 1;\n flex-direction: column;\n justify-content: center;\n min-height: 36px;\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n min-height: auto;\n }\n`;\n\nexport const DescriptionRow = styled.div`\n flex-wrap: nowrap;\n min-height: 20px;\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n min-height: 16px;\n ${FONTS.XXS};\n }\n`;\n\nexport const PriceBlock = styled.div`\n flex: 1;\n flex-direction: column;\n justify-content: center;\n min-height: 36px;\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n min-height: auto;\n }\n`;\n\nexport const Price = styled.div`\n ${FONTS.MediumXS};\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n ${FONTS.MediumXXS};\n }\n`;\nexport const OldPrice = styled.div<{ hasBg: boolean }>`\n text-decoration: line-through;\n ${FONTS.XXS};\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n font-size: 8px;\n position: relative;\n top: 1px;\n left: 2px;\n }\n`;\n","import { useEffect, useMemo, useState } from 'react';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport SingleArrowDown from '@r1-frontend/ui-react/components/svg/arrows/SingleArrowDown';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { getPluralize } from '@r1-frontend/shared/helpers/pluralize';\nimport { channelPluralize } from '@r1-frontend/shared/helpers/pluralize/predifined';\nimport { useMatchMedia } from '@r1-frontend/shared/hooks/useMatchMedia';\n\nimport Subscriptions from '~/src/components/TariffCard/subscriptions';\nimport { ISubscriptionBody } from '~/src/components/TariffCard/subscriptions/types';\nimport { IOfferContents } from '~/src/entities/formattedTariff';\n\nimport * as ST from './styled';\n\nconst channelText = getPluralize(channelPluralize);\n\ninterface IActiveCardWrapper {\n children: React.ReactNode,\n isActive: boolean,\n onClick?: () => void,\n}\n\nexport const ActiveCardWrapper = ({ children, isActive = false, onClick }: IActiveCardWrapper) => {\n return (\n \n {children}\n \n );\n};\n\nexport const ArrowPointer = ({ isActive = false }: { isActive: boolean }) => (\n \n \n \n);\n\ninterface ITariffCardMinimalProps {\n title: string,\n price: number,\n speed: string,\n channelCount?: number,\n priceAction?: number | null,\n promoText?: string,\n bgColor: string | undefined,\n colorText?: string | null,\n imageBackground?: string | null,\n titleColors?: string[],\n isLightCard?: boolean,\n subscriptions: Array,\n}\n\nexport const TariffCardMinimal = ({\n title,\n speed,\n priceAction,\n price,\n promoText,\n channelCount,\n bgColor = '',\n colorText = '',\n imageBackground = '',\n titleColors = [],\n isLightCard,\n subscriptions,\n }: ITariffCardMinimalProps): JSX.Element => {\n const isMobile = useMatchMedia(`(max-width: ${wideBreakpoints.mobile})`);\n const [cardWidth, setCardWidth] = useState(148);\n\n const preparedSubscriptions = useMemo(() => {\n return subscriptions.map(item => ({\n id: item.id,\n image: item.image,\n imageWebp: item.image_webp,\n width: item.width,\n alt: item.title,\n type: 'subscription',\n sort: item.sort,\n }));\n }, [subscriptions]);\n\n useEffect(() => {\n setCardWidth(isMobile ? 100 : 148);\n }, [isMobile]);\n\n const hasBg = !!imageBackground;\n\n const cardBg = isLightCard ? COLORS.BgMain : COLORS.BgSurface;\n const descBg = isLightCard ? COLORS.BgSurface : COLORS.BgMain;\n\n return (\n \n {promoText &&\n \n {promoText}\n \n }\n \n {promoText ? `Тариф «${title}»` : title}\n \n \n \n {speed} Мбит/с\n {!!channelCount && {`${channelCount} ТВ-${channelText(channelCount)}`}}\n \n \n \n {priceAction || price} ₽/мес\n {!!priceAction && {price} ₽/мес}\n \n \n \n );\n};\n","import { ISubscriptionItem } from '~/src/api/common-types/sale-package';\nimport { ActiveCardWrapper, ArrowPointer, TariffCardMinimal } from '~/src/components/TariffCardMinimal';\nimport { IFullBuyTariff } from '~/src/features/full-buy/store/tariffTransformer';\n\nimport { ISubscription } from '../store/helpers/tariffTransformerHelpers';\n\ninterface IProps {\n tariffPackages: IFullBuyTariff[],\n selectedPackageId?: number,\n withArrowPointer?: boolean,\n onSelectTariff: (tariff: IFullBuyTariff) => void,\n sendAnalytics?: (tariffName: string) => void,\n}\n\nexport const renderTariffList = ({ tariffPackages, selectedPackageId, withArrowPointer, onSelectTariff, sendAnalytics }: IProps) => {\n const selectTariffHandler = (_tariff: IFullBuyTariff) => {\n onSelectTariff(_tariff);\n typeof sendAnalytics === 'function' && sendAnalytics(_tariff.tariff_name);\n };\n\n return (\n tariffPackages.map(tariff => {\n const isActive = tariff.sale_package_id === selectedPackageId;\n const imageBackground = tariff.image_background_webp ? tariff.image_background_webp : tariff.image_background;\n const sourceData: (ISubscriptionItem | ISubscription)[] = tariff?.salePackageLinks?.length > 0\n ? tariff.salePackageLinks.flatMap((packageLink) => packageLink.subscriptions || [])\n : tariff.subscriptions;\n\n const uniqueSourceData = sourceData.reduce<(ISubscriptionItem | ISubscription)[]>((acc, item) => {\n if (!acc.some((accItem) => accItem.id === item.id)) {\n acc.push(item);\n }\n return acc;\n }, []);\n\n const subscriptions = uniqueSourceData.map((item) => ({\n id: item.id,\n title: item.title,\n image: item.image,\n image_webp: item.image_webp || '',\n sort: item.sort,\n }));\n\n return (\n null : () => selectTariffHandler(tariff)}\n >\n \n {withArrowPointer &&\n \n }\n \n );\n })\n );\n};\n","import styled from 'styled-components';\n\nimport EquipPreview from '~/src/features/full-buy/EquipPreview';\n\nexport const SEquipPreview = styled(EquipPreview)`\n margin-bottom: 0;\n`;\n","import React from 'react';\n\nimport BasePopup from '@r1-frontend/ui-react/components/popups/basePopup';\n\nimport * as ST from './styled';\n\nexport interface IElementInfoProps {\n className?: string,\n title: string,\n displayImage: string,\n images: string[] | null,\n description: string,\n isOpen: boolean,\n onClose: () => void,\n}\n\nconst ElementInfo: React.FC = ({\n className,\n title,\n displayImage,\n images,\n description,\n isOpen,\n onClose,\n}): JSX.Element => {\n return (\n \n \n \n );\n};\n\nexport default React.memo(ElementInfo);\n","import styled from 'styled-components';\n\nimport { BaseButton } from '@r1-frontend/ui-react/components/buttons/baseButton';\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\nexport const SelectedTariffElements = styled.div`\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n row-gap: 8px;\n`;\n\nexport const IncludedTariffElements = styled.div`\n width: 100%;\n flex-direction: column;\n align-items: flex-start;\n row-gap: 8px;\n`;\n\nexport const RecomendedTitle = styled.div`\n ${FONTS.H3};\n color: ${COLORS.TextPrimary};\n\n @media (max-width: ${wideBreakpoints.tablet}) {\n ${FONTS.H4};\n }\n`;\n\nexport const SectionButton = styled(BaseButton)`\n margin-top: 8px;\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n width: 100%;\n }\n`;\n","/* eslint-disable complexity */\nimport { useCallback, useMemo, useState } from 'react';\nimport uniqBy from 'lodash/uniqBy';\n\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { NBSP } from '@r1-frontend/ui-react/tokens/symbols';\nimport { getPluralize } from '@r1-frontend/shared/helpers/pluralize';\nimport { channelPluralize } from '@r1-frontend/shared/helpers/pluralize/predifined';\n\nimport ChannelListPopup from '~/src/components/Bundles/ChannelListPopup';\nimport { useAnalytics } from '~/src/features/full-buy/analytics/context';\nimport SubscriptionsAdditionalInfoPopup from '~/src/features/full-buy/components/SubscriptionsPopup/SubscriptionsAdditionalInfoPopup';\nimport { selectSubscriptionPopup } from '~/src/features/full-buy/helpers/selectSubscriptionPopup';\nimport ElementInfo from '~/src/features/full-buy/SelectedTariffElements/ElementInfo';\nimport { IFullBuyTariff } from '~/src/features/full-buy/store/tariffTransformer';\nimport { TariffElement } from '~/src/features/full-buy/TariffElementNew';\n\nimport * as ST from './styled';\n\nconst CHANNELS_BLOCK_TEXT = 'Смотрите на любом устройстве в приложении Movix. Подключайте дополнительные пакеты каналов.';\ntype RequiredProducts = {\n displayImage: string,\n images: string[] | null,\n title: string,\n description: string,\n isOpen: boolean,\n}\ntype Subscriptions = {\n displayImage: string,\n title: string,\n description: string[],\n isOpen: boolean,\n}\ninterface IElementsInfo {\n requiredProducts: RequiredProducts,\n subscriptions: Subscriptions,\n}\n\nconst initPopupData: IElementsInfo = {\n requiredProducts: {\n displayImage: '',\n images: [],\n title: '',\n description: '',\n isOpen: false,\n },\n subscriptions: {\n displayImage: '',\n title: '',\n description: [],\n isOpen: false,\n },\n};\n\nconst getChannelsTitle = (channelCount: number | null, hdCount: number | null) => {\n let hdCountsTitle = '';\n if (hdCount) {\n hdCountsTitle = `(включая ${hdCount} HD ${channelText(hdCount)})`;\n }\n if (channelCount) {\n return `${channelCount} ${channelText(channelCount)}${NBSP}${hdCountsTitle}`;\n }\n\n return '';\n};\n\ninterface IProps {\n tariffPackage: IFullBuyTariff,\n}\n\nconst channelText = getPluralize(channelPluralize);\n\n// TODO рефакторинг, пример компонент PurchaseItem (в ui-react)\nexport const SelectedTariffElements = ({\n tariffPackage,\n}: IProps): JSX.Element => {\n const analytics = useAnalytics();\n\n const [isChannelsPopupOpen, setIsChannelsPopupOpen] = useState(false);\n const [selectedTariff, setSelectedTariff] = useState(null);\n\n const {\n downloadSpeed,\n additionalProducts,\n subscriptions,\n channelCount,\n hdCount,\n alias,\n } = tariffPackage;\n const speed = tariffPackage.speed;\n\n const [elementsInfo, setElementInfo] = useState(initPopupData);\n\n const requiredAdditionalProducts = useMemo(() => {\n const filteredProducts = additionalProducts?.filter(item => item.required);\n return uniqBy(filteredProducts, 'id');\n }, [additionalProducts]);\n\n const sortedOfferContents = useMemo(() => [...subscriptions].sort((a, b) => {\n if (a.sort === null) {\n return 1;\n }\n if (b.sort === null) {\n return -1;\n }\n return a.sort - b.sort;\n }), [subscriptions]);\n\n const onProductButtonClickHandler = useCallback((id?: number) => {\n const shopItem = requiredAdditionalProducts.find(item => item.id === id);\n\n setElementInfo({\n ...elementsInfo,\n requiredProducts: {\n displayImage: shopItem?.image || '',\n description: shopItem?.description || '',\n title: shopItem?.title || '',\n images: shopItem?.images || null,\n isOpen: true,\n },\n });\n\n analytics.tariff.popupOpened(shopItem?.title);\n }, [requiredAdditionalProducts]);\n\n const onOfferButtonClickHandler = useCallback((id?: number) => {\n const offer = subscriptions.find(item => item.id === id);\n\n setElementInfo({\n ...elementsInfo,\n subscriptions: offer ? selectSubscriptionPopup(offer) : initPopupData.subscriptions,\n });\n\n analytics.tariff.popupOpened(offer?.title);\n }, [subscriptions]);\n\n const channelsPopupOpen = useCallback((tariff) => {\n setSelectedTariff(tariff);\n setIsChannelsPopupOpen(true);\n\n analytics.tariff.popupOpened('tv_channels');\n }, []);\n\n const channelsPopupClose = useCallback(() => {\n setIsChannelsPopupOpen(false);\n setSelectedTariff(null);\n }, []);\n\n const isShowChannel = !!channelCount;\n\n const hasTariffElements = !!requiredAdditionalProducts?.length || !!subscriptions?.length || isShowChannel;\n\n const isMega = alias?.toString().includes('mega');\n\n const closePopup = useCallback(() => {\n setElementInfo(initPopupData);\n }, []);\n\n return (\n \n {/* Выбранный тариф */}\n \n\n {hasTariffElements &&\n \n {/* Каналы */}\n {isShowChannel &&\n channelsPopupOpen(tariffPackage),\n }}\n />\n }\n\n {/* Оборудование */}\n {requiredAdditionalProducts?.map((requiredProduct) => {\n const isShowButton = requiredProduct.image && requiredProduct.description;\n\n return (\n onProductButtonClickHandler(requiredProduct.id) : null,\n }}\n key={requiredProduct.id}\n />\n );\n })}\n\n {/* Подписки */}\n {sortedOfferContents?.map((item) => {\n const isShowButton = !!item.imageForFullBuyWebp && !!item.bodyForFullBuy;\n\n return (\n onOfferButtonClickHandler(item.id) : null,\n }}\n />\n );\n })}\n \n }\n\n \n \n\n \n \n );\n};\n","import { IRequest } from '@r1-frontend/shared/types/IRequest';\n\n/**\n * @param salePackageId\n * @param withAuth\n * @link https://master.api-tariffs.sandbox.d2c.r-one.io/docs#/Tariffs/TariffsController_equipment\n */\nconst equipment = (salePackageId: number, withAuth = false): IRequest => ({\n uri: `v1/tariffs/${salePackageId}/equipment`,\n method: 'GET',\n\n withProvider: true,\n withAuth,\n});\n\nexport default equipment;\n","import { getABNVariant } from '~/src/helpers/abn-tests';\n\nconst isOnlyPurchaseEquipment = () => {\n return getABNVariant('hiding_payment_installments') === 'hide_installment_plan';\n};\n\nexport default isOnlyPurchaseEquipment;\n","import { doRequest } from '@r1-frontend/do-request';\nimport getBodyForRequestEquipment from '@r1-frontend/api-domru/api-tariffs/v1/tariffs/[salePackageId]/equipment';\nimport { ResponseDto, ResponseEquipmentDto } from '@r1-frontend/api-domru/api-tariffs/v1/tariffs/[salePackageId]/equipment/dto/ResponseDto';\n\nimport isOnlyPurchaseEquipment from '~/src/features/full-buy/helpers/ab/isOnlyPurchaseEquipment';\nimport { setProducts, toggleBackgroundLoading } from '~/src/features/full-buy/store/actions';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { TProduct } from '~/src/features/full-buy/store/transformShopItem';\nimport { TDispatch, TGetState } from '~/src/store';\n\nconst processEquipment = (equipment: ResponseEquipmentDto): TProduct => ({\n id: equipment.globalId || equipment.contentId,\n category: equipment.category.name,\n categoryTitle: equipment.category.title,\n title: equipment.title,\n description: equipment.fullBody,\n body: equipment.body,\n props: equipment.characteristics || [],\n // it is only for type assertion\n labels: equipment.labels.map(l => ({\n id: l.id,\n name: l.name,\n title: l.title,\n color: l.color || '',\n color_text: l.color_text || '',\n })) || [],\n\n image: equipment.images.shift() || '',\n images: equipment.images,\n\n prices: equipment.prices.map(p => ({ duration: p.duration === 1 ? 0 : p.duration, cost: p.value })),\n selectedPrice: { duration: equipment.prices[0].duration === 1 ? 0 : equipment.prices[0].duration, cost: equipment.prices[0].value },\n\n quantity: 0,\n});\n\n/**\n * Getting only purchasing routers for the WEB-50023 issue\n * @link https://ticket.ertelecom.ru/browse/WEB-50023\n */\nconst getOnlyPurchasePrices = (router: ResponseEquipmentDto) => {\n return {\n ...router,\n prices: router.prices.filter(price => price.duration === 1 && price.type === 1),\n };\n};\n\nconst getEquipment = () => async(dispatch: TDispatch, getState: TGetState) => {\n const tariff = selectCurrentTariff(getState());\n\n if (!tariff) {\n return;\n }\n\n dispatch(toggleBackgroundLoading(true));\n\n const response = await doRequest.apiTariffs(getBodyForRequestEquipment(tariff.sale_package_id));\n\n if (response.isSuccess) {\n if (isOnlyPurchaseEquipment()) {\n dispatch(setProducts([\n ...response.payload.routers.map(getOnlyPurchasePrices).map(processEquipment),\n ...response.payload.decoders.map(getOnlyPurchasePrices).map(processEquipment),\n ...response.payload.privateSectorEquipment.map(getOnlyPurchasePrices).map(processEquipment),\n ...response.payload.yandex.map(getOnlyPurchasePrices).map(processEquipment),\n ]));\n } else {\n dispatch(setProducts([\n ...response.payload.routers.map(processEquipment),\n ...response.payload.decoders.map(processEquipment),\n ...response.payload.privateSectorEquipment.map(processEquipment),\n ...response.payload.yandex.map(processEquipment),\n ]));\n }\n }\n\n dispatch(toggleBackgroundLoading());\n};\n\nexport default getEquipment;\n","import styled, { css } from 'styled-components';\n\nimport { BorderRadius } from '../../../tokens/borderRadius';\nimport { COLORS } from '../../../tokens/colors';\nimport { FONTS } from '../../../tokens/fonts';\n\nexport const MultiCheckbox = styled.div<{ isChecked: boolean | undefined, disabled?: boolean }>`\n display: flex;\n align-items: center;\n padding: ${p => p.isChecked ? '4px 16px' : '6px 16px'};\n column-gap: 4px;\n ${FONTS.MediumXS};\n color: ${COLORS.TextPrimary};\n white-space: nowrap;\n background-color: transparent;\n border: 2px solid ${COLORS.ButtonSecondary};\n border-radius: ${BorderRadius.OuterBlockRadius};\n transition: border 0.2s ease;\n cursor: pointer;\n\n @media (hover: hover) {\n &:hover {\n border: 2px solid ${COLORS.ButtonPrimary};\n }\n }\n\n ${p => p.isChecked && css`\n color: ${COLORS.TextWhite};\n background-color: ${COLORS.ButtonPrimary};\n border: 2px solid ${COLORS.ButtonPrimary};\n `}\n\n ${p => p.disabled && css`\n color: ${COLORS.TextHint};\n background-color: ${COLORS.GRAY_LIGHT};\n border: 2px solid ${COLORS.GRAY_LIGHT};\n user-select: none;\n\n @media (hover: hover) {\n &:hover {\n border: 2px solid ${COLORS.GRAY_LIGHT};\n cursor: default;\n }\n }\n `};\n`;\n","import React, { FC } from 'react';\n\nimport CheckIcon from '../../svg/main/Check';\n\nimport * as ST from './styled';\n\ninterface IRadioProps {\n value: string,\n label: string,\n isChecked?: boolean,\n disabled?: boolean,\n onClick: (id: string) => void,\n}\n\nconst MultiCheckboxWithIcon: FC = ({\n value,\n label,\n isChecked,\n onClick,\n disabled,\n ...rest\n}) => {\n const onClickHandler = () => {\n !disabled && onClick(value);\n };\n\n return (\n \n {isChecked && }\n {label}\n \n );\n};\n\nexport default MultiCheckboxWithIcon;\n","import styled from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\n\nexport const CheckboxList = styled.div`\n align-items: center;\n gap: 8px;\n`;\n\nexport const SwitcherWrap = styled.div`\n @media (max-width: ${wideBreakpoints.mobile}) {\n width: 100%;\n }\n`;\n","import React from 'react';\n\nimport MultiCheckboxWithIcon from '@r1-frontend/ui-react/components/controls/multiCheckboxWithIcon';\nimport Toggle from '@r1-frontend/ui-react/components/controls/Toggle';\n\nimport * as ST from './styled';\n\nexport interface ICheckboxItem {\n id: string,\n checked: boolean,\n disabled?: boolean,\n label: string,\n}\n\nexport interface IFiltersProps {\n checkboxItems: ICheckboxItem[],\n switcherValues: { leftText: string, rightText: string },\n onClickCheckbox: (id: string) => void,\n onClickSwitcher: (id: string) => void,\n activeSwitcherTab: string,\n}\n\n/**\n * Выводит свитчер и список чекбоксов\n */\nexport const CheckboxList = ({\n checkboxItems,\n switcherValues,\n onClickSwitcher,\n onClickCheckbox,\n activeSwitcherTab,\n ...rest\n}: IFiltersProps) => {\n return (\n \n \n \n \n\n {checkboxItems.map(item => {\n return (\n \n );\n })}\n \n );\n};\n","import { ICheckboxItem } from 'packages/ui-react/src/components/controls/CheckboxList';\n\nimport { IFullBuyTariff } from '~/src/features/full-buy/store/tariffTransformer';\n\nexport const toggleFilter = (id: string, filters: ICheckboxItem[]): ICheckboxItem[] => {\n const currElem = filters.find(el => el.id === id);\n\n if (currElem) {\n currElem.checked = !currElem.checked;\n\n return [\n ...filters,\n ];\n }\n\n return filters;\n};\n\nconst getFilterTags = (tariffs: IFullBuyTariff[]) => {\n if (!tariffs) {\n return [];\n }\n\n const tagsSet = tariffs.reduce((mySet, tariff) => {\n tariff.tariffTags.forEach(mySet.add, mySet);\n return mySet;\n }, new Set([]));\n\n return [...tagsSet].sort();\n};\n\nexport const getFiltersFromTariffsTag = (tariffs: IFullBuyTariff[], currentFilters: ICheckboxItem[], currTariffs: IFullBuyTariff[] = []): ICheckboxItem[] => {\n const tags = getFilterTags(tariffs);\n\n return tags.map((tag) => {\n const curr = currentFilters.find(el => el.id === tag);\n\n return ({\n id: tag,\n checked: curr ? curr.checked : false,\n disabled: currTariffs.length > 0 ? currTariffs.every((tariff) => tariff.tariffTags.includes(tag)) : false,\n label: tag,\n });\n });\n};\n\nexport const getTariffsFilteredByTags = (tariffs: IFullBuyTariff[], filters: ICheckboxItem[]) => {\n let _tariffs: IFullBuyTariff[] = tariffs;\n\n filters.forEach((filter) => {\n if (filter.checked) {\n _tariffs = _tariffs.filter(el => el.tariffTags.includes(filter.id));\n }\n });\n\n return _tariffs;\n};\n\nexport const getTariffsFilteredByType = (tariffs: IFullBuyTariff[], isMono: boolean) => {\n return tariffs.filter(el => el.isMono === isMono);\n};\n","import styled from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\nexport const Wrapper = styled.div`\n gap: 8px;\n @media (max-width: ${wideBreakpoints.mobile}) {\n flex-direction: column;\n }\n`;\n\nexport const Text = styled.div`\n white-space: nowrap;\n align-items: center;\n ${FONTS.MediumXS};\n`;\n\n","import React, { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { CheckboxList, ICheckboxItem } from '@r1-frontend/ui-react/components/controls/CheckboxList';\nimport MultiCheckboxWithIcon from '@r1-frontend/ui-react/components/controls/multiCheckboxWithIcon';\n\nimport { useAnalytics } from '~/src/features/full-buy/analytics/context';\nimport { IFullBuyTariff } from '~/src/features/full-buy/store/tariffTransformer';\n\nimport { getFiltersFromTariffsTag, getTariffsFilteredByTags, getTariffsFilteredByType, toggleFilter } from './helpers';\n\nimport * as ST from './styled';\n\nenum ESwitcherValues {\n mono = 'Только интернет',\n bundle = 'Интернет+ТВ',\n}\n\nconst switcherValues = {\n leftText: ESwitcherValues.bundle,\n rightText: ESwitcherValues.mono,\n};\n\nexport const useFiltersByTags = (tariffs: IFullBuyTariff[], defaultDisplayMono = false) => {\n const hideSwitcher = useMemo(() => {\n if (!tariffs?.length) {\n return false;\n }\n const firstTariff = tariffs[0].isMono;\n return tariffs.every(tariff => tariff.isMono === firstTariff);\n }, [tariffs]);\n const analytics = useAnalytics();\n\n const [filters, setFilters] = useState([]);\n const [tariffsByType, setTariffsByType] = useState(tariffs);\n const [filteredTariffs, setFilteredTariffs] = useState(tariffs);\n const [activeSwitcherTab, setActiveSwitcherTab] = useState(defaultDisplayMono ? ESwitcherValues.mono : ESwitcherValues.bundle);\n\n const changeTariffs = useCallback((currTariffs, currFilters) => {\n\n const _tariffs = getTariffsFilteredByTags(currTariffs, currFilters);\n\n const filtersByTags = getFiltersFromTariffsTag(_tariffs, currFilters, currTariffs);\n\n _tariffs.sort((a, b) => {\n if (a.sort_on_bundles && b.sort_on_bundles) {\n return a.sort_on_bundles - b.sort_on_bundles;\n }\n return a.speed - b.speed;\n });\n\n setFilteredTariffs(_tariffs);\n setFilters(filtersByTags);\n }, []);\n\n useEffect(() => {\n setActiveSwitcherTab(defaultDisplayMono ? ESwitcherValues.mono : ESwitcherValues.bundle);\n }, [defaultDisplayMono]);\n\n useEffect(() => {\n if (tariffs) {\n const _tariffs = getTariffsFilteredByType(tariffs, defaultDisplayMono);\n setTariffsByType(_tariffs);\n const newFilters = getFiltersFromTariffsTag(_tariffs, []);\n changeTariffs(_tariffs, newFilters);\n }\n }, [tariffs, defaultDisplayMono, changeTariffs]);\n\n const onToggleFilter = useCallback((name) => {\n analytics.tariff.chooseRecommendedFilter(name);\n const newFilters = toggleFilter(name, filters);\n changeTariffs(tariffsByType, newFilters);\n }, [tariffsByType, filters, changeTariffs]);\n\n const onToggleSwitcher = useCallback(() => {\n const values = Object.values(switcherValues);\n\n const newTab = values.find(el => el !== activeSwitcherTab);\n\n if (newTab) {\n const isMono = newTab === ESwitcherValues.mono;\n analytics.tariff.chooseRecommendedFilter(isMono ? ESwitcherValues.mono : ESwitcherValues.bundle);\n const _tariffs = getTariffsFilteredByType(tariffs, isMono);\n const filtersByTags = getFiltersFromTariffsTag(_tariffs, []);\n\n setActiveSwitcherTab(newTab);\n setTariffsByType(_tariffs);\n setFilters(filtersByTags);\n changeTariffs(_tariffs, filtersByTags);\n }\n }, [tariffs, activeSwitcherTab, changeTariffs]);\n\n const Component = useMemo(() => (\n \n В тарифе:\n {hideSwitcher\n ? (\n filters.map(item =>\n )\n )\n : (\n \n )\n }\n \n ), [activeSwitcherTab, filters, onToggleFilter, onToggleSwitcher]);\n\n return {\n TagFilters: () => Component,\n tariffsFilterByTags: filteredTariffs,\n };\n};\n","import styled from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { BorderRadius } from '@r1-frontend/ui-react/tokens/borderRadius';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\n\n\nexport const TariffLineWrapper = styled.div`\n width: 100%;\n flex-direction: column;\n align-items: flex-start;\n padding: 24px 0 14px 20px;\n border-radius: ${BorderRadius.OuterBlockRadius};\n background-color: ${COLORS.BgSurface};\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n padding: 16px 0 6px 16px;\n }\n`;\n\nexport const TariffLineWrapperFullWidth = styled(TariffLineWrapper)`\n @media (max-width: ${wideBreakpoints.mobile}) {\n margin-left: -16px;\n margin-right: -16px;\n width: 100vw;\n border-radius: 0;\n }\n`;\n","import React, { useCallback, useMemo } from 'react';\nimport { batch, shallowEqual, useDispatch, useSelector } from 'react-redux';\n\nimport { H3 } from '@r1-frontend/ui-react/components/typography/heading';\n\nimport { CustomSwiper } from '~/src/components/CustomSwiper';\nimport { useAnalytics } from '~/src/features/full-buy/analytics/context';\nimport { MainLayout } from '~/src/features/full-buy/containers/MainLayout/MainLayout';\nimport {\n CombinedSubscriptionContainerForTariffItem,\n} from '~/src/features/full-buy/containers/Subscriptions';\nimport { renderTariffList } from '~/src/features/full-buy/renderTariffList';\nimport { SelectedTariffElements } from '~/src/features/full-buy/SelectedTariffElements';\nimport { selectTariff } from '~/src/features/full-buy/store/actions';\nimport getEquipment from '~/src/features/full-buy/store/actions/getEquipment';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { selectFilteredTariffs } from '~/src/features/full-buy/store/selectors/selectFilteredTariffs';\nimport { IFullBuyTariff } from '~/src/features/full-buy/store/tariffTransformer';\nimport { useFiltersByTags } from '~/src/features/full-buy/useFiltersByTags';\nimport { TState } from '~/src/store';\n\nimport * as S from '~/src/features/full-buy/containers/pages/styled';\nimport * as ST from './styled';\n\nconst hasBundleTariff = (tariffs: IFullBuyTariff[]) => tariffs.some(el => el.isMono === false);\n\nexport const TariffInfo = (): JSX.Element => {\n const analytics = useAnalytics();\n const dispatch = useDispatch();\n\n const {\n selectedTariff,\n filteredTariffs,\n displayTariffLine,\n } = useSelector((state: TState) => ({\n selectedTariff: selectCurrentTariff(state),\n filteredTariffs: selectFilteredTariffs(state),\n displayTariffLine: state.fullBuy._displayTariffLine,\n }), shallowEqual);\n\n const tariffName = selectedTariff?.title || '';\n\n const onSelectTariff = useCallback((_tariff: IFullBuyTariff) => {\n batch(() => {\n dispatch(selectTariff({\n salePackageId: _tariff.sale_package_id,\n }));\n dispatch(getEquipment());\n });\n\n }, [dispatch]);\n\n const defaultDisplayMono = !!selectedTariff?.isMono || !hasBundleTariff(filteredTariffs);\n const { TagFilters, tariffsFilterByTags } = useFiltersByTags(filteredTariffs, defaultDisplayMono);\n\n const slideIndex = tariffsFilterByTags.findIndex((el) => el.sale_package_id === selectedTariff?.sale_package_id);\n const swiperKey = useMemo(() => {\n return tariffsFilterByTags.map(tariff => tariff.sale_package_id).join(',');\n }, [tariffsFilterByTags]);\n\n return (\n \n {tariffName ? `Вы выбрали тариф «${tariffName}»` : 'Выберите тариф'}
\n \n {!!filteredTariffs.length && displayTariffLine &&\n \n \n\n \n {renderTariffList({\n tariffPackages: tariffsFilterByTags,\n selectedPackageId: selectedTariff?.sale_package_id,\n withArrowPointer: true,\n onSelectTariff,\n sendAnalytics: (name: string) => analytics.tariff.chooseRecommended(name),\n })}\n \n \n }\n\n {selectedTariff &&\n \n }\n \n\n \n \n );\n};\n","import isAdditionalEquipment from '~/src/features/full-buy/helpers/ab/isAdditionalEquipment';\nimport { IFlow } from '~/src/features/full-buy/store/initialState';\nimport { ESteps } from '~/src/features/full-buy/types';\n\n/**\n * Проверка адреса после выбора тарифа\n */\nexport const traditionFlow: IFlow = {\n name: 'traditionFlow',\n steps: [\n ESteps.tariffInfo,\n ESteps.equipments,\n ESteps.equipmentsCottage,\n ESteps.equipmentsTv,\n ESteps.address,\n ESteps.contacts,\n ESteps.agreementCreated,\n ESteps.timeSlots,\n ESteps.final,\n ],\n};\n\n/**\n * Проверка адреса на первом шаге\n */\nexport const notTraditionFlow: IFlow = {\n name: 'FirstAddressSteps',\n steps: [\n ESteps.address,\n ESteps.subscriptions,\n ESteps.equipments,\n ESteps.equipmentsCottage,\n ESteps.equipmentsTv,\n ESteps.contacts,\n ESteps.agreementCreated,\n ESteps.timeSlots,\n ESteps.final,\n ],\n};\n\n/**\n * Логика последовательности шагов\n * Логика пропуска и объединения шагов реализована в контейнерах\n *\n * Если ЧС, то убираем шаг с выбором роутеров.\n * Если не ЧС и включен аб-тест скрытия шагов оборудования, то убираем роутеры и декодеры.\n * Если не ЧС и включен аб-тест отображение доп оборудования, то убираем роутеры и декодеры.\n *\n */\nconst getFlow = (\n isAddressVerificationOnFirstStep = false,\n isCottage?: boolean,\n) => {\n const flow = isAddressVerificationOnFirstStep ? notTraditionFlow : traditionFlow;\n\n if (isCottage) {\n const stepsWithoutRouters = flow.steps.filter(step => step !== ESteps.equipments);\n\n return {\n ...flow,\n steps: stepsWithoutRouters,\n };\n } else {\n\n let needToExclude = [ESteps.equipmentsCottage];\n\n if (isAdditionalEquipment()) {\n needToExclude = [...needToExclude, ESteps.equipments, ESteps.equipmentsTv];\n }\n\n return {\n ...flow,\n steps: flow.steps.filter(step => !needToExclude.includes(step)),\n };\n }\n};\n\nexport default getFlow;\n","import { doRequest } from '@r1-frontend/do-request';\nimport subscriptions, { ResponseDto, ResponseSubscriptionType } from '@r1-frontend/api-domru/api-tariffs/v1/tariffs/[salePackageId]/subscriptions';\n\nimport { setSubscriptions } from '~/src/features/full-buy/store/actions';\nimport { setBundleOfSubscriptions } from '~/src/features/full-buy/store/actions/setBundleOfSubscriptions';\nimport { toggleBackgroundLoading } from '~/src/features/full-buy/store/actions/toggleBackgroundLoading';\nimport { getListDescription } from '~/src/features/full-buy/store/helpers/getListDescription';\nimport { TSubscription } from '~/src/features/full-buy/store/initialState';\nimport { IFullBuyTariff } from '~/src/features/full-buy/store/tariffTransformer';\nimport { TAppThunkDispatch } from '~/src/store';\n\nconst needToLoadSubscriptions = (tariff: IFullBuyTariff) => {\n return 'salePackageLinks' in tariff && Array.isArray(tariff.salePackageLinks) && tariff.salePackageLinks.length > 0;\n};\n\nconst getSubscriptions = (tariff: IFullBuyTariff) => async(dispatch: TAppThunkDispatch) => {\n if (!tariff || !needToLoadSubscriptions(tariff)) {\n return;\n }\n\n dispatch(toggleBackgroundLoading(true));\n\n const response = await doRequest.apiTariffs(subscriptions(tariff.sale_package_id));\n\n if (response.isSuccess) {\n const dataWithFullDescriptionList = response.payload.map(item => {\n return {\n ...item,\n fullDescriptionList: getListDescription(item.fullDescription),\n };\n });\n dispatch(setSubscriptions(tariff.sale_package_id, dataWithFullDescriptionList));\n }\n\n dispatch(toggleBackgroundLoading(false));\n};\n\nconst receiveSubscriptions = async(tariff: IFullBuyTariff) => {\n if (tariff && needToLoadSubscriptions(tariff)) {\n const response = await doRequest.apiTariffs(subscriptions(tariff.sale_package_id));\n\n if (response.isSuccess) {\n return {\n tariffId: tariff.sale_package_id,\n subscriptions: response.payload.map(item => {\n return {\n ...item,\n fullDescriptionList: getListDescription(item.fullDescription),\n };\n }),\n };\n }\n }\n};\n\nexport const getBundleOfSubscriptions = (tariffs: IFullBuyTariff[]) => async(dispatch: TAppThunkDispatch) => {\n dispatch(toggleBackgroundLoading(true));\n\n const response = await Promise.all(tariffs.map(receiveSubscriptions));\n\n const result = response\n // eslint-disable-next-line\n .reduce>(\n (acc, item) => {\n if (!item) {\n return acc;\n }\n\n acc[item.tariffId] = {\n oneOf: item.subscriptions\n .filter(s => s.type === ResponseSubscriptionType.oneOf)\n .map(s => s.serviceId),\n items: item.subscriptions,\n };\n return acc;\n }, {},\n );\n\n dispatch(setBundleOfSubscriptions(result));\n dispatch(toggleBackgroundLoading(false));\n};\n\nexport default getSubscriptions;\n","import { actionTypes } from '~/src/features/full-buy/store';\nimport { TSubscription } from '~/src/features/full-buy/store/initialState';\n\nexport const setBundleOfSubscriptions = (subscriptionsBundle: Record) => ({\n type: actionTypes.SetBundleOfSubscriptions,\n payload: {\n bundle: subscriptionsBundle,\n },\n});\n","import React, { useContext, useEffect, useMemo, useState } from 'react';\nimport { shallowEqual, useDispatch, useSelector } from 'react-redux';\nimport { useRouter } from 'next/router';\n\nimport { resetAddress } from '@r1-frontend/entities/ContactAddress/actions/resetAddress';\n\nimport { isClientSide } from '@r1-frontend/shared/helpers/ssr';\n\nimport { FullBuyContext, TFullBuyContextProperties, useAnalytics } from '~/src/features/full-buy/analytics/context';\nimport { ANALYTICS } from '~/src/features/full-buy/constants/analytics';\nimport AdditionalEquipment from '~/src/features/full-buy/containers/AdditionalEquipment';\nimport OneLineAddress from '~/src/features/full-buy/containers/pages/OneLineAddress';\nimport isFullBuyVillage from '~/src/features/full-buy/helpers/ab/isFullBuyVillage';\nimport isOneLineAddressScreen from '~/src/features/full-buy/helpers/ab/isOneLineAddressScreen';\nimport { TariffInfoPageSkeleton } from '~/src/features/full-buy/skeleton';\nimport selectStepName from '~/src/features/full-buy/store/selectors/selectStepName';\nimport { useSendReferrerToGA } from '~/src/helpers/useSendReferrerToGA';\nimport { TState } from '~/src/store';\n\nimport Loader from './containers/Loader';\nimport { Address } from './containers/pages/Address';\nimport { Contacts } from './containers/pages/Contacts';\nimport { CreateAgreementScreen } from './containers/pages/CreateAgreement';\nimport { EngineerRequest } from './containers/pages/EngineerRequest';\nimport { Equipments } from './containers/pages/Equipments';\nimport { EquipmentsTv } from './containers/pages/EquipmentsTv';\nimport { Final } from './containers/pages/Final';\nimport PrivateSectorEquipments from './containers/pages/PrivateSectorEquipments';\nimport Subscriptions from './containers/pages/Subscriptions';\nimport { TariffInfo } from './containers/pages/TariffInfo';\nimport { resetFullBuy } from './store/actions';\nimport { initFullBuy } from './store/actions/initFullBuy';\nimport { selectCurrentTariff } from './store/selectors/selectCurrentTariff';\nimport { getQueryParams } from './helpers';\nimport { ESteps } from './types';\n\nimport * as ST from './styled';\n\nexport const FullBuy = (): JSX.Element => {\n const analytics = useAnalytics();\n const router = useRouter();\n const dispatch = useDispatch();\n const { isVillage } = useContext(FullBuyContext);\n\n useSendReferrerToGA(analytics.category, ANALYTICS.action.goToPage);\n\n const {\n salePackageId,\n tariffName: tariffNameAlias,\n monoTariff,\n tariffLine: tariffLineAlias,\n filters,\n landingAvailable,\n } = useMemo(() => getQueryParams(router.query), [router]);\n\n const {\n tariffPackage,\n initialized,\n stepIndex,\n stepName,\n isShownLoader,\n isAddressVerification,\n } = useSelector((state: TState) => ({\n tariffPackage: selectCurrentTariff(state),\n initialized: state.fullBuy.initialized,\n stepIndex: state.fullBuy.stepIndex,\n stepName: selectStepName(state),\n flow: state.fullBuy.flow,\n isShownLoader: state.fullBuy.isShownLoader,\n isAddressVerification: state.fullBuy._addressVerificationOnFirstStep,\n }), shallowEqual);\n\n const [isTimeSlotsLoading, setIsTimeSlotsLoading] = useState(false);\n\n const isOneLineAddressFormScreen = isOneLineAddressScreen() || isVillage;\n const isFullBuyVillageRedirect = isFullBuyVillage();\n\n useEffect(() => {\n // если это ЧС (те мы явно заходим в ЧС и есть редирект), то уходим. Оставлять только проверку на АБ тест некорректно, тк в нее могут попасть МКД\n if (isVillage && !isFullBuyVillageRedirect) {\n router.push('/bundles');\n }\n }, []);\n\n // При переключении между страницами fullBuy, прокручиваем в начало страницы\n useEffect(() => {\n window.scrollTo(0, 0);\n }, [stepIndex]);\n\n // Если передали некорректный salePackageId нужно редиректить на страницу /full-buy\n // с использованием полной перезагрузкой страницы(без router.push())\n // так, как не сбрасывается состояние выбранной линейки тарифов при смене домена\n useEffect(() => {\n if (salePackageId && initialized && tariffPackage === null && isClientSide()) {\n location.href = '/full-buy';\n }\n }, [salePackageId, initialized, tariffPackage]);\n\n // Получение данных по линейке\n useEffect(() => {\n dispatch(initFullBuy({\n filters,\n tariffLineAlias,\n landingAvailable,\n\n salePackageId,\n tariffNameAlias,\n monoTariff: monoTariff === 'true',\n analytics,\n }));\n\n return () => {\n dispatch(resetAddress());\n dispatch(resetFullBuy());\n };\n }, []);\n\n // Сброс лоадера после первичной загрузки тайм-слотов\n useEffect(() => {\n if (isClientSide()) {\n const portal = document.getElementById('loader-portal');\n\n if (!isShownLoader && portal) {\n portal.style.minHeight = 'auto';\n portal.innerHTML === '';\n setIsTimeSlotsLoading(true);\n }\n }\n }, [isShownLoader, isTimeSlotsLoading]);\n\n if (!initialized) {\n return (\n \n );\n }\n\n return (\n \n {stepName === ESteps.tariffInfo && }\n {stepName === ESteps.subscriptions && }\n {stepName === ESteps.equipments && }\n {stepName === ESteps.equipmentsTv && }\n {stepName === ESteps.equipmentsCottage && }\n {stepName === ESteps.address && (\n isOneLineAddressFormScreen\n ? \n : \n )}\n {stepName === ESteps.contacts && }\n {stepName === ESteps.agreementCreated && }\n {stepName === ESteps.timeSlots && }\n {stepName === ESteps.final && }\n {(stepName === ESteps.agreementCreated || stepName === ESteps.timeSlots && !isTimeSlotsLoading) &&\n \n }\n \n \n \n );\n};\n","import { batch } from 'react-redux';\n\nimport { IGetCitiesTariffsQueryParams } from '~/src/api/content/cities/tariffs';\nimport FullBuyAnalytics from '~/src/features/full-buy/analytics';\nimport getFlow from '~/src/features/full-buy/helpers/getFlow';\nimport getEquipment from '~/src/features/full-buy/store/actions/getEquipment';\nimport { getBundleOfSubscriptions } from '~/src/features/full-buy/store/actions/getSubscriptions';\nimport { selectCurrentTariff } from '~/src/features/full-buy/store/selectors/selectCurrentTariff';\nimport { TAppThunkDispatch, TGetState } from '~/src/store';\n\nimport { fetchTariffPackages } from '../functions';\nimport { ETariffFilters } from '../initialState';\n\nimport { setTariffFilters } from './filters';\nimport {\n selectTariff,\n setDisplayTariffLineState,\n setFlow,\n setInitialized,\n setTariffLineAlias,\n setTariffs,\n} from './index';\n\nexport type TIncomingQueryString = {\n salePackageId?: string | undefined,\n tariffNameAlias?: string | undefined,\n monoTariff: boolean,\n landingAvailable?: string,\n}\n\ninterface IInitParams {\n filters: ETariffFilters[] | undefined,\n tariffLineAlias: string | undefined,\n analytics: FullBuyAnalytics,\n}\n\n/**\n * Получение данных для страницы fullBuy\n */\nexport const initFullBuy = (\n {\n filters = [],\n tariffLineAlias,\n landingAvailable,\n\n salePackageId,\n tariffNameAlias,\n monoTariff,\n analytics,\n }: IInitParams & TIncomingQueryString,\n) => async(dispatch: TAppThunkDispatch, getState: TGetState): Promise => {\n const { providerId } = getState().city.provider;\n // We should remove the \"Cottage\" filter from the list of filters,\n // as other filters (except \"Cottage\") are involved in the main flow of the \"Full Buy\" logic.\n const withoutCottageFilters = filters?.filter(f => f !== ETariffFilters.COTTAGE) || [];\n const isCottage = filters?.some(f => f === ETariffFilters.COTTAGE) || false;\n\n const isAddressVerificationOnFirstStep = !tariffLineAlias &&\n withoutCottageFilters.length === 0 &&\n (Boolean(salePackageId) || Boolean(tariffNameAlias));\n\n const flow = getFlow(isAddressVerificationOnFirstStep, isCottage);\n\n const fetchTariffPackagesQueryParams: IGetCitiesTariffsQueryParams = {\n availableNew: 1,\n };\n\n if (landingAvailable) {\n fetchTariffPackagesQueryParams.landingAvailable = landingAvailable;\n }\n\n // Очень надеюсь, что это решение в скором времени будет изменено.\n // В админке контента признаки у тарифов 100Мбит/с. отключены, но имеются адреса, у которых только такая максимальная скорость может быть.\n // в api-content был добавлен флаг, позволющий получить отключенные тариф (не все, включаются некоторые в ручном режиме).\n if (filters?.includes(ETariffFilters.SPEED100)) {\n fetchTariffPackagesQueryParams.restrictIgnore = 1;\n }\n\n const tariffPackages = await fetchTariffPackages(\n providerId,\n fetchTariffPackagesQueryParams,\n isCottage,\n );\n\n if (tariffPackages) {\n batch(() => {\n dispatch(setTariffs(tariffPackages));\n dispatch(setTariffFilters(filters));\n dispatch(setTariffLineAlias(tariffLineAlias || ''));\n dispatch(getBundleOfSubscriptions(tariffPackages));\n });\n }\n\n if (tariffLineAlias || (!salePackageId && !tariffNameAlias)) {\n dispatch(setDisplayTariffLineState(true));\n }\n\n if (salePackageId) {\n dispatch(selectTariff({\n salePackageId: Number(salePackageId),\n }));\n }\n\n if (tariffNameAlias) {\n dispatch(selectTariff({\n tariffNameAlias,\n monoTariff,\n }));\n }\n\n // in case when user came from a direct link for tariff, we should send notification to the dataLayer\n if (salePackageId || tariffNameAlias || tariffLineAlias || (salePackageId && tariffLineAlias) || (tariffNameAlias && tariffLineAlias)) {\n const currentTariff = selectCurrentTariff(getState());\n\n if (analytics.category) {\n analytics.initializationByTariffLine(\n [\n tariffLineAlias ?? tariffNameAlias,\n currentTariff?.tariff_name,\n ]\n .filter(Boolean).join(' | '),\n );\n }\n\n dispatch(getEquipment());\n }\n\n batch(() => {\n // set full-buy flow\n dispatch(setFlow(flow));\n dispatch(setInitialized(true, isAddressVerificationOnFirstStep));\n });\n};\n","import { actionTypes } from '../index';\nimport { IFullBuyTariff } from '../tariffTransformer';\n\n// @todo remove action and move implementation to the initialization method\nexport const setTariffs = (tariffs: IFullBuyTariff[]) => ({\n type: actionTypes.SET_TARIFFS,\n payload: tariffs,\n});\n","import { actionTypes } from '~/src/features/full-buy/store';\nimport { IFlow } from '~/src/features/full-buy/store/initialState';\n\nexport const setFlow = (steps: IFlow) => {\n return {\n type: actionTypes.SET_FLOW,\n payload: {\n flow: steps,\n },\n };\n};\n","import { actionTypes } from '../index';\n\nexport const resetFullBuy = () => ({\n type: actionTypes.RESET_FULLBUY,\n payload: null,\n});\n","import { useMemo } from 'react';\n\nimport FullBuyAnalytics from '~/src/features/full-buy/analytics';\nimport FullBuyProvider from '~/src/features/full-buy/analytics/context';\nimport { FullBuy as FullBuySteps } from '~/src/features/full-buy/indexByPage';\n\ntype TFullBuyProps = {\n isVillage: boolean,\n}\n\nconst FullBuy = ({ isVillage }: TFullBuyProps): JSX.Element | null => {\n const analytics = useMemo(() => new FullBuyAnalytics(isVillage ? 'fullbuy_village' : 'fullbuy'), [isVillage]);\n\n return (\n \n \n \n );\n};\n\nexport default FullBuy;\n","import React from 'react';\nimport { NextPage } from 'next';\n\nimport { ICurrentCity } from '@r1-frontend/entities/City/models/ICurrentCity';\n\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\n\nimport Layout from '~/src/features/_layout';\nimport FullBuy from '~/src/features/full-buy';\nimport { ETariffFilters } from '~/src/features/full-buy/store/initialState';\nimport { initialProps } from '~/src/helpers/basePageFunc';\nimport { nonPermanentRedirect } from '~/src/helpers/url';\nimport type { TState } from '~/src/store';\n\ninterface IProps {\n currentCity: ICurrentCity,\n isVillage: boolean,\n}\n\nconst FullBuyPage: NextPage = ({ currentCity, isVillage }): JSX.Element => {\n const cityText = currentCity.cityIn;\n const title = `Пакет услуг в ${cityText}.`;\n const description = 'Выгодный интернет, цифровое ТВ в пакете.';\n\n return (\n \n \n \n );\n};\n\nFullBuyPage.getInitialProps = async(ctx): Promise => {\n const { validatedAccessToken } = await initialProps(ctx, { isNeedAuthData: true });\n const { res, store, query } = ctx;\n\n const state: TState = store.getState();\n const { city: { currentCity } } = state;\n\n if (validatedAccessToken) {\n nonPermanentRedirect({ res, location: '/lk' });\n // @ts-ignore\n return {};\n }\n\n const isVillage = Boolean(query?.filters?.includes(ETariffFilters.COTTAGE));\n\n return {\n currentCity,\n isVillage,\n };\n};\n\nexport default FullBuyPage;\n","export const DEALER_UID = 'dealerUid';\n","import React, { memo } from 'react';\n\nimport HtmlContentFromApi from '@r1-frontend/ui-react/components/HtmlContentFromApi';\n\nimport { ButtonElement, IButtonProps } from './components/ButtonElement';\nimport { IImageProps, ImageElement } from './components/ImageElement';\n\nimport * as ST from './styled';\n\nexport interface TariffElementProps {\n title?: string,\n titleText?: string,\n imageProps: IImageProps,\n btnProps?: IButtonProps,\n}\n\nexport const TariffElement = (item: TariffElementProps): JSX.Element => {\n const {\n title,\n titleText,\n imageProps,\n btnProps,\n } = item;\n\n return (\n \n \n \n \n\n \n {title}\n\n {titleText &&\n \n \n \n {titleText}\n \n \n \n }\n \n \n\n \n \n\n {titleText &&\n \n \n \n {titleText}\n \n \n \n }\n \n );\n};\n\nexport default memo(TariffElement);\n","import styled from 'styled-components';\n\nimport { BaseButton } from '@r1-frontend/ui-react/components/buttons/baseButton';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\nexport const Button = styled(BaseButton)`\n ${FONTS.MediumS};\n svg {\n fill: ${COLORS.Control};\n stroke: ${COLORS.Control};\n }\n`;\n","import React from 'react';\n\nimport { btnSizes, btnTypes } from '@r1-frontend/ui-react/components/buttons/baseButton';\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { useMatchMedia } from '@r1-frontend/shared/hooks/useMatchMedia';\n\nimport { ICONS_PATH } from '~/src/constants';\n\nimport * as ST from './styled';\n\nexport interface IButtonProps {\n btnTextDesktop?: string,\n btnTextMobile?: string,\n iconNameDesktop?: string,\n iconNameMobile?: string,\n isDisabled?: boolean,\n onButtonClick?: (() => void) | null,\n}\n\nexport const ButtonElement = ({\n btnTextDesktop = 'Добавить',\n btnTextMobile = '',\n iconNameDesktop,\n iconNameMobile,\n isDisabled,\n onButtonClick,\n} : IButtonProps): JSX.Element => {\n const isMobile = useMatchMedia(`(max-width: ${wideBreakpoints.mobile})`);\n\n if (!onButtonClick) {\n return <>>;\n }\n\n return (\n \n );\n};\n","import React from 'react';\n\nimport * as ST from './styled';\n\nexport interface IImageProps {\n imgBgColor?: string,\n imageSrc?: string,\n imageAlt?: string,\n textForImage?: string,\n bgForImage?: string,\n channelCount?: number, // костыль для вывода каналов в углу картинки\n isMega?: boolean,\n}\n\nexport const ImageElement = ({\n imgBgColor,\n imageSrc,\n imageAlt = 'иконка',\n textForImage = '',\n bgForImage,\n channelCount,\n isMega,\n} : IImageProps): JSX.Element => {\n const displayText = !imageSrc && !!textForImage;\n\n if (displayText) {\n return (\n \n {textForImage}\n \n );\n }\n\n return (\n \n
\n \n );\n};\n","import styled, { css } from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\nconst ImgWrap = styled.div`\n position: relative;\n flex: 0 0 90px;\n justify-content: center;\n align-items: center;\n width: 90px;\n height: 60px;\n ${FONTS.H4};\n border-radius: 20px;\n overflow: hidden;\n background-color: ${COLORS.BgMain};\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n flex: 0 0 72px;\n width: 72px;\n height: 48px;\n border-radius: 16px;\n }\n`;\n\nexport const ImageElement = styled(ImgWrap)<{ imgBgColor?: string, channelCount?: number }>`\n ${p => p.imgBgColor && css`\n background-color: ${p.imgBgColor};\n `};\n\n ${p => p.channelCount && css`\n &:after {\n content: \"+${p.channelCount}\";\n position: absolute;\n bottom: 2px;\n right: 19px;\n width: 20px;\n height: 20px;\n ${FONTS.XXS};\n fontSize: 10;\n color: ${COLORS.TextPrimary};\n }\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n &:after {\n bottom: -1px;\n right: 14px;\n }\n }\n `};\n\n img {\n width: 100%;\n max-height: 100%;\n }\n`;\n\nexport const ImageElementWithText = styled(ImgWrap)<{ imgSrc?: string, isMega?: boolean }>`\n overflow: hidden;\n ${FONTS.H3};\n color: ${({ imgSrc, isMega }) => isMega ? COLORS.TextPrimary : (imgSrc ? COLORS.TextWhite : COLORS.TextSecondary)};\n background-color: #E6EEF5;\n background-image: ${({ imgSrc }) => imgSrc ? `url(${imgSrc})` : 'none'};\n background-repeat: no-repeat;\n background-size: cover;\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n ${FONTS.H4};\n }\n`;\n","import styled, { css } from 'styled-components';\n\nimport { BaseButton } from '@r1-frontend/ui-react/components/buttons/baseButton';\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { BorderRadius } from '@r1-frontend/ui-react/tokens/borderRadius';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\nexport const TariffElement = styled.div`\n flex-direction: column;\n justify-content: center;\n row-gap: 8px;\n width: 100%;\n min-height: 76px;\n padding: 4px 12px 4px 8px;\n border-radius: ${BorderRadius.InnerBlockRadius};\n background-color: ${COLORS.BgSurface};\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n justify-content: flex-start;\n padding: 8px 12px 12px 8px;\n }\n`;\n\nexport const RowWrap = styled.div`\n flex-wrap: nowrap;\n column-gap: 24px;\n align-items: center;\n width: 100%;\n`;\n\nexport const DescriptionWrap = styled.div`\n flex: 1 0 1%;\n flex-wrap: nowrap;\n align-items: center;\n column-gap: 12px;\n`;\n\nexport const MobileOnlyWrap = styled(RowWrap)`\n display: none;\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n display: flex;\n justify-content: space-between;\n padding: 0 0 0 4px;\n }\n`;\n\nexport const DesktopOnlyWrap = styled.div<{ withCounts?: boolean }>`\n display: flex;\n align-items: center;\n column-gap: 24px;\n\n @media (min-width: ${wideBreakpoints.mobile}) {\n ${({ withCounts }) => withCounts\n ? css`\n width: 240px;\n flex-wrap: nowrap;\n column-gap: initial;\n justify-content: space-between;\n `\n : ''\n }\n }\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n display: none;\n }\n`;\n\nexport const TitleWrap = styled.div`\n flex: 1 0 1%;\n flex-direction: column;\n justify-content: center;\n align-items: flex-start;\n flex-wrap: nowrap;\n row-gap: 4px;\n`;\n\nexport const Title = styled.div`\n width: 100%;\n ${FONTS.MediumS};\n color: ${COLORS.TextPrimary};\n`;\n\nexport const Description = styled.div`\n ${FONTS.XS};\n color: ${COLORS.TextSecondary};\n`;\n\nexport const Button = styled(BaseButton)`\n svg {\n fill: ${COLORS.Control};\n stroke: ${COLORS.Control};\n }\n`;\n","import { useRouter } from 'next/router';\n\n/**\n * @deprecated использовать useRouter\n */\nexport const usePrepareQueryData = (): Record => {\n const { query } = useRouter();\n const _query: Record = {};\n\n for (const key in query) {\n const _value = query[key];\n _query[key] = _value ? (typeof _value === 'string' ? _value : _value[0]) : '';\n }\n\n return _query;\n};\n","import { IRequest } from '@r1-frontend/shared/types/IRequest';\n\n\nexport interface ICheckResponse {\n sum: number,\n type: number,\n expireDate?: string,\n}\n\nexport enum ErrorCodeStatus {\n PROMOCODE_NOT_FOUND = 'PROMOCODE_NOT_FOUND',\n UNKNOWN = 'UNKNOWN'\n}\n\n/*\n* Проверка доступности промокода для неавторизованного пользователя\n* https://master.api-loyalty.sandbox.d2c.r-one.io/docs/v1#/Promocode/7eddd66cd85b641c15598f640c8c4250\n* */\nexport const check = (providerId: number, promoCode: string): IRequest => ({\n uri: '/v1/unauth-promocode/check',\n method: 'GET',\n headers: { providerId: `${providerId}` },\n queryParams: { promocodeName: promoCode },\n});\n","import { IRequest } from '@r1-frontend/shared/types/IRequest';\n\n/*\n* Регистрация платежа\n* https://master.api-pay.sandbox.d2c.r-one.io/docs/v1#/Payment/f5610719af05925870dc02555a45b38d\n*\n*/\nexport const makePaymentAuth = (providerId: number, params = {}): IRequest => ({\n uri: '/payment/add',\n withAuth: true,\n withProvider: true,\n method: 'POST',\n body: JSON.stringify(params),\n queryParams: {\n providerId,\n },\n});\n\n/*\n* Простая оплата без токена по timestamp и client_secret\n* https://master.api-pay.sandbox.d2c.r-one.io/docs/v1#/UnauthPayment/2daace48edd50f86130bdbe7fc5cd644\n*/\nexport const makePaymentUnauth = (providerId: number, params = {}): IRequest => ({\n uri: '/unauth-payment/add',\n method: 'POST',\n body: JSON.stringify(params),\n queryParams: {\n providerId,\n },\n});\n","import { EContactDetailTypes, TResetData } from '../index';\nimport { initialState } from '../initialState';\n\nexport const resetAddress = (): TResetData => ({\n type: EContactDetailTypes.RESET_DATA,\n payload: initialState,\n});\n","import { RefObject, useCallback, useState } from 'react';\n\nimport { useIsomorphicLayoutEffect } from '@r1-frontend/shared/hooks/useIsomorphicLayoutEffect';\n\ninterface IResult {\n height: number | undefined,\n width: number | undefined,\n}\n\nexport const useResizeObserver = (\n ref: RefObject,\n callback?: (entry: DOMRectReadOnly) => void,\n): IResult => {\n const [width, setWidth] = useState();\n const [height, setHeight] = useState();\n\n const handleResize = useCallback(\n (entries) => {\n if (!Array.isArray(entries)) {\n return;\n }\n\n const entry = entries[0];\n setWidth(entry.contentRect.width);\n setHeight(entry.contentRect.height);\n\n if (callback) {\n callback(entry.contentRect);\n }\n },\n [callback],\n );\n\n useIsomorphicLayoutEffect(() => {\n if (!ref.current) {\n return;\n }\n\n let RO: ResizeObserver | null = new ResizeObserver((entries) => window.requestAnimationFrame(() => handleResize(entries)));\n RO.observe(ref.current);\n\n return () => {\n RO?.disconnect();\n RO = null;\n };\n }, [ref]);\n\n return { width, height };\n};\n","import styled from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\nexport const HtmlContentFromApi = styled.div`\n display: block;\n word-break: break-word;\n \n ul, ol {\n display: list-item;\n }\n \n ul {\n list-style: disc;\n }\n \n ol {\n list-style: decimal;\n }\n \n h1 {\n ${FONTS.H2};\n\n @media (min-width: ${wideBreakpoints.mobile}) {\n ${FONTS.H0}\n }\n }\n\n h2 {\n ${FONTS.H3};\n \n @media (min-width: ${wideBreakpoints.mobile}) {\n ${FONTS.H1}\n }\n }\n\n h3 {\n ${FONTS.H4};\n\n @media (min-width: ${wideBreakpoints.mobile}) {\n ${FONTS.H3}\n }\n }\n\n h4 {\n ${FONTS.H5};\n\n @media (min-width: ${wideBreakpoints.mobile}) {\n ${FONTS.H4}\n }\n }\n\n h5, h6 {\n ${FONTS.H6};\n }\n \n p, li {\n ${FONTS.XS};\n \n b {\n ${FONTS.MediumXS};\n }\n\n @media (min-width: ${wideBreakpoints.mobile}) {\n b {\n ${FONTS.MediumS};\n }\n }\n \n @media (min-width: ${wideBreakpoints.mobile}) {\n ${FONTS.S};\n }\n }\n \n a {\n color: ${COLORS.Link}\n }\n \n img {\n max-width: 100%;\n height: auto;\n object-fit: contain;\n }\n`;\n","import * as ST from './styled';\n\ntype THtmlContentFromApiProps = {\n children: string,\n};\n\nconst HtmlContentFromApi = ({ children }: THtmlContentFromApiProps): JSX.Element => {\n return (\n \n );\n};\n\nexport default HtmlContentFromApi;\n","import styled from 'styled-components';\n\n// todo: Этот компонент требует доработки, использовался в 2х местах поэтому вынес в ui-react\nexport const OrderedList = styled.ol`\n padding-left: 16px;\n list-style: decimal;\n`;\n","import { TSliderProps } from '@r1-frontend/ui-react/components/NukaCarousel/SliderHoc/types';\n\n/**\n * Медиавыражения для определения соответствия документа определенному разрешению (Исп-ся для смены контейнера карточек на слайдер)\n *\n * @name constants.EMediaWidth\n * @type {enum}\n */\nexport enum EMediaWidth {\n desktop = '(min-width: 1601px)',\n sDesktop = '(max-width: 1600px) and (min-width: 1280px)',\n laptop = '(max-width: 1279px) and (min-width: 768px)',\n sLaptop = '(max-width: 1024px)',\n mobile = '(max-width: 767px)',\n}\n\n/**\n * Первоначальный стейт maxCardsData\n *\n * @name constants.DEFAULT_STATE_MAX_CARDS\n * @type {TSliderProps}\n */\nexport const DEFAULT_STATE_MAX_CARDS: TSliderProps = { value: 1, gap: 40 };\n\n/**\n * Данные для слайдера в соответсвии разрешению (value - макс кол-во карточек без переполнения, gap - расстояние между слайдами)\n *\n * Страница /promo\n *\n * @name constants.DATA_SLIDER_PARAMS_DEFAULT\n * @type { Record}\n */\nexport const DATA_SLIDER_PARAMS_DEFAULT: Record = {\n mobile: { value: 1, gap: 35 },\n laptop: { value: 2, gap: 66 },\n sDesktop: { value: 3, gap: 96 },\n desktop: { value: 4, gap: 129 },\n};\n\n/**\n * Ширина карточки для слайдера\n *\n * @name constants.CARD_WIDTH\n * @type {string}\n */\nexport const CARD_WIDTH = '316px';\n","import styled from 'styled-components';\n\nexport const Wrapper = styled.div<{needWrapGap?: boolean}>`\n margin-top: 20px;\n ${({ needWrapGap }) => needWrapGap ? 'gap: 32px' : ''};\n`;\n\nexport const Container = styled.div`\n width: 100%;\n\n & > div:first-of-type {\n padding-left: 0;\n padding-right: 0;\n }\n`;\n","import React, { FC, useEffect, useMemo, useState } from 'react';\n\nimport NukaCarousel from '@r1-frontend/ui-react/components/NukaCarousel';\nimport {\n CARD_WIDTH,\n DATA_SLIDER_PARAMS_DEFAULT,\n DEFAULT_STATE_MAX_CARDS,\n EMediaWidth,\n} from '@r1-frontend/ui-react/components/NukaCarousel/SliderHoc/constants';\nimport type { TSliderProps } from '@r1-frontend/ui-react/components/NukaCarousel/SliderHoc/types';\nimport type { IProps } from '@r1-frontend/ui-react/components/NukaCarousel/SliderHoc/types';\nimport { useMatchMedia } from '@r1-frontend/shared/hooks/useMatchMedia';\n\nimport * as ST from './styled';\n\nexport const SliderHoc: FC = ({ children, cardLength, needWrapGap, withoutArrows, slideWidth, cellSpacing }) => {\n const isMobile = useMatchMedia(EMediaWidth.mobile);\n const isLaptop = useMatchMedia(EMediaWidth.laptop);\n const isSDesktop = useMatchMedia(EMediaWidth.sDesktop);\n const isDesktop = useMatchMedia(EMediaWidth.desktop);\n const isTablet = useMatchMedia(EMediaWidth.sLaptop);\n const arrayMedia = [isMobile, isLaptop, isSDesktop, isDesktop];\n const [maxCardsData, setMaxCardsData] = useState(DEFAULT_STATE_MAX_CARDS);\n\n useEffect(() => {\n if (~arrayMedia.indexOf(true)) {\n setMaxCardsData(currentSliderProps);\n }\n }, [isMobile, isLaptop, isSDesktop, isDesktop]);\n\n const currentSliderProps = useMemo((): TSliderProps => {\n switch (true) {\n case isMobile:\n return DATA_SLIDER_PARAMS_DEFAULT.mobile;\n case isLaptop:\n return DATA_SLIDER_PARAMS_DEFAULT.laptop;\n case isSDesktop:\n return DATA_SLIDER_PARAMS_DEFAULT.sDesktop;\n case isDesktop:\n return DATA_SLIDER_PARAMS_DEFAULT.desktop;\n default: return DEFAULT_STATE_MAX_CARDS;\n }\n }, [isMobile, isLaptop, isSDesktop, isDesktop]);\n\n return (\n cardLength > maxCardsData.value\n ? \n \n {children}\n \n \n : {children}\n );\n};\n","import styled, { css } from 'styled-components';\n\nimport { wideBreakpoints } from '@r1-frontend/ui-react/components/layouts/wideContainer';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\nconst StylesTab = css`\n position: relative;\n padding: 6px 24px;\n border-style: solid;\n border-color: transparent;\n background: transparent;\n overflow: hidden;\n font: inherit;\n cursor: pointer;\n`;\n\nexport const Container = styled.div<{isDisabled : boolean, fontSize?: FONTS}>`\n width: fit-content;\n min-width: max-content;\n max-width: 600px;\n display: flex;\n position: relative;\n box-sizing: content-box;\n ${p => p.fontSize || FONTS.MediumXS};\n background-color: transparent;\n border-radius: 100px;\n border: 2px solid ${COLORS.Outline_Light};\n pointer-events: ${p => p.isDisabled ? 'none' : 'auto' };\n user-select: none;\n\n @media (max-width: ${wideBreakpoints.mobile}) {\n max-width: 300px;\n }\n`;\n\nexport const TabLeft = styled.button`\n ${StylesTab};\n border-width: 2px 0 2px 2px;\n border-radius: 100px 0 0 100px;\n`;\n\nexport const TabRight = styled.button`\n ${StylesTab};\n border-width: 2px 2px 2px 0;\n border-radius: 0 100px 100px 0;\n`;\n\nexport const LayoutLeft = styled.span<{translateValue: number, colorTab: string}>`\n position: absolute;\n top: 0;\n height: 100%;\n border-radius: 100px;\n transition: transform 100ms ease-in-out;\n width: 100%;\n right: 0;\n background-color: ${p => p.colorTab};\n transform: ${p => `translateX(${p.translateValue}%)`};\n`;\n\nexport const LayoutRight = styled(LayoutLeft)`\n right: 100%;\n`;\n\nexport const Text = styled.span<{ isActive: boolean, isDifferentColorText: boolean }>`\n position: relative;\n z-index: 1;\n color: ${(p) => p.isDifferentColorText && !p.isActive ? COLORS.TextPrimary : COLORS.TextWhite};\n white-space: pre;\n`;\n","import React, { FC } from 'react';\n\nimport * as ST from '@r1-frontend/ui-react/components/controls/Toggle/styled';\nimport { COLORS } from '@r1-frontend/ui-react/tokens/colors';\nimport { FONTS } from '@r1-frontend/ui-react/tokens/fonts';\n\ninterface IProps {\n textsValues: { leftText: string, rightText: string },\n isDisabled?: boolean,\n colorTab?: string,\n onChangeCallback: (activeTab: string) => void,\n activeTab: string,\n fontSize?: FONTS,\n isDifferentColorText?: boolean,\n}\n\nconst Toggle: FC = ({\n textsValues,\n isDisabled = false,\n colorTab = COLORS.ButtonPrimary,\n onChangeCallback,\n activeTab,\n fontSize,\n isDifferentColorText = true,\n ...args\n}) => {\n const translateData = { max: 100, min: 0 };\n const { leftText, rightText } = textsValues;\n const isRightTabActive = activeTab === rightText;\n\n const onClickHandler = () => {\n const activeText = isRightTabActive ? leftText : rightText;\n onChangeCallback(activeText);\n };\n\n return (\n \n \n \n \n {leftText}\n \n \n \n \n \n {rightText}\n \n \n \n );\n};\n\nexport default Toggle;\n","import PropTypes from 'prop-types';\nimport React from 'react';\nimport ReactSelect, { components } from 'react-select';\nimport styled from 'styled-components';\n\nimport Icon from '../../../deprecated/icon';\nimport { COLORS } from '../../../tokens/colors';\nimport { Menu, MenuList, Option as BigOption, SmallOption } from '../dropdown';\n\nconst ControlTitle = styled.div`\n cursor: pointer;\n`;\nconst Control = (props) => {\n const { children, isDisabled, isFocused, innerRef, innerProps } = props;\n return (\n \n {children}\n \n );\n};\n\nconst ValueContainer = styled(components.ValueContainer)`\n padding: 0!important;\n flex: auto!important;\n align-items: flex-start!important;\n`;\n\nconst TitleValue = styled.div`\n color: ${COLORS.TextPrimary};\n`;\nconst SingleValue = (props) => {\n const { children, isDisabled, innerRef, innerProps } = props;\n return (\n \n {children}\n \n );\n};\n\nconst Indicator = styled(components.DropdownIndicator)`\n min-width: 20px;\n justify-content: center;\n align-items: center;\n margin-left: 5px;\n padding: 0!important;\n`;\nconst DropdownIndicator = (props) => {\n return (\n \n \n \n );\n};\n\nexport default class Select extends React.Component {\n static propTypes = {\n options: PropTypes.arrayOf(PropTypes.shape({\n label: PropTypes.any,\n value: PropTypes.any,\n })),\n defaultValue: PropTypes.any,\n placeholder: PropTypes.string,\n onChange: PropTypes.func,\n value: PropTypes.shape({\n label: PropTypes.any,\n value: PropTypes.any,\n }),\n };\n\n static defaultProps = {\n options: [],\n placeholder: '',\n onChange: () => { },\n };\n\n onChange = (value) => {\n this.props.onChange(value);\n };\n\n render() {\n const { options, defaultValue, value, placeholder, minWidth, extStyle, smallOption, ...rest } = this.props;\n\n const Option = (props) => smallOption ? : ;\n const customComponents = {\n IndicatorSeparator: null,\n Control,\n ValueContainer,\n SingleValue,\n Option,\n Menu,\n MenuList,\n DropdownIndicator,\n };\n\n const customStyles = {\n menu: base => ({\n ...base,\n minWidth: minWidth,\n }),\n ...extStyle,\n };\n return (\n \n );\n }\n}\n","import { createSvg } from '@r1-frontend/ui-react/components/svg/createSvg';\n\nconst Check = (\n {\n strokeWidth = 1.5,\n },\n): JSX.Element => {\n return (\n \n \n \n );\n};\n\nexport default createSvg(\n Check,\n 'check',\n);\n","import { createSvg } from '@r1-frontend/ui-react/components/svg/createSvg';\n\nconst Coin = (\n {\n strokeWidth = 1.5,\n },\n): JSX.Element => {\n return (\n <>\n \n \n \n \n \n >\n );\n};\n\nexport default createSvg(\n Coin,\n 'coin',\n);\n","import { createSvg } from '@r1-frontend/ui-react/components/svg/createSvg';\n\nconst VideoPlay = (\n {\n strokeWidth = 1.5,\n },\n): JSX.Element => {\n return (\n <>\n \n \n \n \n \n \n \n >\n );\n};\n\nexport default createSvg(\n VideoPlay,\n 'video-play',\n);\n","import styled from 'styled-components';\n\n/**\n * @deprecated\n * Use @r1-frontend/ui-react/components/svg instead\n */\nconst Icon = styled.div`\n display: inline-block;\n font-family: 'icomoon' !important;\n font-style: normal;\n font-weight: normal;\n font-variant: normal;\n text-transform: none;\n text-decoration: none;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n font-size: ${props => props.fontSize ? props.fontSize : 'inherit'};\n color: ${props => props.color || 'black'};\n &::before {\n content: ${props => `\"${props.content}\"`};\n }\n`;\n\nexport default Icon;\n","/**\n * Медиавыражения для определения соответствия документа определенному разрешению\n *\n * @name data.EMediaWidth\n * @type {enum}\n */\nexport enum EMediaWidth {\n sDesktop = '(max-width: 1365px)',\n sDesktopMin = '(min-width: 1366px)',\n sDesktopOnly = '(max-width: 1365px) and (min-width: 1023px)',\n tablet = '(max-width: 1023px)',\n tabletOnly = '(max-width: 1023px) and (min-width: 768px)',\n mobile = '(max-width: 767px)',\n}\n","module.exports = \"https://cdn-b2c.dom.ru/b2c-domru/2.357.4/frontend/_next/static/images/banner-152033077c7bae27a78900a7e2a0b07b.png\";"],"names":["module","exports","e","t","default","n","o","Promise","i","a","s","l","next","r","throw","done","value","then","apply","document","createElement","src","async","removeEventListener","remove","Error","addEventListener","body","appendChild","constructor","this","handleClick","config","createLoadPaymentDataRequest","onClick","defaultPrevented","client","loadPaymentData","onLoadPaymentData","statusCode","onCancel","onError","console","error","options","getElement","element","isGooglePayLoaded","window","g","google","payments","api","PaymentsClient","mount","appendStyles","updateElement","unmount","configure","oldInvalidationValues","isClientInvalidated","getInvalidationValues","resolve","createClientOptions","environment","merchantInfo","createMerchantInfo","onPaymentDataChanged","onPaymentAuthorized","paymentDataCallbacks","createIsReadyToPayRequest","paymentRequest","apiVersion","apiVersionMinor","allowedPaymentMethods","existingPaymentMethodRequired","Object","assign","softwareInfo","id","softwareInfoId","version","softwareInfoVersion","isMounted","isConnected","removeButton","ShadowRoot","Element","Array","from","children","tagName","buttonType","buttonColor","buttonSizeMode","buttonLocale","getRootNode","buttonRootNode","createButton","setClassName","className","isReadyToPay","result","paymentMethodPresent","prefetchPaymentData","log","split","filter","onReadyToPayChange","isButtonVisible","join","removeAttribute","cssSelector","replace","getElementById","call","type","innerHTML","Document","head","some","merchantId","merchantName","Component","super","arguments","manager","elementRef","createRef","componentDidMount","current","props","componentWillUnmount","componentDidUpdate","render","ref","style","baseFlatten","baseOrderBy","baseRest","isIterateeCall","sortBy","collection","iteratees","length","baseIteratee","baseUniq","array","iteratee","__NEXT_P","push","ANALYTICS","clickGuide","goToPage","ControlsWithQuantity","quantity","minQuantity","disabled","onIncrement","onDecrement","onClose","isMobile","useMatchMediaByWidth","wideBreakpoints","Stepper","min","summaryLimitsReached","$bgColor","COLORS","$color","Button","bType","size","EquipmentControlsComponent","styled","ListContainer","Cost","Paragraph5","EquipmentControls","cost","onAddClick","text","isMonthly","useMatchMedia","ST","$direction","$wrap","$size","data-bType","NBSP","Item","isChecked","ItemRadio","BaseRadio","TextWrapper","FONTS","period","onSelect","name","customText","onChange","checked","span","br","b","PurchaseContainer","selectedOption","handleSelect","hasAdded","limits","elseOptions","option","useMemo","sortedOptions","values","lowestPriceOption","isFullPriceChecked","fullPriceOption","isFullPriceDisabled","total","isLowestPriceChecked","isLowestPriceDisabled","installment","H4","$smaller","SlideCarousel","withoutArrows","withoutDots","slideWidth","cellSpacing","framePadding","PurchaseOptionsItem","Paragraph4","$withIndent","map","isInstallment","product","selectedPrice","duration","limitsByCategories","EShopCategory","getTotalCount","products","reduce","acc","curr","getLimits","category","limit","productsByCategory","el","installmentCount","installmentItems","getProductsInInstallments","getInstalmentCount","getIsDisabledByLimits","productQuantity","isInstallmentLimit","BasePopupRightAlign","isOpen","dPadding","mPadding","popupHeight","desktopPadding","scrollPaddingDesktop","isIndent","mobilePadding","scrollPaddingMobile","rightIndent","DefaultPopup","width","height","overflowY","alignSelf","margin","popupIndent","maxWidth","maxHeight","borderRadius","BorderRadius","customStyles","popup","closePopup","top","right","mobile","IndentContainer","$desktop","$mobile","display","flexDirection","flexWrap","position","TheScrollbar","CustomScrollbar","view","paddingRight","selectProductsByCategory","createSelector","state","items","fullBuy","item","CarouselContainer","ContentContainer","RoundedContainer","Footer","title","images","characteristics","description","labels","useState","setOption","analytics","useAnalytics","equipments","useSelector","isDisabled","textForOptions","NukaCarousel","slidesToShow","img","alt","FullWidthListContainer","H3","dangerouslySetInnerHTML","__html","PurchaseOptionsSlider","equipment","chooseCostType","chooseDuration","index","Characteristics","HtmlContentFromApi","chooseEquipmentContinue","PopupCustomStyles","Popup","$props","EquipmentPopup","memo","DecoderCardView","openAddEquipmentPopup","handleDecrement","handleIncrement","isSkipImages","image","categoryTitle","TVSetTopSelectable","group","onButtonClick","onCostClick","btnText","DecoderCardsViewWithButton","cardCount","useValueByBreakpoint","desktop","sDesktop","usePartialList","partialEquipments","isPartial","setIsPartial","showMoreText","ControlElement","Icon","SingleArrowDown","SingleArrowUp","clickShowMore","DecoderCardsViewWithCarousel","AdaptiveNukaCarousel","slidesToScroll","desktopSlideWidth","mobileSlideWidth","data-test","getPurchaseOptions","prices","isInstallmentDisable","sort","key","setTariffFilters","filters","actionTypes","payload","addProduct","productId","decProductQuantity","setProducts","selectSubscription","subscriptionId","clickSubscriptionsCheckBox","selectTariff","params","addressData","selectedAddress","setAgreementData","agreementId","agreementNumber","isDouble","hasError","errorMessage","setDisplayTariffLineState","displayState","setInitialized","status","isAddressVerificationOnFirstStep","setPrevStep","stepIndex","setPromoCode","data","setSlot","slot","setStep","setTariffLineAlias","tariffLineAlias","toggleBackgroundLoading","newState","unSelectSubscription","addEquipment","currentEquipment","dispatch","find","batch","changeEquipmentCount","elementId","isIncrement","getState","currentEl","deleteEquipment","DecoderList","withCarousel","useDispatch","isPopupOpen","setIsPopupOpen","currentEquipmentId","setCurrentEquipmentId","setIsInstallmentDisable","isInstallmentDisabled","handleClosePopup","EquipmentInfo","label","Label","bgColor","color","textColor","color_text","prepareCharacteristic","elem","truncate","Flash","RouterCardView","slicedProps","slice","RouterCard","RouterCardsViewWithButton","entity","getShowMoreEquipmentText","RouterCardsViewWithCarousel","EquipmentList","useEffect","clickAddProduct","TOGGLE_MODES","leftText","rightText","getABNVariant","ESteps","tariffInfo","subscriptions","equipmentsTv","equipmentsCottage","address","contacts","agreementCreated","timeSlots","final","EXCLUDE_STEPS","useCheckAdditionalEquipment","useContext","FullBuyContext","isVillage","routerCategory","flow","routerEquipments","decoderEquipments","shallowEqual","step","steps","hasAdditionalEquipment","isAdditionalEquipment","equipmentComponentType","includes","componentForEquipment","toggleState","setToggleState","Toggle","textsValues","onChangeCallback","activeTab","colorTab","fontSize","isDifferentColorText","StyledAdditionalEquipment","EquipmentComponent","WideContainer","$united","Separator","BannerBlockContainer","BlockContainer","BannerView","subtitle","buttonText","indent","rounder","require","selectBannerInfoForFullBuy","selectCurrentTariff","tariff","speedInRange","inRange","speed","isMono","recommendedPackets","recommendedPacket","priceFinal","promoPriceFinal","promoDuration","sale_package_id","tariffName","format","monthly","path","Banner","banner","verifiedAddressDataStatus","contactAddress","verifiedAddressData","isAddressNotVerified","EVerificationStatus","clickBanner","location","href","S","as","$inline","Boolean","isConnectionAvailable","isTariffAvailable","newPrice","checkingResult","connectionPrice","isValid","undefined","selectedSubscriptions","forEach","sId","serviceId","periodText","getPluralize","monthPluralize","productName","finalPrice","startPrice","changePopupState","InfoCircleFlip","ButtonGroup","dMonth","str","max","suffix","substr","lastIndexOf","givenQuantityForCost","isRequired","required","getTitleByQuantity","trim","AdditionalProductDetailedInfo","firstMonthPrice","basePrice","Indentation2SatisfyTheDesignIdea","analyticsCallback","selectedTariff","stepName","selectStepName","isShownLoader","addressCheckingResult","getAddressCheckingResult","orderSummary","fullSummaryData","isApartmentPackage","additionalProducts","tariffPrice","promoPrice","price","productsCost","getProductsCosts","instalmentProducts","oneTimePurchaseProducts","totalCost","once","allData","getDescriptionForTariffForNewSubscriptions","promoPeriod","TariffDetailedInfo","processProduct","isCottage","ItemWithoutCost","previousCost","isDiscounted","base","ConnectionConditions","withoutTitle","clickViewConnectionCostPopup","summary","bind","getSummaryInfo","BaseOrderSummary","gapSize","Wrapper","OrderSummaryItem","providerId","domain","callback","isError","setIsError","setErrorMessage","isLoading","setIsLoading","processCheck","promoCode","respPromoCode","promocodeClickVerification","doRequest","check","isSuccess","amount","sum","promocodeFailVerification","message","clearErrors","PromoWrapper","FormLine","StyledInputSimple","InputSimple","ResultLine","TickCircle","Text","StyledButton","EBonusTypes","AMOUNT","PERCENT","hasAgreement","selectDomain","selectProviderId","bonusAmount","bonusType","promoCodeValue","setPromoCodeValue","startInput","setStartInput","usePrepareQueryData","code","useCheckPromoCode","promocodeSuccessVerification","onCheckCode","useCallback","bonusMessage","onClickClear","onInputCLick","promocodeClickedOnHave","Close","placeholder","promocodeStartedTyping","target","onInputChange","isNotValid","BottomStickyOrderSummaryWrapper","OrderSummaryWrapper","RoundedBlock","TiketContainer","withPromocode","agreementData","agreement","isLaptop","onOpenBottomSticky","useOnceExecute","clickOpenBottomStickySummary","BottomStickyBlock","InnerComponent","OrderSummary","PromoCode","OuterComponent","TotalSummary","onOpen","fio","contactDetails","editedFio","phone","confirmedPhone","getAddressByStr","promoCodeError","InfoBlock","header","isCollapsable","isRightSide","wrapper","InfoBlockItem","icon","User","content","CallCalling","Location","Coin","Phone","StBaseButton","BaseButton","city","currentCity","callCenterNumber","callCenter","clickCallTouch","btnSizes","btnTypes","clickChat","openChat","FeedbackWrapper","FeedbackTitle","FeedbackButtonsContainer","FeedbackButton","clickable","css","FeedbackEmoticon","FeedbackButtonTitle","InputMessage","ButtonMessage","StyledThrobber","Throbber","EFeedback","not_grade","bad_grade","good_grade","feedback","setFeedback","setMessage","setIsValid","isSentFeedback","setIsSentFeedback","sendGoodGrade","positive","sendBadGrade","negative","WebpImage","urlWebp","div","inputType","onChangeMessage","CardWrapper","CardImage","LazyLoadImage","isCover","CardContent","CardTitle","CardDescription","card","webpImg","CardCircle","CardArrow","imgUrl","CardLabel","BlockTitle","SwiperContainer","BlockArray","CardRowWrapper","cardGap","rowCards","arrayCount","cardWidth","amountInRow","rowIndex","isShowAll","innerIndex","CardLoader","Card","shopItemTypeIDs","finalsalePackageLink","showLink","parentBlock","useRef","useResizeObserver","setIsShowAll","EMediaWidth","tariffPackage","salePackageId","calculatedSalePackageId","salePackageLinks","subscriptionsArray","finalSubscriptions","service_id","filteredSubscriptionsArray","requiredAdditionalProducts","filteredProducts","uniqBy","allTariffIncludes","tariffIncludesResult","prop","toString","toLowerCase","image_width","image_height","image_webp","shopItem","extend_image_for_full_buy","extend_image_for_full_buy_webp","extend_body_for_full_buy","body_for_full_buy","imageForFullBuy","imageForFullBuyWebp","extendBodyForFullBuy","bodyForFullBuy","countWithGap","Math","floor","rowsCardsToShow","res","chunk","SliderHoc","cardLength","needWrapGap","CardRow","Link","USER_LOGIN_ROUTE","passHref","fetchAuthorizeApplePaySession","headers","resp","axios","url","method","captureQueryError","cachedScripts","loadScript","existing","promise","reject","script","onScriptLoad","onScriptError","AppleBtnGlobalStyle","createGlobalStyle","AppleBtnWrapper","ApplePayBtn","paySumm","onPaymentCreate","isLoadedScript","setIsLoadedScript","paymentMethodData","setPaymentMethodData","onPayClick","paymentResp","details","request","payToken","payResult","currency","PaymentRequest","onmerchantvalidation","event","appleSession","complete","show","token","paymentData","initialazeClient","methodData","uri","withProvider","withAuth","info","supportedMethods","IS_PRODUCTION_ENVIROMENT","merchantIdentifier","merchantCapabilities","supportedNetworks","countryCode","canMakePayment","appleBtn","querySelector","apple-pay-button","buttonstyle","locale","GoogleBtnWrapper","GooglePayBtn","paymentDataRequest","setPaymentDataRequest","setMerchantInfo","parameters","allowedAuthMethods","allowedCardNetworks","tokenizationSpecification","gateway","gatewayMerchantId","transactionInfo","totalPriceStatus","totalPriceLabel","totalPrice","currencyCode","getDataRequest","ev","preventDefault","tokenizationData","GooglePayButton","PaymentVariants","isLastStep","isGoogleBtnDisplay","setGoogleBtnDisplay","isAppleBtnDisplay","setAppleBtnDisplay","router","useRouter","onPaymentMake","pathname","query","pay","MD","gateTransactionId","PaReq","TermUrl","acsUrl","billingTransactionId","paymentToken","tokenType","paymentResult","btoa","JSON","stringify","number_type","number_value","payment_token","payment_token_type","payment_value","payment_source","return_url","origin","makePaymentUnauth","regStatus","captureException","abnGoogleVariant","abnAppleVariant","onGoToPayment","clickPayment","StyledTicket","TicketFinal","isEquipment","marginBottom","p","successStatus","isLeasingPrice","isName","Select","RubleSymbol","bottomContent","DoubleColumnLayout","isHide","StageWrap","Section","BlocksWrapper","TiketContainerFinal","calculateTotalPrices","monthlyPayment","oncePayment","dateTime","date","AgreementInfo","Feedback","TariffInclude","CallbackContacts","goToNextStep","newIndex","selectFilteredTariffs","tariffs","filteredPackages","tariffPackages","packages","tariffPack","getTariffsByTariffLine","filterType","ETariffFilters","pack","available_on_address_restrict","GIGABIT_SPEED","getfilteredPack","filteredTariffs","addressStatus","isEdit","isAgree","isConfirmButtonActive","isAddressFilled","isHouseConnected","isHouseCottage","availableSpeed","tariffSpeed","addressIsVerified","tariffSpeedAcrossEnum","EAvailableSpeed","MEGABIT_SPEED","shouldConnect","Number","stopPropagation","checkAddress","setAddressEdit","checkClicked","continueClicked","getSelectedProductsByCategory","hasSelected","clickContinue","ADDRESS_VERIFICATION_SINGLE_INPUT","on","off","getStep","getFlow","isOneLineAddressFormScreen","isOneLineAddressScreen","_step","String","selectIsPhoneConfirmed","editedPhone","isPhoneConfirmed","isConfirmButtonDisabled","getStateForContactsButton","openVerification","showPopup","submitVerificationForm","isHaveSelectedProducts","hasProducts","doNotDisplay","needToSelect","subscriptionsSummary","cnt","leftToSelect","selected","tariff_name","subscriptionPlural","getSubscriptionsWithConditions","choose","_backgroundLoading","loading","getStateForTariffInfoButton","UnifiedAddressFormContext","uafDispatch","unifiedAddressFormHooks","submitButtonProps","getSubmitButtonProps","onAddressConfirmedCallback","setAddress","isTariffAvailableForActivation","connectionCost","submit","unifiedAddressAnalytics","hooksList","useTariffInfoNextButton","useSubscriptionsNextButton","useEquipmentsNextButton","useEquipmentsTvNextButton","usePrivateSectorEquipmentNextButton","useUnifiedAddressFormNextButton","useOldAddressFormNextButton","useContactsNextButton","useStubNextButton","getStepForNextButton","useDynamicHook","createSvg","strokeWidth","d","strokeLinecap","strokeLinejoin","stroke","guideSteps","isActive","Game","House","VideoPlay","ProfileCircle","CalendarSecond","MovixHelper","CloseBox","getGuideData","isSalePackageId","currentStep","hasEquipmentInTariff","hasRequiredTvBox","hasSubscriptions","findStep","mappedItem","isTruthy","GuideFullBuy","guideData","createDescriptionElements","OpenChat","Guide","goToPrevStep","onClickInfoIcon","_addressVerificationOnFirstStep","gigabitAvail","canConnectAfterCheckedAddress","_gigabitMayConnect","MEGABIT_AVAIL_CODES_LIST","_shouldConnect","progress","dynamicProps","hasPrevBtn","imgName","getProgressTitles","imgPath","SteppableProgressBar","RequestContent","LeftSide","MainLayout","showFinalTicket","isOpenGuide","setIsOpenGuide","isHideGuideIcon","UnifiedAddressFormCtx","unifiedAddressForm","ProgressBarWithBackBtnContainer","GoToNextStepButton","HasAgreementPopup","popupAddressAgreement","PersonForm","onChangeFio","onChangePhone","isNeedToBlockInvalidFio","actionButtonProps","onLoadSuggestions","suggestFio","suggestions","suggestion","PersonFormComponent","EditableContactsForm","BlockWrap","RequestForm","csrf","selectCsrf","useResultPopup","PopupResult","showResult","setFio","setPhone","unifiedSelectedAddress","addressParams","selectAddressParamsMemoize","gigabitMayConnect","isGigabitCanConnected","requiredGigaSpeed","isGigaSpeedRequired","isTariffCanConnected","onSubmitRequest","ok","submitRequest","street","house","flat","EResultPopupStatus","OneLineAddressInput","AddressInput","withoutFlat","BoldText","Alert","BaseAlert","Block","GrayBlock","RounderContainer","addressFormDispatch","useCtxDispatch","scrollTo","handleChangeAddress","changeAddressClicked","flush","FullBuyST","InfoCircle","ListItemWithIcon","isCompatible","ResultMessage","restrictions","only100Clicked","lessThan1000Clicked","isFullBuyVillage","PolicyNote","agreeUrl","POLICY_PAGE_LINK","$lastIndent","UnifiedAddressForm","FullBuy","FullBuyByPage","isNotNeedGap","RightSide","isLastStage","isOnTimeslots","SkeletonTheme","inline","StageTitle","stageTitle","stageNumber","currentNumber","Skeleton","count","useSendReferrerToGA","action","referrer","withoutOrigin","dataLayerPush","EVENTS","sendReferrer","SInteractiveLoader","InteractiveLoader","parent","root","setRoot","isClientSide","portal","minHeight","createPortal","textItems","agreementCreationStatuses","delay","loopSegmentAtIndex","results","canConnected","getText","hasCallRequest","messageType","notConnected","gigabitError","checkError","flatError","AddressCheckMessage","isNotFlatAddress","isGigabitError","isTariffCanConnect","resultType","EditableForm","onFillAddress","onConfirmBtnClick","defaultAddress","showConfirmButton","withSatelliteFilter","AddressInputFields","catchAddressData","disableCityChange","gtmCategory","gtmSenderCallback","send","AddressWrapper","StyledMenu","STrobber","ContactAddress","showConfirmForm","addressBlockRef","verifiedAddress","editedAddress","editedAddressData","useStorageAddress","onEdit","fillAddressAction","ConfirmedForm","isDisableBtn","Address","displayAdditionalTariffLine","setDisplayAdditionalTariffLine","allowedSpeed","verificationFailed","verificationSuccess","hideBtn","onFillFio","onFillPhone","ContactPerson","popupId","Contacts","confirmPopup","getPopupData","isFIOEnterStarted","setIsFIOEnterStarted","isPhoneEnterStarted","setIsPhoneEnterStarted","_person","startEnterName","fillFioAction","_phone","startEnterPhoneNumber","fillPhoneAction","ConfirmNumberPopup","isShow","onClosePopup","hidePopup","onConfirmed","setConfirmedPhone","dataLayerPushCategory","queryParams","getCitiesTariffs","response","contentRequest","accessMode","getAccessModeByRights","isWebp","isServerSide","Image","onerror","onload","catch","fetchTariffPackages","forCottage","retrieveTariffsFunction","bundles","mono","bundlePackages","isSupportsWebp","getOnlyCottageTariffPackages","getOnlyCityTariffPackages","tariffTransformer","salePackage2in1","is_cottage","getSummaryCheckInfo","connectPrice","oncePaymentSum","monthlyPaymentSum","showPrice","oncePaymentEquipment","connection","monthlyPaymentEquipment","createOfferRequestBody","unifiedAddress","tariffId","productsByProps","summaryCheckInfo","analytics_id","dealerUid","sessionStorage","getItem","DEALER_UID","companyId","office","houseId","unifiedHouseId","personalInformation","clientName","clientPhone","comment","promocodeName","analyticsId","managerId","removeItem","selectDataForCreateAgreement","provider","CreateAgreementScreen","lastStepKey","offerRequestBody","respAgreement","agreementDataString","fromCache","plbRegistrationSuccessful","promoCodeSuccessful","getPackageIdBySubscriptionIds","buildProductsForRequest","getGaId","offerCreate","createAgreement","try","itogInMonth","itogInOnce","getErrorMessage","fail","promocodeActivation","isFromCache","double","success","isInstallationHardware","isTimeSelected","endDot","ESlotsContainerState","SHOW_SLOTS","HIDE_SLOTS","SLOTS_EMPTY","EngineerRequest","failureResponseFromSelectSlot","setFailureResponseFromSelectSlot","errorMsg","slotResult","setSlotResult","isTimeSlotLoading","setIsTimeSlotLoading","hasEquipment","flag","hour","requestData","dateFrom","saleAgentClientName","ESaleAgentClientName","selectTimeSlot","failed","selectTimeSubText","Danger","DateOfServiceEngineerVisitWrapper","getTimeSlotsFunc","saleAgentTimeSlots","onConfirm","prevState","onClickConfirm","start","contractId","withComment","gaCategory","onUpdateLoading","RouterChoiceInfo","marginRight","OrderedList","li","isBackward","prevStepIndex","Equipments","skipEquipmentStep","DecoderInfo","VideoVertical","Forward","VideoAdd","VoiceSquare","EquipmentsTv","sla","engineerText","getEngineerText","howToPrepareText","getHowToPrepareText","isBiggerFont","Electricity","Clock","Final","minutes","padStart","EmployeeVisit","skipPrivateSectorEquipmentStep","getSubscriptionsSummary","currentTariff","activeSubscriptions","alias","active","currentVariant","findIndex","hasNext","nextStep","isLast","WantMoreSubscriptions","initializationByTariffLine","getSubscriptionText","clickMoreSubscriptions","ImageBlock","BenefitsText","Svg","displayImage","fullWidth","visibleByDefault","selectSubscriptionPopup","subscription","fullDescriptionList","getRequiredAndSelectivelySubscriptions","needToSelectMultiple","isOneOfSelected","sbs","cur","ResponseSubscriptionType","oneOf","multiple","initPopupData","selectedSubscription","setState","handleIconClick","TvSubscription","onToggle","listOfActions","imagePath","onIconClick","SubscriptionsAdditionalInfoPopup","handleToggle","RequiredAndSelectivelySubscriptionsContainer","SubscriptionsContainer","skipSubscriptionsStep","CombinedContainerForMainPage","dynamic","CustomSwiper","slideIndex","disableEdgeSwiping","cursorType","React","child","getGradient","colors","leftColor","rightColor","ActiveCardWrapper","BoxShadow","ArrowPositioner","TariffCardMinimal","colorText","bg","PromoText","hasBg","TariffTitle","isSmall","TariffDescription","defaultBg","PropsBlock","DescriptionRow","PriceBlock","Price","OldPrice","channelText","channelPluralize","ArrowPointer","priceAction","promoText","channelCount","imageBackground","titleColors","isLightCard","setCardWidth","preparedSubscriptions","imageWebp","cardBg","descBg","Subscriptions","imageHeight","hasBorderRadius","cardInnerWidth","parentWithOneBtn","parentWithTwoBtn","buttonWidth","renderTariffList","selectedPackageId","withArrowPointer","onSelectTariff","sendAnalytics","image_background_webp","image_background","flatMap","packageLink","accItem","_tariff","sdCount","hdCount","SEquipPreview","EquipPreview","ElementInfo","BasePopup","customScrollBarStyles","customDefaultPopupStyles","withDescTitle","SelectedTariffElements","IncludedTariffElements","requiredProducts","getChannelsTitle","hdCountsTitle","isChannelsPopupOpen","setIsChannelsPopupOpen","setSelectedTariff","downloadSpeed","elementsInfo","setElementInfo","sortedOfferContents","onProductButtonClickHandler","popupOpened","onOfferButtonClickHandler","offer","channelsPopupOpen","channelsPopupClose","isShowChannel","hasTariffElements","isMega","TariffElement","titleText","imageProps","textForImage","bgForImage","imageSrc","imgBgColor","btnProps","btnTextDesktop","iconNameMobile","requiredProduct","isShowButton","image_mobile","ChannelListPopup","freePackets","processEquipment","globalId","contentId","fullBody","shift","getOnlyPurchasePrices","getBodyForRequestEquipment","isOnlyPurchaseEquipment","routers","decoders","privateSectorEquipment","yandex","MultiCheckbox","rest","CheckIcon","CheckboxList","SwitcherWrap","checkboxItems","switcherValues","onClickSwitcher","onClickCheckbox","activeSwitcherTab","MultiCheckboxWithIcon","toggleFilter","currElem","getFilterTags","tagsSet","mySet","tariffTags","add","Set","getFiltersFromTariffsTag","currentFilters","currTariffs","tags","tag","every","getTariffsFilteredByTags","_tariffs","getTariffsFilteredByType","ESwitcherValues","bundle","TariffLineWrapper","TariffLineWrapperFullWidth","TariffInfo","displayTariffLine","_displayTariffLine","getEquipment","useFiltersByTags","defaultDisplayMono","hideSwitcher","firstTariff","setFilters","tariffsByType","setTariffsByType","setFilteredTariffs","setActiveSwitcherTab","changeTariffs","currFilters","filtersByTags","sort_on_bundles","newFilters","onToggleFilter","chooseRecommendedFilter","onToggleSwitcher","newTab","TagFilters","tariffsFilterByTags","swiperKey","chooseRecommended","CombinedSubscriptionContainerForTariffItem","traditionFlow","notTraditionFlow","stepsWithoutRouters","needToExclude","needToLoadSubscriptions","isArray","receiveSubscriptions","getListDescription","fullDescription","getBundleOfSubscriptions","all","subscriptionsBundle","getQueryParams","monoTariff","tariffLine","landingAvailable","initialized","isAddressVerification","isTimeSlotsLoading","setIsTimeSlotsLoading","isFullBuyVillageRedirect","tariffNameAlias","withoutCottageFilters","fetchTariffPackagesQueryParams","f","availableNew","restrictIgnore","initFullBuy","resetAddress","PrivateSectorEquipments","OneLineAddress","Loader","AdditionalEquipment","TariffInfoPageSkeleton","FullBuyAnalytics","FullBuyProvider","FullBuySteps","FullBuyPage","cityText","cityIn","Layout","withMenu","withFooter","withChat","getInitialProps","ctx","validatedAccessToken","store","initialProps","isNeedAuthData","nonPermanentRedirect","ImageElement","ButtonElement","btnTextMobile","iconNameDesktop","iconsSprite","ICONS_PATH","symbolId","imageAlt","imgSrc","ImgWrap","ImageElementWithText","RowWrap","DescriptionWrap","MobileOnlyWrap","DesktopOnlyWrap","withCounts","TitleWrap","Title","Description","_query","_value","ErrorCodeStatus","PROMOCODE_NOT_FOUND","UNKNOWN","makePaymentAuth","EContactDetailTypes","initialState","setWidth","setHeight","handleResize","entries","entry","contentRect","useIsomorphicLayoutEffect","RO","ResizeObserver","requestAnimationFrame","observe","disconnect","DEFAULT_STATE_MAX_CARDS","gap","DATA_SLIDER_PARAMS_DEFAULT","Container","laptop","isSDesktop","isDesktop","isTablet","sLaptop","arrayMedia","maxCardsData","setMaxCardsData","indexOf","currentSliderProps","wrapAround","StylesTab","TabLeft","TabRight","LayoutLeft","translateValue","LayoutRight","args","translateData","isRightTabActive","onClickHandler","ControlTitle","Control","isFocused","innerRef","innerProps","ValueContainer","components","TitleValue","SingleValue","Indicator","DropdownIndicator","defaultValue","minWidth","extStyle","smallOption","customComponents","IndicatorSeparator","Option","SmallOption","BigOption","Menu","MenuList","menu","ReactSelect","isClearable","isSearchable","styles","propTypes","PropTypes","defaultProps","strokeMiterlimit"],"sourceRoot":""}