product-admin
Version:
EA admin screens
359 lines (313 loc) • 11.5 kB
HTML
<link rel="import" href="../admin-shared-styles/admin-shared-styles.html" />
<link rel="import" href="./edit-product-styles.html" />
<link rel="import" href="../bms-behaviors-util/bms-behaviors-util.html" />
<dom-module id="edit-product">
<template>
<style include="admin-shared-styles"></style>
<style include="edit-product-styles"></style>
<px-modal
id="pxModalContainer"
modal-id="editCreateProductModal"
modal-heading="[[ localizedHeading ]]"
btn-modal-positive="[[ localize('btnCreateEditPositive') ]]"
btn-modal-negative="[[ localize('btnCreateEditNegative') ]]"
btn-modal-positive-disabled="{{!isFormValid}}"
>
<!--
This will be updated imperetively on #attached if isCreate
POST | PUT
"/updateProduct/[[ id ]]" | "/createProduct"
-->
<iron-ajax
method="[[ productApiRequestMethod ]]"
id="productApiRequest"
url="[[ productApiRequestUrl ]]"
handle-as="json"
headers='{ "accept": "application/json" }'
content-type="application/json"
on-response="_handleProductApiSuccess"
on-error="_handleProductApiError"
body="[[ product ]]"
loading="{{loading}}"
></iron-ajax>
<form name="edit-create-form" id="editCreateForm">
<label for$="productDescription" class="label--inline">[[ localize("productDescription") ]]</label>
<input
placeholder="[[ localize('productDescription') ]]"
id="productDescription"
type="text"
class="text-input input--tiny"
value="{{product.productDescription::input}}"
pattern=".{0,255}"
/>
<label for$="productCode" class="label--inline">[[ localize("productCode") ]]</label>
<input placeholder="[[ localize('productCode') ]]"
id="productCode"
type="text"
class="text-input input--tiny"
readonly$="{{!isCreate}}" value="{{product.productCode::input}}"
required
pattern=".{1,255}"
on-input="_validateField" />
<hr />
<label for$="productLongDescription">[[ localize("productLongDescription") ]] <span class="label--light">[[ localize("productDescriptionParen") ]]</span></label>
<div
placeholder='[[ localize("productLongDescription") ]]'
id="longDescription"
class="textarea--long-description"
name="longDescription"
contenteditable="true"
value="{{ product.longDescription }}"
pattern=".{0,150}"
on-input="_validateField"
></div>
<hr />
<label for$="currentSpecificationRate" class="label--inline">[[ localize("currentSpecificationRate") ]]</label>
<input
class="text-input input--tiny"
placeholder="[[ localize('currentSpecificationRate') ]]"
id="currentSpecificationRate"
type="number" pattern="[0-9.]{0,8}"
on-input="_validateField"
step="0.001"
min="0"
max="9999999999999999"
value="{{product.currentSpecificationRate::input}}"
/>
<label for$="currentSpecificationRate" class="label--inline label--light label--space-right-large">[[ localize("currentSpecificationRateLabel") ]]</label>
<wbr />
<label for="estCycleTimeHours" class="label--inline label--space-right-small">{{ localize("estCycleTime") }}</label>
<input class="text-input text-input--four-char" type="number"
min="0"
max="9999"
pattern="[0-9]{0,255}"
on-input="_validateField"
step="1"
id="estCycleTimeHours"
placeholder="0"
type="number"
maxlength="4"
value="{{product.estCycleTimeHours::input}}" />
<label for$="estCycleTimeHours" class="label--inline label--light label--space-right-medium label--space-left-small">[[ localize("hours") ]]</label>
<wbr />
<input
class="text-input text-input--two-char"
type="number"
min="0"
maxlength="2"
pattern="[0-9]{0,255}"
step="1"
id="estCycleTimeMinutes"
type="number"
placeholder="0"
on-input="_validateField"
value="{{ product.estCycleTimeMinutes::input }}" />
<label for$="estCycleTimeMinutes" on-input="_validateField" class="label--inline label--light label--space-left-small">[[ localize("minutes") ]]</label>
<template is="dom-if" if="{{ showUnitsSection }}">
<hr />
<label>{{ localize("produceOnUnits") }}</label>
</template>
<section class="section--scrollable">
<template is="dom-repeat" id="produceOnUnitsId" items="{{ assets }}" initialCount="24">
<div class="container--col__units">
<paper-checkbox
checked$="{{item.selected}}"
value="[[ item.value ]]"
on-change="_changeAssetSelection"
class="checkbox__unit"
id="asset-[[ item.value ]]"
></paper-checkbox>
<label class="label--inline label__checkbox--unit" for$="asset-[[ item.value ]]" on-tap="_selectCorrespondingCheckbox">[[ item.name ]]</label>
</div>
</template>
</section>
</form>
</px-modal>
</template>
</dom-module>
<script>
(function (Polymer, util, undefined) {
"use strict";
Polymer({
is: 'edit-product',
behaviors: [
Polymer.AppLocalizeBehavior,
bms.behaviors.util
// TODO: create validations behavior or add to util
],
properties: {
isCreate: {
type: Boolean,
value: false
},
isFormValid: {
type: Boolean,
value: false
},
product: {
type: Object,
value: function () {
return {
productDescription: "",
longDescription: "",
productCode: "",
currentSpecificationRate: 0,
estCycleTimeHours: 0,
estCycleTimeMinutes: 0,
assets: [],
specifications: []
};
}
},
assets: Array, // units
productApiRequestUrl: String,
productApiRequestMethod: String,
baseUrl: {
type: String,
readOnly: true,
value: function () {
return util.properties.BASE_PATH.value;
}
}
},
attached: attached,
_handleProductApiSuccess: _handleProductApiSuccess,
_handleProductApiError: _handleProductApiError,
_btnModalPositiveClicked: _btnModalPositiveClicked,
_changeAssetSelection: _changeAssetSelection,
_hasDisplayAssets: _hasDisplayAssets,
_updateLocalization: _updateLocalization,
_selectCorrespondingCheckbox: _selectCorrespondingCheckbox,
_validateField: _validateField,
refresh: refresh,
listeners: {
btnModalPositiveClicked: "_btnModalPositiveClicked",
refresh: "refresh"
},
observers: [
"_updateLocalization(resources.*)",
],
});
function _validateField (event) {
var field = event.target;
if (field.id === "longDescription") {
if (field.innerHTML.length < 150) return;
return field.innerHTML = field.innerHTML.slice(-150);
}
var isValid = field.validity.valid;
if (!isValid) {
this.isFormValid = false;
field.reportValidity();
} else {
this.isFormValid = this.$.editCreateForm.checkValidity();
}
}
function refresh () {
// INITIALIZE MODAL HERE
// loop smaller or larger array first?
// [1, 2, 3] ... [1, 5, 6, 7, 8, 9, 10, 2, 3]
// how many times does it loop the entire larger array? smaller?
// cycles?
this.$.longDescription.innerHTML = this.product.longDescription;
this.showUnitsSection = this.assets && this.assets.length > 0;
if (this.assets) {
this.assets.forEach(function (asset) {
asset.selected = false;
checkboxDisplayControl.call(this, asset.value, false);
}, this);
}
this.product = Object.assign(this.product, {
assets: this.product.assets || [],
estCycleTimeMinutes: this.product.estCycleTimeMinutes || 0,
estCycleTimeHours: this.product.estCycleTimeHours || 0,
currentSpecificationRate: this.product.currentSpecificationRate || 0
});
this.product.assets.forEach(function (selectedAssetId) {
for (var i = 0; i < this.assets.length; i += 1) {
if (this.assets[i].value !== selectedAssetId) continue;
this.assets[i].selected = true;
}
checkboxDisplayControl.call(this, selectedAssetId, true);
}, this);
this.isFormValid = this.$.editCreateForm.checkValidity();
if (!this.isFormValid) this.$.editCreateForm.reportValidity();
function checkboxDisplayControl (elementValue, toggle) {
var checkbox = this.$$("#asset-" + elementValue);
if (!checkbox) return;
if (toggle) checkbox.setAttribute("checked", true);
else checkbox.removeAttribute("checked");
}
}
function _updateLocalization () {
var resources = this.resources[this.language];
if (!resources) {
this.language = "en";
resources = this.resources.en;
}
this.localizedHeading = this.isCreate? resources.headingCreate: resources.headingEdit;
}
function _hasDisplayAssets () {
return this.assets && this.assets.length > 0;
}
function attached () {
this.isCreate = this.isCreate === (true || "true");
}
function _selectCorrespondingCheckbox (ev) {
var id = ev.target.getAttribute("for");
var checkbox = this.$$("#" + id);
checkbox.checked = !checkbox.checked;
checkbox.fire("change"); // #_changeAssetSelection
}
function _changeAssetSelection (ev) {
if (ev.target.checked) {
addToRequestBodyAssets.call(this, ev.target);
} else {
removeFromRequestBodyAssets.call(this, ev.target);
}
}
function _btnModalPositiveClicked (e) {
if (this.isCreate) {
this.productApiRequestUrl = this.baseUrl.concat("/createProduct");
this.productApiRequestMethod = "POST";
} else {
this.productApiRequestUrl = this.baseUrl.concat("/updateProduct/", this.product.pk);
this.productApiRequestMethod = "PUT";
}
var form = this.$.editCreateForm;
if (!form.checkValidity()) return form.reportValidity();
this.product.longDescription = cleanHtml(this.$.longDescription.innerHTML).slice(0, 150);
//TODO: I am not a big fan of data manipulation in what we are trying to do here. If there is a cleaner approach that will satisfy both edit-product and product-table-view, lets refactor it. for now, this works for drop2.
this.product.currentSpecificationCycleTime = util.convertHrMinToCycleTime(this.product.estCycleTimeHours, this.product.estCycleTimeMinutes);
this.$.productApiRequest.generateRequest();
}
function _handleProductApiSuccess (response) {
response = response.detail.__data__.response;
this.product = response;
if (this.isCreate) {
this.fire("createProduct", this.product);
} else {
this.fire("updateProduct", this.product);
}
}
function _handleProductApiError (errResponse) {
errResponse.messageTitle = this.localize("error");
errResponse.errorMessage = this.localize("editProductError");
this.fire('alert-error-message', errResponse)
console.error("Failed to get response", errResponse);
}
function addToRequestBodyAssets (unit) {
this.push("product.assets", unit.value);
}
function removeFromRequestBodyAssets (unit) {
var unitIndex = this.product.assets.indexOf(unit.value);
this.splice("product.assets", unitIndex, 1);
}
function cleanHtml (innerHtml) {
innerHtml = innerHtml || "";
var tmp = document.createElement("DIV");
var regexp = new RegExp("(<\/?div>|<br\s*\/?>)", "gi");
tmp.innerHTML = innerHtml.replace(regexp, " \n");
return tmp.textContent || tmp.innerText || " ";
}
})(Polymer, bms.behaviors.util);
</script>