From 4ad502839c04cceec67c9d3a7c28bff28c07d6f5 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 23 May 2024 08:04:08 -0600 Subject: [PATCH 1/4] ci(workflows): renaming the project board for Snap in Github --- .github/workflows/patchGenerate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/patchGenerate.yml b/.github/workflows/patchGenerate.yml index ec933a24a..23a8db58d 100644 --- a/.github/workflows/patchGenerate.yml +++ b/.github/workflows/patchGenerate.yml @@ -54,6 +54,6 @@ jobs: - name: Create PR run: | - gh pr create --title "Patch file ${{ matrix.framework }}/${{ env.version }}" --body "" --repo "https://github.com/searchspring/snapfu-patches" --base "main" --head "patch-generate-${{ matrix.framework }}-${{ env.version }}" --project "Snap Beta" --reviewer "searchspring/snap-team" + gh pr create --title "Patch file ${{ matrix.framework }}/${{ env.version }}" --body "" --repo "https://github.com/searchspring/snapfu-patches" --base "main" --head "patch-generate-${{ matrix.framework }}-${{ env.version }}" --project "Snap" --reviewer "searchspring/snap-team" env: GITHUB_TOKEN: ${{ secrets.MACHINE_ACTION_WORKFLOW_PAT }} From 14306a16b88a5b51e38c944a06d08d7630148e23 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 23 May 2024 12:40:05 -0600 Subject: [PATCH 2/4] docs(platforms/groovy): adding groovy scripts for reference --- .../bigcommerce/groovy/ss_variants.groovy | 67 +++++++ .../magento2/groovy/ss_variants.groovy | 124 ++++++++++++ .../shopify/groovy/ss_variants.groovy | 188 ++++++++++++++++++ 3 files changed, 379 insertions(+) create mode 100644 packages/snap-platforms/bigcommerce/groovy/ss_variants.groovy create mode 100644 packages/snap-platforms/magento2/groovy/ss_variants.groovy create mode 100644 packages/snap-platforms/shopify/groovy/ss_variants.groovy diff --git a/packages/snap-platforms/bigcommerce/groovy/ss_variants.groovy b/packages/snap-platforms/bigcommerce/groovy/ss_variants.groovy new file mode 100644 index 000000000..9342475ce --- /dev/null +++ b/packages/snap-platforms/bigcommerce/groovy/ss_variants.groovy @@ -0,0 +1,67 @@ +/* + Snap variants script for BigCommerce + + Generates a JSON string with format: + ss_variants = [ + { + attributes: { ... }, + mappings: { core: { ... } }, + options: { + [optionName]: { value: '', ... } + } + } + ] + + Each object (variant) in the array represents a variation of the product and each of the `options` should reflect that configuration. + When using this in Snap any properties found in `mappings.core` and `attributes` will be "masked" when the variant is selected. + See Snap documentation for more details. + +*/ + +import groovy.json.JsonOutput +import groovy.json.JsonSlurper +import org.apache.commons.lang.StringUtils + +def slurper = new JsonSlurper() +def ss_variants = [] + +if (Objects.nonNull(doc?.child_sku_options) && !StringUtils.isEmpty(doc?.child_sku_options)) { + def sku_options = slurper.parseText(doc.child_sku_options as String) + if(Objects.nonNull(sku_options) && !(sku_options as List).isEmpty()){ + sku_options.each { sku_option -> + def sku = [:] + def mappings = [:] + def core = [:] + def attributes = [:] + def option_data = [:] + def options = [:] + + core.put("imageUrl" , sku_option?.image_url) + core.put("url", doc.url) + core.put("uid" ,sku_option.child_sku) + mappings.put("core", core) + sku.put("mappings",mappings) + + if(Objects.nonNull(sku_option?.inventory_level)){ + attributes.put("available", sku_option?.inventory_level > 0) + } + + if(Objects.nonNull(sku_option?.option) && !StringUtils.isEmpty(sku_option?.option) && Objects.nonNull(sku_option?.value) && !StringUtils.isEmpty(sku_option?.value)){ + attributes.put("title", sku_option?.option + " / " + sku_option?.value) + + } + sku.put("attributes",attributes) + + option_data.put("value", sku_option?.value) + + if(Objects.nonNull(sku_option?.option)){ + options.put(sku_option?.option, option_data) + } + + sku.put("options",options) + ss_variants.add(sku) + } + } +} + +index.put("ss_variants", JsonOutput.toJson(ss_variants)) \ No newline at end of file diff --git a/packages/snap-platforms/magento2/groovy/ss_variants.groovy b/packages/snap-platforms/magento2/groovy/ss_variants.groovy new file mode 100644 index 000000000..163a5da4c --- /dev/null +++ b/packages/snap-platforms/magento2/groovy/ss_variants.groovy @@ -0,0 +1,124 @@ +/* + Snap variants script for Magento2 + + Generates a JSON string with format: + ss_variants = [ + { + attributes: { ... }, + mappings: { core: { ... } }, + options: { + [optionName]: { value: '', ... } + } + } + ] + + Each object (variant) in the array represents a variation of the product and each of the `options` should reflect that configuration. + When using this in Snap any properties found in `mappings.core` and `attributes` will be "masked" when the variant is selected. + See Snap documentation for more details. + +*/ + +import groovy.json.JsonSlurper +import groovy.json.JsonOutput +import org.apache.commons.lang.StringUtils + + +def slurper = new JsonSlurper() + +def imageUrls = [:] +if (Objects.nonNull(doc.swatch_json_data) && !StringUtils.isEmpty(doc.swatch_json_data as String)) { + def swatchData = slurper.parseText(doc.swatch_json_data as String) + if (Objects.nonNull(swatchData)) { + swatchData.each { imageData -> + if (Objects.nonNull(imageData?.color) && Objects.nonNull(imageData?.image)) { + imageUrls.put(imageData?.color, imageData?.image) + } + } + } +} + +if (Objects.nonNull(doc.json_config) && !StringUtils.isEmpty(doc.json_config as String)) { + def jsonConfig = slurper.parseText(doc.json_config as String) + def ss_swatches = [] + + if (Objects.nonNull(jsonConfig?.attributes)) { + def productIds = [] + jsonConfig.attributes*.value*.options*.products?.each { rawProductIds -> + if (Objects.nonNull(rawProductIds)) { + rawProductIds.each { + if (Objects.nonNull(it)) { + productIds.addAll(it) + } + } + } + } + productIds = productIds?.unique() + + productIds.each { uniqueProductId -> + def productId = uniqueProductId + def ss_variants = [:] + def options = [:] + + def colour = null + def size = null + def colourAttributeId = null + def colourOptionId = null + def sizeAttributeId = null + def sizeOptionId = null + jsonConfig?.attributes?.each { attribute -> + if (Objects.nonNull(attribute?.value?.code)) { + def isColour = attribute?.value?.code == "colour" + def optionData = [:] + + optionData.put("attributeId", attribute?.key) + + if (Objects.nonNull(attribute?.value?.options) && !(attribute?.value?.options as List).isEmpty()) { + (attribute?.value?.options as List).each { attributeSubOption -> + if (Objects.nonNull(attributeSubOption?.products) && (attributeSubOption?.products as List).contains(productId)) { + if (isColour) { + colour = attributeSubOption?.label + colourAttributeId = attribute?.key + colourOptionId = attributeSubOption?.id + } else { + size = attributeSubOption?.label + sizeAttributeId = attribute?.key + sizeOptionId = attributeSubOption?.id + } + optionData.put("value", attributeSubOption?.label) + optionData.put("optionId", attributeSubOption?.id) + } + } + } + options.put(attribute?.value?.code, optionData) + } + } + + def core = [:] + + if (colourAttributeId && colourOptionId && sizeOptionId && sizeAttributeId) { + core.put("url", doc?.url + "#" + colourAttributeId + "=" + colourOptionId + "&" + sizeAttributeId + "=" + sizeOptionId) + } + + if (Objects.nonNull(colour) && Objects.nonNull(imageUrls?.get(colour))) { + core.put("imageUrl", imageUrls?.get(colour)) + } + + core.put("uid", uniqueProductId) + def mappings = [:] + mappings.put("core", core) + + ss_variants.put("mappings", mappings) + + def attributes = [:] + attributes.put("available", true) + if (Objects.nonNull(colour) && Objects.nonNull(size)) { + attributes.put("title", "$colour / $size") + } + ss_variants.put("attributes", attributes) + ss_variants.put("options", options) + ss_swatches.add(ss_variants) + } + + index.ss_variants = JsonOutput.toJson(ss_swatches) + } +} \ No newline at end of file diff --git a/packages/snap-platforms/shopify/groovy/ss_variants.groovy b/packages/snap-platforms/shopify/groovy/ss_variants.groovy new file mode 100644 index 000000000..584130eec --- /dev/null +++ b/packages/snap-platforms/shopify/groovy/ss_variants.groovy @@ -0,0 +1,188 @@ +/* + Snap variants script for Shopify + + Generates a JSON string with format: + ss_variants = [ + { + attributes: { ... }, + mappings: { core: { ... } }, + options: { + [optionName]: { value: '', ... } + } + } + ] + + Each object (variant) in the array represents a variation of the product and each of the `options` should reflect that configuration. + When using this in Snap any properties found in `mappings.core` and `attributes` will be "masked" when the variant is selected. + See Snap documentation for more details. + +*/ + +import groovy.json.JsonSlurper +import groovy.json.JsonOutput + +/* CONFIGURATION */ + +// optional image to use if no variant image is found +def fallback_image = '' + +// dimension modification for variant images +def shopify_image_dimension_suffix = '' +def shopify_thumbnail_dimension_suffix = '' + + +/* CODE */ + +// helper function to add a suffix to the Shopify images +def addImageSuffix = { img, suffix -> + matcher = (img =~ /(.+)(\.(?:(?i)jpg|jpeg|gif|png|svg|webp|avif|heic).+)/) + if (matcher) { + return matcher[0][1] + "_" + suffix + matcher[0][2] + } else { + return img + } +} + +// JSON slurper +def slurper = new JsonSlurper() +def variants_json = slurper.parseText(doc.variants) +def options_json = slurper.parseText(doc.options) +def variant_images_json +try{ + variant_images_json = slurper.parseText(doc.variant_images_json) +} catch (err) { + variant_images_json = [] +} + +/* create an options map and array from options_json */ +def options_map = [:] + +options_json.each { option -> + def option_position_string = 'option' + option.position + def option_name = option.name.toLowerCase().replace(' ', '_') + options_map[option_position_string] = option_name +} + +/* create an options_image_map from variant_images_json*/ +def options_image_map = [:] + +variant_images_json.each { variant_image -> + def option_map_reference = options_image_map + + options_map.eachWithIndex { option_key, option, idx -> + def option_value = variant_image[option] + if (idx + 1 == options_map.size()) { + if ( option_value ) { + option_map_reference[option_value] = variant_image.img + } + } else { + if (!option_map_reference[option_value] && option_value) { + option_map_reference[option_value] = [:] + } + if (option_value) { + option_map_reference = option_map_reference[option_value] + } + } + } +} + +/* map variants_json -> variants structure and put into array */ +def variant_array = [] + +// variant data to put into core fields +def core_fields_mapping = [ + uid: "id", + msrp: "compare_at_price", + price: "price", + sku: "sku", +] + +// attributes outside of the options +def attributes_fields_mapping = [ + quantity: "inventory_quantity", // property must be named "quantity" for proper functionality + title: "title", +] + +variants_json.each { variant -> + def variant_object = [:] + variant_object.mappings = [:] + variant_object.mappings.core = [:] + variant_object.attributes = [:] + variant_object.options = [:] + + // convert into a variant object + /* + { + "mappings": { + "core": { ... } + }, + "attributes": { + ... + } + } + */ + + /* populate core mappings */ + core_fields_mapping.each { core_field_name, variant_field_name -> + variant_object.mappings.core[core_field_name] = variant[variant_field_name] + } + // add variant URL to core fields + variant_object.mappings.core.url = "/products/" + doc.handle + "?variant=" + variant.id + // add image core fields if an image if found for the variant + def option_path = [variant.option1, variant.option2, variant.option3] + + def variant_image_reference = options_image_map + option_path.each { option -> + try { + if (option && variant_image_reference[option]) { + variant_image_reference = variant_image_reference[option] + } + } catch (err) { + variant_image_reference = variant_image_reference + } + } + + // image found in mapping + if (variant_image_reference && variant_image_reference instanceof String) { + variant_object.mappings.core.imageUrl = variant_image_reference + variant_object.mappings.core.thumbnailImageUrl = variant_image_reference + + // add image suffix + if (shopify_image_dimension_suffix) { + variant_object.mappings.core.imageUrl = addImageSuffix(variant_image_reference, shopify_image_dimension_suffix) + } + // add thumbnail image suffix + if (shopify_thumbnail_dimension_suffix) { + variant_object.mappings.core.thumbnailImageUrl = addImageSuffix(variant_image_reference, shopify_thumbnail_dimension_suffix) + } + } else if (fallback_image) { + variant_object.mappings.core.imageUrl = fallback_image + variant_object.mappings.core.thumbnailImageUrl = fallback_image + } + + /* populate attributes */ + attributes_fields_mapping.each { attribute_field_name, variant_field_name -> + variant_object.attributes[attribute_field_name] = variant[variant_field_name] + } + + // determine availability + if (variant.inventory_policy == "continue" || variant.inventory_management == "null" || (variant.inventory_policy == "deny" && variant.inventory_quantity > 0)) { + variant_object.attributes.available = true + } else { + variant_object.attributes.available = false + } + + /* populate options */ + options_map.each { option_number, option_name -> + if(variant[option_number]) { + variant_object.options[option_name] = [ + value: variant[option_number] + ] + } + } + + // add variant object to the array + variant_array.push(variant_object) +} + +index.ss_variants = JsonOutput.toJson(variant_array) \ No newline at end of file From 310317b55fcabc931ff2b6a0fffca6944e272d5b Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 23 May 2024 12:43:31 -0600 Subject: [PATCH 3/4] build(preact/package.json): adding snap-platforms as a dependency so that snapps won't have to --- packages/snap-preact/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/snap-preact/package.json b/packages/snap-preact/package.json index f7daa0760..677ec2e34 100644 --- a/packages/snap-preact/package.json +++ b/packages/snap-preact/package.json @@ -24,6 +24,7 @@ "@searchspring/snap-controller": "^0.56.1", "@searchspring/snap-event-manager": "^0.56.1", "@searchspring/snap-logger": "^0.56.1", + "@searchspring/snap-platforms": "^0.56.1", "@searchspring/snap-preact-components": "^0.56.1", "@searchspring/snap-profiler": "^0.56.1", "@searchspring/snap-store-mobx": "^0.56.1", From aad0337a7458e7899678fcbf283f1804e500dbd9 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 23 May 2024 14:40:40 -0600 Subject: [PATCH 4/4] build(platforms/bigcommerce): fixing case issue for bigcommerce typescript config --- packages/snap-platforms/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/snap-platforms/tsconfig.json b/packages/snap-platforms/tsconfig.json index b10fe7f07..4769a6cfd 100644 --- a/packages/snap-platforms/tsconfig.json +++ b/packages/snap-platforms/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../tsconfig.json", "include": [ - "bigCommerce/src", + "bigcommerce/src", "magento2/src", "shopify/src" ],