@searchspring/snap-store-mobx
Advanced tools
Comparing version 0.53.4 to 0.54.0
@@ -1,2 +0,2 @@ | ||
import type { StoreServices, StoreConfigs, VariantSelectionOptions } from '../../types'; | ||
import type { StoreServices, StoreConfigs, VariantSelectionOptions, VariantConfig } from '../../types'; | ||
import type { SearchResponseModelResult, SearchResponseModelPagination, SearchResponseModelMerchandising, SearchResponseModelResultMappings, SearchResponseModelMerchandisingContentInline, SearchResponseModelMerchandisingContentConfig } from '@searchspring/snapi-types'; | ||
@@ -20,3 +20,7 @@ export declare class SearchResultStore extends Array<Product | Banner> { | ||
attributes: Record<string, unknown>; | ||
options: Record<string, string>; | ||
options: Record<string, { | ||
value: string; | ||
attributeId?: string; | ||
optionId?: string; | ||
}>; | ||
}; | ||
@@ -53,5 +57,7 @@ type ProductMinimal = { | ||
setActive: (variant: Variant) => void; | ||
constructor(variantData: VariantData[], mask: ProductMask); | ||
makeSelections(options?: Record<string, string>): void; | ||
update(fromSelection: VariantSelection): void; | ||
private config?; | ||
constructor(variantData: VariantData[], mask: ProductMask, config?: VariantConfig); | ||
update(variantData: VariantData[], config?: VariantConfig | undefined): void; | ||
makeSelections(options?: Record<string, string[]>): void; | ||
refineSelections(fromSelection: VariantSelection): void; | ||
} | ||
@@ -73,3 +79,3 @@ type SelectionValue = { | ||
constructor(variants: Variants, selectorConfig: VariantSelectionOptions); | ||
refineSelections(variants: Variants): void; | ||
refineValues(variants: Variants): void; | ||
reset(): void; | ||
@@ -82,3 +88,7 @@ select(value: string, internalSelection?: boolean): void; | ||
attributes: Record<string, unknown>; | ||
options: Record<string, string>; | ||
options: Record<string, { | ||
value: string; | ||
attributeId?: string; | ||
optionId?: string; | ||
}>; | ||
mappings: SearchResponseModelResultMappings; | ||
@@ -85,0 +95,0 @@ custom: {}; |
@@ -98,3 +98,3 @@ "use strict"; | ||
function Product(services, result, config) { | ||
var _a, _b, _c; | ||
var _a, _b, _c, _d; | ||
this.type = 'product'; | ||
@@ -117,3 +117,3 @@ this.attributes = {}; | ||
var parsedVariants = JSON.parse(this.attributes[variantsField]); | ||
this.variants = new Variants(parsedVariants, this.mask); | ||
this.variants = new Variants(parsedVariants, this.mask, (_c = config.settings) === null || _c === void 0 ? void 0 : _c.variants); | ||
} | ||
@@ -125,3 +125,3 @@ catch (err) { | ||
} | ||
if ((_c = result === null || result === void 0 ? void 0 : result.children) === null || _c === void 0 ? void 0 : _c.length) { | ||
if ((_d = result === null || result === void 0 ? void 0 : result.children) === null || _d === void 0 ? void 0 : _d.length) { | ||
this.children = result.children.map(function (variant, index) { | ||
@@ -184,24 +184,6 @@ return new Child(services, __assign({ id: "".concat(result.id, "-").concat(index) }, variant)); | ||
var Variants = /** @class */ (function () { | ||
function Variants(variantData, mask) { | ||
function Variants(variantData, mask, config) { | ||
var _this = this; | ||
this.data = []; | ||
this.selections = []; | ||
var options = []; | ||
// create variants objects | ||
this.data = variantData.map(function (variant) { | ||
Object.keys(variant.options).forEach(function (variantOption) { | ||
if (!options.includes(variantOption)) { | ||
options.push(variantOption); | ||
} | ||
}); | ||
return new Variant(variant); | ||
}); | ||
options.map(function (option) { | ||
// TODO - merge with variant config before constructing selection (for label overrides and swatch mappings) | ||
var optionConfig = { | ||
field: option, | ||
label: option, | ||
}; | ||
_this.selections.push(new VariantSelection(_this, optionConfig)); | ||
}); | ||
// setting function in constructor to prevent exposing mask as class property | ||
@@ -212,7 +194,46 @@ this.setActive = function (variant) { | ||
}; | ||
// select first available | ||
this.makeSelections(); | ||
this.config = config; | ||
this.update(variantData, config); | ||
} | ||
Variants.prototype.update = function (variantData, config) { | ||
var _this = this; | ||
if (config === void 0) { config = this.config; } | ||
try { | ||
var options_1 = []; | ||
// create variants objects | ||
this.data = variantData.map(function (variant) { | ||
Object.keys(variant.options).forEach(function (variantOption) { | ||
if (!options_1.includes(variantOption)) { | ||
options_1.push(variantOption); | ||
} | ||
}); | ||
return new Variant(variant); | ||
}); | ||
//need to reset this.selections first | ||
this.selections = []; | ||
options_1.map(function (option) { | ||
// TODO - merge with variant config before constructing selection (for label overrides and swatch mappings) | ||
var optionConfig = { | ||
field: option, | ||
label: option, | ||
}; | ||
_this.selections.push(new VariantSelection(_this, optionConfig)); | ||
}); | ||
var preselectedOptions_1 = {}; | ||
if (config === null || config === void 0 ? void 0 : config.options) { | ||
Object.keys(config === null || config === void 0 ? void 0 : config.options).forEach(function (option) { | ||
if (config.options[option].preSelected) { | ||
preselectedOptions_1[option] = config.options[option].preSelected; | ||
} | ||
}); | ||
} | ||
// select first available | ||
this.makeSelections(preselectedOptions_1); | ||
} | ||
catch (err) { | ||
// failed to parse the variant JSON | ||
console.error(err, "Invalid variant JSON for: ".concat(variantData)); | ||
} | ||
}; | ||
Variants.prototype.makeSelections = function (options) { | ||
// TODO - support for affinity to attempt to pre-selected options | ||
// options = {color: 'Blue', size: 'L'}; | ||
@@ -228,4 +249,36 @@ if (!options) { | ||
} | ||
else { | ||
this.selections.forEach(function (selection, idx) { | ||
// filter by first available, then by preselected option preference | ||
//make all options available for first selection. | ||
var availableOptions = selection.values.filter(function (value) { return (idx == 0 ? true : value.available); }); | ||
var preferedOptions = options[selection.field]; | ||
var preferencedOption = availableOptions[0]; | ||
// if theres a preference for that field | ||
if (preferedOptions) { | ||
var checkIfAvailable_1 = function (preference) { | ||
//see if that option is in the available options | ||
var availablePreferedOptions = availableOptions.find(function (value) { return value.value.toLowerCase() == preference.toLowerCase(); }); | ||
//use it | ||
if (availablePreferedOptions) { | ||
preferencedOption = availablePreferedOptions; | ||
} | ||
}; | ||
if (Array.isArray(preferedOptions)) { | ||
//loop through each preference option | ||
preferedOptions.forEach(function (preference) { | ||
checkIfAvailable_1(preference); | ||
}); | ||
} | ||
else { | ||
checkIfAvailable_1(preferedOptions); | ||
} | ||
} | ||
if (preferencedOption) { | ||
selection.select(preferencedOption.value); | ||
} | ||
}); | ||
} | ||
}; | ||
Variants.prototype.update = function (fromSelection) { | ||
Variants.prototype.refineSelections = function (fromSelection) { | ||
var _this = this; | ||
@@ -241,9 +294,9 @@ // need to ensure the update originator is at the BOTTOM of the list for refinement | ||
// refine selections ensuring that the selection that triggered the update refines LAST | ||
orderedSelections.forEach(function (selection) { return selection.refineSelections(_this); }); | ||
orderedSelections.forEach(function (selection) { return selection.refineValues(_this); }); | ||
// check to see if we have enough selections made to update the display | ||
var selectedSelections = this.selections.filter(function (selection) { var _a; return (_a = selection.selected) === null || _a === void 0 ? void 0 : _a.length; }); | ||
var selectedSelections = this.selections.filter(function (selection) { return selection.selected; }); | ||
if (selectedSelections.length) { | ||
var availableVariants = this.data; | ||
var _loop_1 = function (selectedSelection) { | ||
availableVariants = availableVariants.filter(function (variant) { return selectedSelection.selected == variant.options[selectedSelection.field] && variant.available; }); | ||
availableVariants = availableVariants.filter(function (variant) { return selectedSelection.selected == variant.options[selectedSelection.field].value && variant.available; }); | ||
}; | ||
@@ -273,5 +326,5 @@ // loop through selectedSelections and only include available products that match current selections | ||
// needed to prevent attaching variants as class property | ||
this.variantsUpdate = function () { return variants.update(_this); }; | ||
this.variantsUpdate = function () { return variants.refineSelections(_this); }; | ||
// create possible values from the data and refine them | ||
this.refineSelections(variants); | ||
this.refineValues(variants); | ||
(0, mobx_1.makeObservable)(this, { | ||
@@ -282,3 +335,3 @@ selected: mobx_1.observable, | ||
} | ||
VariantSelection.prototype.refineSelections = function (variants) { | ||
VariantSelection.prototype.refineValues = function (variants) { | ||
var _this = this; | ||
@@ -289,3 +342,3 @@ // current selection should only consider OTHER selections for availability | ||
var _loop_2 = function (selectedSelection) { | ||
availableVariants = availableVariants.filter(function (variant) { return selectedSelection.selected == variant.options[selectedSelection.field] && variant.available; }); | ||
availableVariants = availableVariants.filter(function (variant) { return selectedSelection.selected == variant.options[selectedSelection.field].value && variant.available; }); | ||
}; | ||
@@ -301,11 +354,7 @@ // loop through selectedSelections and remove products that do not match | ||
var _a; | ||
if (!values.some(function (val) { return variant.options[_this.field] == val.value; })) { | ||
values.push({ | ||
value: variant.options[_this.field], | ||
label: variant.options[_this.field], | ||
if (!values.some(function (val) { return variant.options[_this.field].value == val.value; })) { | ||
values.push(__assign({ label: variant.options[_this.field].value, | ||
// TODO: use configurable mappings from config | ||
// TODO: set background for swatches (via configurable mappings) from config | ||
thumbnailImageUrl: (_a = variant.mappings.core) === null || _a === void 0 ? void 0 : _a.thumbnailImageUrl, | ||
available: Boolean(availableVariants.some(function (availableVariant) { return availableVariant.options[_this.field] == variant.options[_this.field]; })), | ||
}); | ||
thumbnailImageUrl: (_a = variant.mappings.core) === null || _a === void 0 ? void 0 : _a.thumbnailImageUrl, available: Boolean(availableVariants.some(function (availableVariant) { return availableVariant.options[_this.field].value == variant.options[_this.field].value; })) }, variant.options[_this.field])); | ||
} | ||
@@ -361,3 +410,2 @@ // TODO: use sorting function from config | ||
this.attributes = {}; | ||
this.options = {}; | ||
this.mappings = { | ||
@@ -364,0 +412,0 @@ core: {}, |
@@ -7,4 +7,9 @@ import type { UrlManager } from '@searchspring/snap-url-manager'; | ||
}; | ||
type VariantConfig = { | ||
export type VariantConfig = { | ||
field: string; | ||
options?: { | ||
[field: string]: { | ||
preSelected?: string[]; | ||
}; | ||
}; | ||
}; | ||
@@ -124,3 +129,2 @@ export type VariantSelectionOptions = { | ||
}; | ||
export {}; | ||
//# sourceMappingURL=types.d.ts.map |
@@ -1,2 +0,2 @@ | ||
import type { StoreServices, StoreConfigs, VariantSelectionOptions } from '../../types'; | ||
import type { StoreServices, StoreConfigs, VariantSelectionOptions, VariantConfig } from '../../types'; | ||
import type { SearchResponseModelResult, SearchResponseModelPagination, SearchResponseModelMerchandising, SearchResponseModelResultMappings, SearchResponseModelMerchandisingContentInline, SearchResponseModelMerchandisingContentConfig } from '@searchspring/snapi-types'; | ||
@@ -20,3 +20,7 @@ export declare class SearchResultStore extends Array<Product | Banner> { | ||
attributes: Record<string, unknown>; | ||
options: Record<string, string>; | ||
options: Record<string, { | ||
value: string; | ||
attributeId?: string; | ||
optionId?: string; | ||
}>; | ||
}; | ||
@@ -53,5 +57,7 @@ type ProductMinimal = { | ||
setActive: (variant: Variant) => void; | ||
constructor(variantData: VariantData[], mask: ProductMask); | ||
makeSelections(options?: Record<string, string>): void; | ||
update(fromSelection: VariantSelection): void; | ||
private config?; | ||
constructor(variantData: VariantData[], mask: ProductMask, config?: VariantConfig); | ||
update(variantData: VariantData[], config?: VariantConfig | undefined): void; | ||
makeSelections(options?: Record<string, string[]>): void; | ||
refineSelections(fromSelection: VariantSelection): void; | ||
} | ||
@@ -73,3 +79,3 @@ type SelectionValue = { | ||
constructor(variants: Variants, selectorConfig: VariantSelectionOptions); | ||
refineSelections(variants: Variants): void; | ||
refineValues(variants: Variants): void; | ||
reset(): void; | ||
@@ -82,3 +88,7 @@ select(value: string, internalSelection?: boolean): void; | ||
attributes: Record<string, unknown>; | ||
options: Record<string, string>; | ||
options: Record<string, { | ||
value: string; | ||
attributeId?: string; | ||
optionId?: string; | ||
}>; | ||
mappings: SearchResponseModelResultMappings; | ||
@@ -85,0 +95,0 @@ custom: {}; |
@@ -64,3 +64,3 @@ import { computed, makeObservable, observable } from 'mobx'; | ||
const parsedVariants = JSON.parse(this.attributes[variantsField]); | ||
this.variants = new Variants(parsedVariants, this.mask); | ||
this.variants = new Variants(parsedVariants, this.mask, config.settings?.variants); | ||
} | ||
@@ -127,23 +127,5 @@ catch (err) { | ||
export class Variants { | ||
constructor(variantData, mask) { | ||
constructor(variantData, mask, config) { | ||
this.data = []; | ||
this.selections = []; | ||
const options = []; | ||
// create variants objects | ||
this.data = variantData.map((variant) => { | ||
Object.keys(variant.options).forEach((variantOption) => { | ||
if (!options.includes(variantOption)) { | ||
options.push(variantOption); | ||
} | ||
}); | ||
return new Variant(variant); | ||
}); | ||
options.map((option) => { | ||
// TODO - merge with variant config before constructing selection (for label overrides and swatch mappings) | ||
const optionConfig = { | ||
field: option, | ||
label: option, | ||
}; | ||
this.selections.push(new VariantSelection(this, optionConfig)); | ||
}); | ||
// setting function in constructor to prevent exposing mask as class property | ||
@@ -154,7 +136,44 @@ this.setActive = (variant) => { | ||
}; | ||
// select first available | ||
this.makeSelections(); | ||
this.config = config; | ||
this.update(variantData, config); | ||
} | ||
update(variantData, config = this.config) { | ||
try { | ||
const options = []; | ||
// create variants objects | ||
this.data = variantData.map((variant) => { | ||
Object.keys(variant.options).forEach((variantOption) => { | ||
if (!options.includes(variantOption)) { | ||
options.push(variantOption); | ||
} | ||
}); | ||
return new Variant(variant); | ||
}); | ||
//need to reset this.selections first | ||
this.selections = []; | ||
options.map((option) => { | ||
// TODO - merge with variant config before constructing selection (for label overrides and swatch mappings) | ||
const optionConfig = { | ||
field: option, | ||
label: option, | ||
}; | ||
this.selections.push(new VariantSelection(this, optionConfig)); | ||
}); | ||
const preselectedOptions = {}; | ||
if (config?.options) { | ||
Object.keys(config?.options).forEach((option) => { | ||
if (config.options[option].preSelected) { | ||
preselectedOptions[option] = config.options[option].preSelected; | ||
} | ||
}); | ||
} | ||
// select first available | ||
this.makeSelections(preselectedOptions); | ||
} | ||
catch (err) { | ||
// failed to parse the variant JSON | ||
console.error(err, `Invalid variant JSON for: ${variantData}`); | ||
} | ||
} | ||
makeSelections(options) { | ||
// TODO - support for affinity to attempt to pre-selected options | ||
// options = {color: 'Blue', size: 'L'}; | ||
@@ -170,4 +189,36 @@ if (!options) { | ||
} | ||
else { | ||
this.selections.forEach((selection, idx) => { | ||
// filter by first available, then by preselected option preference | ||
//make all options available for first selection. | ||
const availableOptions = selection.values.filter((value) => (idx == 0 ? true : value.available)); | ||
const preferedOptions = options[selection.field]; | ||
let preferencedOption = availableOptions[0]; | ||
// if theres a preference for that field | ||
if (preferedOptions) { | ||
const checkIfAvailable = (preference) => { | ||
//see if that option is in the available options | ||
const availablePreferedOptions = availableOptions.find((value) => value.value.toLowerCase() == preference.toLowerCase()); | ||
//use it | ||
if (availablePreferedOptions) { | ||
preferencedOption = availablePreferedOptions; | ||
} | ||
}; | ||
if (Array.isArray(preferedOptions)) { | ||
//loop through each preference option | ||
preferedOptions.forEach((preference) => { | ||
checkIfAvailable(preference); | ||
}); | ||
} | ||
else { | ||
checkIfAvailable(preferedOptions); | ||
} | ||
} | ||
if (preferencedOption) { | ||
selection.select(preferencedOption.value); | ||
} | ||
}); | ||
} | ||
} | ||
update(fromSelection) { | ||
refineSelections(fromSelection) { | ||
// need to ensure the update originator is at the BOTTOM of the list for refinement | ||
@@ -182,5 +233,5 @@ const orderedSelections = [...this.selections]; | ||
// refine selections ensuring that the selection that triggered the update refines LAST | ||
orderedSelections.forEach((selection) => selection.refineSelections(this)); | ||
orderedSelections.forEach((selection) => selection.refineValues(this)); | ||
// check to see if we have enough selections made to update the display | ||
const selectedSelections = this.selections.filter((selection) => selection.selected?.length); | ||
const selectedSelections = this.selections.filter((selection) => selection.selected); | ||
if (selectedSelections.length) { | ||
@@ -190,3 +241,3 @@ let availableVariants = this.data; | ||
for (const selectedSelection of selectedSelections) { | ||
availableVariants = availableVariants.filter((variant) => selectedSelection.selected == variant.options[selectedSelection.field] && variant.available); | ||
availableVariants = availableVariants.filter((variant) => selectedSelection.selected == variant.options[selectedSelection.field].value && variant.available); | ||
} | ||
@@ -208,5 +259,5 @@ // set active variant | ||
// needed to prevent attaching variants as class property | ||
this.variantsUpdate = () => variants.update(this); | ||
this.variantsUpdate = () => variants.refineSelections(this); | ||
// create possible values from the data and refine them | ||
this.refineSelections(variants); | ||
this.refineValues(variants); | ||
makeObservable(this, { | ||
@@ -217,3 +268,3 @@ selected: observable, | ||
} | ||
refineSelections(variants) { | ||
refineValues(variants) { | ||
// current selection should only consider OTHER selections for availability | ||
@@ -224,3 +275,3 @@ const selectedSelections = variants.selections.filter((selection) => selection.field != this.field && selection.selected); | ||
for (const selectedSelection of selectedSelections) { | ||
availableVariants = availableVariants.filter((variant) => selectedSelection.selected == variant.options[selectedSelection.field] && variant.available); | ||
availableVariants = availableVariants.filter((variant) => selectedSelection.selected == variant.options[selectedSelection.field].value && variant.available); | ||
} | ||
@@ -230,10 +281,10 @@ const newValues = variants.data | ||
.reduce((values, variant) => { | ||
if (!values.some((val) => variant.options[this.field] == val.value)) { | ||
if (!values.some((val) => variant.options[this.field].value == val.value)) { | ||
values.push({ | ||
value: variant.options[this.field], | ||
label: variant.options[this.field], | ||
label: variant.options[this.field].value, | ||
// TODO: use configurable mappings from config | ||
// TODO: set background for swatches (via configurable mappings) from config | ||
thumbnailImageUrl: variant.mappings.core?.thumbnailImageUrl, | ||
available: Boolean(availableVariants.some((availableVariant) => availableVariant.options[this.field] == variant.options[this.field])), | ||
available: Boolean(availableVariants.some((availableVariant) => availableVariant.options[this.field].value == variant.options[this.field].value)), | ||
...variant.options[this.field], | ||
}); | ||
@@ -287,3 +338,2 @@ } | ||
this.attributes = {}; | ||
this.options = {}; | ||
this.mappings = { | ||
@@ -290,0 +340,0 @@ core: {}, |
@@ -7,4 +7,9 @@ import type { UrlManager } from '@searchspring/snap-url-manager'; | ||
}; | ||
type VariantConfig = { | ||
export type VariantConfig = { | ||
field: string; | ||
options?: { | ||
[field: string]: { | ||
preSelected?: string[]; | ||
}; | ||
}; | ||
}; | ||
@@ -124,3 +129,2 @@ export type VariantSelectionOptions = { | ||
}; | ||
export {}; | ||
//# sourceMappingURL=types.d.ts.map |
{ | ||
"name": "@searchspring/snap-store-mobx", | ||
"version": "0.53.4", | ||
"version": "0.54.0", | ||
"description": "Snap MobX Store", | ||
@@ -23,8 +23,8 @@ "main": "dist/cjs/index.js", | ||
"dependencies": { | ||
"@searchspring/snap-toolbox": "^0.53.4", | ||
"@searchspring/snap-toolbox": "^0.54.0", | ||
"mobx": "6.9.0" | ||
}, | ||
"devDependencies": { | ||
"@searchspring/snap-client": "^0.53.4", | ||
"@searchspring/snap-url-manager": "^0.53.4" | ||
"@searchspring/snap-client": "^0.54.0", | ||
"@searchspring/snap-url-manager": "^0.54.0" | ||
}, | ||
@@ -35,3 +35,3 @@ "sideEffects": false, | ||
], | ||
"gitHead": "9e15f63d93f34ccf0af5ce33eca1d6c9e5b794f5" | ||
"gitHead": "a54d2c6579bf83500ed2faca8ff72b3e3495f063" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
342728
6529
+ Added@searchspring/snap-toolbox@0.54.0(transitive)
- Removed@searchspring/snap-toolbox@0.53.4(transitive)