\n `,\n }}\n />\n );\n};\n","import { styled, theme } from '@notino/react-styleguide';\n\nexport const StoreTitle = styled.p`\n ${theme.typography.labelRegular400}\n margin-bottom: 0.25rem;\n`;\n\nexport const StoreDescription = styled.span`\n font-weight: 300;\n ${theme.typography.labelRegular400}\n color:${theme.color.text.tertiary};\n padding-bottom: 0.25rem;\n`;\n\nexport const StoreStockAvailabilityWrapper = styled.div`\n color: ${theme.color.text.positive};\n ${theme.typography.labelRegular400}\n`;\n","/**\n * @return [tomorrow, date after tomorrow]\n */\nconst getNextTwoDays = (): [Date, Date] => {\n const now = new Date();\n const tomorrowTime = new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate() + 1,\n 0,\n 0,\n 0\n );\n const dayAfterTomorrowTime = new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate() + 2,\n 0,\n 0,\n 0\n );\n return [tomorrowTime, dayAfterTomorrowTime];\n};\n\nexport const isTomorrow = (date: Date) => {\n const timeToCompare = new Date(date).getTime();\n const [tomorrow, dayAfterTomorrow] = getNextTwoDays();\n\n return (\n timeToCompare >= tomorrow.getTime() &&\n timeToCompare < dayAfterTomorrow.getTime()\n );\n};\n\nexport const isToday = (date: Date) => {\n const timeToCompare = new Date(date).getTime();\n const startOfToday = new Date();\n startOfToday.setHours(0, 0, 0, 0);\n const [tomorrow] = getNextTwoDays();\n\n return (\n timeToCompare >= startOfToday.getTime() &&\n timeToCompare < tomorrow.getTime()\n );\n};\n","import { defineMessages } from 'react-intl';\n\nexport const messages = defineMessages({\n chooseStore: {\n id: 'pd.clickandcollect.choose.store',\n defaultMessage: 'Vyberte pobočku',\n },\n pickHere: {\n id: 'pd.clickandcollect.pick.here',\n defaultMessage: 'Vyzvednout zde',\n },\n availableFrom: {\n id: 'pd.clickandcollect.available.from',\n defaultMessage: '{date} od {time}',\n },\n today: {\n id: 'pd.clickandcollect.today',\n defaultMessage: 'dnes',\n },\n tomorrow: {\n id: 'pd.clickandcollect.tomorrow',\n defaultMessage: 'zítra',\n },\n lessThan5: {\n id: 'pd.clickandcollect.lessThan5',\n defaultMessage: '{count} ks',\n },\n moreThan5: {\n id: 'pd.clickandcollect.moreThan5',\n defaultMessage: 'Více než 5 ks',\n },\n moreThan20: {\n id: 'pd.clickandcollect.moreThan20',\n defaultMessage: 'Více než 20 ks',\n },\n pickUpGiftInformation: {\n id: 'pd.clickandcollect.pickUp.gift.information',\n defaultMessage:\n 'Na objednávky prostřednictvím služby Vyzvednout ihned se nevztahují akce dárků zdarma.',\n },\n});\n","import * as React from 'react';\n\nimport { IStore } from '../../model';\n\nimport { StoreStockAvailabilityWrapper } from './styled';\nimport { usePickUpTime } from './usePickupTime';\nimport { useStockCount } from './useStockCount';\n\nexport const StoreStockAvailability = ({\n stockCount,\n earliestPickup,\n}: IStore): JSX.Element => {\n const stockCountMessage = useStockCount(stockCount);\n const pickupTime = usePickUpTime(earliestPickup);\n return (\n
\n {`${stockCountMessage} | ${pickupTime}`}\n \n );\n};\n","import { useIntl } from 'react-intl';\n\nimport { StockAvailability } from '@notino/shared/definitions/types';\n\nimport { messages } from '../../messages';\n\nexport const useStockCount = (stockCount: string): string => {\n const { formatMessage } = useIntl();\n switch (stockCount) {\n case StockAvailability.Last1:\n return formatMessage(messages.lessThan5, { count: 1 });\n case StockAvailability.Last2:\n return formatMessage(messages.lessThan5, { count: 2 });\n case StockAvailability.Last3:\n return formatMessage(messages.lessThan5, { count: 3 });\n case StockAvailability.Last4:\n return formatMessage(messages.lessThan5, { count: 4 });\n case StockAvailability.Last5:\n return formatMessage(messages.lessThan5, { count: 5 });\n case StockAvailability.MoreThan20:\n return formatMessage(messages.moreThan20, {});\n case StockAvailability.MoreThan5:\n return formatMessage(messages.moreThan5, {});\n }\n};\n","import { useIntl } from 'react-intl';\n\nimport { isToday, isTomorrow } from '../../../../utils/dateUtils';\nimport { messages } from '../../messages';\n\nimport { getEarliestPickupDate } from './utils';\n\nexport const usePickUpTime = (earliestPickup: string): string => {\n const { formatTime, formatDate, formatMessage } = useIntl();\n\n const earliestPickupDate = getEarliestPickupDate(new Date(earliestPickup));\n\n const time = formatTime(earliestPickupDate, {\n hour: 'numeric',\n minute: 'numeric',\n });\n\n let dateName: string;\n if (isToday(earliestPickupDate)) {\n dateName = formatMessage(messages.today);\n } else if (isTomorrow(earliestPickupDate)) {\n dateName = formatMessage(messages.tomorrow);\n } else {\n dateName = formatDate(earliestPickupDate, {\n weekday: 'long',\n });\n }\n\n return formatMessage(messages.availableFrom, {\n date: dateName,\n time,\n });\n};\n","/**\n * in case that API returns time in the past, change it to now\n * @param earliestPickup\n */\nexport const getEarliestPickupDate = (earliestPickup: Date) => {\n const now = new Date();\n return earliestPickup > now ? earliestPickup : now;\n};\n","import * as React from 'react';\n\nimport { IStore } from '../../model';\n\nimport { StoreStockAvailability } from './StoreStockAvailability';\nimport { StoreDescription, StoreTitle } from './styled';\n\ninterface IStoreProps {\n data: IStore;\n}\n\nexport const Store: React.FC
= ({ data }) => {\n return (\n <>\n {data.name}\n \n \n >\n );\n};\n","import styled from 'styled-components';\n\nimport {\n ActionButtonWithConfirmation,\n breakpoints,\n theme,\n} from '@notino/react-styleguide';\n\nexport const StoreWrapper = styled.div`\n padding: 1.25rem 0;\n &:not(:last-child) {\n border-bottom: solid 1px ${theme.color.border.disabled};\n }\n &:first-child {\n padding-top: 0;\n }\n`;\nexport const ContentWrapper = styled.div<{\n shouldShowGiftInformationBox: boolean;\n}>`\n overflow-y: auto;\n padding: 1.5rem;\n margin-bottom: ${({ shouldShowGiftInformationBox }) =>\n shouldShowGiftInformationBox ? '8rem' : '4rem'};\n\n @media (min-width: ${breakpoints.md}) {\n max-height: 50vh;\n margin-bottom: 0;\n padding-bottom: 0;\n }\n`;\n\nexport const CenterWrapper = styled.div`\n padding-top: 2.8125rem;\n display: flex;\n justify-content: center;\n`;\n\nexport const ActionButtonWithConfirmationWrapper = styled.div`\n padding: 1rem;\n\n position: fixed;\n bottom: 0;\n left: 0;\n right: 0;\n\n background-color: white;\n\n box-shadow: 0px -2px 4px rgba(0, 0, 0, 0.1);\n\n @media (min-width: ${breakpoints.md}) {\n position: relative;\n padding: 1.5rem;\n }\n`;\n\nexport const StyledActionButtonWithConfirmation = styled(\n ActionButtonWithConfirmation\n)`\n @media (min-width: ${breakpoints.sm}) {\n margin: auto;\n display: block;\n }\n`;\n\nexport const GiftInformationBox = styled.div`\n padding: 0.75rem;\n background-color: ${theme.color.background.secondary};\n\n display: flex;\n gap: 0.5rem;\n\n margin-bottom: 1rem;\n\n svg {\n flex-shrink: 0;\n }\n`;\n","import * as React from 'react';\n\nimport { useMutation, useQuery } from '@apollo/client';\n\nimport {\n AddToClickAndCollectMutation,\n AddToClickAndCollectMutationVariables,\n GetStoresQuery,\n} from '@notino/shared/definitions/types';\n\nimport { useSettings } from '@containers/ProductDetailContainer/hooks/useSettings';\n\nimport addToClickAndCollectMutation from './mutations/addToClickAndCollect.graphql';\nimport getStoresQuery from './queries/stores.graphql';\nimport { redirectToClickAndCollectCart } from './utils';\n\nexport const useClickAndCollect = (variantId: number) => {\n const { Settings: { isNewShoppingCartEndpointEnabled: isNewEndpoint } = {} } =\n useSettings();\n\n const { data: stores, loading: storesLoading } = useQuery(\n getStoresQuery,\n {\n variables: { productId: variantId },\n }\n );\n\n const [addToClickAndCollectCart, addToClickAndCollectData] = useMutation<\n AddToClickAndCollectMutation,\n AddToClickAndCollectMutationVariables\n >(addToClickAndCollectMutation, {\n onCompleted: (response) => {\n redirectToClickAndCollectCart(\n response.addProductToClickAndCollect.cartId,\n isNewEndpoint\n );\n },\n });\n\n const handleAddToClickAndCollect = React.useCallback(\n async (warehouseCode: string) => {\n await addToClickAndCollectCart({\n variables: {\n productId: variantId,\n warehouseCode: warehouseCode,\n },\n });\n },\n [addToClickAndCollectCart, variantId]\n );\n\n return React.useMemo(\n () => ({\n stores,\n storesLoading,\n handleAddToClickAndCollect,\n addToClickAndCollectData,\n }),\n [\n stores,\n storesLoading,\n handleAddToClickAndCollect,\n addToClickAndCollectData,\n ]\n );\n};\n","import * as React from 'react';\nimport { FormattedMessage } from 'react-intl';\n\nimport { snakeCase } from 'lodash';\n\nimport {\n ButtonModel,\n IconSolidInfo,\n RadioButton,\n Spinner,\n Text,\n} from '@notino/react-styleguide';\nimport {\n GetCatalogProductViewQuery,\n StockAvailability,\n} from '@notino/shared/definitions/types';\nimport { CartType } from '@notino/web-tracking';\n\nimport { useModifaceVariants } from '@containers/ProductDetailContainer/ProductDetail/hooks/useModifaceVariants';\nimport { usePriceLogic } from '@containers/ProductDetailContainer/ProductDetail/hooks/usePriceLogic';\nimport {\n MIN_PRICE_PROMO_LABEL,\n RRP_PRICE_PROMO_LABEL,\n} from '@containers/ProductDetailContainer/ProductDetail/hooks/usePriceLogic/tracking';\nimport { useProductDetailContext } from '@containers/ProductDetailContainer/ProductDetail/ProductDetailContext';\nimport { useFeatureFlags } from '@context/featureFlags/FeatureFlagsProvider';\nimport { dispatchTrackingEvent } from '@context/tracking/utils';\nimport { ProductEventWither } from '@helpers/googleTagManager';\n\nimport { getRenderableDiscoBoxSampleId } from '../../DiscoveryBoxSelfChoice';\nimport { getGiftCampaigns } from '../../Gift';\n\nimport { Store } from './components/Store';\nimport { useTrackModalOrDrawerShow } from './hooks/useTrackModalShow';\nimport { messages } from './messages';\nimport {\n ContentWrapper,\n StoreWrapper,\n CenterWrapper,\n StyledActionButtonWithConfirmation,\n ActionButtonWithConfirmationWrapper,\n GiftInformationBox,\n} from './styled';\nimport { useClickAndCollect } from './useClickAndCollect';\n\ninterface IClickAndCollectContentProps {\n product: GetCatalogProductViewQuery['productDetailByCatalogMasterId'];\n selectedVariant: GetCatalogProductViewQuery['productDetailByCatalogMasterId']['variants'][number];\n}\n\nexport const ClickAndCollectContent = ({\n selectedVariant,\n product,\n}: IClickAndCollectContentProps) => {\n const [selectedStore, setSelectedStore] = React.useState('');\n const { rrpShown, minimalPriceShown } = usePriceLogic(selectedVariant);\n const flags = useFeatureFlags();\n\n const { giftCampaigns } = getGiftCampaigns({\n product,\n variant: selectedVariant,\n });\n\n const shouldShowGiftInformationBox = giftCampaigns?.length > 0;\n\n const {\n tryItFirstAvailable,\n engravingAvailable,\n product: { variants },\n } = useProductDetailContext();\n const modifaceVariants = useModifaceVariants(variants);\n\n const {\n stores,\n storesLoading,\n handleAddToClickAndCollect,\n addToClickAndCollectData: {\n loading: addToCnCLoading,\n error: addToCnCError,\n },\n } = useClickAndCollect(Number(selectedVariant.webId));\n\n useTrackModalOrDrawerShow();\n\n if (storesLoading) {\n return (\n \n \n \n );\n }\n\n const onRadioButtonClick = (storeId: string) => () => {\n setSelectedStore(storeId);\n };\n\n const handleSubmit = async () => {\n dispatchTrackingEvent({\n event: 'add_to_cart',\n product: ProductEventWither()\n .withProduct(product)\n .withVariant(selectedVariant)\n .withServices({\n modifaceVariants,\n tryItFirstAvailable,\n engravingAvailable,\n discoveryBoxAvailable: Boolean(\n getRenderableDiscoBoxSampleId(product, selectedVariant, flags)\n ),\n })\n .withAdditionalData({\n quantity: 1,\n cart_type: snakeCase(CartType.clickAndCollect),\n })\n .withAdditionalPromoLabels([\n rrpShown && RRP_PRICE_PROMO_LABEL,\n minimalPriceShown && MIN_PRICE_PROMO_LABEL,\n ])\n .build(),\n _clear: true,\n });\n\n await handleAddToClickAndCollect(selectedStore);\n };\n\n return (\n <>\n \n {stores?.collectStoresByProductId?.map((store) => {\n const outOfStock = store.stockCount === StockAvailability.OutOfStock;\n if (outOfStock) {\n return null;\n }\n\n return (\n \n \n \n \n \n );\n })}\n \n\n \n {shouldShowGiftInformationBox && (\n \n \n \n \n \n \n )}\n\n \n \n \n \n >\n );\n};\n","import * as React from 'react';\n\nimport { useTrackingContext } from '@context/tracking/TrackingContext';\nimport { dispatchTrackingEvent } from '@context/tracking/utils';\n\nexport const useTrackModalOrDrawerShow = () => {\n const { getTimeFromInit } = useTrackingContext();\n\n React.useEffect(() => {\n dispatchTrackingEvent({\n event: 'subpage_view',\n subpage: {\n name: 'click_and_collect_modal',\n interaction: 'automatic',\n timing: getTimeFromInit(),\n action: 'click_and_collect_opened',\n type: 'click_and_collect',\n },\n _clear: true,\n });\n }, [getTimeFromInit]);\n};\n","export const redirectToClickAndCollectCart = (\n cartId: string,\n isNewEndpoint: boolean\n) => {\n window.location.href = isNewEndpoint\n ? `/reservation/${cartId}`\n : `/reservation-1/${cartId}`;\n};\n","import { TrackingAttributes } from '@context/tracking/types';\nimport { dispatchTrackingEvent } from '@context/tracking/utils';\n\nexport const trackModalOrDrawerClose = ({\n timing,\n}: Omit) => {\n dispatchTrackingEvent({\n event: 'element_click',\n element: {\n name: 'click_and_collect',\n interaction: 'click',\n action: 'close_click_and_collect',\n timing,\n mode: 'off',\n type: 'product_detail',\n promo_labels: undefined,\n },\n _clear: true,\n });\n};\n\nexport const trackModalOrDrawerOpen = ({\n timing,\n}: Omit) => {\n dispatchTrackingEvent({\n event: 'element_click',\n element: {\n name: 'click_and_collect',\n interaction: 'click',\n action: 'open_click_and_collect',\n timing,\n mode: 'on',\n type: 'product_detail',\n promo_labels: undefined,\n },\n _clear: true,\n });\n};\n","import { defineMessages } from 'react-intl';\n\nexport const messages = defineMessages({\n pickupNow: {\n id: 'pd.clickandcollect.pickup.now',\n defaultMessage: 'Vyzvednout ihned',\n },\n});\n","import styled, { css } from 'styled-components';\n\nimport { breakpoints, Button, theme } from '@notino/react-styleguide';\n\nexport const PickUpButtonWrapper = styled.div`\n margin-top: 0.5rem;\n flex: 0 1 100%;\n @media (min-width: ${breakpoints.sm}) {\n margin-top: 0;\n flex: auto;\n }\n`;\n\nexport const PickUpButton = styled(Button)<{ newDesign: boolean }>`\n width: 100%;\n ${({ newDesign }) =>\n newDesign\n ? css`\n height: 3.25rem;\n ${theme.typography.labelRegular}\n `\n : css`\n @media (min-width: ${breakpoints.sm}) {\n width: auto;\n }\n `}\n`;\n","import * as React from 'react';\nimport { FormattedMessage, useIntl } from 'react-intl';\n\nimport {\n ButtonModel,\n ModalContext,\n Text,\n useBreakpointValue,\n} from '@notino/react-styleguide';\nimport { GetCatalogProductViewQuery } from '@notino/shared/definitions/types';\n\nimport { useDrawer } from '@components/BottomSheet/DrawerProvider';\nimport { useTrackingContext } from '@context/tracking/TrackingContext';\n\nimport { useNewPdDesignEnabled } from '../../hooks/useNewPdDesignEnabled';\n\nimport { ClickAndCollectContent } from './Content';\nimport { messages as modalMessages } from './Content/messages';\nimport {\n trackModalOrDrawerClose,\n trackModalOrDrawerOpen,\n} from './gtm/tracking';\nimport { messages } from './messages';\nimport { PickUpButton, PickUpButtonWrapper } from './styled';\n\ntype IClickAndCollectProps = {\n selectedVariant: GetCatalogProductViewQuery['productDetailByCatalogMasterId']['variants'][number];\n product: GetCatalogProductViewQuery['productDetailByCatalogMasterId'];\n onModalClosing: () => void;\n disabled?: boolean;\n};\n\nexport const ClickAndCollect: React.FC = ({\n selectedVariant,\n product,\n onModalClosing,\n disabled = false,\n}) => {\n const newDesign = useNewPdDesignEnabled();\n const { formatMessage } = useIntl();\n const { getTimeFromInit } = useTrackingContext();\n const isDesktop = useBreakpointValue({ md: true });\n const { toggleModal, hideModal } = ModalContext.useModalContext();\n const { toggleDrawer } = useDrawer();\n const header = formatMessage(modalMessages.chooseStore);\n\n const onOpenClickAndCollectModalOrDrawer = React.useCallback(() => {\n trackModalOrDrawerOpen({ timing: getTimeFromInit() });\n\n if (!isDesktop) {\n toggleDrawer(\n ,\n {\n header,\n onDismiss: () =>\n trackModalOrDrawerClose({ timing: getTimeFromInit() }),\n }\n );\n return;\n }\n\n const handleCloseTracking = () => {\n hideModal();\n trackModalOrDrawerClose({ timing: getTimeFromInit() });\n onModalClosing();\n };\n\n toggleModal(\n ,\n {\n header: {header},\n center: true,\n withFocusTrap: true,\n onClose: handleCloseTracking,\n noBorders: true,\n onlyTopBorder: true,\n }\n );\n }, [\n getTimeFromInit,\n isDesktop,\n toggleModal,\n selectedVariant,\n product,\n header,\n toggleDrawer,\n hideModal,\n onModalClosing,\n ]);\n\n return (\n \n \n \n \n \n );\n};\n","export const REGISTER_URL = '/myaccount.asp#registration';\nexport const MY_NOTINO_BENEFIT_PAGE = '/mynotino/my-benefits/';\n\nexport const STANDARD_MODAL_IMAGE_PATH =\n 'https://cdn.notinoimg.com/images/gallery/loyalty/new-vip-modal.jpg';\nexport const RETINA_MODAL_IMAGE_PATH =\n 'https://cdn.notinoimg.com/images/gallery/loyalty/new-vip-modal-retina.jpg';\nexport const MOBILE_MODAL_IMAGE_PATH =\n 'https://cdn.notinoimg.com/images/gallery/loyalty/mobile-vip-modal.jpg';\n","import { dispatchTrackingEvent } from '@context/tracking/utils';\n\nimport { FullfilledSteps } from './components/HowToLoyaltyDiscountModal';\n\nexport enum LoyaltyStatus {\n nonRegistered = 'non-registered',\n registered = 'registered',\n subscribed = 'subscribed',\n activated = 'activated',\n unsubscribed = 'unsubscribed',\n}\n\nexport const determineStatus = (fullfilledSteps: FullfilledSteps) => {\n let status = LoyaltyStatus.nonRegistered;\n\n if (fullfilledSteps.registerStep) {\n status = LoyaltyStatus.registered;\n }\n\n if (fullfilledSteps.registerStep && fullfilledSteps.newsletterStep) {\n status = LoyaltyStatus.subscribed;\n }\n\n if (\n fullfilledSteps.registerStep &&\n fullfilledSteps.chooseBrandAndCategoryStep &&\n !fullfilledSteps.newsletterStep\n ) {\n status = LoyaltyStatus.unsubscribed;\n }\n\n return status;\n};\n\nexport const trackLoyaltyModalOpen = (\n status: LoyaltyStatus,\n timing: number\n) => {\n dispatchTrackingEvent({\n event: 'subpage_view',\n _clear: true,\n subpage: {\n name: `/overlay_vip-discount/${status}/`,\n action: 'open_vip_overlay',\n interaction: 'click',\n type: 'service',\n title: 'VIP program',\n timing,\n },\n });\n};\n\nexport const trackLoyaltyModalClose = () =>\n dispatchTrackingEvent({\n event: 'subpage_close',\n subpage: undefined,\n _clear: true,\n });\n","import{_ as e}from\"./_rollupPluginBabelHelpers-c70560be.js\";import*as l from\"react\";import{Pictogram as m}from\"./utils/index.js\";import\"./getSemanticColor.js\";import\"./theme.js\";var t=function(t){return l.createElement(m,e({},t,{viewBox:\"0 0 256.62 256\"}),l.createElement(\"path\",{fill:\"#6e6e6e\",d:\"M201.7,52.25H67.58L13.77,111,134.64,256,255.51,111ZM137.18,113.1H172l-20.43,72.12Zm-19.51,72.12L97.24,113.1H132.1ZM97,108.94,102.77,76l27.42,32.91Zm42.12,0L166.51,76l5.8,32.91Zm37.45,0L171,77.37l29.71,31.57Zm-41.9-1.18L104.58,71.69l30.06-15,30.06,15Zm-41.9,1.18H68.6L98.31,77.37Zm.17,4.16,19.15,67.61L67.64,113.1Zm41.73,8.54L149.12,194,134.64,245.1,120.17,194Zm41.73-8.54h25.27l-44.42,67.61Zm28-6.33L170.7,71l11.73-14.07L212.55,72Zm11.13-29.12,12.89,31.29H208.13ZM167.44,68.4l-24-12h34Zm-65.6,0-10-12h34ZM98.58,71,64.92,106.77,56.73,72,86.85,56.93ZM61.15,108.94H40.9L53.79,77.65Zm1,4.16L82.8,187.28l-5.48-6.57-36-67.61Zm7.16,10.19L115.84,194,130,243.88,89.29,195.07ZM153.44,194l46.49-70.75L180,195.07l-40.68,48.81Zm53.65-80.94H228l-36,67.61-5.48,6.57Zm25.65,0H248.3L205.07,165Zm.14-4.16L220.54,79l27.47,30ZM207.61,64.86l-16.9-8.45h9.15ZM69.42,56.41h9.15l-16.9,8.45ZM48.74,79l-12.34,30H21.27ZM36.54,113.1,64.21,165,21,113.1Z\"}),l.createElement(\"polygon\",{fill:\"#dc0069\",points:\"42.52 56.69 48.19 34.01 70.86 28.34 48.19 22.68 42.52 0 36.85 22.68 14.17 28.34 36.85 34.01 42.52 56.69\"}),l.createElement(\"polygon\",{fill:\"#6e6e6e\",points:\"18.9 87.4 22.68 72.28 37.79 68.5 22.68 64.72 18.9 49.6 15.12 64.72 0 68.5 15.12 72.28 18.9 87.4\"}),l.createElement(\"polygon\",{fill:\"#dc0069\",points:\"226.76 56.69 229.6 45.35 240.94 42.52 229.6 39.68 226.76 28.34 223.93 39.68 212.59 42.52 223.93 45.35 226.76 56.69\"}),l.createElement(\"polygon\",{fill:\"#6e6e6e\",points:\"108.66 44.88 111.49 33.54 122.83 30.71 111.49 27.87 108.66 16.54 105.82 27.87 94.48 30.71 105.82 33.54 108.66 44.88\"}))};export{t as PictogramRegularDiamond};\n//# sourceMappingURL=PictogramRegularDiamond.js.map\n","import { defineMessages } from 'react-intl';\n\nexport const messages = defineMessages({\n imgAlt: {\n id: 'pd.loyalty.modal.img.alt',\n defaultMessage: 'zákaznická sleva',\n },\n});\n","import styled, { css } from 'styled-components';\n\nimport {\n Heading,\n breakpoints,\n ImagePlaceholder,\n theme,\n} from '@notino/react-styleguide';\n\nexport const ModalHeader = styled(Heading.H3)`\n text-align: left;\n margin: 0 auto;\n ${theme.typography.titleLarge}\n`;\n\nexport const DiamondIconWrapper = styled.div`\n display: flex;\n flex-basis: 20%;\n height: 100%;\n`;\n\nexport const ModalContent = styled.div`\n display: flex;\n flex-direction: column;\n text-align: center;\n max-height: 90vh;\n\n @media (min-width: ${breakpoints.md}) {\n flex-direction: row-reverse;\n height: auto;\n }\n\n flex-direction: column-reverse;\n max-height: 80vh;\n overflow-y: auto;\n`;\n\nexport const ContentWrapper = styled.div`\n width: 100%;\n padding: 2rem 0;\n\n @media (min-width: ${breakpoints.md}) {\n width: 50%;\n }\n`;\n\nexport const TextContentWrapper = styled.div`\n display: flex;\n padding: 1rem;\n\n @media (min-width: ${breakpoints.md}) {\n padding: 2rem;\n }\n\n padding: 0 1.25rem 1.5rem;\n flex-direction: column;\n gap: 1rem;\n\n @media (min-width: ${breakpoints.md}) {\n padding: 0 2rem 1.5rem;\n }\n`;\n\nexport const InfoWrapper = styled.div`\n flex-basis: 75%;\n\n @media (min-width: ${breakpoints.md}) {\n flex-basis: 80%;\n }\n`;\n\nexport const ImageWrapper = styled.div<{ hideOnMobile: boolean }>`\n display: flex;\n justify-content: center;\n align-items: flex-start;\n overflow: hidden;\n\n ${({ hideOnMobile }) =>\n hideOnMobile &&\n css`\n display: none;\n `}\n\n @media (min-width: ${breakpoints.md}) {\n display: flex;\n align-items: center;\n }\n`;\n\nexport const StyledImagePlaceholder = styled(ImagePlaceholder)`\n min-width: 100%;\n min-height: 100%;\n`;\n","import * as React from 'react';\nimport { useIntl } from 'react-intl';\n\nimport { PictogramRegularDiamond } from '@notino/react-styleguide';\n\nimport { useIsDesktop } from '@utils/helpers';\n\nimport {\n STANDARD_MODAL_IMAGE_PATH,\n RETINA_MODAL_IMAGE_PATH,\n MOBILE_MODAL_IMAGE_PATH,\n} from '../../constants';\n\nimport { messages } from './messages';\nimport {\n ModalHeader,\n ModalContent,\n TextContentWrapper,\n DiamondIconWrapper,\n InfoWrapper,\n ContentWrapper,\n ImageWrapper,\n StyledImagePlaceholder,\n} from './styled';\n\ninterface IBaseLoyaltyModalProps {\n headerMessage: string;\n children: JSX.Element;\n footerContent: JSX.Element;\n hideImageOnMobile?: boolean;\n}\n\nexport const BaseLoyaltyModal: React.FC = ({\n headerMessage,\n children,\n footerContent,\n hideImageOnMobile,\n}) => {\n const { formatMessage } = useIntl();\n const isDesktop = useIsDesktop();\n\n return (\n \n \n \n \n \n \n \n {headerMessage}\n {children}\n \n \n {footerContent}\n \n \n \n \n \n );\n};\n","import styled from 'styled-components';\n\nimport { Button } from '@notino/react-styleguide';\n\nexport const StyledButton = styled(Button)`\n padding: 0 3rem;\n`;\n","import { defineMessages, MessageDescriptor } from 'react-intl';\n\nexport const benefitsModalTableMessages: {\n [key: string]: MessageDescriptor;\n} = defineMessages({\n notChosen: {\n id: 'pd.loyalty.benefits.modal.table.not.chosen',\n defaultMessage: 'nevybráno',\n },\n ok: {\n id: 'pd.loyalty.benefits.modal.ok',\n defaultMessage: 'Ok',\n },\n settings: {\n id: 'pd.loyalty.benefits.modal.settings',\n defaultMessage: 'Nastavení',\n },\n});\n","import styled from 'styled-components';\n\nimport { theme } from '@notino/react-styleguide';\n\nexport const BenefitsModalTableWrapper = styled.div``;\n\ninterface IBenefitsModalTableLineProps {\n isOpaque?: boolean;\n}\n\nexport const BenefitsModalTableLine = styled.div`\n display: flex;\n justify-content: space-between;\n padding: 0.5rem 0 0.5rem 0.5rem;\n border-bottom: 1px solid ${theme.color.border.divider};\n opacity: ${({ isOpaque }) => (isOpaque ? '0.5' : '1')};\n`;\n\nexport const BrandName = styled.span`\n text-align: left;\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n width: 75%;\n`;\n","import * as React from 'react';\nimport { FormattedMessage } from 'react-intl';\n\nimport { GetCustomerBenefitsQuery } from '@notino/shared/definitions/types';\n\nimport { benefitsModalTableMessages } from './messages';\nimport {\n BenefitsModalTableLine,\n BenefitsModalTableWrapper,\n BrandName,\n} from './styled';\n\ninterface IBenefitsModalTableProps {\n customerBenefits: GetCustomerBenefitsQuery['customerBenefits'];\n}\n\nexport const BenefitsModalTable: React.FC = ({\n customerBenefits,\n}) => {\n const availableDiscounts = new Array(\n customerBenefits.brandDiscountLimit +\n customerBenefits.categoryDiscountLimit -\n (customerBenefits.brandDiscounts.length +\n customerBenefits.categoryDiscounts.length)\n ).fill(0);\n\n return (\n \n {customerBenefits.brandDiscounts.map((brandDiscount) => (\n \n \n {brandDiscount.subjectName}\n \n -{brandDiscount.value}%\n \n ))}\n {customerBenefits.categoryDiscounts.map((brandDiscount) => (\n \n \n {brandDiscount.subjectName}\n \n -{brandDiscount.value}%\n \n ))}\n {availableDiscounts.map((_, i) => (\n // eslint-disable-next-line react/no-array-index-key\n \n \n \n \n 0%\n \n ))}\n \n );\n};\n","import { defineMessages } from 'react-intl';\n\nexport const benefitsModalMessages = defineMessages({\n header: {\n id: 'pd.benefits.modal.header',\n defaultMessage: 'Vaše oblíbené značky a kategorie se slevou',\n },\n});\n","import styled from 'styled-components';\n\nimport { breakpoints, theme } from '@notino/react-styleguide';\n\nexport const BenefitsModalContentWrapper = styled.div`\n margin-top: 1rem;\n @media (min-width: ${breakpoints.sm}) {\n width: 75%;\n }\n`;\n\nexport const ButtonWrapper = styled.div`\n margin: 1rem 0 0.5rem 0;\n display: flex;\n justify-content: center;\n`;\n\nexport const SettingsWrapper = styled.a`\n margin-top: 0.5rem;\n text-decoration: underline;\n text-align: center;\n cursor: pointer;\n color: ${theme.color.text.primary};\n &:hover {\n text-decoration: none;\n }\n`;\n\nexport const FooterContent = styled.div`\n display: flex;\n flex-direction: column;\n padding: 0 1.25rem;\n button {\n width: 100%;\n }\n\n @media (min-width: ${breakpoints.md}) {\n padding: 0 2rem;\n align-items: flex-start;\n }\n`;\n","import * as React from 'react';\nimport { FormattedMessage, useIntl } from 'react-intl';\n\nimport { useQuery } from '@apollo/client';\n\nimport { ButtonModel, ModalContext } from '@notino/react-styleguide';\nimport { GetCustomerBenefitsQuery } from '@notino/shared/definitions/types';\n\nimport { dispatchTrackingEvent } from '@context/tracking/utils';\n\nimport { MY_NOTINO_BENEFIT_PAGE } from '../../constants';\nimport getCustomerBenefitsQuery from '../../queries/getCustomerBenefits.graphql';\nimport {\n LoyaltyStatus,\n trackLoyaltyModalClose,\n trackLoyaltyModalOpen,\n} from '../../trackLoyaltyModal';\nimport { BaseLoyaltyModal } from '../BaseLoyaltyModal';\nimport { StyledButton } from '../styled';\n\nimport { BenefitsModalTable } from './BenefitsModalTable';\nimport { benefitsModalTableMessages } from './BenefitsModalTable/messages';\nimport { benefitsModalMessages } from './messages';\nimport {\n BenefitsModalContentWrapper,\n ButtonWrapper,\n FooterContent,\n SettingsWrapper,\n} from './styled';\n\nexport const BenefitsModal: React.FC<{ timing: number }> = ({ timing }) => {\n const { formatMessage } = useIntl();\n const { hideModal } = ModalContext.useModalContext();\n\n const { data } = useQuery(getCustomerBenefitsQuery);\n\n React.useEffect(() => {\n trackLoyaltyModalOpen(LoyaltyStatus.activated, timing);\n }, [timing]);\n\n const handleSettingsClick = () => {\n dispatchTrackingEvent({\n event: 'vip_overlay_cta',\n vip: {\n action: 'click_on_overlay',\n name: 'change_settings',\n },\n });\n };\n\n const handleOkClick = () => {\n trackLoyaltyModalClose();\n hideModal();\n };\n\n return (\n \n \n \n \n \n \n \n \n \n \n }\n >\n \n {data?.customerBenefits && (\n \n \n \n )}\n
\n \n );\n};\n","import { defineMessages } from 'react-intl';\n\nexport const messages = defineMessages({\n howToGetLoyaltyDiscountHeader: {\n id: 'pd.loyalty.discount.how.to.header',\n defaultMessage: 'Kupujte oblíbené značky a kategorie se slevou',\n },\n registerStep: {\n id: 'pd.loyalty.discount.how.to.register',\n defaultMessage: 'Registrujte se',\n },\n newsletterStep: {\n id: 'pd.loyalty.discount.how.to.newsletter',\n defaultMessage: 'Odebírejte náš newsletter',\n },\n chooseBrandAndCategoryStep: {\n id: 'pd.loyalty.discount.how.to.choose.brand.category',\n defaultMessage: 'Vyberte si 3 značky a kategorii',\n },\n alreadyHaveAccount: {\n id: 'pd.loyalty.discount.how.to.already.have.account',\n defaultMessage: 'Již máte účet?',\n },\n logIn: {\n id: 'pd.loyalty.discount.how.to.log.in',\n defaultMessage: 'Přihlásit se',\n },\n registerNow: {\n id: 'pd.loyalty.discount.how.to.register.now',\n defaultMessage: 'Registrovat se',\n },\n setUpNow: {\n id: 'pd.loyalty.discount.how.to.set.up.now',\n defaultMessage: 'Nastavit',\n },\n});\n","import styled from 'styled-components';\n\nimport { breakpoints, theme } from '@notino/react-styleguide';\n\nexport const LoginWrapper = styled.div`\n text-align: center;\n margin-top: 1rem;\n color: ${theme.color.text.secondary};\n`;\n\nexport const LoginLink = styled.a`\n cursor: pointer;\n text-decoration: underline;\n color: ${theme.color.text.secondary};\n margin-left: 0.5rem;\n\n &:hover {\n text-decoration: none;\n }\n\n color: ${theme.color.text.primary};\n font-weight: 500;\n`;\n\nexport const StepProgressCircle = styled.div<{\n isFulfilled: boolean;\n}>`\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.125rem;\n height: 1.125rem;\n background: ${(props) =>\n props.isFulfilled\n ? theme.color.background.inverse\n : theme.color.background.tertiary};\n border-radius: 50%;\n margin-right: 1.125rem;\n width: 1.25rem;\n height: 1.25rem;\n`;\n\nexport const StepWrapper = styled.span`\n display: flex;\n width: 100%;\n margin: 1rem auto;\n text-align: left;\n\n &:first-child {\n margin: 0.75rem 0 0.5rem;\n }\n &:last-child {\n margin: 0;\n }\n margin: 0 0 0.5rem;\n`;\n\nexport const FooterContent = styled.div`\n display: flex;\n flex-direction: column;\n padding: 0 1.25rem;\n @media (min-width: ${breakpoints.md}) {\n padding: 0 2rem;\n align-items: flex-start;\n }\n`;\n","import { dispatchTrackingEvent } from '@context/tracking/utils';\n\nexport const trackLoyaltyCTA = (\n eventName: 'register' | 'log_in' | 'change_settings'\n) => {\n dispatchTrackingEvent({\n event: 'vip_overlay_cta',\n vip: {\n action: 'click_on_overlay',\n name: eventName,\n },\n });\n};\n","import * as React from 'react';\nimport { FormattedMessage, useIntl } from 'react-intl';\n\nimport { useQuery } from '@apollo/client';\n\nimport {\n ButtonModel,\n IconRegularCheckmark,\n IconRegularClose,\n} from '@notino/react-styleguide';\nimport {\n Roles,\n GetCustomerBenefitsQuery,\n GetUserLoyaltyProgressQuery,\n} from '@notino/shared/definitions/types';\n\nimport { LOGIN_URL } from '@constants';\n\nimport { MY_NOTINO_BENEFIT_PAGE, REGISTER_URL } from '../../constants';\nimport getCustomerBenefitsQuery from '../../queries/getCustomerBenefits.graphql';\nimport {\n determineStatus,\n trackLoyaltyModalOpen,\n} from '../../trackLoyaltyModal';\nimport { BaseLoyaltyModal } from '../BaseLoyaltyModal';\nimport { StyledButton } from '../styled';\n\nimport { messages } from './messages';\nimport getUserLoyaltyProgressQuery from './queries/getUserLoyaltyProgress.graphql';\nimport {\n LoginWrapper,\n LoginLink,\n StepProgressCircle,\n StepWrapper,\n FooterContent,\n} from './styled';\nimport { trackLoyaltyCTA } from './trackLoyaltyCTA';\n\nenum HowToGetDiscountSteps {\n Register = 'registerStep',\n Newsletter = 'newsletterStep',\n ChooseBrandAndCategory = 'chooseBrandAndCategoryStep',\n}\n\nexport type FullfilledSteps = Record;\n\nexport const HowToLoyaltyModal: React.FC<{ timing: number }> = ({ timing }) => {\n const { formatMessage } = useIntl();\n const { data: getUser, loading: getUserLoading } =\n useQuery(getUserLoyaltyProgressQuery);\n\n const { data: checkCustomerBenefitsResult } =\n useQuery(getCustomerBenefitsQuery);\n\n const brandDiscountsSelected =\n checkCustomerBenefitsResult?.customerBenefits?.brandDiscounts?.length > 0;\n const categoryDiscountsSelected =\n checkCustomerBenefitsResult?.customerBenefits?.categoryDiscounts?.length >\n 0;\n\n const fulfilledSteps = React.useMemo(\n () => ({\n [HowToGetDiscountSteps.Register]:\n getUser && getUser.user ? getUser.user.role !== Roles.Anonymous : false,\n [HowToGetDiscountSteps.Newsletter]: getUser?.isUserSubscribed ?? false,\n [HowToGetDiscountSteps.ChooseBrandAndCategory]: Boolean(\n brandDiscountsSelected || categoryDiscountsSelected\n ),\n }),\n [brandDiscountsSelected, categoryDiscountsSelected, getUser]\n );\n\n const onButtonClick = () => {\n if (!fulfilledSteps.registerStep) {\n trackLoyaltyCTA('register');\n location.href = REGISTER_URL;\n } else {\n trackLoyaltyCTA('change_settings');\n location.href = MY_NOTINO_BENEFIT_PAGE;\n }\n };\n\n const handleLoginClick = () => {\n trackLoyaltyCTA('log_in');\n };\n\n React.useEffect(() => {\n if (!getUserLoading) {\n trackLoyaltyModalOpen(determineStatus(fulfilledSteps), timing);\n }\n }, [fulfilledSteps, timing, getUserLoading]);\n\n return (\n \n \n {fulfilledSteps.registerStep ? (\n \n ) : (\n \n )}\n \n {!fulfilledSteps.registerStep && (\n \n \n \n \n \n \n )}\n \n )\n }\n >\n \n {Object.values(HowToGetDiscountSteps).map((step) => (\n \n \n {fulfilledSteps[step] ? (\n \n ) : (\n \n )}\n \n \n \n ))}\n
\n \n );\n};\n","import { defineMessages } from 'react-intl';\n\nexport const messages = defineMessages({\n possibleDiscount: {\n id: 'pd.loyalty.discount.possible.discount',\n defaultMessage: 'Chci slevu {value}',\n },\n customerDiscountBold: {\n id: 'pd.loyalty.discount.customer.discount.bold',\n defaultMessage: 'Vaše sleva {value}',\n },\n customerDiscount: {\n id: 'pd.loyalty.discount.customer.discount',\n defaultMessage:\n '{customerDiscountBold} na {subjectType} {discountSubject} se uplatní v košíku. {more}',\n },\n moreDiscountInfo: {\n id: 'pd.loyalty.discount.more.discount.info',\n defaultMessage: 'Více',\n },\n categoryDiscount: {\n id: 'pd.loyalty.discount.category.discount',\n defaultMessage: 'kategorii',\n },\n brandDiscount: {\n id: 'pd.loyalty.discount.brand.discount',\n defaultMessage: 'značku',\n },\n});\n","import styled, { css } from 'styled-components';\n\nimport { IconRegularDiamond, theme } from '@notino/react-styleguide';\n\ninterface LoyaltyDiscountStyledWrapperProps {\n isCustomerDiscount: boolean;\n newDesign: boolean;\n}\n\nexport const LoyaltyDiscountStyledWrapper = styled.button`\n display: flex;\n align-items: center;\n font-size: 0.9rem;\n text-decoration: ${({ isCustomerDiscount }) =>\n isCustomerDiscount ? 'none' : 'underline'};\n cursor: pointer;\n background: none;\n border: none;\n color: #000 !important;\n &:hover {\n text-decoration: none;\n }\n\n ${({ newDesign }) =>\n newDesign &&\n css`\n color: ${theme.color.text.secondary} !important;\n `}\n`;\n\nexport const CustomerDiscountWrapper = styled.span`\n text-decoration: underline;\n &:hover {\n text-decoration: none;\n }\n`;\n\nexport const StyledDiamondIcon = styled(IconRegularDiamond)`\n margin-right: 1rem;\n`;\n\nexport const CustomerDiscountBoldWrapper = styled.span`\n font-weight: 600;\n`;\n","import{_ as e}from\"./_rollupPluginBabelHelpers-c70560be.js\";import*as t from\"react\";import{I as r}from\"./index-3097346b.js\";import\"./getSemanticColor.js\";import\"./theme.js\";var l=function(l){return t.createElement(r,e({},l,{viewBox:\"0 0 68 64\"}),t.createElement(\"path\",{fill:\"#6e6e6e\",d:\"M48.27,12.69H18.85L8.31,28.11,33.56,63.9,58.81,28.11ZM32.17,54.4l-17-24.14H35.51Zm7.72-24.14H52L36.93,51.6Zm12.17-4.34H39.4l-4-8.89H46ZM21.14,17h9.49l4,8.89H15.06Z\"}),t.createElement(\"rect\",{fill:\"#6e6e6e\",x:\"2.59\",y:\"13.57\",width:\"4.34\",height:\"8.78\",transform:\"translate(-11.31 8.63) rotate(-45)\"}),t.createElement(\"rect\",{fill:\"#dc0069\",x:\"14.34\",y:\"1.57\",width:\"4.34\",height:\"8.79\",transform:\"translate(-0.97 7.57) rotate(-25.1)\"}),t.createElement(\"rect\",{fill:\"#dc0069\",x:\"31.39\",y:\"0.07\",width:\"4.34\",height:\"8.78\"}),t.createElement(\"rect\",{fill:\"#dc0069\",x:\"57.97\",y:\"15.79\",width:\"8.78\",height:\"4.34\",transform:\"translate(5.56 49.36) rotate(-45)\"}),t.createElement(\"rect\",{fill:\"#6e6e6e\",x:\"46.22\",y:\"3.79\",width:\"8.78\",height:\"4.34\",transform:\"translate(23.75 49.27) rotate(-64.9)\"}))};export{l as IconRegularDiamond};\n//# sourceMappingURL=IconRegularDiamond.js.map\n","import { DiscountType, SubjectType } from '@notino/shared/definitions/types';\n\nimport { messages } from './messages';\n\nexport const getDiscountWithSymbol = (\n discountType: DiscountType,\n value: number\n) =>\n ({\n // In future there is open possibility for other DiscountTypes\n [DiscountType.Percentage]: `${value}%`,\n }[discountType]);\n\nexport const subjectTypeMessages: Record<\n SubjectType,\n { id: string; defaultMessage: string }\n> = {\n [SubjectType.BrandDiscount]: messages.brandDiscount,\n [SubjectType.CategoryDiscount]: messages.categoryDiscount,\n};\n","import * as React from 'react';\nimport { FormattedMessage } from 'react-intl';\n\nimport { useQuery } from '@apollo/client';\n\nimport { ModalModel, ModalContext } from '@notino/react-styleguide';\nimport {\n CatalogVariantFragmentFragment,\n GetCustomerBenefitsQuery,\n} from '@notino/shared/definitions/types';\nimport { resetDataLayer } from '@notino/web-tracking';\n\nimport {\n TrackingContextProvider,\n useTrackingContext,\n} from '@context/tracking/TrackingContext';\n\nimport { useNewPdDesignEnabled } from '../../hooks/useNewPdDesignEnabled';\nimport { trackPageReload } from '../../tracking';\n\nimport { BenefitsModal } from './components/BenefitsModal';\nimport { HowToLoyaltyModal } from './components/HowToLoyaltyDiscountModal';\nimport { messages } from './messages';\nimport getCustomerBenefitsQuery from './queries/getCustomerBenefits.graphql';\nimport {\n CustomerDiscountBoldWrapper,\n CustomerDiscountWrapper,\n LoyaltyDiscountStyledWrapper,\n StyledDiamondIcon,\n} from './styled';\nimport { trackLoyaltyModalClose } from './trackLoyaltyModal';\nimport { getDiscountWithSymbol, subjectTypeMessages } from './utils';\n\ninterface ILoyaltyDiscount {\n customerBenefits: CatalogVariantFragmentFragment['features']['customerBenefits'];\n // We need these props to track pageView of PD after modal close\n gtmPageReloadProps: Parameters[0];\n}\n\nexport const LoyaltyDiscount: React.FC = ({\n customerBenefits,\n gtmPageReloadProps,\n}) => {\n const newDesign = useNewPdDesignEnabled();\n const { data, loading } = useQuery(\n getCustomerBenefitsQuery,\n {\n ssr: false,\n }\n );\n\n const { getTimeFromInit } = useTrackingContext();\n const { toggleModal, hideModal } = ModalContext.useModalContext();\n const modalLastClosedMs = React.useRef(0);\n TrackingContextProvider.useSubscribeToInitTimeReset(() => {\n modalLastClosedMs.current = 0;\n });\n\n const handleClick = () => {\n const hasBenefits = data?.customerBenefits?.hasActiveBenefits;\n const timing = getTimeFromInit() - modalLastClosedMs.current;\n toggleModal(\n hasBenefits ? (\n \n ) : (\n \n ),\n {\n noBorders: true,\n size: ModalModel.Sizes.large,\n showOverflow: true,\n positionBottomOnMobile: true,\n closeIconColor: !hasBenefits\n ? { xs: 'icon.inverse', md: 'icon.tertiary' }\n : undefined,\n onClose: () => {\n trackLoyaltyModalClose();\n modalLastClosedMs.current = getTimeFromInit();\n resetDataLayer();\n trackPageReload(gtmPageReloadProps);\n hideModal();\n },\n }\n );\n };\n\n const formattedBenefits = React.useMemo(\n () => ({\n availableDiscount: customerBenefits.availableDiscount && {\n value: getDiscountWithSymbol(\n customerBenefits.availableDiscount.discountType,\n customerBenefits.availableDiscount.value\n ),\n },\n customerDiscount: customerBenefits.customerDiscount && {\n value: getDiscountWithSymbol(\n customerBenefits.customerDiscount.discountType,\n customerBenefits.customerDiscount.value\n ),\n },\n }),\n [customerBenefits.availableDiscount, customerBenefits.customerDiscount]\n );\n\n if (\n !formattedBenefits.availableDiscount &&\n !formattedBenefits.customerDiscount\n ) {\n return null;\n }\n\n const isCustomerDiscount = Boolean(formattedBenefits.customerDiscount);\n\n return (\n \n <>\n \n {customerBenefits.availableDiscount && (\n \n )}\n {customerBenefits.customerDiscount && (\n \n \n ),\n customerDiscountBold: (\n \n \n \n ),\n more: (\n \n \n \n ),\n }}\n />\n \n )}\n >\n \n );\n};\n","import { defineMessages } from 'react-intl';\n\nexport const messages = defineMessages({\n engravingMaxOrderQtyHeader: {\n id: 'engraving.max.order.quantity.header',\n defaultMessage: 'Lze objednat pouze {quantity} {unit}',\n },\n engravingMaxOrderQtyDesc: {\n id: 'engraving.max.order.quantity.description',\n defaultMessage:\n 'Aby se dostalo na co nejvíce zákazníku, z výrobních důvodů zatím neumožňujeme gravírování více kusů na jednu objednávku.',\n },\n addToCartQuantity: {\n id: 'pd.addToCart.quantity',\n defaultMessage: 'Množství',\n },\n});\n","import{a as e,_ as t}from\"./_rollupPluginBabelHelpers-c70560be.js\";import*as n from\"react\";import{T as o}from\"./index-f47e1a81.js\";import\"./TextAlign.js\";import\"./index-2be00b15.js\";import\"./utils-ec9be121.js\";import\"./StyledDropdown.js\";import\"./breakpoints.js\";import\"./theme.js\";import\"./styled.js\";import\"styled-components\";import\"./IconRegularCheckmark.js\";import\"./createSvgIcon-7ca544ca.js\";import\"./index-3097346b.js\";import\"./getSemanticColor.js\";import\"./HorizontalChevron.js\";import\"./IconRegularChevronDown.js\";import\"./IconRegularChevronUp.js\";var r=[\"options\",\"unit\",\"handleOptionSelect\",\"currentOption\",\"disableSelectWhenSingleOption\"],i=function(i){var p=i.options,l=i.unit,s=i.handleOptionSelect,a=void 0===s?function(){return null}:s,c=i.currentOption,m=void 0===c?0:c,u=i.disableSelectWhenSingleOption,d=e(i,r),j=n.useMemo((function(){var e=l?\" \"+l:\"\";return p.map((function(t){return{id:t,label:\"\"+t+e}}))}),[p,l]),b=n.useCallback((function(e){var t=e.id;a(Number(t))}),[a]),f=n.useMemo((function(){return m&&j.find((function(e){return e.id===m}))||j[0]}),[m,j]);return n.createElement(o,t({},d,{options:j,disableSelectWhenSingleOption:u,currentOption:f,handleOptionSelect:b}))};export{i as QuantitySelector};\n//# sourceMappingURL=QuantitySelector.js.map\n","import styled, { css } from 'styled-components';\n\nimport { breakpoints, QuantitySelector } from '@notino/react-styleguide';\n\nconst getGridTemplateAreas = (\n isClickAndCollect: boolean,\n isLoyaltyDiscount: boolean\n) => {\n if (isClickAndCollect && isLoyaltyDiscount) {\n return css`\n grid-template-areas:\n 'loyalty'\n 'addToCart'\n 'clickAndCollect';\n @media (min-width: ${breakpoints.sm}) {\n grid-template-columns: 1fr 1fr 1fr;\n grid-template-areas:\n 'loyalty loyalty loyalty'\n 'addToCart clickAndCollect _';\n }\n `;\n }\n if (isLoyaltyDiscount) {\n return css`\n grid-template-areas:\n 'loyalty'\n 'addToCart';\n `;\n }\n if (isClickAndCollect) {\n return css`\n grid-template-areas:\n 'addToCart'\n 'clickAndCollect';\n @media (min-width: ${breakpoints.sm}) {\n grid-template-columns: auto auto 1fr;\n grid-template-areas: 'addToCart clickAndCollect';\n }\n `;\n }\n return css`\n grid-template-areas: 'addToCart';\n `;\n};\n\nconst getNewGridTemplateAreas = (\n isClickAndCollect: boolean,\n isLoyaltyDiscount: boolean\n) => {\n if (isClickAndCollect && isLoyaltyDiscount) {\n return css`\n grid-template-areas:\n 'loyalty'\n 'addToCart'\n 'clickAndCollect';\n `;\n }\n if (isLoyaltyDiscount) {\n return css`\n grid-template-areas:\n 'loyalty'\n 'addToCart';\n `;\n }\n if (isClickAndCollect) {\n return css`\n grid-template-areas:\n 'addToCart'\n 'clickAndCollect';\n `;\n }\n return css`\n grid-template-areas: 'addToCart';\n `;\n};\n\nexport const BuyButtons = styled.div`\n display: grid;\n align-items: center;\n\n ${({ newDesign, isClickAndCollect, isLoyaltyDiscount, canBuy }) =>\n newDesign\n ? css`\n width: 100%;\n grid-gap: 0.5rem;\n padding: 1rem 0 1.5rem;\n ${getNewGridTemplateAreas(isClickAndCollect, isLoyaltyDiscount)}\n `\n : css`\n ${getGridTemplateAreas(isClickAndCollect, isLoyaltyDiscount)}\n grid-gap: 1rem;\n padding: 1rem 0;\n\n @media (min-width: ${breakpoints.sm}) {\n grid-gap: ${canBuy ? '2rem 1rem' : '0rem'};\n }\n `}\n`;\n\nexport const ButtonWrapper = styled.div<{ newDesign: boolean }>`\n & > button,\n form button {\n padding: 0 0.5625rem !important;\n height: 2.75rem;\n min-width: 7.5rem;\n text-transform: none !important;\n font-weight: normal !important;\n }\n flex: 1;\n min-width: 7.5rem;\n\n ${({ newDesign }) =>\n newDesign\n ? css`\n & > button,\n form button {\n height: 3.25rem;\n }\n `\n : css`\n @media (min-width: ${breakpoints.sm}) {\n flex: 0 1;\n }\n `}\n`;\n\nexport const Label = styled.label`\n display: none;\n`;\n\nexport const DropdownButtonSeparator = styled.div<{ newDesign: boolean }>`\n ${({ newDesign }) =>\n newDesign ? 'padding-right: 0.5rem' : 'padding-right: 1rem'}\n`;\n\nexport const QuantityWrapper = styled.div`\n width: 5.25rem;\n font-size: 0.875rem;\n & > div > div {\n min-height: 2.75rem;\n }\n`;\n\ninterface IWrapperProps {\n isClickAndCollect?: boolean;\n isLoyaltyDiscount?: boolean;\n canBuy?: boolean;\n newDesign: boolean;\n}\n\nexport const AddToCartWrapper = styled.div`\n grid-area: addToCart;\n\n display: flex;\n align-items: center;\n`;\n\nexport const ClickAndCollectWrapper = styled.div`\n grid-area: clickAndCollect;\n\n ${({ isClickAndCollect, newDesign }) =>\n isClickAndCollect &&\n css`\n margin-top: ${newDesign ? '-0.5rem' : '-1rem'};\n `}\n\n @media (min-width: ${breakpoints.sm}) {\n margin-top: 0;\n }\n`;\n\nexport const LoyaltyDiscountWrapper = styled.div`\n grid-area: loyalty;\n\n ${({ newDesign }) =>\n newDesign &&\n css`\n margin-bottom: 0.75rem;\n width: 100%;\n `}\n`;\n\nexport const StyledQuantitySelector = styled(QuantitySelector)<{\n newDesign: boolean;\n}>`\n ${({ newDesign }) =>\n newDesign &&\n css`\n [role='combobox'] {\n height: 3.25rem;\n }\n `}\n`;\n","import { snakeCase } from 'lodash';\n\nimport { GetCatalogProductViewQuery } from '@notino/shared/definitions/types';\nimport { CartType } from '@notino/web-tracking';\n\nimport { dispatchTrackingEvent } from '@context/tracking/utils';\nimport { ProductEventWither } from '@helpers/googleTagManager';\n\nexport const ENGRAVING_CODE = 'ENGXXXU_SENG01';\n\nexport const engravingPrefix = (text: string) => {\n return `Engraving - ${text}`;\n};\n\nexport const trackEngravingAddToCart = (\n productInfo: GetCatalogProductViewQuery['productDetailByCatalogMasterId'],\n variant: GetCatalogProductViewQuery['productDetailByCatalogMasterId']['variants'][number],\n quantity,\n additionalPromoLabels: string[]\n) => {\n dispatchTrackingEvent({\n event: 'add_to_cart',\n product: ProductEventWither()\n .withProduct(productInfo)\n .withVariant(variant)\n .withAdditionalData({\n // use engraving product code instead of product code\n // more info in comments: https://notino.tpondemand.com/entity/132907-nushopweb-pd-trackovani-pridavani-gravirovani-do\n product_code: ENGRAVING_CODE,\n price: variant.features.engraving.config.price,\n brand_name: engravingPrefix(productInfo.brand.name),\n ...(variant.name && {\n name: engravingPrefix(variant.name),\n }),\n cart_type: snakeCase(CartType.cart),\n quantity,\n })\n .withAdditionalPromoLabels(additionalPromoLabels)\n .build(),\n _clear: true,\n });\n};\n","export const prepareOptions = (maxQuantity: number): number[] => {\n const options = [];\n\n for (let option = 1; option <= maxQuantity; option++) {\n options.push(option);\n }\n\n return options;\n};\n","import * as React from 'react';\nimport { FormattedMessage, useIntl } from 'react-intl';\n\nimport { snakeCase } from 'lodash';\n\nimport { ModalModel, TextAlign, ModalContext } from '@notino/react-styleguide';\nimport {\n AvailabilityState,\n CartServiceType,\n GetCatalogProductViewQuery,\n} from '@notino/shared/definitions/types';\nimport { AdditionalServicesAvailability, CartType } from '@notino/web-tracking';\nimport { Ga4Events } from '@notino/web-tracking/dist/types/package/ga4/events';\n\nimport ErrorBoundary from '@components/ErrorBoundary';\nimport { useTrackingDisplayType } from '@containers/ProductDetailContainer/utils';\nimport { useFeatureFlags } from '@context/featureFlags/FeatureFlagsProvider';\nimport { useTrackingContext } from '@context/tracking/TrackingContext';\nimport { dispatchTrackingEvent } from '@context/tracking/utils';\nimport { ProductEventWither } from '@helpers/googleTagManager';\nimport { useAddToCardCloudTracking } from '@hooks/useAddToCardCloudTracking';\nimport { AddToCartButton } from '@sharedComponents/AddToCartButton/AddToCartButton';\n\nimport { ICurrency } from '../../../../App/model';\nimport { useNewPdDesignEnabled } from '../../hooks/useNewPdDesignEnabled';\nimport { usePriceLogic } from '../../hooks/usePriceLogic';\nimport {\n MIN_PRICE_PROMO_LABEL,\n RRP_PRICE_PROMO_LABEL,\n} from '../../hooks/usePriceLogic/tracking';\nimport { IModifaceEffectVariants } from '../../ModiFaceModal/model';\nimport { trackPageReload } from '../../tracking';\nimport { ClickAndCollect } from '../ClickAndCollect';\nimport { useEngravingTryItFirstContext } from '../context/EngravingTryItFirst';\nimport { getRenderableDiscoBoxSampleId } from '../DiscoveryBoxSelfChoice';\nimport { LoyaltyDiscount } from '../LoyaltyDiscount';\n\nimport { messages } from './addToCartMessages';\nimport {\n ButtonWrapper,\n BuyButtons,\n Label,\n DropdownButtonSeparator,\n QuantityWrapper,\n AddToCartWrapper,\n ClickAndCollectWrapper,\n LoyaltyDiscountWrapper,\n StyledQuantitySelector,\n} from './styled';\nimport { trackEngravingAddToCart } from './tracking';\nimport { prepareOptions } from './utils/prepareOptions';\n\ninterface IAddToCartProps {\n product: GetCatalogProductViewQuery['productDetailByCatalogMasterId'];\n variant: GetCatalogProductViewQuery['productDetailByCatalogMasterId']['variants'][number];\n orderUnit: string;\n productCode: string;\n currency: ICurrency;\n onProductAdded: () => void;\n modifaceVariants: IModifaceEffectVariants;\n engravingAvailable: AdditionalServicesAvailability;\n tryItFirstAvailable: AdditionalServicesAvailability;\n}\n\nconst QUANTITY_SELECTOR_KEYBOARD_CONFIG = {\n keyNavigation: true,\n};\n\nexport const AddToCart: React.FC = React.memo(\n ({\n variant,\n product,\n orderUnit,\n onProductAdded,\n modifaceVariants,\n engravingAvailable,\n tryItFirstAvailable,\n }) => {\n const {\n state: { engravingInitials, withEngraving, withTryItFirst },\n } = useEngravingTryItFirstContext();\n const { hideModal, toggleModal } = ModalContext.useModalContext();\n const { getTimeFromInit } = useTrackingContext();\n const { formatMessage } = useIntl();\n const newDesign = useNewPdDesignEnabled();\n const [quantity, setQuantity] = React.useState(1);\n const { rrpShown, minimalPriceShown } = usePriceLogic(variant);\n const featureFlags = useFeatureFlags();\n\n const addToCardCloudTracking = useAddToCardCloudTracking();\n\n const trackingDisplayType = useTrackingDisplayType(product);\n\n const onModalClose = React.useCallback(() => {\n setQuantity(1);\n hideModal();\n }, [hideModal]);\n\n const changeAmount = React.useCallback(\n (newQuantity: number): void => {\n if (withEngraving && newQuantity > 1) {\n const modalOptions = {\n header: (\n \n {formatMessage(messages.engravingMaxOrderQtyHeader, {\n quantity: 1,\n unit: orderUnit,\n })}\n
\n ),\n type: ModalModel.Types.default,\n onClose: onModalClose,\n };\n\n const modalContent = (\n \n );\n\n toggleModal(modalContent, modalOptions);\n }\n setQuantity(newQuantity);\n },\n [formatMessage, onModalClose, orderUnit, toggleModal, withEngraving]\n );\n\n const handleGtmPushProductDetail = React.useCallback(() => {\n trackPageReload({\n rrpShown,\n minimalPriceShown,\n variant,\n product,\n modifaceVariants,\n engravingAvailable,\n tryItFirstAvailable,\n trackingDisplayType,\n featureFlags,\n });\n }, [\n variant,\n product,\n modifaceVariants,\n engravingAvailable,\n tryItFirstAvailable,\n rrpShown,\n minimalPriceShown,\n trackingDisplayType,\n featureFlags,\n ]);\n\n const handleQuantitySelectorClick = () => {\n dispatchTrackingEvent({\n event: 'element_click',\n element: {\n timing: getTimeFromInit(),\n interaction: 'click',\n mode: undefined,\n name: 'quantity_selector',\n type: 'product_detail',\n action: 'click_on_element',\n promo_labels: undefined,\n },\n _clear: true,\n });\n };\n\n const services = React.useMemo(\n () =>\n withEngraving && [\n {\n type: CartServiceType.Engraving,\n value: engravingInitials,\n count: quantity,\n productId: variant.webId,\n },\n ],\n [withEngraving, engravingInitials, quantity, variant.webId]\n );\n\n const trackingProduct: Extract<\n Ga4Events,\n { event: 'add_to_cart' }\n >['product'] = React.useMemo(\n () =>\n ProductEventWither()\n .withProduct(product)\n .withVariant(variant)\n .withServices({\n modifaceVariants,\n tryItFirstAvailable,\n engravingAvailable,\n discoveryBoxAvailable: Boolean(\n getRenderableDiscoBoxSampleId(product, variant, featureFlags)\n ),\n })\n .withAdditionalData({ quantity, cart_type: snakeCase(CartType.cart) })\n .withAdditionalPromoLabels([\n rrpShown && RRP_PRICE_PROMO_LABEL,\n minimalPriceShown && MIN_PRICE_PROMO_LABEL,\n ])\n .build(),\n [\n engravingAvailable,\n tryItFirstAvailable,\n product,\n minimalPriceShown,\n rrpShown,\n modifaceVariants,\n quantity,\n variant,\n featureFlags,\n ]\n );\n\n const handleProductAdded = React.useCallback(() => {\n onProductAdded();\n\n const additionalPromoLabels = [\n rrpShown && RRP_PRICE_PROMO_LABEL,\n minimalPriceShown && MIN_PRICE_PROMO_LABEL,\n ];\n dispatchTrackingEvent({\n event: 'add_to_cart',\n product: trackingProduct,\n _clear: true,\n });\n\n addToCardCloudTracking({\n quantity,\n productCode: variant.productCode,\n });\n\n if (withEngraving) {\n trackEngravingAddToCart(\n product,\n variant,\n quantity,\n additionalPromoLabels\n );\n }\n }, [\n onProductAdded,\n rrpShown,\n minimalPriceShown,\n trackingProduct,\n addToCardCloudTracking,\n withEngraving,\n product,\n variant,\n quantity,\n ]);\n\n const trackAddFailed = React.useCallback(\n (message: string) => {\n dispatchTrackingEvent({\n event: 'add_to_cart_failed',\n add: {\n products: [trackingProduct],\n },\n error: {\n status: message || '',\n },\n _clear: true,\n });\n },\n [trackingProduct]\n );\n\n const canBuy = variant.availability.state === AvailabilityState.CanBeBought;\n const isClickAndCollect = variant.availability.availablePickUpStores > 0;\n const isLoyaltyDiscount =\n Boolean(variant.features.customerBenefits?.availableDiscount) ||\n Boolean(variant.features.customerBenefits?.customerDiscount);\n\n return (\n \n \n {canBuy && (\n \n \n \n \n \n \n (\n \n )}\n showAddToCartModal={product.config.showAddToCartModal}\n buttonElementId=\"pd-buy-button\"\n onProductAdded={handleProductAdded}\n onProductAddFailed={trackAddFailed}\n onClosingModal={handleGtmPushProductDetail}\n withLegacyAddToCart={true}\n />\n \n )}\n {isClickAndCollect && (\n \n 1}\n />\n \n )}\n {isLoyaltyDiscount && canBuy && (\n \n \n \n )}\n \n \n );\n }\n);\n\nAddToCart.displayName = 'AddToCart';\n","import styled, { css } from 'styled-components';\n\nimport { breakpoints } from '@notino/react-styleguide';\n\nimport { IExpandableTextProps } from './model';\n\nconst useOnlyOnCss = ({\n useOnlyOn,\n}: Pick) => {\n if (useOnlyOn === 'mobile') {\n return css`\n @media (min-width: ${breakpoints.lg}) {\n display: none;\n }\n `;\n }\n if (useOnlyOn === 'desktop') {\n return css`\n display: none;\n @media (min-width: ${breakpoints.lg}) {\n display: block;\n }\n `;\n }\n return css``;\n};\n\nexport const ExpandableTextWrapper = styled.div<\n Pick & {\n newDesign: boolean;\n }\n>`\n height: ${({ isExpanded, height }) =>\n isExpanded ? 'auto' : height || '5.5rem'};\n overflow: ${({ isExpanded }) => (isExpanded ? 'auto' : 'hidden')};\n\n position: relative;\n\n ${({ useOnlyOn }) => {\n if (useOnlyOn === 'mobile') {\n return css`\n @media (min-width: ${breakpoints.lg}) {\n height: auto;\n overflow: auto;\n }\n `;\n }\n if (useOnlyOn === 'desktop') {\n return css`\n @media (max-width: ${breakpoints.lg}) {\n height: auto;\n overflow: auto;\n }\n `;\n }\n }}\n\n ${({ newDesign }) =>\n newDesign &&\n css`\n @media (min-width: ${breakpoints.lg}) {\n padding-right: 2rem;\n }\n `}\n`;\n\nexport const Gradient = styled.div>`\n position: absolute;\n bottom: 0;\n width: 100%;\n height: 100%;\n background: rgb(255, 255, 255);\n background: linear-gradient(\n 0deg,\n rgba(255, 255, 255, 1) 0%,\n rgba(0, 0, 0, 0) 100%\n );\n\n ${useOnlyOnCss}\n`;\n\nexport const DefaultExpandableTextButton = styled.button`\n background: none;\n border: none;\n text-decoration: underline;\n cursor: pointer;\n padding: 0.5rem 0;\n margin-top: 0.25rem;\n`;\n\nexport const ExpandableTextButtonWrapper = styled.div<\n Pick\n>`\n ${useOnlyOnCss}\n`;\n","import * as React from 'react';\n\nimport { ReactFCC } from '@notino/react-styleguide';\n\nimport { useNewPdDesignEnabled } from '@containers/ProductDetailContainer/ProductDetail/hooks/useNewPdDesignEnabled';\n\nimport { IExpandableTextProps } from './model';\nimport {\n Gradient,\n ExpandableTextWrapper,\n DefaultExpandableTextButton,\n ExpandableTextButtonWrapper,\n} from './styled';\n\nexport const ExpandableText: ReactFCC = ({\n isExpanded: isExpandedProp,\n buttonText,\n onClick,\n children,\n useOnlyOn,\n height,\n disabled,\n}) => {\n const newDesign = useNewPdDesignEnabled();\n const [isExpanded, setIsExpanded] = React.useState(false);\n\n const isControlledComponent = isExpandedProp !== undefined;\n\n const resolvedIsExpanded = isControlledComponent\n ? isExpandedProp\n : isExpanded;\n\n const handleClick = () => {\n if (isControlledComponent) {\n onClick?.();\n return;\n }\n setIsExpanded(true);\n };\n\n if (disabled) {\n // eslint-disable-next-line react/jsx-no-useless-fragment\n return <>{children}>;\n }\n\n return (\n <>\n \n {children}\n\n {!resolvedIsExpanded && (\n \n )}\n \n\n {!resolvedIsExpanded &&\n getButtonComponent({ useOnlyOn, buttonText, handleClick })}\n >\n );\n};\n\nconst getButtonComponent = ({\n useOnlyOn,\n handleClick,\n buttonText,\n}: Pick & {\n handleClick: () => void;\n}) => {\n const btnCommonProps = {\n useOnlyOn,\n onClick: handleClick,\n ['data-testid']: 'expandable-text-button',\n };\n\n return typeof buttonText === 'string' ? (\n \n