{"version":3,"file":"782c08b75ff57d5f8ea402180ca0550e08932a03-89aa4fbd2dd6637e7631.js","mappings":"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","sources":["webpack://@nitro/gatsby-harvia.com/../gatsby-source-harvia-pim/helpers/attribute.ts","webpack://@nitro/gatsby-harvia.com/../gatsby-source-harvia-pim/helpers/media.ts","webpack://@nitro/gatsby-harvia.com/../gatsby-source-harvia-pim/utils/media.ts","webpack://@nitro/gatsby-harvia.com/../gatsby-source-harvia-pim/utils/process.ts","webpack://@nitro/gatsby-harvia.com/../gatsby-source-harvia-pim/hooks/useOnlineProductQuery.ts","webpack://@nitro/gatsby-harvia.com/../gatsby-theme-harvia/src/components/atoms/PimImage.tsx","webpack://@nitro/gatsby-harvia.com/../gatsby-theme-harvia/src/components/organisms/product/ProductCard.tsx","webpack://@nitro/gatsby-harvia.com/../gatsby-theme-harvia/src/components/organisms/product/ProductCard.module.scss","webpack://@nitro/gatsby-harvia.com/../gatsby-theme-harvia/src/components/molecules/ProductList.tsx","webpack://@nitro/gatsby-harvia.com/../gatsby-theme-harvia/src/components/molecules/ProductList.module.scss","webpack://@nitro/gatsby-harvia.com/../gatsby-theme-harvia/src/components/organisms/product/ProductFilter.tsx","webpack://@nitro/gatsby-harvia.com/../gatsby-theme-harvia/src/components/organisms/product/ProductFilter.module.scss","webpack://@nitro/gatsby-harvia.com/../gatsby-theme-harvia/src/components/organisms/localeDialog/localePimConfig.ts","webpack://@nitro/gatsby-harvia.com/../gatsby-theme-harvia/src/components/organisms/product/utils.tsx"],"sourcesContent":["import { Product, ProductAttributeValue, ProductValue } from \"gatsby-source-harvia-pim/types/plugin\"\n\n/**\n * Get formatted unit as string.\n * @param unit\n */\nexport function formatUnit(unit: string) {\n if (typeof unitMap[unit] != \"undefined\") {\n return unitMap[unit]\n }\n console.warn(\"Unhandled unit\", unit)\n return `${unit}`\n}\n\n/**\n * Ei näytetä tietoja näillä arvoilla\n */\nexport const filteredValues = [\"na\", \"N/A\", \"NA\"]\n\n/**\n * PIM units mapped to string representation.\n */\nconst unitMap: Record = {\n METER: \"m\",\n MILLIMETER: \"mm\",\n CUBIC_METER: \"m³\",\n KILOGRAM: \"kg\",\n CELSIUS: \"°C\",\n EUR: \"€\",\n HOUR: \"h\",\n WATT: \"W\",\n KELVIN: \"K\",\n SECOND: \"s\",\n SQUARE_METER: \"m²\",\n SQUARE_MILLIMETER: \"mm²\",\n LITER: \"l\",\n undefined: \"\",\n null: \"\",\n}\n\n/**\n * Get single value from product data.\n * @param data\n * @param key\n */\nexport function getValue(values?: ProductValue[], key?: string): ProductValue | undefined {\n const res = values?.find(value => value.name === key)\n // console.debug(`Product value \"${key}\"`, res)\n return res\n}\n\n/**\n * Get multiple values from product data as array.\n */\nexport const getValues = (values: ProductValue[], keys: string[]): ProductValue[] => {\n const res: ProductValue[] = []\n for (let i = 0; i < keys.length; i++) {\n const value = getValue(values, keys[i])\n if (value) {\n res.push(value)\n }\n }\n return res\n}\n\n/**\n * Get product values as string.\n * @param list\n */\nexport function stringValue(list?: ProductValue | string): string {\n if (!list) {\n return \"\"\n }\n if (typeof list === \"string\") {\n return list\n }\n\n return list.value\n .map((attr: ProductAttributeValue) => {\n if (filteredValues.includes(attr.data)) {\n return\n }\n\n switch (attr.type) {\n case \"ProductMetric\": {\n const val = attr.metric\n //if (isNaN(val.amount)) return \"na\"\n return `${!isNaN(val.amount) ? val.amount : \"-\"} ${formatUnit(val.unit)}`\n }\n case \"ProductOption\":\n return attr.text\n case \"ProductPrice\":\n return attr.prices.map(itm => `${itm.amount} ${formatUnit(itm.currency)}`).join(\", \")\n case \"string\":\n return attr.text // TODO: Joidenkin kenttien arvo on html tai json\n case \"number\":\n return attr.numeric\n case \"boolean\":\n return attr.boolean\n default:\n console.warn(\"Unhandled value type:\", attr.type)\n return `${attr.text}`\n }\n })\n .join(\", \")\n}\n\nexport type ProductCompareValue = { name: string; label: string; value: (ProductValue | null)[] }\n\n/**\n * Get multiple values from multiple products as comparison array. Empty rows are omitted.\n * @param products\n * @param keys\n */\nexport function getCompareValues(products: Product[], keys: string[]) {\n const res: ProductCompareValue[] = []\n\n keys.forEach(key => {\n const row: ProductCompareValue = { name: key, label: \"\", value: [] }\n\n let hasVal = false\n\n products.forEach((product, i) => {\n const val = getValue(product.values, key)\n let validVal = false\n if (val && val.value[0]) {\n const attr = val.value[0]\n if (!row.label) {\n row.label = attr.label\n }\n switch (attr.type) {\n case \"ProductMetric\":\n if (typeof attr.metric.amount !== \"undefined\" && attr.metric.amount !== null) validVal = true\n break\n case \"string\":\n if (!filteredValues.includes(attr.text)) validVal = true\n break\n case \"ProductOption\":\n if (!filteredValues.includes(attr.data) || val.value.length > 1) validVal = true\n break\n case \"ProductPrice\":\n if (typeof attr.prices[0]?.amount !== \"undefined\" && attr.prices[0]?.amount !== null) validVal = true\n break\n default:\n if (typeof attr.data !== \"undefined\" && attr.data !== null) validVal = true\n }\n }\n if (validVal && val) {\n hasVal = true\n row.value[i] = val\n } else {\n row.value[i] = null\n }\n })\n\n // jos koko rivillä ei labeleita, näytetään key\n if (!row.label) {\n row.label = key\n }\n\n // jos koko rivillä ei arvoja, piilotetaan rivi\n if (hasVal) {\n res.push(row)\n }\n })\n\n // console.log(res)\n\n return res\n}\n","import { ExternalMedia } from \"gatsby-source-harvia-pim/types/plugin\"\nimport { ExternalMediaAssetType } from \"gatsby-source-harvia-pim/types/rockon\"\n\n/**\n * Parse External media array from product value: \"external_media_textarea\"\n * @param product Product data\n * @param type Get only elements of this asset type\n */\nexport const getExternalMedia = (productMedia: ExternalMedia[], type: ExternalMediaAssetType): ExternalMedia[] => {\n if (!productMedia?.length) {\n return []\n }\n return productMedia.filter(itm => itm.type === type)\n}\n","import { ExternalMedia, LocaleLabel } from \"gatsby-source-harvia-pim/types/plugin\"\nimport { RockonExternalMediaType } from \"gatsby-source-harvia-pim/types/rockon\"\n\nexport function transformExternalMedia(externalMedia: RockonExternalMediaType): ExternalMedia {\n const { baseType, children, previewLink, properties, ...rest } = externalMedia\n\n // \"name\" should always be in \"en-US\" locale (TODO make sure assumption is correct)\n const labels: LocaleLabel[] = [{ locale: \"en-US\", value: rest.name }]\n // add translations\n if (properties.TitleFinnish) {\n labels.push({ locale: \"fi-FI\", value: properties.TitleFinnish })\n }\n return {\n ...rest,\n labels,\n type: properties.AssetType,\n thumbnail: properties.Thumbnail,\n language: properties.Language,\n masterImage: properties.MasterImage === \"true\",\n }\n}\n","import type {\n Association,\n AttributeTranslation,\n ExternalMedia,\n Product,\n ProductAttributeValue,\n StructureCategory,\n} from \"../types/plugin\"\nimport type {\n ProductMetric,\n ProductPrice,\n RockonAssociation,\n RockonAttributeTranslation,\n RockonExternalMediaType,\n RockonProduct,\n RockonProductAttribute,\n RockonProductAttributeOption,\n RockonStructureCategory,\n} from \"../types/rockon\"\nimport { transformExternalMedia } from \"./media\"\n\n/**\n * Convert product attribute so that `data` is moved to a property named after its value type.\n *\n * Why: RockOn Product attributes values have properties `valueType` and `data` (among others).\n * Value of `data` can be string, number, boolean, null(?) or object.\n * To expose data in Gastby GraphQL queries all field value types should not conflict.\n * In most cases, conflicting type would mean that a warning will be reported for the user\n * and the field won’t appear in the data.\n */\nfunction transformProductValue(value: RockonProductAttribute): ProductAttributeValue {\n const { data, attributeLabel } = value\n\n const val = { label: attributeLabel, data: data?.toString() }\n\n switch (value.valueType) {\n case \"ProductMetric\":\n return { ...val, type: \"ProductMetric\", metric: data as ProductMetric }\n case \"ProductPrice\":\n return { ...val, type: \"ProductPrice\", prices: data as ProductPrice[] }\n case \"ProductOption\": {\n // ProductOption seems to be always string so we put it in `text`\n // and we use translated `optionLabel` if it's set, or fall back to untranslated `data` if not\n const text = value.optionLabel || data?.toString()\n return { ...val, type: \"ProductOption\", text: text }\n }\n default: {\n if (typeof data === \"string\") {\n // TODO tutki onko JSON?\n return { ...val, type: \"string\", text: data }\n } else if (typeof data === \"number\") {\n return { ...val, type: \"number\", numeric: data }\n } else if (typeof data === \"boolean\") {\n return { ...val, type: \"boolean\", boolean: data }\n }\n return { ...val, type: \"unknown\", text: data?.toString() }\n }\n }\n}\n\nfunction transformProductValues(values: RockonProductAttribute[]): ProductAttributeValue[] {\n return values.filter(Boolean).map(transformProductValue)\n}\n\ntype TransformFunc = (value: T) => O\n\n/**\n * Convert object entries/properties to array of { name: string, value: any } objects where\n * \"name\" comes from input property name and \"value\" from the value of that property.\n * Value can be optionally transformed by passing a callback function as second parameter.\n *\n * @param obj Object to convert\n * @param trasform Optional callback function. If given gets called with each property value and returned value is\n */\nfunction arrayifyObject(\n obj: {\n [key: string]: T\n },\n transform?: TransformFunc\n): {\n name: string\n value: O\n}[] {\n const result: {\n name: string\n value: O\n }[] = []\n for (const [name, value] of Object.entries(obj)) {\n const val = transform ? transform(value) : (value as unknown as O)\n result.push({ name, value: val })\n }\n return result\n}\n\n/**\n * Convert product association data from API response format to Gatsby Node format\n */\nfunction arrayifyAssociationData(data: RockonAssociation, locale: string): Association[] {\n const result: Association[] = []\n data.products.forEach(sku => {\n if (!Object.prototype.hasOwnProperty.call(data.associationData, sku)) {\n return\n }\n result.push({\n sku,\n localeId: `${sku}-${locale}`,\n data: data.associationData[sku],\n })\n })\n return result\n}\n\n/**\n * Convert product associations from API response format to Gatsby Node format\n */\nfunction arrayifyAssociations(\n associations: Record,\n locale: string\n): Record {\n const result: Record = {}\n for (const [name, value] of Object.entries(associations)) {\n result[name] = arrayifyAssociationData(value, locale)\n }\n return result\n}\n\n/**\n * Convert single product object from RockOn API response format to Gastby Node format\n * @param product Product data raw from RockOn API\n * @param locale Language code (e.g. \"en-US\") used as parameter on Rockon API request\n */\nexport function processProduct(product: RockonProduct, locale: string): Product {\n const extMedia = product.values[\"external_media_textarea\"]\n\n const media: ExternalMedia[] = []\n const media_images: ExternalMedia[] = []\n const media_videos: ExternalMedia[] = []\n const media_manuals: ExternalMedia[] = []\n const media_brochures: ExternalMedia[] = []\n const media_technicalImages: ExternalMedia[] = []\n const media_technicalModels: ExternalMedia[] = []\n const media_certificates: ExternalMedia[] = []\n const media_materials: ExternalMedia[] = []\n if (extMedia && extMedia.length > 0) {\n delete product.values[\"external_media_textarea\"]\n extMedia.forEach(extM => {\n const raw = extM.data as string\n if (!raw) {\n return\n }\n const mediaList: RockonExternalMediaType[] = JSON.parse(raw)\n if (mediaList && mediaList.length) {\n media.push(...mediaList.map(transformExternalMedia))\n media_images.push(...media.filter(m => [\"Product image\", \"Feeling image\", \"Detail image\"].includes(m.type)))\n media_videos.push(...media.filter(m => [\"Product video\", \"Technical video\"].includes(m.type)))\n media_manuals.push(...media.filter(m => [\"User manual\"].includes(m.type)))\n media_brochures.push(...media.filter(m => [\"Brochure\"].includes(m.type)))\n media_technicalImages.push(...media.filter(m => [\"Technical image\"].includes(m.type)))\n media_technicalModels.push(...media.filter(m => [\"3D CAD file\", \"2D CAD file\", \"BIM object\"].includes(m.type)))\n media_certificates.push(...media.filter(m => [\"Certificate\", \"Safety data sheet\"].includes(m.type)))\n media_materials.push(...media.filter(m => [\"Package material\"].includes(m.type)))\n }\n })\n }\n\n const values = arrayifyObject(\n product.values,\n transformProductValues\n )\n\n return {\n ...product,\n locale,\n associations: arrayifyAssociations(product.associations, locale),\n values,\n media,\n media_images,\n media_videos,\n media_manuals,\n media_brochures,\n media_technicalImages,\n media_technicalModels,\n media_certificates,\n media_materials,\n product_family: product.values[\"product_family\"]?.[0]?.data?.toString(),\n name:\n product.values[\"product_marketing_name_short\"]?.[0]?.data?.toString() ||\n // fallback nimi tuotteelle: \"product_group_2 product_family sku\"\n [\n (product.values[\"product_group_2\"]?.[0] as RockonProductAttributeOption)?.optionLabel?.toString(),\n (product.values[\"product_family\"]?.[0] as RockonProductAttributeOption)?.optionLabel?.toString(),\n product.identifier,\n ]\n .filter(Boolean)\n .join(\" \"),\n }\n}\n\nexport function processStructureTree(\n structure: RockonStructureCategory[],\n productData: RockonProduct[]\n): StructureCategory[] {\n function handleStructure(s: RockonStructureCategory): StructureCategory {\n // Kerättävät tuotteiden arvot\n const containsProductValues: StructureCategory[\"containsProductValues\"] = {\n product_family: [],\n color: [],\n control_panel_type: [],\n // extra_option_category: [], // nämä ei jostain syystä tule tuotteen tiedoissa?\n // controlled_devices: [],\n }\n\n // Etsitään tuotteiden saatavilla olevat valuet, jotka kuuluvat tähän kategoriaan\n productData\n .filter(p => p.categories.includes(s.code))\n .forEach(rockonProduct => {\n // kerätään valitut arvot tuotteilta joita tästä kategoriasta löytyy\n for (const key of Object.keys(containsProductValues)) {\n // huom toString(), toiminee tällä hetkellä vain RockonProductAttributeGeneric tyyppisillä arvoilla\n const val = rockonProduct.values[key]?.[0]?.data?.toString()\n\n // lisätään arrayhyn, jos vielä puuttuu\n if (val && !containsProductValues[key].includes(val)) {\n containsProductValues[key].push(val)\n }\n }\n })\n\n return {\n code: s.code,\n labels: s.labels ? arrayifyObject(s.labels) : [],\n subCategories: s.subCategories ? s.subCategories.map(handleStructure) : [],\n containsProductValues,\n }\n }\n return structure ? structure.map(handleStructure) : []\n}\n\nexport function processTranslation(translation: RockonAttributeTranslation, lang: string): AttributeTranslation {\n return { ...translation, locale: lang }\n}\n","import { RockonQueryResultType } from \"@nitro/gatsby-theme-harvia/src/components/organisms/product/types\"\nimport { useEffect, useState } from \"react\"\nimport { Product } from \"../types/plugin\"\nimport { PagedResponse, RockonProduct } from \"../types/rockon\"\nimport { processProduct } from \"../utils/process\"\n\nexport type QueryResultParams = Omit\n\ntype Query = {\n parameters: QueryParams\n subQueries?: Query[]\n condition?: string | \"AND\" | \"OR\"\n}\ntype QueryParams = Record\n\ntype QueryPart = {\n operator: string\n firstOperand: string\n secondOperand?: string\n}\n\nfunction getQueryParam(parts: string[]): [string, QueryPart] {\n //const parts = queryString.split(\":\")\n const attr = parts[0]\n let operator = \"EQ\" // oletus\n let firstOperand = \"\"\n let secondOperand = \"\"\n\n // Normi haku\n if (parts.length == 2) {\n //\n firstOperand = parts[1]\n } else if (parts.length == 3) {\n // haku operaattorilla, esim \"heater_power:lte:10_5\"\n operator = parts[1]\n firstOperand = parts[2]\n } else if (parts.length == 4) {\n // haku operaattorilla, kahdella parametrilla esim \"heater_power:between_incl:10_5:20\"\n operator = parts[1]\n firstOperand = parts[2]\n secondOperand = parts[3]\n }\n\n return [attr, { operator, firstOperand, secondOperand }]\n}\n\nfunction getQuery(params: string[]) {\n const query = { condition: \"AND\", parameters: {}, subQueries: [] } as Query\n params?.forEach(itm => {\n const parts = itm.split(\":\")\n\n const [attr, queryPart] = getQueryParam(parts)\n\n // luodaan parametri nimellä\n if (!query.parameters[attr]) query.parameters[attr] = []\n\n // lisätään hakuparametrit\n query.parameters[attr].push(queryPart)\n })\n\n return query\n}\n/**\n * Tuotehaku RockOn:in rajapinnasta. Query-parametri on string, jossa pilkulla eroteltuna hakutermit.\n *\n * Hakutermin muoto on : tai :: jos halutaan lisätä joku kenttä sub-queryksi. Sub-query on aina basequeryä rajaava.\n * Kaikki samaan kenttään kohdistuvat parametrit yhdistetään huomioiden mahdollinen and|or parametri.\n *\n * Huom. tutustu tähän koodiin, niin selviää paremmin mitä parametreilla tehdään.\n * */\nconst useOnlineProductQuery = (\n /** RockOn rajapinnan query parametri. \"and\" ja \"or\" operaattorit lisäyksenä. Muilta osin voisi käyttää suoraan GET rajapintahakuna */\n query: string | null,\n /** Url params for rockon query */\n parameters: {\n language: string\n /** Number as string */\n size?: string\n /** Number as string */\n page?: string\n sort?: string\n /** Boolean as string */\n fullAssociations?: string\n /** Products with status enabled:false */\n includeDisabledProducts?: boolean\n },\n options?: {\n /** Base query params from website config. */\n baseQuery?: string\n },\n projection?: string[]\n) => {\n const [data, setData] = useState<[Product[] | undefined, QueryResultParams | undefined]>([undefined, undefined])\n\n /** Kaikkiin hakuihin alkurajaus. */\n const baseQueryParams = options?.baseQuery?.split(\",\") || []\n\n const paramsString = new URLSearchParams({\n ...parameters,\n includeDisabledProducts: parameters.includeDisabledProducts ? \"true\" : \"false\",\n }).toString()\n\n useEffect(() => {\n if (query === null) {\n return\n }\n const controller = new AbortController()\n\n function makeRequest() {\n // console.debug(\"Fetching\", queryParam)\n\n /* TODO. Nämä sivustokohtaisesta konffista!! Ehkä options objektissa mukana? */\n const baseUrl = \"https://pim.harvia.com/rockon-ext/api/v1/\"\n const apiChannel = \"web_pages_harvia_global\"\n const apiUrl = `${baseUrl}products/projectionsearch/${apiChannel}`\n\n /** Alustava rajaus, verkkosivukohtaiset filtterit. Loput rajaukset tehdään subQueryillä */\n const baseQuery = getQuery(baseQueryParams)\n\n const queryParams = query.split(\",\")\n\n /**\n * Kerätään kaikki parametrit joissa on \"or\" operaattori, ja luodaan niistä oma subQuery jolla condition:\"OR\"\n * Näin haku kohdistuu eri attribuutteihin, mutta palauttaa jos jokin niistä täsmää. Normihaku vaatii kaikki täsmäämään.\n */\n const orParams: string[] = queryParams\n .map(str => {\n const parts = str.split(\":\")\n if (parts[1].toLowerCase() === \"or\") {\n parts.splice(1, 1)\n return parts.join(\":\")\n }\n return null\n })\n .filter((val): val is string => typeof val === \"string\")\n\n /**\n * Kerätään kaikki parametrit joissa on \"and\" operaattori, ja luodaan niistä jokaisesta oma subQuery\n * Näin saadaan samalla attribuutilla tehtyä hakuja, joissa kaikki arvot pitää täsmätä\n */\n const andParams: string[] = queryParams\n .map(str => {\n const parts = str.split(\":\")\n // \"sub\" on taaksepäin yhteensopivuuden takia\n if (parts[1].toLowerCase() === \"and\" || parts[1].toLowerCase() === \"sub\") {\n parts.splice(1, 1)\n return parts.join(\":\")\n }\n return null\n })\n .filter((val): val is string => typeof val === \"string\")\n\n /**\n * Loput parametrit, joilla ei ole \"and|or\" operaattoria.\n * Oletuksena samaa attribuuttia palautetaan \"or\" operaattorilla, ja eri attribuutit \"and\" operaattorilla\n * ks. Rockon rest api dokumentaatio\n */\n const restParams = queryParams.filter(str => {\n const parts = str.split(\":\")\n return parts[1].toLowerCase() !== \"or\" && parts[1].toLowerCase() !== \"and\" && parts[1].toLowerCase() !== \"sub\"\n })\n\n // Perus hakuparametrit yhteen subQueryyn\n const userQuery = getQuery(restParams)\n baseQuery.subQueries?.push(userQuery)\n\n // \"AND\" operaattorilla haut omiin subQueryihin\n andParams.forEach(param => baseQuery.subQueries?.push(getQuery([param])))\n\n // \"OR\" operaattorilla haut yhteen subQueryyn\n const orQuery = getQuery(orParams)\n orQuery.condition = \"OR\"\n orParams.length && baseQuery.subQueries?.push(orQuery)\n\n /** Lopullinen hakuparametri */\n const finalQuery = {\n projection: projection,\n query: baseQuery,\n }\n\n window\n .fetch(`${apiUrl}?${paramsString}`, {\n signal: controller.signal,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(finalQuery),\n })\n .then(res => res.json())\n .then((res: PagedResponse) => {\n if (res.content) {\n const { content, ...rest } = res\n // console.debug(\"Fetched\", queryParam, res)\n const newData = res.content.map(rockonProduct => processProduct(rockonProduct, parameters.language))\n // console.debug(\"Processed fetched data to\", newData)\n\n // Process fullAssociations\n if (res.fullAssociations) {\n newData.forEach(product => {\n for (const key in product.associations) {\n const tempAssoc = product.associations[key].map(assoc => {\n const prod = res.fullAssociations?.find(p => p.identifier === assoc.sku)\n return {\n ...assoc,\n product: prod && processProduct(prod, parameters.language),\n }\n })\n product.associations[key] = tempAssoc\n }\n })\n }\n\n setData([newData, rest])\n }\n })\n .catch(err => {\n console.error(\"Request failed\", err)\n })\n }\n\n if (query) {\n makeRequest()\n }\n\n return function cancel() {\n controller.abort()\n }\n }, [query, baseQueryParams.join(), paramsString, projection?.join()])\n\n return data\n}\n\nexport default useOnlineProductQuery\n","import React from \"react\"\n//import placeholder from \"../../images/Harvia_no_image.png\"\n//import * as styles from \"./PimImage.module.scss\"\n\ntype PimImageProps = React.DetailedHTMLProps, HTMLImageElement>\n\nconst PimImage = (props: PimImageProps) => {\n //console.log('Rendering PimImage', props)\n if (!props.src && !props.srcSet)\n return (\n <>\n {/*\n \n HUOM. vaihdettu käyttämään static-kansion fallaback kuvatiedostoa, koska product category sivuista tulee buildissa muuten > Mt kokoisia.\n \n */}\n \n \n )\n\n return \n}\n\nexport default PimImage\n","import { Link } from \"gatsby\"\nimport React from \"react\"\nimport { IoWifi } from \"react-icons/io5\"\nimport PimImage from \"../../atoms/PimImage\"\nimport BgColor, { HarviaBackgroundColor } from \"../../layouts/BgColor\"\nimport * as styles from \"./ProductCard.module.scss\"\nimport { textFormat } from \"./utils\"\n\nexport type ProductCardProps = {\n url: string // luodaan linkki tämän perusteella\n image?: string\n imageAlt?: string\n group?: string\n family?: string\n title: string\n text?: string\n tags?: string[]\n labels?: Label[]\n itemCode?: string\n wifi?: boolean\n}\n\ntype Label = { label: string; color: HarviaBackgroundColor }\n\nconst TagBox = (props: { label: string }) => {\n return {props.label}\n}\n\nconst LabelBox = (props: Label) => {\n return (\n \n {props.label}\n \n )\n}\n\nconst ProductCard = (props: ProductCardProps) => {\n //console.log('Rendering ProductCard', props)\n\n return (\n
\n \n \n
\n {props.labels?.map((itm: Label, i: number) => {\n return \n })}\n
\n\n {props.wifi && }\n \n
\n
\n {[props.group, props.family].filter(e => e).join(\" | \")}\n
\n\n

\n {textFormat(props.title)}\n

\n\n
\n {props.itemCode}\n
\n {props.text &&
}\n\n
\n {props.tags?.map(itm => (\n \n ))}\n
\n
\n
\n )\n}\n\nexport default ProductCard\n","// extracted by mini-css-extract-plugin\nexport var category = \"ProductCard-module--category--09d92\";\nexport var container = \"ProductCard-module--container--b9034\";\nexport var image = \"ProductCard-module--image--28db3\";\nexport var label = \"ProductCard-module--label--1dc61\";\nexport var labels = \"ProductCard-module--labels--89710\";\nexport var sku = \"ProductCard-module--sku--5078f\";\nexport var tag = \"ProductCard-module--tag--38cf9\";\nexport var tags = \"ProductCard-module--tags--d1b9f\";\nexport var textArea = \"ProductCard-module--textArea--5405c\";\nexport var title = \"ProductCard-module--title--a748c\";\nexport var wifi = \"ProductCard-module--wifi--96d01\";","import { getValue, stringValue } from \"@nitro/gatsby-source-harvia-pim/helpers/attribute\"\nimport { getExternalMedia } from \"@nitro/gatsby-source-harvia-pim/helpers/media\"\nimport React, { useContext } from \"react\"\nimport { PageContext } from \"../../context/PageContext\"\nimport { useUserPreferences } from \"../../context/UserContext\"\nimport useDatoMicrocopy from \"../../hooks/useDatoMicrocopy\"\nimport useProductPath from \"../../hooks/useProductPath\"\nimport { HarviaBackgroundColor } from \"../layouts/BgColor\"\nimport ProductCard from \"../organisms/product/ProductCard\"\nimport { ProductFilterProduct } from \"../organisms/product/ProductFilter\"\nimport { isAvailable } from \"../organisms/product/utils\"\nimport * as styles from \"./ProductList.module.scss\"\n\nexport type ProductListProps = { products: ProductFilterProduct[] }\n/**\n * Simple product card renderer.\n * @param props products[]\n * @returns\n */\nconst ProductList: React.FC = props => {\n //console.log(\"Rendering ProductList\", props)\n const userPrefs = useUserPreferences()\n const { locale } = useContext(PageContext)\n const t = useDatoMicrocopy(\"productFinder\", locale)\n const getProductPath = useProductPath()\n const products = props.products\n\n return (\n
\n
    \n {products.map(product => {\n const val = (key: string) => stringValue(getValue(product.values, key))\n\n /** hakee masterImagen */\n const masterImage =\n product.media &&\n (product.media.find(img => img.masterImage) || getExternalMedia(product.media, \"Product image\")[0])\n\n /** tagit / ominaisuudet */\n const tags = [\n stringValue(getValue(product.values, \"control_type\")).split(\", \"),\n // ...(getValue(product, \"features_electric_heaters\") || []),\n ]\n .flat()\n .filter(Boolean) //.map(itm => itm.label)\n\n /** Labelit tuotteen iän ja life cyclen perusteella */\n const labels: { label: string; color: HarviaBackgroundColor }[] = []\n\n // Tuotteen enabled tila on false, mutta silti tullut hakutuloksissa\n if (product.enabled === false) {\n labels.push({ label: t(\"labelDiscontinued\", \"Discontinued\"), color: \"BrandRed\" })\n }\n\n // tuotteen lifecycle status\n const status = getValue(product.values, \"product_life_cycle_status\")\n switch (status?.value[0].data) {\n case \"s0_concept_creation\":\n case \"s1_development\":\n // case \"gate_0_concepting\":\n // case \"gate_1_design_and_prototyping\":\n // case \"gate_2_development\":\n // case \"gate_3_go_to_market_support\":\n // this should never happen anymore. See https://nitrogroup.atlassian.net/browse/HAR-445\n labels.push({ label: t(\"labelComingSoon\", \"Coming soon\"), color: \"BrandRed\" })\n break\n\n case \"s5_discontinued\":\n // ei laiteta tuplana samaa labelia\n if (product.enabled !== false) {\n labels.push({ label: t(\"labelDiscontinued\", \"Discontinued\"), color: \"BrandRed\" })\n }\n break\n\n case \"s3_maintenance\":\n case \"s4_rampdown\":\n default: {\n // uutuusaika 360 päivää\n const prod_date = getValue(product.values, \"available_from_date\")?.value[0].data\n if (!prod_date) break\n\n const newAtAge = 1000 * 60 * 60 * 24 * 360\n\n const age = Date.now() - Date.parse(prod_date)\n\n if (age && age < newAtAge) labels.push({ label: t(\"labelNew\", \"New\"), color: \"BrandRed\" })\n break\n }\n }\n\n // varaosan tarvittava määrä\n if (product.quantityNeeded && product.quantityNeeded !== \"1\") {\n labels.push({\n label: `${product.quantityNeeded} ${t(\"labelUnitsNeeded\", \"pieces needed\")}`,\n color: \"BrandGreyWarmDark\",\n })\n }\n\n const url = getProductPath(product.identifier)\n\n // ei buildattu tuote\n // if (~url.indexOf(\"?id=\"))\n // labels.push({\n // color: \"BrandGreyWarmDark\",\n // label: t(\"labelUnavailable\", \"Unavailable\"),\n // })\n\n if (isAvailable(product, userPrefs.localeArea) === false) {\n labels.push({\n color: \"BrandGreyWarmDark\",\n label: t(\"labelUnavailable\", \"Unavailable\"),\n })\n }\n return (\n
  • \n \n
  • \n )\n })}\n
\n
\n )\n}\n\nexport default ProductList\n","// extracted by mini-css-extract-plugin\nexport var li = \"ProductList-module--li--42126\";\nexport var ul = \"ProductList-module--ul--f5701\";","import useOnlineProductQuery from \"@nitro/gatsby-source-harvia-pim/hooks/useOnlineProductQuery\"\nimport { ExternalMedia, ProductValue } from \"@nitro/gatsby-source-harvia-pim/types/plugin\"\nimport React, { useContext, useEffect, useRef, useState } from \"react\"\nimport { PageContext } from \"../../../context/PageContext\"\nimport { useUserPreferences } from \"../../../context/UserContext\"\nimport useDatoMicrocopy from \"../../../hooks/useDatoMicrocopy\"\nimport useSiteMetadata from \"../../../hooks/useSiteMetadata\"\nimport { isBrowser } from \"../../../utils\"\nimport LoadingSpinner from \"../../atoms/LoadingSpinner\"\nimport Pagination from \"../../molecules/Pagination\"\nimport ProductList from \"../../molecules/ProductList\"\nimport * as styles from \"./ProductFilter.module.scss\"\nimport { productCategoriesForArea } from \"./utils\"\n\n/**\n * Tuotedata siinä muodossa kuin ProductFilter sen tarvitsee\n */\nexport type ProductFilterProduct = {\n identifier: string\n categories: string[]\n created?: string\n media?: ExternalMedia[]\n /**\n \"item_code_harvia_finland\",\n \"external_media_textarea\",\n \"product_marketing_name_short\",\n \"product_family\",\n \"product_life_cycle_status\",\n \"control_type\",\n \"available_from_date\",\n \"product_group_2\",\n \"control_panel_type\",\n */\n values?: ProductValue[]\n /** Spare parts association quantity */\n quantityNeeded?: string\n enabled?: boolean\n name?: string\n}\n\ntype ProductListHeadingProps = {\n title?: string\n category?: string\n description?: string\n}\n/** Heading texts */\nconst ProductListHeading = (props: ProductListHeadingProps) => {\n return (\n
\n {props.title && (\n <>\n {props.category &&

{props.category}

}\n

{props.title}

\n \n )}\n {props.description &&

{props.description}

}\n
\n )\n}\n\ntype OnlineProductListProps = {\n query?: string\n pageSize?: number\n sort?: string\n hideIfEmpty?: boolean\n /** Buildin aikana saadaan tuotteen assisiaatioiden vaaditut määrät, jotka syötetään tarvittaessa mukaan {:} -objektina */\n quantities?: Record\n} & ProductListHeadingProps\n\n/** Online list handler */\nconst OnlineProductList = (props: OnlineProductListProps) => {\n const { locale, localePim } = useContext(PageContext)\n const userPrefs = useUserPreferences()\n const t = useDatoMicrocopy(\"common\", locale)\n\n const [products, setProducts] = useState([])\n const [loading, setLoading] = useState(true)\n const [page, setPage] = useState(0)\n const { pim } = useSiteMetadata()\n\n const { pageSize = 16 } = props\n\n /* Tarkistetaan onko queryssä product_life_cycle_status toiveita, tai muutoin lisätään oletusarvot */\n let query = props.query || \"\"\n if (!query.includes(\"product_life_cycle_status\")) {\n query = [props.query, \"product_life_cycle_status:s3_maintenance\", \"product_life_cycle_status:s4_rampdown\"].join()\n }\n\n // Lisätään and -operaattori kaikkiin verkkosivuston siteMetadatassa määriteltyihin hakuehtoihin, jolloin niistä tulee rajaavia ehtoja\n /* const baseParams = pim.baseParams.filter(Boolean).map(param => {\n const [key, ...rest] = param.split(\":\")\n return [key, \"and\", ...rest].join(\":\")\n }) */\n\n /* if (baseParams.length) {\n query = [baseParams, query].join(\",\")\n } */\n\n // Lisätään maakohtaiset filtterit tuotehakuun\n const countryProductFilters = userPrefs.localeArea\n ? productCategoriesForArea(userPrefs.localeArea).map(cat => `categories:${cat}`)\n : []\n const baseQuery = [...(pim?.baseParams || []), ...countryProductFilters].join(\",\")\n\n // Haetaan tuotteet\n const [onlineProducts, queryResult] = useOnlineProductQuery(\n query,\n {\n language: localePim,\n size: pageSize.toString(),\n page: page.toString(),\n sort: props.sort || \"item_code_harvia_finland,asc\",\n includeDisabledProducts: true,\n },\n {\n baseQuery,\n },\n // Projection arvot, jotka tuotteelta haetaan. Nämä pitää olla samat kuin mitä ProductList käyttää.\n [\n \"item_code_harvia_finland\",\n \"external_media_textarea\",\n \"product_marketing_name_short\",\n \"product_family\",\n \"product_life_cycle_status\",\n \"control_type\",\n \"available_from_date\",\n \"product_group_2\",\n \"control_panel_type\",\n ]\n )\n useEffect(() => {\n setPage(0)\n setProducts([])\n setLoading(true)\n }, [query, baseQuery, props.sort])\n\n useEffect(() => {\n // console.debug(\"ProductFilter useEffect()\", onlineProducts, products)\n if (onlineProducts) {\n if (\n !products.length ||\n (products.length &&\n onlineProducts.length &&\n products[products.length - 1].identifier != onlineProducts[onlineProducts.length - 1].identifier) // tarkistetaan onko uutta dataa\n ) {\n setProducts([...products, ...onlineProducts])\n } else {\n // why clone and set to the same but new value? To trigger re-render?\n setProducts([...products])\n }\n\n setLoading(false)\n }\n }, [onlineProducts])\n\n function nextPage() {\n setPage(page + 1)\n setLoading(true)\n }\n\n if (!loading && props.hideIfEmpty && !products?.length) return null\n\n // Lisätään määrät, jos saatavilla. Näistä tulee tuotelistauksessa labeleita.\n if (props.quantities) {\n products.forEach(product => (product.quantityNeeded = props.quantities?.[product.identifier]))\n }\n\n return (\n <>\n \n {products?.length ? :
- {t(\"noResults\", \"No results\")} -
}\n \n {!loading && (\n \n )}\n\n
\n \n )\n}\n\nexport type OfflineProductListProps = {\n /** Staattista tuotedataa ssr renderointiin */\n products?: ProductFilterProduct[]\n pageSize?: number\n hideIfEmpty?: boolean\n} & ProductListHeadingProps\n\n/** Offline list handler */\nexport const OfflineProductList: React.FC = props => {\n const [page, setPage] = React.useState(0)\n const pageSize = props.pageSize || 48\n\n const products = props.products?.slice(page, (page + 1) * pageSize)\n\n if (!products?.length && props.hideIfEmpty) return null\n\n return (\n <>\n \n {products && }\n setPage(page + 1)}\n />\n\n
\n \n )\n}\n\nexport type ProductFilterProps = { lazyLoading?: boolean } & OnlineProductListProps & OfflineProductListProps\n\n/** Yhdistetty Online ja Offline tuotelistaukset */\nconst ProductFilter: React.FC = props => {\n //console.debug(\"Rendering ProductFilter\", props)\n\n const container = useRef(null)\n const [shown, setShown] = useState(!props.lazyLoading)\n\n const onlineMode = !!props.query\n\n useEffect(() => {\n onlineMode && props.lazyLoading && window.addEventListener(\"scroll\", scrolling)\n\n function scrolling(e: Event) {\n if (!shown && container.current && window.innerHeight > container.current?.getBoundingClientRect().top) {\n setShown(true)\n window.removeEventListener(\"scroll\", scrolling)\n }\n }\n\n return () => {\n window.removeEventListener(\"scroll\", scrolling)\n }\n }, [])\n\n return (\n
\n {isBrowser && onlineMode ? (\n shown && \n ) : (\n \n )}\n
\n )\n}\n\nexport default ProductFilter\n","// extracted by mini-css-extract-plugin\nexport var container = \"ProductFilter-module--container--bcc30\";\nexport var heading = \"ProductFilter-module--heading--c53ec\";","import { LocaleArea } from \"gatsby-theme-harvia/src/types\"\n\ntype PimProductCategory = string\n\ntype LocalePimConfig = Record\n\nconst localePimConfig: LocalePimConfig = {\n // Pohjois-Eurooppa (Pohjoistmaat + Baltian maat), kielet: FI, EN, SV, ET\n \"north-europe\": [\n // \"05_harvia_finland_portfolio_main_areas_finland_main\",\n // \"05_harvia_finland_portfolio_european_spareparts\",\n \"06_harvia_group_portfolio_nordic_current\",\n \"06_harvia_group_portfolio_nordic_discontinued\",\n \"06_harvia_group_portfolio_spareparts_europe_current\",\n \"06_harvia_group_portfolio_spareparts_europe_discontinued\",\n ],\n // Eurooppa (kielet: DE, EN)\n europe: [\n // \"05_harvia_finland_portfolio_main_areas_europe_other\",\n // \"05_harvia_finland_portfolio_CN_main\",\n // \"05_harvia_finland_portfolio_european_spareparts\",\n // \"05_harvia_finland_portfolio_european_hagebau\",\n \"06_harvia_group_portfolio_middle_europe_current\",\n \"06_harvia_group_portfolio_middle_europe_discontinued\",\n \"06_harvia_group_portfolio_spareparts_europe_current\",\n \"06_harvia_group_portfolio_spareparts_europe_discontinued\",\n ],\n\n // Yhdysvallat (kielet: EN-US)\n // alias to \"usa\", make sure this is the same\n \"north-america\": [\n \"05_harvia_finland_portfolio_usa_all\",\n \"05_harvia_finland_portfolio_CN_USA\",\n \"05_harvia_finland_portfolio_north_america_spare_parts\",\n ],\n // the effective \"north-america\"\n // usa: [\n // \"05_harvia_finland_portfolio_usa_all\",\n // \"05_harvia_finland_portfolio_CN_USA\",\n // \"05_harvia_finland_portfolio_north_america_spare_parts\",\n // ],\n\n // Afrikka (kielet: EN)\n africa: [\n \"05_harvia_finland_portfolio_main_areas_europe_other\",\n \"05_harvia_finland_portfolio_CN_main\",\n \"05_harvia_finland_portfolio_european_spareparts\",\n ],\n\n // Etelä-Amerikka (kielet: EN)\n \"south-america\": [\n \"05_harvia_finland_portfolio_main_areas_europe_other\",\n \"05_harvia_finland_portfolio_CN_main\",\n \"05_harvia_finland_portfolio_european_spareparts\",\n ],\n\n // Kanada (kielet: EN)\n // canada: [\"05_harvia_finland_portfolio_canada_all\", \"05_harvia_finland_portfolio_north_america_spare_parts\"],\n\n // Aasia (kielet: EN, JPN (Japani ohjaa harvia.jp-osoitteeseen)\n asia: [\"05_harvia_finland_portfolio_CN_main\", \"05_harvia_finland_portfolio_european_spareparts\"],\n\n // Lähi-Itä (kielet: EN)\n \"middle-east\": [\n \"05_harvia_finland_portfolio_main_areas_europe_other\",\n \"05_harvia_finland_portfolio_CN_main\",\n \"05_harvia_finland_portfolio_european_spareparts\",\n ],\n\n // Oseania (kielet: EN)\n oceania: [\n \"05_harvia_finland_portfolio_main_areas_europe_other\",\n \"05_harvia_finland_portfolio_CN_main\",\n \"05_harvia_finland_portfolio_european_spareparts\",\n ],\n\n // Globaali: (kielet: EN)\n global: [\"05_harvia_finland_portfolio_main_areas_all\"],\n}\n\nexport default localePimConfig\n","import { Product } from \"gatsby-source-harvia-pim/types/plugin\"\nimport React from \"react\"\nimport type { ProductCategoryStructureNode } from \"../../../hooks/useProductCategoryStructure\"\nimport { LocaleArea, isLocaleArea } from \"../../../types\"\nimport { ProductAssociation } from \"../../pages/productPage/ProductPageContent\"\nimport localePimConfig from \"../localeDialog/localePimConfig\"\n\n/* \n \nPIM / PRODUCT UTILS\n\n*/\n\nexport const apiChannel = \"web_pages_harvia_global\"\nexport const apiUrl = `https://pim.harvia.com/rockon-ext/api/v1/products/search/${apiChannel}`\n\n/**\n * Try to parse string to JSON. No errors, only return value if successful.\n * @param str\n */\nexport const parseJSON = (str: string) => {\n // palauttaa json objektin jos pystyy\n try {\n return JSON.parse(str)\n } catch (e) {\n //return null\n }\n}\n\n// export const getFullAssociations = (\n// fullAssociations: Array | undefined,\n// product: ProductDataType,\n// association: string\n// ) => {\n// if (fullAssociations && product.associations?.[association]?.[\"products\"]) {\n// return fullAssociations.filter(itm => ~product.associations[association].products.indexOf(itm.identifier))\n// }\n// }\n\n/**\n * Lisää \\  - välit ennen tiettyjä sanoja\n * @param text\n * @returns\n */\nexport const textFormat = (text: string) => {\n if (!text) return \"\"\n\n const nonBreakingWords = [\"kW\", \"V\", \"mm\", \"m\", \"cm\", \"kg\", \"%\"]\n\n return (\n <>\n {text\n ?.split(/\\s/g)\n .map((word, i) =>\n nonBreakingWords.includes(word) ? [ , word] : ` ${word}`\n )}\n \n )\n}\n\nexport function findDeepestCategory(\n nodes: ProductCategoryStructureNode[],\n categories: string[]\n): ProductCategoryStructureNode | undefined {\n if (!categories || !nodes || !nodes.length) return\n let found\n\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i]\n\n // etsitään löytyykö lapsien joukosta kategorioita\n const child = findDeepestCategory(node.subCategories, categories)\n if (child) {\n found = child\n } else {\n // Jos ei lapsien joukosta löytynyt, niin tarkistetaan onko itsellä\n const cur = categories.find(itm => itm === node.code)\n if (cur) {\n found = node\n }\n }\n }\n\n return found\n}\n\n/**\n * Hakee buildatun tuotteen assosiaatioiden QUANTITY arvot\n * @param data\n * @returns\n */\nexport function getAssocQuantities(data: ProductAssociation[]) {\n const res: Record = {}\n data.forEach((assoc: ProductAssociation) => {\n res[assoc.sku] = assoc.data?.QUANTITY || \"\"\n })\n return res\n}\n\n/**\n * Utility function for labeling products that are not available in current user location area.\n *\n * Uses categories set in {@link localePimConfig} and tries to find a match from Products categories.\n *\n * - If any matches are found, returns `true`.\n * - If none are found, return `false`.\n * - If passed an invalid or unknown location area, returns `undefined`. This indicates availability cannot be determined.\n *\n * @param product - Product to evaluate for availability\n * @param localeArea - \"Location area\" to look for\n * @returns `true` if product is available, `false` if it's not or `undefined` if availability cannot be determined from location area\n */\nexport const isAvailable = (\n product: Pick,\n localeArea?: LocaleArea | null\n): boolean | undefined => {\n //console.log(product.identifier, product.categories, country)\n if (localeArea === undefined) {\n // we don't have the users preferred \"location area\"\n return undefined\n }\n if (!isLocaleArea(localeArea)) {\n // we don't have the users preferred \"location area\"\n return undefined\n }\n\n const cats = productCategoriesForArea(localeArea)\n\n return !cats.length || !!cats.find(cat => product.categories.includes(cat))\n}\n\n/** Return categories that (ANY of) must be available for selected area/country */\nexport const productCategoriesForArea = (localeArea: LocaleArea): string[] => {\n if (!localeArea) return []\n\n return localePimConfig[localeArea] || []\n}\n"],"names":["formatUnit","unit","unitMap","filteredValues","METER","MILLIMETER","CUBIC_METER","KILOGRAM","CELSIUS","EUR","HOUR","WATT","KELVIN","SECOND","SQUARE_METER","SQUARE_MILLIMETER","LITER","undefined","null","getValue","values","key","find","value","name","stringValue","list","map","attr","includes","data","type","val","metric","isNaN","amount","text","prices","itm","currency","join","numeric","boolean","getCompareValues","products","keys","res","forEach","row","label","hasVal","product","i","_attr$prices$","_attr$prices$2","validVal","length","push","getExternalMedia","productMedia","filter","transformExternalMedia","externalMedia","baseType","children","previewLink","properties","rest","labels","locale","TitleFinnish","AssetType","thumbnail","Thumbnail","language","Language","masterImage","MasterImage","transformProductValue","attributeLabel","toString","valueType","optionLabel","transformProductValues","Boolean","arrayifyObject","obj","transform","result","Object","entries","arrayifyAssociationData","sku","prototype","hasOwnProperty","call","associationData","localeId","arrayifyAssociations","associations","processProduct","_product$values$produ","_product$values$produ2","_product$values$produ3","_product$values$produ4","_product$values$produ5","_product$values$produ6","_product$values$produ7","_product$values$produ8","_product$values$produ9","_product$values$produ10","_product$values$produ11","_product$values$produ12","extMedia","media","media_images","media_videos","media_manuals","media_brochures","media_technicalImages","media_technicalModels","media_certificates","media_materials","extM","raw","mediaList","JSON","parse","apply","_toConsumableArray","m","product_family","identifier","getQuery","params","query","condition","parameters","subQueries","parts","split","queryPart","operator","firstOperand","secondOperand","getQueryParam","useOnlineProductQuery","options","projection","_options$baseQuery","setData","useState","baseQueryParams","baseQuery","paramsString","URLSearchParams","includeDisabledProducts","useEffect","controller","AbortController","_baseQuery$subQueries","_baseQuery$subQueries3","queryParams","orParams","str","toLowerCase","splice","andParams","userQuery","param","_baseQuery$subQueries2","orQuery","finalQuery","window","fetch","signal","method","headers","body","stringify","then","json","content","newData","rockonProduct","fullAssociations","tempAssoc","assoc","_res$fullAssociations","prod","p","catch","err","console","error","makeRequest","abort","props","src","srcSet","React","assign","alt","style","objectFit","loading","TagBox","className","LabelBox","BgColor","color","_props$labels","_props$tags","itemScope","itemType","Link","to","url","tabIndex","PimImage","image","imageAlt","itemProp","wifi","IoWifi","title","group","family","e","textFormat","itemCode","dangerouslySetInnerHTML","__html","tags","userPrefs","useUserPreferences","useContext","PageContext","t","useDatoMicrocopy","getProductPath","useProductPath","_getValue2","_getValue2$value","_getValue2$value$","img","flat","enabled","status","_getValue","prod_date","newAtAge","age","Date","now","quantityNeeded","isAvailable","localeArea","ProductCard","ProductListHeading","category","description","OnlineProductList","localePim","setProducts","setLoading","page","setPage","pim","useSiteMetadata","pageSize","countryProductFilters","productCategoriesForArea","cat","concat","baseParams","onlineProducts","queryResult","size","sort","hideIfEmpty","quantities","_props$quantities","ProductList","LoadingSpinner","Pagination","number","totalElements","onNextPage","OfflineProductList","_props$products","_props$products2","slice","container","useRef","shown","setShown","lazyLoading","onlineMode","scrolling","_container$current","current","innerHeight","getBoundingClientRect","top","removeEventListener","addEventListener","ref","isBrowser","europe","africa","asia","oceania","global","parseJSON","nonBreakingWords","word","findDeepestCategory","nodes","categories","found","node","child","subCategories","code","getAssocQuantities","_assoc$data","QUANTITY","isLocaleArea","cats","localePimConfig"],"sourceRoot":""}