{"version":3,"sources":["webpack:///./src/web-api/quantity-service.ts"],"names":["QuantityService","ServiceWithSession","constructor","hasInitialState","session","super","pendingRefresh","initialState","initialized","Deferred","entity","this","Map","initialize","root","watchedProps","visitType","meta","type","t","path","prop","properties","some","otherProp","name","isList","isEntityType","propertyType","propPath","length","push","getPath","qs","addRule","execute","refresh","onChangeOf","register","getState","_ref","getNormalizedPropertyValue","fieldValue","value","trim","result","serializer","serializePropertyValue","force","useAliases","concat","replace","toLowerCase","updateQuantities","quantityData","updates","usedQty","limits","key","count","countIsLimit","filter","d","visitLimitedProperties","e","getKeyFor","canLimitValue","offset","hasProp","forEach","run","callback","visitEntity","undefined","followCircularProperties","followLookups","state","p","promise","keyFormat","normalizedValue","task","setTimeout","async","success","refreshQuantitiesRequest","err","pending","resolve","reject","keys","Object","serviceRequest","method","endpoint","data","response","parseError","error"],"mappings":"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","file":"164.e5aed0372750f368832e.js","sourcesContent":["import { ServiceWithSession } from './base-service';\r\nimport type { Entity, Property } from '@cognitoforms/model.js';\r\nimport { isEntityType } from '@cognitoforms/model.js';\r\nimport { Deferred } from 'src/util/deferred';\r\nimport type { Quantity } from '@cognitoforms/types/server-types/forms/model/quantity';\r\nimport type { FormSession } from './form-session';\r\nimport { visitEntity, visitType } from 'src/util/model';\r\nimport { hasProp } from 'src/util/helpers';\r\n\r\nconst DEBOUNCE_RATE = 100;\r\nconst QTY_SELECTED = '_QuantitySelected';\r\nconst QTY_USED = '_QuantityUsed';\r\nconst QTY_LIMIT = '_QuantityLimit';\r\nconst QTY_LIMIT_CALC = '_QuantityLimitCalculated';\r\nconst QTY_FORMAT = '_QuantityKeyFormat';\r\n\r\nexport type QuantityData = {\r\n\tkey: string;\r\n\tcount: number;\r\n\tcountIsLimit: boolean;\r\n}\r\n\r\nexport default class QuantityService extends ServiceWithSession {\r\n\tprivate pendingRefresh: Promise;\r\n\tprivate initialState: Map = null;\r\n\tprivate initialized: Deferred = new Deferred();\r\n\tprivate entity: Entity;\r\n\r\n\tconstructor(hasInitialState: boolean, session: FormSession) {\r\n\t\tsuper(session);\r\n\r\n\t\tif (hasInitialState)\r\n\t\t\tthis.initialState = new Map();\r\n\t}\r\n\r\n\tinitialize(root: Entity) {\r\n\t\tthis.entity = root;\r\n\t\tconst watchedProps = [];\r\n\t\tvisitType(root.meta.type, (t, path) => {\r\n\t\t\tfor (const prop of t.properties) {\r\n\t\t\t\tif (t.properties.some(otherProp => otherProp.name === prop.name + QTY_FORMAT) || prop.isList && isEntityType(prop.propertyType)) {\r\n\t\t\t\t\tlet propPath = path;\r\n\t\t\t\t\tif (path.length)\r\n\t\t\t\t\t\tpropPath += '.';\r\n\r\n\t\t\t\t\tpropPath += prop.name;\r\n\t\t\t\t\twatchedProps.push(root.meta.type.getPath(propPath));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// eslint-disable-next-line @typescript-eslint/no-this-alias\r\n\t\tconst qs = this;\r\n\t\troot.meta.type.addRule({\r\n\t\t\texecute() {\r\n\t\t\t\tif (this !== qs.entity)\r\n\t\t\t\t\treturn;\r\n\r\n\t\t\t\tqs.refresh();\r\n\t\t\t},\r\n\t\t\tonChangeOf: watchedProps\r\n\t\t}).register();\r\n\r\n\t\tif (this.initialState)\r\n\t\t\tthis.initialState = this.getState();\r\n\r\n\t\tthis.refresh();\r\n\t}\r\n\r\n\tasync reset({ hasInitialState, root }: { hasInitialState: boolean; root: Entity }) {\r\n\t\tthis.entity = root;\r\n\t\tif (hasInitialState)\r\n\t\t\tthis.initialState = this.getState();\r\n\t\telse\r\n\t\t\tthis.initialState = null;\r\n\r\n\t\tawait this.refresh();\r\n\t}\r\n\r\n\tprivate getNormalizedPropertyValue(entity: Entity, prop: Property): string {\r\n\t\tlet fieldValue = prop.value(entity);\r\n\t\tif (fieldValue && typeof fieldValue === 'string')\r\n\t\t\tfieldValue = fieldValue.trim();\r\n\r\n\t\tconst result = entity.serializer.serializePropertyValue(entity, prop, fieldValue, { force: true, useAliases: false });\r\n\r\n\t\tif (!result || result.value === null)\r\n\t\t\treturn '';\r\n\r\n\t\treturn `${result ? result.value : result}`\r\n\t\t\t.replace(/Σ([_\\-,!?\\s\\d]+|$)/g, 'σ$1') // JS toLowerCase() is inconsistent with C# toLower() for Greek when a string ends with upper case sigma. https://en.wikipedia.org/wiki/Sigma\r\n\t\t\t.toLowerCase();\r\n\t}\r\n\r\n\t/**\r\n\t * Updates `QuantityUsed` fields on tracked entities by combining the provided quantity data with the quantity data\r\n\t * currently represented by tracked entities.\r\n\t */\r\n\tprivate updateQuantities(quantityData: QuantityData[]) {\r\n\t\tconst updates = [];\r\n\t\tconst usedQty = {};\r\n\t\tconst limits = {};\r\n\r\n\t\tfor (const { key, count, countIsLimit } of quantityData.filter(d => d !== null)) {\r\n\t\t\tif (countIsLimit)\r\n\t\t\t\tlimits[key] = count;\r\n\t\t\telse\r\n\t\t\t\tusedQty[key] = (usedQty[key] || 0) + count;\r\n\t\t}\r\n\r\n\t\tthis.visitLimitedProperties((e, prop) => {\r\n\t\t\tconst key = this.getKeyFor(e, prop);\r\n\t\t\tconst value = prop.value(e);\r\n\r\n\t\t\t// If value cannot be limited or the limit is null ignore the validation\r\n\t\t\tif (!this.canLimitValue(value) || e[prop.name + QTY_LIMIT] === null) {\r\n\t\t\t\tupdates.push(() => (e[prop.name + QTY_USED] = 0));\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\tusedQty[key] = (usedQty[key] || 0) + e[prop.name + QTY_SELECTED];\r\n\r\n\t\t\t\t// Once we're done collecting all the quantity information, update the model\r\n\t\t\t\tupdates.push(() => {\r\n\t\t\t\t\tconst offset = (this.initialState ? this.initialState[key] : 0) || 0;\r\n\t\t\t\t\te[prop.name + QTY_USED] = usedQty[key] - offset;\r\n\r\n\t\t\t\t\t// set the limit based on server data if we have it\r\n\t\t\t\t\tif (hasProp(limits, key))\r\n\t\t\t\t\t\te[prop.name + QTY_LIMIT] = limits[key];\r\n\t\t\t\t\t// keep limit updated with calculated value for \"normal\" fields\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\te[prop.name + QTY_LIMIT] = e[prop.name + QTY_LIMIT_CALC];\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tupdates.forEach(run => run());\r\n\t}\r\n\r\n\tprivate canLimitValue(value: any) {\r\n\t\treturn value !== null\r\n\t\t\t&& value !== ''\r\n\t\t\t&& value !== false;\r\n\t}\r\n\r\n\tprivate visitLimitedProperties(callback: (e: Entity, p: Property) => void) {\r\n\t\tvisitEntity(this.entity, (e, prop) => {\r\n\t\t\tconst format = e[prop.name + QTY_FORMAT];\r\n\t\t\tif (format !== undefined)\r\n\t\t\t\tcallback(e, prop);\r\n\t\t}, { followCircularProperties: false, followLookups: false });\r\n\t}\r\n\r\n\tgetState(): Map {\r\n\t\tconst state = new Map();\r\n\t\tthis.visitLimitedProperties((e, p) => {\r\n\t\t\tconst key = this.getKeyFor(e, p);\r\n\t\t\tstate[key] = (state[key] || 0) + e[p.name + QTY_SELECTED];\r\n\t\t});\r\n\r\n\t\treturn state;\r\n\t}\r\n\r\n\tget ready() {\r\n\t\treturn this.initialized.promise;\r\n\t}\r\n\r\n\tget loadingComplete() {\r\n\t\treturn this.pendingRefresh;\r\n\t}\r\n\r\n\t/**\r\n\t * Get a key that can be used to load quantity information for a specific property and value combination.\r\n\t * @param prop The model property that is quantity limited.\r\n\t * @param value The normalized value of the property.\r\n\t */\r\n\tprivate getKeyFor(entity: Entity, prop: Property) {\r\n\t\tconst keyFormat = entity[prop.name + QTY_FORMAT];\r\n\t\tconst normalizedValue = this.getNormalizedPropertyValue(entity, prop);\r\n\t\treturn keyFormat.replace('{value}', normalizedValue);\r\n\t}\r\n\r\n\t/**\r\n\t * Initiates a service request for quantity records. Multiple calls within a short time frame will be batched together.\r\n\t * The remote quantity information is then used to update the `QuantityUsed` properties associated with all tracked\r\n\t * fields.\r\n\t */\r\n\trefresh() {\r\n\t\tif (!this.pendingRefresh) {\r\n\t\t\tconst task = new Deferred();\r\n\t\t\tthis.pendingRefresh = task.promise;\r\n\r\n\t\t\tsetTimeout(async () => {\r\n\t\t\t\tlet success = false;\r\n\t\t\t\ttry {\r\n\t\t\t\t\tconst result = await this.refreshQuantitiesRequest();\r\n\t\t\t\t\tsuccess = true;\r\n\t\t\t\t\tthis.updateQuantities(result);\r\n\t\t\t\t}\r\n\t\t\t\tcatch (err) { }\r\n\r\n\t\t\t\tthis.pendingRefresh = null;\r\n\r\n\t\t\t\tif (this.initialized.pending)\r\n\t\t\t\t\tthis.initialized.resolve();\r\n\r\n\t\t\t\tif (success)\r\n\t\t\t\t\ttask.resolve();\r\n\t\t\t\telse\r\n\t\t\t\t\ttask.reject();\r\n\t\t\t}, DEBOUNCE_RATE);\r\n\t\t}\r\n\r\n\t\treturn this.pendingRefresh;\r\n\t}\r\n\r\n\tasync refreshQuantitiesRequest() {\r\n\t\tlet result;\r\n\t\tconst state = this.getState();\r\n\t\tconst keys = Object.keys(state);\r\n\t\tif (keys && keys.length)\r\n\t\t\tresult = await this.serviceRequest({\r\n\t\t\t\tmethod: 'post',\r\n\t\t\t\tendpoint: 'svc/quantity-limit/load-quantity-data',\r\n\t\t\t\tdata: { keys }\r\n\t\t\t});\r\n\t\telse\r\n\t\t\treturn [];\r\n\r\n\t\tif (result.response && result.response.data)\r\n\t\t\treturn result.response.data as QuantityData[];\r\n\r\n\t\tthrow this.parseError(result.error);\r\n\t}\r\n}"],"sourceRoot":""}