{"version":3,"file":"coopse.script.8154.666d8993.chunk.js","mappings":"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","sources":["webpack:///./src/microApps/common/components/organisms/MissingItemBody/MissingItemBody.module.less","webpack:///./src/microApps/cart/components/molecules/RecipeProductListingItem/RecipeProductListingItem.tsx","webpack:///./src/microApps/cart/components/molecules/RecipeProductListingItem/RecipeProductListingItem.utils.ts","webpack:///./src/microApps/cart/components/molecules/RecipePortionCounter/RecipePortionCounter.tsx","webpack:///./src/microApps/common/components/molecules/RecipeModal/RecipeModalFooter.tsx","webpack:///./src/microApps/common/components/molecules/RecipeModal/RecipeModalHeader.tsx","webpack:///./src/microApps/common/components/molecules/RecipeModal/RecipeModalAccordion.module.less","webpack:///./src/microApps/common/components/molecules/RecipeModal/RecipeModalAccordion.tsx","webpack:///./src/microApps/common/components/molecules/RecipeModal/RecipeModalProductsFooter.tsx","webpack:///./src/microApps/common/components/molecules/RecipeModal/RecipeModalProducts.tsx","webpack:///./src/microApps/common/components/molecules/RecipeModal/RecipeModalRecept.tsx","webpack:///./src/microApps/common/components/molecules/RecipeModal/RecipeModalBody.tsx","webpack:///./src/microApps/common/components/molecules/RecipeModalTrigger/BuyableRecipeModalBody.tsx","webpack:///./src/microApps/common/components/organisms/MissingItemBody/MissingItemInfo.tsx","webpack:///./src/microApps/common/components/organisms/MissingItemBody/MissingItemBody.tsx","webpack:///./src/microApps/common/components/organisms/PurchasableItemBody/PurchasableItemBody.tsx","webpack:///./src/microApps/common/tracking/ga4/recipes/ga4Recipes.utils.ts","webpack:///./src/microApps/recipe/hooks/useRecipeCart.ts","webpack:///./src/microApps/recipe/hooks/useSubstitute.ts","webpack:///./src/microApps/recipe/models.ts","webpack:///./src/microApps/recipe/utils.ts"],"sourcesContent":["// extracted by mini-css-extract-plugin\nexport default {\"MissingItemInfo\":\"XyD819sD\",\"RecipeItemActions\":\"xGNPEbje\",\"RecipeItemActionsContainer\":\"t3_zjtbW\"};","import type { AnalyticsListOptions } from '../../../../../analytics/analyticsHandler';\nimport type { SwiperBreakpoints } from '../../../../../utility/coopSwiperBreakpoints';\nimport { Helpers } from '../../../../../utility/helpers';\nimport ProductPrice from '../../../../common/components/atoms/ProductPrice';\nimport EcomPromoSplash from '../../../../common/components/molecules/EcomPromoSplash';\nimport ProductSubstitutes from '../../../../common/components/molecules/ProductSubstitutes';\nimport type { PriceData } from '../../../../common/models/priceData/priceData';\nimport { PriceType } from '../../../../common/models/priceData/priceData';\nimport { mapProductToEcomPromotion } from '../../../../common/utils/productUtils';\nimport ProductListingItem from '../ProductListingItem';\n\ninterface RecipeItemProps {\n priceData: PriceData;\n totalPriceData: PriceData;\n name: string;\n packageSizeInformation: string;\n image?: string;\n manufacturer?: string;\n selectedVarianceCode?: string;\n}\n\ninterface RecipeProductListingItemProps {\n recipeProduct: RecipeItemProps;\n product?: ApiProduct;\n recipeProductSubstitutes: ApiProduct[];\n isSubstituteActive: boolean;\n buyable: boolean;\n handleSubstituteChange: (product: ApiProduct) => void;\n productSubstitutesBreakpoints: SwiperBreakpoints;\n analyticsOptions?: AnalyticsListOptions;\n additionalClassNames?: string;\n isConstrained?: boolean;\n priceType: PriceType;\n}\n\nconst RecipeProductListingItem = ({\n recipeProduct: recipeProductItem,\n product,\n recipeProductSubstitutes,\n isSubstituteActive,\n buyable,\n children,\n handleSubstituteChange,\n additionalClassNames,\n analyticsOptions,\n productSubstitutesBreakpoints,\n isConstrained,\n priceType,\n}: React.PropsWithChildren<RecipeProductListingItemProps>) => {\n const getVariantName = () => {\n if (recipeProductItem.selectedVarianceCode && product) {\n const variant = product.variants?.find(\n (_variant) => _variant.id === recipeProductItem.selectedVarianceCode,\n );\n\n return variant?.name;\n }\n\n return undefined;\n };\n\n const productPromotion = mapProductToEcomPromotion(product);\n\n return (\n <>\n <ProductListingItem\n slotPrice={\n buyable && (\n <div className=\"Cart-itemSummary\">\n <span className=\"Cart-itemPrice\">\n {/* Use price with tax for recipes and weekly menu */}\n <ProductPrice\n totalPrice={recipeProductItem.totalPriceData}\n priceType={priceType}\n align=\"right\"\n showExcludingTaxInfo={false}\n />\n </span>\n {priceType === PriceType.ExcludeTax && (\n <span className=\"u-flex u-textXXXSmall u-flexJustifyEnd u-textWeightNormal\">\n {Helpers.getPriceTypeText(priceType)}\n </span>\n )}\n </div>\n )\n }\n slotSplash={\n productPromotion && (\n <EcomPromoSplash promotion={productPromotion} priceType={priceType} />\n )\n }\n isNicotineProduct={!!product?.details?.isNicotineProduct}\n isPharmaceutical={!!product?.details?.pharmaceuticalData?.isPharmaceutical}\n name={product?.name || recipeProductItem.name}\n packageSizeInformation={recipeProductItem.packageSizeInformation}\n variantName={getVariantName()}\n image={recipeProductItem.image}\n manufacturer={product?.manufacturer || recipeProductItem.manufacturer}\n additionalClassNames={additionalClassNames}\n analyticsOptions={null}\n >\n {children}\n </ProductListingItem>\n {isSubstituteActive && (\n <div\n className=\"u-borderBottomGrayLight2 u-bgGrayLight\"\n style={{ position: 'relative', overflow: 'hidden' }}\n >\n <ProductSubstitutes\n productSubstitutesBreakpoints={productSubstitutesBreakpoints}\n substitutes={recipeProductSubstitutes}\n handleProductSubstitution={handleSubstituteChange}\n analyticsOptions={analyticsOptions}\n isConstrained={isConstrained}\n priceType={priceType}\n />\n </div>\n )}\n </>\n );\n};\n\nexport default RecipeProductListingItem;\n","import { CoopSwiperBreakpointsUnique } from '../../../../../utility/coopSwiperBreakpointsUnique';\n\nexport const recipeModalProductSubstitutesBreakpoints =\n CoopSwiperBreakpointsUnique.getUniqueBreakpointsFor(\n CoopSwiperBreakpointsUnique.AREA_RECIPE_MODAL,\n ).ProductList;\n","/* eslint-disable react/jsx-props-no-spreading */\n/* eslint-disable react/no-unstable-nested-components */\nimport { ChipIconButton } from '@coop/components';\nimport { MinusIcon, PlusIcon } from '@coop/icons';\n\nimport { useNumericStepperCalculation } from '../../../../common/components/atoms/NumericStepper';\n\ninterface RecipePortionCounterProps {\n portions: number;\n setPortions: (quantity: number) => void;\n minValue: number;\n maxValue: number;\n incrementBy?: number;\n}\n\nconst RecipePortionCounter = (props: RecipePortionCounterProps) => {\n const { calculateAdditionValue, calculateSubstractValue } = useNumericStepperCalculation({\n incrementBy: props.incrementBy || 2,\n minValue: props.minValue,\n maxValue: props.maxValue,\n });\n\n return (\n <div className=\"u-flex u-flexAlignCenter u-flexJustifyCenter\">\n <span>{props.portions} portioner</span>\n <div style={{ marginLeft: 24 }}>\n <ChipIconButton\n icon={MinusIcon}\n label=\"Ta bort en portion\"\n theme=\"whiteGreen\"\n size={32}\n onClick={() => {\n const newValue = calculateSubstractValue(props.portions);\n props.setPortions(newValue);\n }}\n />\n </div>\n <div style={{ marginLeft: 8 }}>\n <ChipIconButton\n icon={PlusIcon}\n label=\"Lägg till en portion\"\n theme=\"whiteGreen\"\n size={32}\n onClick={() => {\n const newValue = calculateAdditionValue(props.portions);\n props.setPortions(newValue);\n }}\n />\n </div>\n </div>\n );\n};\n\nexport default RecipePortionCounter;\n","import { Button } from '@coop/components';\n\nimport { Helpers } from '../../../../../utility/helpers';\nimport { buildRecipeRedirectUrl } from '../../../../recipe/utils';\nimport { PriceType } from '../../../models/priceData/priceData';\n\ninterface RecipeModalFooterProps {\n totalProducts?: number;\n totalPrice: number;\n externalId: number;\n buyable: boolean;\n handleBuy: () => void;\n handleLinkClick: () => void;\n priceType: PriceType;\n isFoodBox: boolean;\n}\n\nconst RecipeModalFooter: React.FC<React.PropsWithChildren<RecipeModalFooterProps>> = ({\n totalProducts,\n totalPrice,\n externalId,\n buyable,\n handleBuy,\n handleLinkClick,\n priceType,\n isFoodBox,\n}) => {\n return (\n <div className=\"RecipeModal-footer u-md-flex\">\n {buyable && (\n <div>\n {totalProducts !== undefined && (\n <span className=\"u-block u-textXSmall\">\n Totalt{' '}\n <span className=\"u-textWeightNormal\">\n (<span>{totalProducts}</span> varor)\n </span>\n </span>\n )}\n <div>{Helpers.toEcommercePriceWithCurrency(totalPrice)}</div>\n {priceType === PriceType.ExcludeTax && (\n <div className=\"u-textWeightNormal u-textXSmall\">\n {Helpers.getPriceTypeText(priceType)}\n </div>\n )}\n </div>\n )}\n <div className=\"u-flex\">\n <Button asChild size={40} theme=\"primaryOutline\" className=\"u-marginRxsm\">\n <a\n href={buildRecipeRedirectUrl(externalId.toString())}\n onClick={handleLinkClick}\n >\n {isFoodBox ? 'GÃ¥ till produktsida' : 'GÃ¥ till receptsida'}\n </a>\n </Button>\n {buyable && (\n <Button size={40} theme=\"primary\" onClick={handleBuy}>\n Köp varor\n </Button>\n )}\n </div>\n </div>\n );\n};\n\nexport default RecipeModalFooter;\n","import { ChipIconButton, Icon } from '@coop/components';\nimport { ClockIcon, CloseIcon } from '@coop/icons';\n\nimport { Helpers } from '../../../../../utility/helpers';\nimport { getTransformedImageUrl } from '../../../utils/cloudinaryImageUtils';\nimport { RatingStars } from '../RatingStars';\n\ninterface RecipeModalHeaderProps {\n recipeName: string;\n imageUrl: string;\n rating: number | null;\n votes?: number;\n time: string;\n buyable: boolean;\n pricePortion?: number;\n close: () => void;\n}\n\nconst RecipeModalHeader: React.FC<React.PropsWithChildren<RecipeModalHeaderProps>> = ({\n recipeName,\n imageUrl,\n rating,\n votes,\n time,\n buyable,\n pricePortion,\n close,\n}) => {\n const transformedImageUrl = getTransformedImageUrl(imageUrl, 'w_400,h_400');\n\n return (\n <div className=\"RecipeModal-header\">\n {transformedImageUrl && (\n <div\n className=\"RecipeModal-bgImage\"\n style={{\n backgroundImage: `url(${transformedImageUrl})`,\n }}\n />\n )}\n <div className=\"RecipeModal-overlay\" />\n <div className=\"RecipeModal-close\">\n <ChipIconButton\n icon={CloseIcon}\n size={32}\n theme=\"whiteGreen\"\n label=\"Stäng\"\n onClick={close}\n />\n </div>\n <h3 className=\"RecipeModal-heading\">{recipeName}</h3>\n <div className=\"u-posRelative\">\n <div className=\"Grid Grid--gutterHmd Grid--fit\">\n <div className=\"Grid-cell Grid-cell--fit\">\n {!!rating && !!votes && (\n <RatingStars rating={rating} votes={votes} color=\"white\" />\n )}\n </div>\n {time && (\n <div className=\"Grid-cell Grid-cell--fit u-flexAlignCenter\">\n <Icon icon={ClockIcon} className=\"u-marginRxxsm\" />\n <span className=\"u-textXSmall\">{time}</span>\n </div>\n )}\n {buyable && pricePortion && (\n <div className=\"Grid-cell Grid-cell--fit\">\n <span className=\"u-textXSmall\">{`Ca ${Helpers.toEcommercePriceWithCurrency(\n pricePortion,\n )}/port`}</span>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n\nexport default RecipeModalHeader;\n","// extracted by mini-css-extract-plugin\nexport default {\"RadioBox\":\"QpkilH1D\"};","import { Icon, RadioGroup } from '@coop/components';\nimport { MinusIcon, PlusIcon } from '@coop/icons';\nimport classnames from 'classnames';\nimport { useState } from 'react';\n\nimport type { RecipeCalculationType, RecipePrioritizationType } from '../../../../recipe/models';\nimport styles from './RecipeModalAccordion.module.less';\n\ninterface RecipeModalAccordionProps {\n handleCalculationTypeChange: (\n calculationType: RecipeCalculationType,\n prioritization: RecipePrioritizationType | null,\n ) => void;\n}\n\ntype RecipeModalAccordionRadioValues = RecipeCalculationType | RecipePrioritizationType;\ninterface RecipeModalAccordionRadioButtonData {\n name: string;\n description: string;\n value: RecipeModalAccordionRadioValues;\n}\n\nconst RecipeModalAccordion = (props: RecipeModalAccordionProps) => {\n const [isExpanded, setIsExpanded] = useState<boolean>(false);\n const [inputSelected, setInputSelected] = useState<RecipeModalAccordionRadioButtonData>({\n name: 'Bästa val',\n description: 'Varorna kombineras och väljs för att du ska fÃ¥ sÃ¥ lite svinn som möjligt.',\n value: 'waste',\n });\n\n const accordionExpandedToggle = () => setIsExpanded(!isExpanded);\n const handleInputSelect = (selectedInput: RecipeModalAccordionRadioButtonData) => {\n setInputSelected({ ...selectedInput });\n\n let calculationType: RecipeCalculationType;\n let recipeProritization: RecipePrioritizationType | null = null;\n\n switch (selectedInput.value) {\n case 'waste':\n calculationType = 'waste';\n break;\n case 'price':\n calculationType = 'price';\n break;\n case 'organic':\n calculationType = 'waste';\n recipeProritization = 'organic';\n break;\n default:\n calculationType = 'waste';\n break;\n }\n\n props.handleCalculationTypeChange?.(calculationType, recipeProritization);\n };\n\n const onValueChange = (value: string) => {\n switch (value) {\n case 'waste':\n handleInputSelect({\n name: 'Bästa val',\n description:\n 'Varorna kombineras och väljs för att du ska fÃ¥ sÃ¥ lite svinn som möjligt.',\n value: 'waste',\n });\n break;\n case 'price':\n handleInputSelect({\n name: 'Billigt',\n description:\n 'Vi föreslÃ¥r det billigaste alternativet. Självklart med sÃ¥ lite svinn som möjligt.',\n value: 'price',\n });\n break;\n case 'organic':\n handleInputSelect({\n name: 'Eko',\n description:\n 'Vi föreslÃ¥r en ekologisk vara om det finns. Alltid med sÃ¥ lite svinn som möjligt.',\n value: 'organic',\n });\n break;\n default:\n break;\n }\n };\n\n // TODO A11Y: Redo accordion into Radix Accordion, remove Accordion.less\n return (\n <div className=\"Accordion Accordion--single\">\n <ul className=\"Accordion-list\">\n <li className={classnames('Accordion-item', isExpanded && 'is-expanded')}>\n <div\n className=\"Accordion-header u-textMedium u-paddingHmd\"\n onClick={accordionExpandedToggle}\n >\n <span className=\"u-inlineBlock u-textSmall u-md-textMedium u-marginRxxsm\">\n Önskade varor:{' '}\n </span>\n <span className=\"u-textWeightBold u-textSmall u-md-textMedium u-inlineBlock u-marginRxxsm\">\n {inputSelected.name}\n </span>\n <Icon\n icon={PlusIcon}\n className=\"Accordion-icon Accordion-icon--plus\"\n width={20}\n height={20}\n />\n <Icon\n icon={MinusIcon}\n className=\"Accordion-icon Accordion-icon--minus\"\n width={20}\n height={20}\n />\n </div>\n <div className=\"Accordion-panel\">\n <div className=\"u-paddingAmd\">\n <RadioGroup.Root onValueChange={onValueChange} defaultValue=\"waste\">\n <div className=\"Grid Grid--gutterAxsm\">\n <div className=\"Grid-cell u-sm-size1of3\">\n <RadioGroup.Item\n value=\"price\"\n id=\"calctype_price\"\n label={\n <>\n Billigt\n <i className=\"u-block u-sm-hidden u-md-hidden u-textXSmall u-marginTxxxsm\">\n Vi föreslÃ¥r det billigaste alternativet.\n Självklart med sÃ¥ lite svinn som möjligt.\n </i>\n </>\n }\n className={styles.RadioBox}\n />\n </div>\n <div className=\"Grid-cell u-sm-size1of3\">\n <RadioGroup.Item\n value=\"waste\"\n id=\"calctype_waste\"\n label={\n <>\n Bästa val\n <i className=\"u-block u-sm-hidden u-md-hidden u-textXSmall u-marginTxxxsm\">\n Varorna kombineras och väljs för att du ska\n fÃ¥ sÃ¥ lite svinn som möjligt.\n </i>\n </>\n }\n className={styles.RadioBox}\n />\n </div>\n <div className=\"Grid-cell u-sm-size1of3\">\n <RadioGroup.Item\n value=\"organic\"\n id=\"calctype_eko\"\n label={\n <>\n Eko\n <i className=\"u-block u-sm-hidden u-md-hidden u-textXSmall u-marginTxxxsm\">\n Vi föreslÃ¥r en ekologisk vara om det finns.\n Alltid med sÃ¥ lite svinn som möjligt.\n </i>\n </>\n }\n className={styles.RadioBox}\n />\n </div>\n </div>\n </RadioGroup.Root>\n\n <div className=\"Grid-cell u-sm-block u-md-block u-sm-paddingTxsm u-md-paddingTsm\">\n <span className=\"u-textSmall\">{inputSelected.description}</span>\n </div>\n </div>\n </div>\n </li>\n </ul>\n </div>\n );\n};\n\nexport default RecipeModalAccordion;\n","import { Button } from '@coop/components';\n\nimport { Helpers } from '../../../../../utility/helpers';\n\ninterface RecipeModalProductsFooterProps {\n totalProducts?: number;\n totalPrice: number;\n handleBuy: () => void;\n}\n\nconst RecipeModalProductsFooter: React.FC<\n React.PropsWithChildren<RecipeModalProductsFooterProps>\n> = ({ totalProducts, totalPrice, handleBuy }) => {\n return (\n <div className=\"RecipeModal-footer u-md-hidden\">\n <div className=\"u-marginBxsm\">\n Totalt\n {totalProducts !== undefined && (\n <>\n {' '}\n (<span>{totalProducts}</span> varor)\n </>\n )}\n :{' '}\n <span className=\"u-textWeightBold\">\n {Helpers.toEcommercePriceWithCurrency(totalPrice)}\n </span>\n </div>\n <Button size={40} theme=\"primary\" onClick={handleBuy} fullWidth>\n Köp varor\n <div />\n </Button>\n </div>\n );\n};\n\nexport default RecipeModalProductsFooter;\n","import type { FC } from 'react';\n\nimport { Helpers } from '../../../../../utility/helpers';\nimport type { RecipeCartState, RecipeSection } from '../../../../recipe/hooks/useRecipeCart';\nimport type {\n RecipeCalculationType,\n RecipeItemState,\n RecipePrioritizationType,\n} from '../../../../recipe/models';\nimport { PriceType } from '../../../models/priceData/priceData';\nimport RecipeModalAccordion from './RecipeModalAccordion';\nimport RecipeModalProductsFooter from './RecipeModalProductsFooter';\n\nexport interface RecipeProductItemsGroup {\n cart: RecipeCartState | null;\n}\n\ninterface RecipeModalProductsProps extends RecipeProductItemsGroup {\n renderCartItem: (item: RecipeItemState) => JSX.Element;\n handleCalculationTypeChange: (\n calculationType: RecipeCalculationType,\n prioritization: RecipePrioritizationType | null,\n ) => void;\n buyable: boolean;\n handleBuy: () => void;\n totalProducts?: number;\n}\n\ninterface RecipeModalProductsListProps {\n list: RecipeItemState[];\n title: string | null;\n renderCartItem: (item: RecipeItemState) => JSX.Element;\n}\n\ninterface RecipeModalSectionProps {\n section: RecipeSection;\n allItems: RecipeItemState[];\n renderCartItem: (item: RecipeItemState) => JSX.Element;\n}\n\nconst RecipeModalSection: FC<React.PropsWithChildren<RecipeModalSectionProps>> = (props) => {\n const sectionItems = props.allItems.filter((item) =>\n props.section.substituteIdentifiers.includes(item.substituteIdentifier),\n );\n\n const getSectionTitle = () => {\n switch (props.section.type) {\n case 'shared':\n return 'Varor som delas mellan recept';\n case 'common':\n return 'Bra att ha till receptet';\n default:\n return null;\n }\n };\n\n return (\n <RecipeModalProductsList\n list={sectionItems}\n title={getSectionTitle()}\n renderCartItem={props.renderCartItem}\n />\n );\n};\n\nexport const RecipeModalProductsList: React.FC<\n React.PropsWithChildren<RecipeModalProductsListProps>\n> = ({ list, title, renderCartItem }) => (\n <div className=\"Cart-group\">\n {title && (\n <div className=\"Cart-groupHeader\">\n <span className=\"Cart-groupHeading\">{title}</span>\n </div>\n )}\n <ul className=\" Cart-itemList\">{list.map((item) => renderCartItem(item))}</ul>\n </div>\n);\n\nconst RecipeModalProducts: React.FC<React.PropsWithChildren<RecipeModalProductsProps>> = ({\n cart,\n renderCartItem,\n handleCalculationTypeChange,\n buyable,\n handleBuy,\n totalProducts,\n}) => {\n return (\n <>\n <RecipeModalAccordion handleCalculationTypeChange={handleCalculationTypeChange} />\n <div className=\"Cart Cart--borderB\">\n {cart?.sections.map((section) => (\n <RecipeModalSection\n key={section.id}\n section={section}\n allItems={cart?.items}\n renderCartItem={renderCartItem}\n />\n ))}\n </div>\n {buyable && (\n <RecipeModalProductsFooter\n totalProducts={totalProducts}\n // use price with tax for recipes\n totalPrice={\n (cart && Helpers.getPrice(cart.totalPriceData, PriceType.IncludeTax)) || 0\n }\n handleBuy={handleBuy}\n />\n )}\n </>\n );\n};\n\nexport default RecipeModalProducts;\n","/* eslint-disable react/no-array-index-key */\nimport { Button } from '@coop/components';\nimport * as React from 'react';\nimport { useMemo } from 'react';\n\nimport type { ApiRecipe } from '../../../../../models/recipe/recipeModel';\nimport { buildRecipeRedirectUrl } from '../../../../recipe/utils';\nimport { mapToIngredientProps, mapToRecipeCookingInstructions } from '../../../utils/recipeUtils';\nimport RawHtml from '../../atoms/RawHtml';\n\nconst RecipeModalRecept = ({ recipe, readonly }: { recipe: ApiRecipe; readonly?: boolean }) => {\n const cookingInstructions = useMemo(\n () => mapToRecipeCookingInstructions(recipe.cookingInstructions),\n [recipe.cookingInstructions],\n );\n\n const recipePart = recipe.recipePart.map((part) => ({\n part: part.name,\n ingredients: mapToIngredientProps(part.ingredients),\n }));\n\n const ingredientLine = (formattedQuantity: string, unit: string, friendlyText: string) => {\n if (formattedQuantity) {\n return `${formattedQuantity} ${unit} ${friendlyText}`;\n }\n\n return friendlyText;\n };\n\n return (\n <div\n className=\"Tab-panel u-md-marginTz u-paddingA u-paddingTxlg is-active\"\n data-panel=\"2\"\n data-external-id={recipe.externalId}\n data-recipe-name={recipe.name}\n >\n {recipe.preamble && (\n <p className=\"u-marginTz u-md-marginTz u-marginBxlg u-textCenter\">\n <RawHtml html={recipe.preamble} />\n </p>\n )}\n <div className=\"Grid Grid--gutterA\">\n <div className=\"Grid-cell u-sm-size1of2\">\n <h5>\n Ingredienser{' '}\n {recipe.yieldValue > 0 && `(för ${recipe.yieldValue} portioner)`}\n </h5>\n <ul className=\"List List--noSpacing u-textSmall\">\n {recipePart.map(({ part, ingredients }, i) => (\n <div key={`${i}_${part}`}>\n {part && (\n <li className=\"u-textWeightBold\">\n <p>{part}</p>\n </li>\n )}\n {ingredients.map(\n ({ formattedQuantity, unit, friendlyText }, index) => (\n <li\n key={`${index}_${friendlyText}`}\n className=\"u-colorBaseMid\"\n >\n <p>\n {ingredientLine(\n formattedQuantity,\n unit,\n friendlyText,\n )}\n </p>\n </li>\n ),\n )}\n </div>\n ))}\n </ul>\n </div>\n\n {!recipe.isFoodBox && (\n <div className=\"Grid-cell u-sm-size1of2\">\n <h5>Gör sÃ¥ här</h5>\n <div className=\"List List--ordered-container\">\n {cookingInstructions.map(({ title, instructions }, i) => (\n <React.Fragment key={i}>\n {title && <h5 className=\"u-textWeightBold\">{title}</h5>}\n {!!instructions?.length && (\n <ol className=\"List List--ordered u-textSmall\">\n {instructions.map((el, e) => (\n <li key={e} className=\"u-colorBaseMid\">\n {el}\n </li>\n ))}\n </ol>\n )}\n </React.Fragment>\n ))}\n </div>\n </div>\n )}\n </div>\n {!readonly && (\n <div className=\"Grid Grid--gutterA u-paddingH u-paddingTmd hideme\">\n <Button\n asChild\n size={40}\n theme=\"primaryOutline\"\n fullWidth\n className=\"u-md-hidden\"\n >\n <a href={buildRecipeRedirectUrl(recipe.externalId.toString())}>\n Gå till receptsidan\n </a>\n </Button>\n </div>\n )}\n </div>\n );\n};\n\nexport default RecipeModalRecept;\n","import { OverlayLoader } from '@coop/components';\nimport * as React from 'react';\n\nimport type { ApiRecipe } from '../../../../../models/recipe/recipeModel';\nimport { Helpers } from '../../../../../utility/helpers';\nimport RecipePortionCounter from '../../../../cart/components/molecules/RecipePortionCounter';\nimport type {\n RecipeCalculationType,\n RecipeItemState,\n RecipeModalTab,\n RecipePrioritizationType,\n} from '../../../../recipe/models';\nimport type { PriceType } from '../../../models/priceData/priceData';\nimport type { TabItem } from '../TabSwitcher';\nimport { TabSwitcher } from '../TabSwitcher';\nimport RecipeModalFooter from './RecipeModalFooter';\nimport RecipeModalHeader from './RecipeModalHeader';\nimport type { RecipeProductItemsGroup } from './RecipeModalProducts';\nimport RecipeModalProducts from './RecipeModalProducts';\nimport RecipeModalRecept from './RecipeModalRecept';\n\ninterface RecipeModalProps extends RecipeProductItemsGroup {\n recipeData?: ApiRecipe;\n modalTabToDisplay: RecipeModalTab;\n renderCartItem: (item: RecipeItemState) => JSX.Element;\n close: () => void;\n isLoading: boolean;\n handlePortionChange: (quantity: number) => void;\n handleCalculationTypeChange: (\n calculationType: RecipeCalculationType,\n prioritization: RecipePrioritizationType | null,\n ) => void;\n handleBuy: () => void;\n handleLinkClick: () => void;\n readonly?: boolean;\n priceType: PriceType;\n}\n\nconst RecipeModalBody: React.FC<React.PropsWithChildren<RecipeModalProps>> = ({\n recipeData,\n modalTabToDisplay = 1,\n renderCartItem,\n close,\n isLoading,\n handlePortionChange,\n handleCalculationTypeChange,\n handleBuy,\n handleLinkClick,\n readonly,\n cart,\n priceType,\n}) => {\n let buyable = false;\n\n if (cart) {\n buyable = true;\n }\n\n buyable = readonly ? false : buyable;\n\n const totalProducts = cart?.items\n .filter((item) => item.purchasable)\n .reduce((curr, next) => curr + (next.quantity || 0), 0);\n\n return (\n <div className=\"RecipeModal RecipeModal--fullHeight\">\n <OverlayLoader isLoading={isLoading} />\n {recipeData && (\n <RecipeModalBodyWithData\n recipeData={recipeData}\n buyable={buyable}\n close={close}\n totalProducts={totalProducts}\n handlePortionChange={handlePortionChange}\n handleLinkClick={handleLinkClick}\n handleBuy={handleBuy}\n cart={cart}\n renderCartItem={renderCartItem}\n handleCalculationTypeChange={handleCalculationTypeChange}\n modalTabToDisplay={modalTabToDisplay}\n readonly={readonly}\n priceType={priceType}\n />\n )}\n </div>\n );\n};\n\nconst RecipeModalBodyWithData = ({\n recipeData,\n modalTabToDisplay = 1,\n renderCartItem,\n close,\n handlePortionChange,\n handleCalculationTypeChange,\n handleBuy,\n handleLinkClick,\n readonly,\n cart,\n buyable,\n totalProducts,\n priceType,\n}: Omit<RecipeModalProps, 'recipeData' | 'isLoading'> &\n Required<Pick<RecipeModalProps, 'recipeData'>> & {\n buyable: boolean;\n totalProducts?: number;\n }) => {\n const defaultPortions = recipeData.yieldValue || 4;\n const rating = recipeData.avgRating || null;\n const display = modalTabToDisplay === 2 && cart ? 2 : 1;\n\n const [portions, setPortions] = React.useState(defaultPortions);\n\n const createTabs = (): TabItem[] => {\n return [\n {\n id: '1',\n name: !recipeData?.isFoodBox ? 'Recept' : 'Beskrivning',\n component: <RecipeModalRecept recipe={recipeData!} readonly={readonly} />,\n },\n ...(buyable\n ? [\n {\n id: '2',\n name: 'Varor',\n component: (\n <RecipeModalProducts\n renderCartItem={renderCartItem}\n buyable={buyable}\n cart={cart}\n handleCalculationTypeChange={handleCalculationTypeChange}\n handleBuy={handleBuy}\n totalProducts={totalProducts}\n />\n ),\n },\n ]\n : []),\n ];\n };\n\n return (\n <>\n <RecipeModalHeader\n recipeName={recipeData.name}\n imageUrl={recipeData.imageUrl}\n rating={rating}\n time={recipeData.totalTime}\n buyable={buyable}\n close={close}\n />\n <TabSwitcher\n items={createTabs()}\n wrapperClasses=\"RecipeModal-body Tab--recipeModal\"\n containerClasses=\"RecipeModal-contentTop\"\n panelClasses=\"RecipeModal-content\"\n listClasses=\"RecipeModal-tabs\"\n itemClasses={() => 'RecipeModal-tabs'}\n renderNextToTabs={() =>\n buyable && (\n <div className=\"RecipeModal-amountSelector\">\n <div className=\"u-sizeFull\">\n <RecipePortionCounter\n minValue={1}\n maxValue={20}\n incrementBy={1}\n portions={portions}\n setPortions={(p) => {\n setPortions(p);\n handlePortionChange(p);\n }}\n />\n </div>\n </div>\n )\n }\n initialActiveId={display.toString()}\n />\n {!readonly && (\n <RecipeModalFooter\n priceType={priceType}\n totalProducts={totalProducts}\n // use price with tax for recipes\n totalPrice={(cart && Helpers.getPrice(cart.totalPriceData, priceType)) || 0}\n externalId={recipeData.externalId}\n buyable={buyable}\n handleBuy={handleBuy}\n handleLinkClick={handleLinkClick}\n isFoodBox={recipeData.isFoodBox}\n />\n )}\n </>\n );\n};\n\nexport default RecipeModalBody;\n","import { useCallback, useEffect, useRef } from 'react';\n\nimport type { ApiRecipe } from '../../../../../models/recipe/recipeModel';\nimport RecipeProductListingItem from '../../../../cart/components/molecules/RecipeProductListingItem/RecipeProductListingItem';\nimport { recipeModalProductSubstitutesBreakpoints } from '../../../../cart/components/molecules/RecipeProductListingItem/RecipeProductListingItem.utils';\nimport recipeFlow from '../../../../recipe/flow/recipeFlow';\nimport useRecipeCart from '../../../../recipe/hooks/useRecipeCart';\nimport useSubstitutes from '../../../../recipe/hooks/useSubstitute';\nimport type {\n RecipeCalculationType,\n RecipeItemState,\n RecipePrioritizationType,\n} from '../../../../recipe/models';\nimport { RecipeModalTab } from '../../../../recipe/models';\nimport type { ApiAddMultipleRecipesRequest } from '../../../api/recipe/recipeModels';\nimport { useAsyncDispatcher } from '../../../hooks/useAsyncDispatcher';\nimport { useCurrentPriceType } from '../../../hooks/useCurrentPriceType';\nimport { useGroupError } from '../../../hooks/useGroupError';\nimport { useRequestEffects } from '../../../hooks/useRequestEffects';\nimport { useAppDispatch, useAppSelector } from '../../../hooks/useThunkDispatch';\nimport { storeSelectors } from '../../../selectors/storeSelectors';\nimport { ErrorGroup } from '../../../store/structureDefinitions/errorsState';\nimport { cartThunks } from '../../../thunks/cartThunks';\nimport { ga4CartTracking } from '../../../tracking/ga4/cart';\nimport type { ModifyCartAnalyticsOptions } from '../../../tracking/ga4/cart/ga4CartEvents';\nimport tracking from '../../../tracking/tracking';\nimport MissingItemBody from '../../organisms/MissingItemBody';\nimport PurchasableItemBody from '../../organisms/PurchasableItemBody/PurchasableItemBody';\nimport RecipeModalBody from '../RecipeModal/RecipeModalBody';\n\ninterface BuyableRecipeModalProps {\n recipeId: string;\n portions: number;\n tabToDisplay: RecipeModalTab;\n close: () => void;\n readonly?: boolean;\n analyticsListName: string;\n}\n\nconst useBuyableRecipeModalTracking = () => {\n const modalPopupSent = useRef(false);\n\n const trackModalPopup = useCallback((recipe: ApiRecipe, portions: number) => {\n if (!modalPopupSent.current) {\n tracking.ecommerce.recipes.modalPopup(recipe, RecipeModalTab.Products, portions);\n modalPopupSent.current = true;\n }\n }, []);\n\n const trackAddToCart = useCallback(\n (\n products: { quantity: number; productId: string; variantId?: string; index?: number }[],\n storeId: string,\n listOptions: ModifyCartAnalyticsOptions | null,\n ) => {\n ga4CartTracking.modifyCartItems(\n products.map((item) => ({\n index: item.index,\n productId: item.productId,\n previousQuantity: 0,\n newQuantity: item.quantity,\n variantId: item.variantId,\n })),\n storeId,\n listOptions,\n );\n },\n [],\n );\n\n return {\n trackModalPopup,\n trackBuyRecipe: tracking.ecommerce.recipes.buyRecipe,\n trackCalculationChange: tracking.ecommerce.recipes.calculationChange,\n trackPortionChange: tracking.ecommerce.recipes.portionChange,\n trackLinkClick: tracking.ecommerce.recipes.linkClick,\n trackSubstituteProduct: tracking.ecommerce.recipes.substituteProduct,\n trackAddToCart,\n };\n};\n\nconst BuyableRecipeModalBody: React.FC<React.PropsWithChildren<BuyableRecipeModalProps>> = (\n props,\n) => {\n const recipeId = props.recipeId.toString();\n const currentProductionUnit = useAppSelector(storeSelectors.currentProductionUnit);\n\n const getRecipeDispatcher = useAsyncDispatcher(recipeFlow.getRecipeById, {\n initialLoadingState: true,\n keepPreviousResult: true,\n });\n\n const { currentPriceType } = useCurrentPriceType();\n\n const { close, tabToDisplay } = props;\n\n const { execute: getRecipe, result: getRecipeResult, isLoading, error } = getRecipeDispatcher;\n\n useEffect(() => {\n if (error) {\n close();\n }\n }, [close, error]);\n\n useGroupError(ErrorGroup.Global, error);\n\n const {\n trackModalPopup,\n trackBuyRecipe,\n trackCalculationChange,\n trackPortionChange,\n trackLinkClick,\n trackSubstituteProduct,\n trackAddToCart,\n } = useBuyableRecipeModalTracking();\n\n const {\n updateItemQuantity,\n updateSubstituteProduct,\n updatePortions,\n updateCalculation,\n removeItem,\n calculateCart,\n recipeCart,\n recipeCartProducts,\n getProductExceptions,\n isLoading: isLoadingRecipeCart,\n } = useRecipeCart(!props.readonly);\n\n const handleSubstituteChangeClick = (item: RecipeItemState, product: ApiProduct) => {\n updateSubstituteProduct(item, product.identifier);\n trackSubstituteProduct(item.name, recipeId, product.identifier, product.name);\n };\n\n const {\n onSubsituteChangeClick,\n onSubstituteTriggerClick,\n expandedSubstituteIds,\n isLoadingSubstitutes,\n substitutes,\n } = useSubstitutes(handleSubstituteChangeClick, recipeCart?.items);\n\n const dispatch = useAppDispatch();\n\n useEffect(() => {\n getRecipe(recipeId);\n if (!props.readonly) {\n calculateCart({\n calculation: 'waste',\n prioritization: null,\n recipes: [{ recipeId, portions: props.portions }],\n });\n }\n }, [calculateCart, getRecipe, props.portions, props.readonly, recipeId]);\n\n useEffect(() => {\n if (getRecipeResult) {\n trackModalPopup(getRecipeResult, getRecipeResult?.yieldValue);\n }\n }, [getRecipeResult, trackModalPopup]);\n\n const buyRecipeDispatcher = useAsyncDispatcher((request: ApiAddMultipleRecipesRequest) =>\n dispatch(cartThunks.buyMultipleRecipes(request)),\n );\n\n const {\n execute: buyRecipe,\n isLoading: buyRecipeLoading,\n result: buyRecipeResult,\n } = buyRecipeDispatcher;\n useRequestEffects(\n buyRecipeDispatcher,\n {\n onSuccess: () => {\n const itemsToTrack = recipeCart?.items?.filter(\n (item) => !!item.quantity && item.quantity > 0 && item.purchasable,\n );\n if (itemsToTrack?.length) {\n trackAddToCart(\n itemsToTrack.map((item, index) => ({\n quantity: item.quantity!,\n productId: item.id,\n index,\n })),\n currentProductionUnit,\n {\n list: props.analyticsListName,\n listPosition: 0,\n recipe_list_id: recipeCart?.recipes\n ?.map((recipe) => recipe.code)\n .join('|'),\n recipe_list_name: recipeCart?.recipes\n ?.map((recipe) => recipe.title)\n .join('|'),\n recipe_origin: 'recipes',\n },\n );\n }\n },\n },\n ErrorGroup.Modal,\n );\n\n useEffect(() => {\n if (buyRecipeResult) {\n close();\n }\n }, [close, buyRecipeResult]);\n\n const recipePortions = recipeCart?.recipes.find((recipe) => recipe.code === recipeId)?.portions;\n\n const handlePortionChange = (portionQuantity: number) => {\n if (getRecipeResult) {\n trackPortionChange(getRecipeResult.name, recipeId, recipePortions, portionQuantity);\n }\n updatePortions(recipeId, portionQuantity);\n };\n\n const handleCalculationTypeChange = (\n calculationType: RecipeCalculationType,\n prioritization: RecipePrioritizationType | null,\n ) => {\n if (getRecipeResult) {\n trackCalculationChange(\n getRecipeResult.name,\n recipeId,\n calculationType,\n prioritization,\n recipePortions,\n );\n }\n\n updateCalculation(calculationType, prioritization);\n };\n\n const handleRecipeLinkClick = () => {\n if (getRecipeResult) {\n trackLinkClick(getRecipeResult.name, recipeId, recipePortions);\n }\n };\n\n const handleBuy = () => {\n const productExceptions = getProductExceptions();\n if (getRecipeResult) {\n trackBuyRecipe(getRecipeResult.name, recipeId, recipePortions);\n }\n\n if (recipeCart) {\n buyRecipe({\n calculation: recipeCart.calculation,\n prioritization: recipeCart.prioritization,\n recipes: recipeCart.recipes.map((x) => ({\n recipeId: x.code,\n portions: x.portions,\n group: getRecipeResult?.isFoodBox ? 'foodbox' : 'recipe',\n })),\n products: productExceptions?.map((x) => ({\n productId: x.id,\n qty: x.quantity,\n substituteId: x.substituteIdentifier,\n })),\n });\n }\n };\n\n return (\n <RecipeModalBody\n recipeData={getRecipeResult}\n modalTabToDisplay={tabToDisplay}\n handlePortionChange={handlePortionChange}\n handleCalculationTypeChange={handleCalculationTypeChange}\n handleBuy={handleBuy}\n close={close}\n priceType={currentPriceType}\n isLoading={isLoading || isLoadingRecipeCart || isLoadingSubstitutes || buyRecipeLoading}\n renderCartItem={(item) => {\n return (\n <RecipeProductListingItem\n key={item.id}\n recipeProduct={item}\n priceType={currentPriceType}\n product={recipeCartProducts?.find(\n (product) => product.identifier === item.id,\n )}\n recipeProductSubstitutes={\n substitutes[item.substituteIdentifier]?.substituteProducts\n }\n buyable={item.purchasable}\n isSubstituteActive={expandedSubstituteIds.includes(\n item.substituteIdentifier,\n )}\n handleSubstituteChange={(product: ApiProduct) => {\n onSubsituteChangeClick(item, product);\n }}\n analyticsOptions={{ list: 'produktersättare - varukorg' }}\n productSubstitutesBreakpoints={recipeModalProductSubstitutesBreakpoints}\n >\n {item.purchasable ? (\n <PurchasableItemBody\n item={item}\n sectionType=\"recipe\"\n hasActiveSubstitutes={expandedSubstituteIds.includes(\n item.substituteIdentifier,\n )}\n handleQuantityChange={updateItemQuantity}\n handleSubsituteTriggerClick={() =>\n onSubstituteTriggerClick(item.substituteIdentifier)\n }\n />\n ) : (\n <MissingItemBody\n item={item}\n recipeSectionType=\"recipe\"\n hasActiveSubstitutes={expandedSubstituteIds.includes(\n item.substituteIdentifier,\n )}\n handleSubsituteTriggerClick={() =>\n onSubstituteTriggerClick(item.substituteIdentifier)\n }\n handleRemoveItem={removeItem}\n />\n )}\n </RecipeProductListingItem>\n );\n }}\n cart={recipeCart}\n handleLinkClick={handleRecipeLinkClick}\n readonly={props.readonly}\n />\n );\n};\n\nexport default BuyableRecipeModalBody;\n","import { Icon } from '@coop/components';\nimport { Info1Icon } from '@coop/icons';\n\nimport styles from './MissingItemBody.module.less';\n\nconst MissingItemInfo = (props: { text: string }) => {\n return (\n <div className={styles.MissingItemInfo}>\n <Icon icon={Info1Icon} width={16} height={16} color=\"red\" />\n <span>{props.text}</span>\n </div>\n );\n};\n\nexport default MissingItemInfo;\n","import { ChipIconButton } from '@coop/components';\nimport { TrashIcon } from '@coop/icons';\nimport type { FC } from 'react';\n\nimport SharedBetweenRecipesTooltip from '../../../../recipe/components/SharedBetweenRecipesTooltip/SharedBetweenRecipesTooltip';\nimport type { RecipeItemState, RecipeSectionType } from '../../../../recipe/models';\nimport SubstituteTrigger from '../../atoms/SubstituteTrigger';\nimport styles from './MissingItemBody.module.less';\nimport MissingItemInfo from './MissingItemInfo';\n\ninterface MissingItemBodyProps {\n item: RecipeItemState;\n recipeSectionType: RecipeSectionType;\n hasActiveSubstitutes: boolean;\n handleSubsituteTriggerClick: (item: RecipeItemState) => void;\n handleRemoveItem: (item: RecipeItemState) => void;\n}\n\nconst MissingItemBody: FC<React.PropsWithChildren<MissingItemBodyProps>> = (props) => {\n return (\n <div className={styles.RecipeItemActionsContainer}>\n <MissingItemInfo text=\"Varan saknas i sortimentet.\" />\n <div className={styles.RecipeItemActions}>\n <div className={styles['RecipeItemActions-info']}>\n {props.item.belongsToRecipes && (\n <SharedBetweenRecipesTooltip\n sectionType={props.recipeSectionType}\n belongsToRecipes={props.item.belongsToRecipes}\n />\n )}\n </div>\n {props.item.substituteProductsAmount > 0 && (\n <SubstituteTrigger\n handleSubsituteTrigger={() => props.handleSubsituteTriggerClick(props.item)}\n theme=\"greenCta\"\n isActive={props.hasActiveSubstitutes}\n />\n )}\n {props.recipeSectionType !== 'common' && (\n <ChipIconButton\n icon={TrashIcon}\n label=\"Ta bort\"\n size={32}\n theme=\"green2\"\n onClick={() => props.handleRemoveItem(props.item)}\n />\n )}\n </div>\n </div>\n );\n};\n\nexport default MissingItemBody;\n","import type { FC } from 'react';\n\nimport SharedBetweenRecipesTooltip from '../../../../recipe/components/SharedBetweenRecipesTooltip/SharedBetweenRecipesTooltip';\nimport type { RecipeItemState, RecipeSectionType } from '../../../../recipe/models';\nimport SubstituteTrigger from '../../atoms/SubstituteTrigger';\nimport { QuantityStepper } from '../../QuantityStepper';\n\ninterface PurchasableItemBodyProps {\n item: RecipeItemState;\n sectionType: RecipeSectionType;\n hasActiveSubstitutes: boolean;\n handleQuantityChange: (item: RecipeItemState, newQuantity: number) => void;\n handleSubsituteTriggerClick: (item: RecipeItemState) => void;\n}\n\nconst PurchasableItemBody: FC<React.PropsWithChildren<PurchasableItemBodyProps>> = (props) => {\n return (\n <>\n {props.item.belongsToRecipes && (\n <SharedBetweenRecipesTooltip\n sectionType={props.sectionType}\n belongsToRecipes={props.item.belongsToRecipes}\n />\n )}\n {props.item.substituteProductsAmount > 0 && (\n <SubstituteTrigger\n handleSubsituteTrigger={() => props.handleSubsituteTriggerClick(props.item)}\n theme=\"whiteGreen\"\n isActive={props.hasActiveSubstitutes}\n />\n )}\n {(!!props.item.quantity || props.item.quantity === 0) && ( // 0 is allowed for good to have, !!0 = false, hence additional check for 0\n <QuantityStepper\n quantity={props.item.quantity}\n setQuantity={(newQuantity) => {\n props.handleQuantityChange(props.item, newQuantity);\n }}\n />\n )}\n </>\n );\n};\n\nexport default PurchasableItemBody;\n","import type { RecipeItemState } from '../../../../recipe/models';\n\nexport const getRecipeSection = (item: RecipeItemState) => {\n return {\n recipeId: item.group === 'singleProducts' ? item.belongsToRecipes[0].code : 'shared',\n recipeName: item.group === 'singleProducts' ? item.belongsToRecipes[0].name : 'shared',\n };\n};\n","/* eslint-disable no-param-reassign */\nimport produce from 'immer';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport _ from 'underscore';\n\nimport type {\n ApiHybrisRecipe,\n ApiRecipeList,\n ApiRecipeProductItem,\n} from '../../common/api/recipe/recipeModels';\nimport { SyncronQueue } from '../../common/api/SyncronQueue';\nimport { productFlow } from '../../common/flow/product/productFlow';\nimport { useAsyncDispatcher } from '../../common/hooks/useAsyncDispatcher';\nimport { useGroupErrorEffect } from '../../common/hooks/useGroupError';\nimport { useAppSelector } from '../../common/hooks/useThunkDispatch';\nimport { storeSelectors } from '../../common/selectors/storeSelectors';\nimport { ErrorGroup } from '../../common/store/structureDefinitions/errorsState';\nimport { ga4RecipesTracking } from '../../common/tracking/ga4/recipes';\nimport { getRecipeSection } from '../../common/tracking/ga4/recipes/ga4Recipes.utils';\nimport recipeFlow from '../flow/recipeFlow';\nimport type {\n RecipeCalculationType,\n RecipeItemState,\n RecipePrioritizationType,\n RecipeProductException,\n RecipeProductGroupType,\n RecipeSectionType,\n ResolveRecipesRequest,\n} from '../models';\nimport { ItemState } from '../models';\n\nexport interface JoinedRecipe {\n name: string;\n id: string;\n}\n\nexport interface RecipeItemProductSubstitute extends RecipeItemState {\n product: ApiProduct;\n}\n\nexport const mapItem = (\n recipeProductItem: ApiRecipeProductItem,\n group: RecipeProductGroupType,\n isRemoved: boolean,\n): RecipeItemState => {\n return {\n id: recipeProductItem.id,\n priceData: recipeProductItem.priceData,\n purchasable: recipeProductItem.purchasable,\n quantity: recipeProductItem.quantity,\n substituteProductsAmount: recipeProductItem.substituteProductsAmount,\n image: recipeProductItem.image,\n manufacturer: recipeProductItem.manufacturer,\n name: recipeProductItem.name,\n substituteIdentifier: recipeProductItem.substituteIdentifier,\n packageSizeInformation: recipeProductItem.packageSizeInformation,\n belongsToRecipes:\n recipeProductItem.belongsToRecipes?.map((item) => ({\n name: item.name,\n code: item.recipeId,\n })) || [],\n selectedVarianceCode: recipeProductItem.selectedVarianceCode,\n totalPriceData: recipeProductItem.rowTotalPriceData,\n group,\n state: isRemoved ? ItemState.Removed : ItemState.Default,\n };\n};\n\nexport type RecipeSection =\n | ({\n type: Extract<RecipeSectionType, 'common'>;\n } & Omit<Section, 'portions'>)\n | ({\n type: Extract<RecipeSectionType, 'recipe'>;\n } & Section)\n | ({\n type: Extract<RecipeSectionType, 'shared'>;\n } & Omit<Section, 'portions'>);\n\nexport interface Section {\n id: string; // could be shared or common\n type: RecipeSectionType;\n name: string;\n imageUrl: string;\n portions: number;\n substituteIdentifiers: string[];\n productIdentifiers: string[];\n sharedSubstituteIdentifiers?: string[];\n}\n\nconst mapItems = (\n hybrisRecipeList: ApiRecipeList,\n removedSubsituteIdentifiers: string[],\n): RecipeItemState[] => {\n const singleProducts = (hybrisRecipeList.singleProducts || []).map((item) =>\n mapItem(\n item,\n 'singleProducts',\n removedSubsituteIdentifiers.includes(item.substituteIdentifier),\n ),\n );\n const sharedProducts = (hybrisRecipeList.sharedProducts || []).map((item) =>\n mapItem(\n item,\n 'sharedProducts',\n removedSubsituteIdentifiers.includes(item.substituteIdentifier),\n ),\n );\n const goodToHaveProducts = (hybrisRecipeList.goodToHaveProducts || []).map((item) =>\n mapItem(\n item,\n 'commonProducts',\n removedSubsituteIdentifiers.includes(item.substituteIdentifier),\n ),\n );\n\n const allItems = [...singleProducts, ...sharedProducts, ...goodToHaveProducts];\n return allItems;\n};\n\nconst mapSections = (\n recipeList: ApiRecipeList,\n removedSubsituteIdentifiers: string[],\n): RecipeSection[] => {\n const singleProducts = (recipeList.singleProducts || []).filter(\n (item) => !removedSubsituteIdentifiers.includes(item.substituteIdentifier),\n );\n const sharedProducts = recipeList.sharedProducts.filter(\n (item) => !removedSubsituteIdentifiers.includes(item.substituteIdentifier),\n );\n const goodToHaveProducts = recipeList.goodToHaveProducts.filter(\n (item) => !removedSubsituteIdentifiers.includes(item.substituteIdentifier),\n );\n\n const recipeSectionsMap = singleProducts.reduce<Record<string, RecipeSection>>(\n (prev, next) => {\n const sectionId = next.belongsToRecipes[0].recipeId;\n const sectionName = next.belongsToRecipes[0].name;\n const recipe = recipeList.recipes.find((_recipe) => _recipe.code === sectionId);\n\n const final = { ...prev };\n\n if (recipe) {\n final[sectionId] = {\n id: sectionId,\n type: 'recipe',\n name: sectionName,\n imageUrl: recipe.imageUrl,\n portions: recipe.portions,\n substituteIdentifiers: prev[sectionId]?.substituteIdentifiers\n ? [...prev[sectionId].substituteIdentifiers, next.substituteIdentifier]\n : [next.substituteIdentifier],\n productIdentifiers: prev[sectionId]?.productIdentifiers\n ? [...prev[sectionId].productIdentifiers, next.id]\n : [next.id],\n };\n }\n\n return final;\n },\n {} as Record<string, RecipeSection>,\n );\n\n // add info how many products are in shared section for each recipe\n Object.keys(recipeSectionsMap).forEach((sectionId) => {\n const sharedProductsBelongingToRecipe = sharedProducts\n .filter((sharedProduct) =>\n sharedProduct.belongsToRecipes\n .map((joinedRecipe) => joinedRecipe.recipeId)\n .includes(sectionId),\n )\n .map((product) => product.substituteIdentifier);\n\n recipeSectionsMap[sectionId].sharedSubstituteIdentifiers = sharedProductsBelongingToRecipe;\n });\n\n const sharedRecipeProductIds = sharedProducts.map((x) => x.id);\n const goodToHaveProductIds = goodToHaveProducts.map((x) => x.id);\n\n const sharedRecipeSubstituteIds = sharedProducts.map((x) => x.substituteIdentifier);\n const goodToHaveSubstituteIds = goodToHaveProducts.map((x) => x.substituteIdentifier);\n\n const recipeSectionList = Object.values<RecipeSection>(recipeSectionsMap);\n\n if (sharedRecipeSubstituteIds.length) {\n recipeSectionList.push({\n id: 'shared',\n type: 'shared',\n name: 'Delas mellan recepten',\n substituteIdentifiers: sharedRecipeSubstituteIds,\n productIdentifiers: sharedRecipeProductIds,\n imageUrl: '/Assets/Images/recipe-shared.png',\n });\n }\n\n if (goodToHaveProductIds.length) {\n recipeSectionList.push({\n id: 'common',\n type: 'common',\n name: 'Basvaror du behöver ha hemma',\n substituteIdentifiers: goodToHaveSubstituteIds,\n productIdentifiers: goodToHaveProductIds,\n imageUrl: '/Assets/Images/recipe-good-to-have.png',\n });\n }\n\n return recipeSectionList;\n};\n\nconst createCartState = (\n recipeList: ApiRecipeList,\n removedItems: RecipeItemState[],\n): RecipeCartState => {\n const removedSubstituteIds = removedItems.map((item) => item.substituteIdentifier);\n const sections = mapSections(recipeList, removedSubstituteIds);\n\n return {\n calculation: recipeList.calculation,\n prioritization: recipeList.prioritization,\n recipes: recipeList.recipes,\n items: mapItems(recipeList, removedSubstituteIds),\n sections,\n totalPriceData: {\n inclTaxPrice: recipeList.recipesTotalPrice.value,\n exclTaxPrice: recipeList.recipesTotalPrice.valueWithoutTax,\n },\n };\n};\n\nconst recipeCartQueue = new SyncronQueue();\n\ninterface RecipeData {\n recipeId: string;\n portions: number;\n}\n\nexport interface RecipeCartState {\n recipes: ApiHybrisRecipe[];\n prioritization?: RecipePrioritizationType;\n calculation: RecipeCalculationType;\n items: RecipeItemState[];\n sections: RecipeSection[];\n totalPriceData: ApiPriceData;\n}\n\ninterface RecipeItemChangeState extends RecipeItemState {\n removed?: boolean;\n}\n\ninterface RecipeCartChangesState {\n recipes: RecipeData[];\n prioritization: RecipePrioritizationType | null;\n calculation: RecipeCalculationType;\n productChanges: Record<string, RecipeItemChangeState>;\n}\n\nconst mapProductChangesToExceptions = (productChanges: Record<string, RecipeItemState>) => {\n if (!productChanges) return [];\n\n const changedProducts = Object.values(productChanges);\n const productExceptions = changedProducts.map<RecipeProductException>((cp) => ({\n productId: cp.id,\n substituteId: cp.substituteIdentifier,\n qty: cp.quantity,\n }));\n\n return productExceptions;\n};\n\nconst useRecipeCart = (initialLoading: boolean = true) => {\n const [cartState, setCartState] = useState<RecipeCartState | null>(null);\n const [cartChangesState, setCartChangesState] = useState<RecipeCartChangesState | null>(null);\n const removedItems = useRef<RecipeItemState[]>([]);\n\n const currentProductionUnit = useAppSelector(storeSelectors.currentProductionUnit);\n\n const updateSubstituteProduct = useCallback((item: RecipeItemState, newProductId: string) => {\n setCartChangesState((prevChanges) => {\n return produce(prevChanges, (draft) => {\n if (draft) {\n draft.productChanges[item.substituteIdentifier] = {\n ...item,\n id: newProductId,\n quantity: null,\n };\n }\n\n return draft;\n });\n });\n\n const recipeSection = getRecipeSection(item);\n\n ga4RecipesTracking.weeklyMenu.handleIngredient('change item')?.(\n recipeSection.recipeId,\n recipeSection.recipeName,\n item.id,\n item.name,\n );\n }, []);\n\n const updateItemQuantity = useCallback((item: RecipeItemState, newQuantity: number) => {\n setCartChangesState((prevChanges) => {\n return produce(prevChanges, (draft) => {\n if (draft) {\n draft.productChanges[item.substituteIdentifier] = {\n ...item,\n quantity: newQuantity,\n };\n }\n return draft;\n });\n });\n\n const recipeSection = getRecipeSection(item);\n\n if (item.quantity === null) {\n return;\n }\n\n if (newQuantity > item.quantity) {\n // add\n ga4RecipesTracking.weeklyMenu.handleIngredient('add')?.(\n recipeSection.recipeId,\n recipeSection.recipeName,\n item.id,\n item.name,\n );\n }\n\n if (newQuantity < item.quantity) {\n // remove\n ga4RecipesTracking.weeklyMenu.handleIngredient('remove')?.(\n recipeSection.recipeId,\n recipeSection.recipeName,\n item.id,\n item.name,\n );\n }\n }, []);\n\n const updatePortions = useCallback((recipeId: string, portions: number) => {\n removedItems.current = [];\n setCartChangesState((prevChanges) => {\n return produce(prevChanges, (draft) => {\n if (draft) {\n Object.values(draft.productChanges).forEach((pc) => {\n pc.quantity = null;\n });\n const recipeToChange = draft.recipes.find((cr) => cr.recipeId === recipeId);\n if (recipeToChange) {\n recipeToChange.portions = portions;\n }\n }\n\n return draft;\n });\n });\n }, []);\n\n const updateCalculation = useCallback(\n (\n calculationType: RecipeCalculationType,\n prioritizationType: RecipePrioritizationType | null,\n ) => {\n removedItems.current = [];\n setCartChangesState((prevChanges) => {\n return produce(prevChanges, (draft) => {\n if (draft) {\n draft.productChanges = {}; // what to do here, keep substitues or always recalculate?\n draft.calculation = calculationType;\n draft.prioritization = prioritizationType;\n }\n\n return draft;\n });\n });\n },\n [],\n );\n\n const calculateCart = useCallback((request: ResolveRecipesRequest) => {\n removedItems.current = [];\n setCartChangesState((prevChanges) => {\n return produce(prevChanges, (draft) => ({\n ...draft,\n calculation: request.calculation,\n prioritization: request.prioritization,\n recipes: request.recipes,\n productChanges: {}, // what to do here, keep substitues or always recalculate?\n }));\n });\n }, []);\n\n const reCalculateCart = useCallback(() => {\n removedItems.current = [];\n setCartChangesState((prevChanges) => {\n return produce(prevChanges, (draft) => {\n if (draft) {\n draft.productChanges = {};\n }\n\n return draft; // what to do here, keep substitues or always recalculate?\n });\n });\n }, []);\n\n const removeItem = useCallback((item: RecipeItemState) => {\n removedItems.current.push(item);\n\n // fake cart recalculate\n setCartChangesState((prevChanges) => {\n return produce(prevChanges, (draft) => {\n if (draft) {\n return { ...draft };\n }\n\n return draft;\n });\n });\n\n const recipeSection = getRecipeSection(item);\n\n ga4RecipesTracking.weeklyMenu.handleIngredient('empty')?.(\n recipeSection.recipeId,\n recipeSection.recipeName,\n item.id,\n item.name,\n );\n }, []);\n\n const {\n execute: resolve,\n result: resolvedRecipes,\n isLoading,\n error: resolveError,\n } = useAsyncDispatcher(\n async (request: ResolveRecipesRequest, storeId: string) => {\n // direct resolve to nortfork\n // const normalResolve = await recipeFlow.resolveGastrofyRecipes({\n // options: {\n // calculation: request.calculation,\n // prioritization: request.prioritization || undefined,\n // productExceptions: request.products?.map((x) => ({\n // amount: x.qty || 0,\n // externalId: x.productId,\n // substituteIdentifier: x.substituteId,\n // })),\n // },\n // recipes: request.recipes.map((x) => ({\n // externalId: x.recipeId,\n // portions: x.portions,\n // })),\n // storeId,\n // });\n\n return recipeCartQueue.run(async () =>\n recipeFlow.resolveRecipes(\n {\n calculation: request.calculation,\n prioritization: request.prioritization,\n recipes: request.recipes,\n products: request.products,\n },\n storeId,\n ),\n );\n },\n {\n keepPreviousResult: true,\n initialLoadingState: initialLoading,\n },\n );\n\n useGroupErrorEffect(ErrorGroup.Global, !!resolveError, resolveError);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const debouncedResolve = useCallback(_.debounce(resolve, 200), []);\n\n useEffect(() => {\n if (cartChangesState) {\n debouncedResolve(\n {\n calculation: cartChangesState.calculation,\n prioritization: cartChangesState.prioritization,\n recipes: cartChangesState.recipes,\n products: mapProductChangesToExceptions(cartChangesState.productChanges),\n },\n currentProductionUnit,\n );\n }\n }, [cartChangesState, currentProductionUnit, debouncedResolve]);\n\n const productChanges = useMemo(\n () => (cartChangesState ? Object.values(cartChangesState.productChanges) : []),\n [cartChangesState],\n );\n\n const isDirty = productChanges.length > 0 || removedItems.current.length;\n\n useEffect(() => {\n if (resolvedRecipes) {\n // we need to fake removing items, thats why i keep them in ref\n setCartState(createCartState(resolvedRecipes, removedItems.current));\n }\n }, [resolvedRecipes]);\n\n const { execute, result: recipeCartProducts } = useAsyncDispatcher(\n productFlow.getProductsByIds,\n {\n keepPreviousResult: true,\n initialResultState: [],\n },\n );\n\n useEffect(() => {\n if (cartState?.items && cartState.items.length) {\n execute(\n cartState.items.map((x) => x.id),\n currentProductionUnit,\n );\n }\n }, [execute, cartState, currentProductionUnit]);\n\n const getProductExceptions = () => {\n const changedSubstituteIds =\n cartChangesState && Object.keys(cartChangesState.productChanges);\n\n const changedItems = cartState?.items.filter(\n (item) =>\n changedSubstituteIds && changedSubstituteIds.includes(item.substituteIdentifier),\n );\n\n return changedItems;\n };\n\n return {\n updateItemQuantity,\n updateSubstituteProduct,\n updatePortions,\n updateCalculation,\n removeItem,\n calculateCart,\n reCalculateCart,\n recipeCart: cartState,\n recipeCartChanges: cartChangesState,\n getProductExceptions,\n recipeCartProducts,\n isLoading,\n isDirty,\n };\n};\n\nexport default useRecipeCart;\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { productFlow } from '../../common/flow/product/productFlow';\nimport { useAsyncDispatcher } from '../../common/hooks/useAsyncDispatcher';\nimport { useRequestEffects } from '../../common/hooks/useRequestEffects';\nimport { useAppSelector } from '../../common/hooks/useThunkDispatch';\nimport { storeSelectors } from '../../common/selectors/storeSelectors';\nimport { ErrorGroup } from '../../common/store/structureDefinitions/errorsState';\nimport recipeFlow from '../flow/recipeFlow';\nimport type { RecipeItemState } from '../models';\n\nconst loadHybrisSubstitutes = async (storeId: string, substituteIdentifier: string) => {\n const recipeProducts = await recipeFlow.getRecipeSubstitutes(storeId, substituteIdentifier);\n const products =\n (await productFlow.getProductsByIds(\n recipeProducts\n .filter((substitute) => substitute.purchasable)\n .map((substitute) => substitute.id),\n storeId,\n )) || [];\n\n return {\n substituteIdentifier,\n substitutes: products,\n };\n};\n\nconst useSubstitutes = (\n handleSubstituteChangeClick: (item: RecipeItemState, product: ApiProduct) => void,\n allItems?: RecipeItemState[],\n) => {\n const [expandedSubstituteIds, setExpandedSubstituteIds] = useState<string[]>([]);\n const substituteSentForChange = useRef<{ substituteIdentifier: string; productId: string }>();\n\n const onSubstituteToggle = useCallback((substituteIdentifier: string) => {\n setExpandedSubstituteIds((prevIds) => {\n const newIds = [...prevIds];\n const index = newIds.findIndex((item) => item === substituteIdentifier);\n\n if (index === -1) {\n newIds.push(substituteIdentifier);\n } else {\n newIds.splice(index, 1);\n }\n\n return newIds;\n });\n }, []);\n\n // since we dont have a substitute change endpoint like in cart, we need to wait for the resolve to return,\n // this is not ideal, we then try to see if its in the returned items\n useEffect(() => {\n if (\n !!substituteSentForChange.current &&\n allItems?.find(\n (item) =>\n item.id === substituteSentForChange.current?.productId &&\n item.substituteIdentifier ===\n substituteSentForChange.current.substituteIdentifier,\n )\n ) {\n onSubstituteToggle(substituteSentForChange.current.substituteIdentifier);\n }\n substituteSentForChange.current = undefined;\n }, [onSubstituteToggle, allItems]);\n\n const onSubsituteChangeClick = useCallback(\n (item: RecipeItemState, product: ApiProduct) => {\n substituteSentForChange.current = {\n substituteIdentifier: item.substituteIdentifier,\n productId: product.identifier,\n };\n handleSubstituteChangeClick(item, product);\n },\n [handleSubstituteChangeClick],\n );\n\n const onSubstitutesLoaded = useCallback(\n (substituteIdentifier: string, subsituteCount: number) => {\n if (subsituteCount > 0) {\n onSubstituteToggle(substituteIdentifier);\n }\n },\n [onSubstituteToggle],\n );\n\n const [substitutes, setSubstitutes] = useState<\n Record<string, { loadedCount: number; substituteProducts: ApiProduct[] }>\n >({});\n const currentProductionUnit = useAppSelector(storeSelectors.currentProductionUnit);\n\n const substitutesDispatcher = useAsyncDispatcher(loadHybrisSubstitutes);\n const {\n execute: loadSubstitutes,\n result: substitutesById,\n isLoading: isLoadingSubstitutes,\n } = substitutesDispatcher;\n useRequestEffects(substitutesDispatcher, {}, ErrorGroup.Global);\n\n useEffect(() => {\n if (substitutesById) {\n setSubstitutes((substituteMap) => ({\n ...substituteMap,\n [substitutesById.substituteIdentifier]: {\n substituteProducts: substitutesById.substitutes,\n loadedCount: substitutesById.substitutes.length,\n },\n }));\n onSubstitutesLoaded(\n substitutesById.substituteIdentifier,\n substitutesById.substitutes.length,\n );\n }\n }, [substitutesById, onSubstitutesLoaded]);\n\n const onSubstituteTriggerClick = useCallback(\n (substituteIdentifier: string) => {\n if (substitutes[substituteIdentifier]?.substituteProducts.length) {\n onSubstituteToggle(substituteIdentifier);\n } else {\n loadSubstitutes(currentProductionUnit, substituteIdentifier);\n }\n },\n [onSubstituteToggle, loadSubstitutes, currentProductionUnit, substitutes],\n );\n\n return {\n onSubsituteChangeClick,\n onSubstituteTriggerClick,\n substitutes,\n isLoadingSubstitutes,\n expandedSubstituteIds,\n };\n};\n\nexport default useSubstitutes;\n","import type { PriceData } from '../common/models/priceData/priceData';\nimport type { EpiRecipeStartPageType } from '../episerver/components/pages/EpiRecipeStartPage/epiRecipeStartPageType';\n\ntype CategoryName = string;\ntype CategoryUrlSegment = string;\nexport type UrlSegmentToCategoryName = Record<CategoryUrlSegment, CategoryName>;\nexport type CategoryNameToUrlSegment = Record<CategoryName, CategoryUrlSegment>;\nexport type CategoryNameToContentReference = Record<CategoryName, string>;\nexport type CategoryNamesUnderLevel1 = Record<CategoryName, boolean>;\nexport type GetUrlForCategoriesSignature = (args: { categories: string[] }) => string;\nexport type RecipeQueryParam = 'page' | 'sort' | 'filter' | 'query';\nexport type SelectedEpiRecipeStartPageType = Pick<\n EpiRecipeStartPageType,\n | 'startpageModules'\n | 'contentLink'\n | 'contentType'\n | 'name'\n | 'startPublish'\n | 'metaDescription'\n | 'preamble'\n | 'popularCategories'\n | 'url'\n | 'pageTypeNameForAnalytics'\n>;\nexport type RecipeCalculationType = 'waste' | 'price';\nexport type RecipePrioritizationType = 'organic' | 'sugar-free' | 'lactose-free' | 'gluten-free';\n\nexport const sectionTypes = {\n recipe: 'recipe',\n shared: 'shared',\n common: 'common',\n};\n\n// export const sectionTypes = ['recipe', 'shared', 'common'] as const;\nexport type RecipeSectionType = keyof typeof sectionTypes;\n\nexport const productGroupTypes = ['singleProducts', 'sharedProducts', 'commonProducts'] as const;\nexport type RecipeProductGroupType = (typeof productGroupTypes)[number];\n\nexport enum ItemState {\n Default = 'default',\n Removed = 'removed',\n}\nexport interface RecipeProductException {\n productId: string;\n qty: number | null;\n substituteId: string;\n variantId?: string;\n}\n\nexport interface RecipeItemState {\n id: string;\n name: string;\n image?: string;\n manufacturer?: string;\n substituteIdentifier: string;\n substituteProductsAmount: number;\n quantity: number | null;\n purchasable: boolean;\n priceData: PriceData;\n totalPriceData: PriceData;\n packageSizeInformation: string;\n belongsToRecipes: SharedRecipe[];\n selectedVarianceCode?: string;\n\n // derived:\n group: RecipeProductGroupType;\n state: ItemState;\n}\n\nexport interface ResolveRecipesRequest {\n recipes: { recipeId: string; portions: number }[];\n products?: RecipeProductException[];\n prioritization: RecipePrioritizationType | null;\n calculation: RecipeCalculationType;\n}\n\nexport enum RecipeModalTab {\n Overview = 1,\n Products = 2,\n}\n\nexport const gastrofyAllergies = ['gluten', 'sugar', 'high-lactose', 'low-lactose', 'fodmap'];\n\nexport type GastrofyAllergiesType = (typeof gastrofyAllergies)[number];\n\nexport const gastrofyDiets = [\n 'paleo',\n 'vegan',\n 'vegetarian',\n 'pregnant',\n 'low-carb',\n 'inflammatory',\n 'anti-inflammatory',\n];\n\nexport type GastrofyDietsType = (typeof gastrofyDiets)[number];\n\nexport const gastrofyExcludes = [\n 'beef',\n 'pork',\n 'poultry',\n 'fish',\n 'shellfish',\n 'wild-meat',\n 'lamb',\n] as const;\n\nexport type GastrofyExcludeType = (typeof gastrofyExcludes)[number];\n\nexport interface RecipeDiscoveryRequest {\n offset?: number;\n limit: number;\n storeId: string;\n dataFields?: string[];\n extraData?: string[];\n tags?: string[];\n exclude?: GastrofyExcludeType[];\n allergies?: GastrofyAllergiesType[];\n diets?: GastrofyDietsType[];\n randomize?: boolean;\n excludeRecipeIds?: string[];\n externalRecipeIds?: string[];\n mustHaveImage?: boolean;\n isPublished?: boolean;\n matchAllProducts?: boolean;\n productIds?: string[];\n orderBy?: string[];\n}\n\nexport interface RecipeResolveRequest {\n storeId: string;\n options: Options;\n recipes: RecipeResolveData[];\n}\n\ninterface ProductException {\n externalId: string;\n substituteIdentifier: string;\n amount: number;\n}\n\ninterface Options {\n productExceptions?: ProductException[];\n calculation: RecipeCalculationType;\n prioritization?: RecipePrioritizationType;\n}\n\ninterface RecipeResolveData {\n externalId: string;\n portions: number;\n}\n\nexport interface SaveRecipeCommentRequest {\n recipeExternalId: string;\n authorName: string;\n comment: string;\n}\n\nexport interface RecipeComment {\n id: number;\n recipeId: number;\n name: string;\n comment: string;\n date: Date;\n isAdmin: boolean;\n}\n\nexport interface ImageSticker {\n imageUrl: string;\n keyword: string;\n}\n\nexport interface RecipePart {\n name?: string;\n ingredients: Ingredient[];\n}\n\nexport interface Ingredient {\n friendlyText: string;\n formattedQuantity: string;\n unit: string;\n sequenceNumber: number;\n}\n\nexport interface CookingInstructions {\n title: string;\n instructions: string[];\n}\n\nexport interface RecipeCategory {\n order: number;\n categories: string[];\n}\n\nexport interface SharedRecipe {\n code: string;\n name: string;\n}\nexport interface RecipeProps {\n id: number;\n externalId: string;\n name: string;\n imageUrl: string;\n stickerUrl?: string;\n portions: number;\n portionsUnit: string;\n parts: RecipePart[];\n averageRating: number;\n ratingPercent: number;\n ratingCount: number;\n preamble: string;\n climateImpactKg: number | null;\n ovenTemperature: string;\n cookingTime: string;\n prepTime: string;\n totalTime: string;\n cookingInstructions: CookingInstructions[];\n servingTips: string;\n tips: string;\n numberOfIngredients: number;\n recipeCreator?: string;\n categories: RecipeCategory[];\n comments: RecipeComment[];\n isFoodBox: boolean;\n}\n","import type { ApiCategoriesUrlOrder } from '../../models/recipe/recipeModel';\nimport type { RecipeCategoryFacet } from '../search/models/models';\nimport type {\n CategoryNamesUnderLevel1,\n CategoryNameToUrlSegment,\n GetUrlForCategoriesSignature,\n} from './models';\n\n/**\n *\n * @param currStringArray current state of array\n * @param newString to be added or removed from currStringArray\n * @returns new array with or without newString\n */\nexport const createNewArrayByTogglingString = (currStringArray: string[], newString: string) => {\n const shouldRemoveString = currStringArray.includes(newString);\n\n if (shouldRemoveString) {\n return currStringArray.filter((name) => name !== newString);\n }\n\n return [...currStringArray, newString];\n};\n\n/**\n * @returns a function that creates a path string where the categories are ordered correctly\n */\nexport const createGetUrlForCategories =\n (\n categoryNameToUrlSegment: CategoryNameToUrlSegment,\n categoriesUrlOrder: ApiCategoriesUrlOrder,\n recipeRootUrl: string,\n ): GetUrlForCategoriesSignature =>\n ({ categories }: { categories: string[] }) => {\n const sortByCategoryUrlOrder = (a: string, b: string) =>\n categoriesUrlOrder[a.toLowerCase()] - categoriesUrlOrder[b.toLowerCase()];\n\n const mapCategoryNameToUrlSegment = (categoryName: string) =>\n categoryName ? categoryNameToUrlSegment[categoryName.toLowerCase()] : null;\n\n const removedPotentialLastSlashFromRoot =\n recipeRootUrl.slice(-1) === '/'\n ? recipeRootUrl.slice(0, recipeRootUrl.length - 1)\n : recipeRootUrl;\n\n const hasFilterQuery = categories.length > 2;\n\n const builtPath = categories\n .slice()\n .sort(sortByCategoryUrlOrder)\n .map(mapCategoryNameToUrlSegment)\n .filter(Boolean)\n .reduce((acc, currSegment, index) => {\n if (index < 2) {\n return `${acc}/${currSegment}`;\n }\n\n if (index === 2) {\n return `${acc}?filter=${currSegment}`;\n }\n\n return `${acc},${currSegment}`;\n }, removedPotentialLastSlashFromRoot);\n\n return hasFilterQuery ? builtPath : `${builtPath}/`;\n };\n\nexport const getCategoriesWhileRemovingCategoryFacetChildren = ({\n currentCategories,\n category,\n}: {\n currentCategories: string[];\n category: RecipeCategoryFacet;\n}) => {\n if (Array.isArray(category.categories)) {\n const childrenNames = category.categories.map((childCategory) =>\n childCategory.item.toLowerCase(),\n );\n\n const categoriesWithoutChildren = currentCategories.filter(\n (currCategory) => !childrenNames.includes(currCategory),\n );\n\n return createNewArrayByTogglingString(\n categoriesWithoutChildren,\n category.item.toLowerCase(),\n );\n }\n\n return createNewArrayByTogglingString(currentCategories, category.item.toLowerCase());\n};\n\nexport const getCategoriesWhileRemovingCategoryFacetsParent = ({\n currentCategories,\n category,\n parentCategory,\n}: {\n currentCategories: string[];\n category: RecipeCategoryFacet;\n parentCategory: RecipeCategoryFacet;\n}) => {\n const lowerCaseParentName = parentCategory.item.toLowerCase();\n\n const categoriesWithoutParent = currentCategories.filter(\n (categoryName) => categoryName !== lowerCaseParentName,\n );\n\n return createNewArrayByTogglingString(categoriesWithoutParent, category.item.toLowerCase());\n};\n\nexport const getAllCategoryNamesFromLevel2AndDown = (\n categories: RecipeCategoryFacet[] | null,\n collectedNames: string[] = [],\n rootCall: boolean = true,\n): string[] => {\n if (!categories) {\n return collectedNames;\n }\n\n return categories.reduce((acc, facet) => {\n const childCategories = getAllCategoryNamesFromLevel2AndDown(\n facet.categories,\n collectedNames,\n false,\n );\n\n if (rootCall) {\n return [...acc, ...childCategories];\n }\n\n return [...acc, ...childCategories, facet.item];\n }, collectedNames);\n};\n\n/**\n * Removes categories on level 1\n * @returns the categories we can show\n */\nexport const getCategoryNamesUnderLevel1 = (\n ssrCategoriesUrlOrder: ApiCategoriesUrlOrder,\n): CategoryNamesUnderLevel1 => {\n const obj = ssrCategoriesUrlOrder ?? {};\n return Object.entries(obj).reduce((acc, [key, val]) => {\n if (val % 1000 !== 0) {\n return {\n ...acc,\n [key]: true,\n };\n }\n\n return acc;\n }, {});\n};\n\nexport const buildRecipeRedirectUrl = (externalId: string) => `/redirect/recipe/${externalId}`;\n"],"names":["recipeProduct","recipeProductItem","product","recipeProductSubstitutes","isSubstituteActive","buyable","children","handleSubstituteChange","additionalClassNames","analyticsOptions","productSubstitutesBreakpoints","isConstrained","priceType","productPromotion","slotPrice","className","totalPrice","totalPriceData","align","showExcludingTaxInfo","ExcludeTax","getPriceTypeText","slotSplash","promotion","isNicotineProduct","details","isPharmaceutical","pharmaceuticalData","name","packageSizeInformation","variantName","selectedVarianceCode","variant","variants","find","_variant","id","getVariantName","image","manufacturer","style","position","overflow","substitutes","handleProductSubstitution","recipeModalProductSubstitutesBreakpoints","getUniqueBreakpointsFor","AREA_RECIPE_MODAL","ProductList","props","calculateAdditionValue","calculateSubstractValue","incrementBy","minValue","maxValue","portions","marginLeft","ChipIconButton","icon","label","theme","size","onClick","newValue","setPortions","totalProducts","externalId","handleBuy","handleLinkClick","isFoodBox","undefined","toEcommercePriceWithCurrency","Button","asChild","href","toString","recipeName","imageUrl","rating","votes","time","pricePortion","close","transformedImageUrl","backgroundImage","RatingStars","color","Icon","isExpanded","setIsExpanded","useState","inputSelected","setInputSelected","description","value","handleInputSelect","selectedInput","calculationType","recipeProritization","handleCalculationTypeChange","width","height","RadioGroup","Root","onValueChange","defaultValue","Item","fullWidth","RecipeModalSection","sectionItems","allItems","filter","item","section","substituteIdentifiers","includes","substituteIdentifier","RecipeModalProductsList","list","title","type","getSectionTitle","renderCartItem","map","cart","sections","items","getPrice","IncludeTax","recipe","readonly","cookingInstructions","useMemo","recipePart","part","ingredients","ingredientLine","formattedQuantity","unit","friendlyText","preamble","RawHtml","html","yieldValue","i","index","instructions","length","el","e","RecipeModalBodyWithData","recipeData","modalTabToDisplay","handlePortionChange","defaultPortions","avgRating","display","totalTime","TabSwitcher","component","wrapperClasses","containerClasses","panelClasses","listClasses","itemClasses","renderNextToTabs","p","initialActiveId","isLoading","purchasable","reduce","curr","next","quantity","OverlayLoader","recipeId","currentProductionUnit","storeSelectors","getRecipeDispatcher","useAsyncDispatcher","recipeFlow","getRecipeById","initialLoadingState","keepPreviousResult","currentPriceType","useCurrentPriceType","tabToDisplay","execute","getRecipe","result","getRecipeResult","error","useEffect","useGroupError","Global","trackModalPopup","trackBuyRecipe","trackCalculationChange","trackPortionChange","trackLinkClick","trackSubstituteProduct","trackAddToCart","modalPopupSent","useRef","useCallback","current","tracking","ecommerce","recipes","modalPopup","Products","products","storeId","listOptions","modifyCartItems","productId","previousQuantity","newQuantity","variantId","buyRecipe","calculationChange","portionChange","linkClick","substituteProduct","useBuyableRecipeModalTracking","updateItemQuantity","updateSubstituteProduct","updatePortions","updateCalculation","removeItem","calculateCart","recipeCart","recipeCartProducts","getProductExceptions","isLoadingRecipeCart","useRecipeCart","onSubsituteChangeClick","onSubstituteTriggerClick","expandedSubstituteIds","isLoadingSubstitutes","useSubstitute","identifier","dispatch","calculation","prioritization","buyRecipeDispatcher","request","cartThunks","buyMultipleRecipes","buyRecipeLoading","buyRecipeResult","useRequestEffects","onSuccess","itemsToTrack","analyticsListName","listPosition","recipe_list_id","code","join","recipe_list_name","recipe_origin","Modal","recipePortions","portionQuantity","productExceptions","x","group","qty","substituteId","RecipeProductListingItem","substituteProducts","PurchasableItemBody","sectionType","hasActiveSubstitutes","handleQuantityChange","handleSubsituteTriggerClick","MissingItemBody","recipeSectionType","handleRemoveItem","MissingItemInfo","text","RecipeItemActionsContainer","RecipeItemActions","belongsToRecipes","SharedBetweenRecipesTooltip","substituteProductsAmount","SubstituteTrigger","handleSubsituteTrigger","isActive","setQuantity","getRecipeSection","mapItem","isRemoved","priceData","rowTotalPriceData","state","Removed","Default","recipeCartQueue","SyncronQueue","initialLoading","cartState","setCartState","cartChangesState","setCartChangesState","removedItems","newProductId","prevChanges","draft","productChanges","recipeSection","weeklyMenu","handleIngredient","Object","values","forEach","pc","recipeToChange","cr","prioritizationType","reCalculateCart","push","resolve","resolvedRecipes","resolveError","run","resolveRecipes","debouncedResolve","cp","isDirty","recipeList","removedSubstituteIds","removedSubsituteIdentifiers","singleProducts","sharedProducts","goodToHaveProducts","recipeSectionsMap","prev","sectionId","sectionName","_recipe","final","productIdentifiers","keys","sharedProductsBelongingToRecipe","sharedProduct","joinedRecipe","sharedSubstituteIdentifiers","sharedRecipeProductIds","goodToHaveProductIds","sharedRecipeSubstituteIds","goodToHaveSubstituteIds","recipeSectionList","mapSections","hybrisRecipeList","inclTaxPrice","recipesTotalPrice","exclTaxPrice","valueWithoutTax","createCartState","productFlow","getProductsByIds","initialResultState","recipeCartChanges","changedSubstituteIds","loadHybrisSubstitutes","recipeProducts","getRecipeSubstitutes","substitute","handleSubstituteChangeClick","setExpandedSubstituteIds","substituteSentForChange","onSubstituteToggle","prevIds","newIds","findIndex","splice","onSubstitutesLoaded","subsituteCount","setSubstitutes","substitutesDispatcher","loadSubstitutes","substitutesById","substituteMap","loadedCount","ItemState","RecipeModalTab","createNewArrayByTogglingString","currStringArray","newString","createGetUrlForCategories","categoryNameToUrlSegment","categoriesUrlOrder","recipeRootUrl","categories","removedPotentialLastSlashFromRoot","slice","hasFilterQuery","builtPath","sort","a","b","toLowerCase","categoryName","Boolean","acc","currSegment","getCategoriesWhileRemovingCategoryFacetChildren","currentCategories","category","Array","isArray","childrenNames","childCategory","categoriesWithoutChildren","currCategory","getCategoriesWhileRemovingCategoryFacetsParent","parentCategory","lowerCaseParentName","categoriesWithoutParent","getAllCategoryNamesFromLevel2AndDown","collectedNames","rootCall","facet","childCategories","getCategoryNamesUnderLevel1","ssrCategoriesUrlOrder","obj","entries","key","val","buildRecipeRedirectUrl"],"sourceRoot":""}