@oxyshop/admin 1.3.50 → 1.3.51

Sign up to get free protection for your applications and to get access to all the features.
package/lib/index.js CHANGED
@@ -24,14 +24,16 @@ import 'semantic-ui-css/components/video';
24
24
  import 'semantic-ui-css/components/visibility';
25
25
  import 'semantic-ui-css/components/visit';
26
26
  import 'jquery.dirtyforms/jquery.dirtyforms';
27
- import 'chart.js/dist/Chart.min';
27
+ import 'chart.js/dist/chart.min';
28
+ import { Chart as Chart$1 } from 'chart.js';
29
+ import { axios } from '@oxyshop/shop/lib/plugins/Axios';
30
+ import axios$1 from 'axios';
28
31
  import 'semantic-ui-css/semantic.css';
29
32
  import '@oxyshop/admin/scss/main.scss';
30
33
  import '@oxyshop/admin/lib/style.css';
31
34
  import '@oxyshop/admin/images/logo.png';
32
35
  import '@oxyshop/admin/images/admin-logo.svg';
33
36
  import '@oxyshop/admin/images/50x50.png';
34
- import { axios } from '@oxyshop/shop/lib/plugins/Axios';
35
37
 
36
38
  window.$ = $$1;
37
39
  window.jQuery = $$1;
@@ -396,6 +398,7 @@ $$1.fn.extend({
396
398
  search: 250,
397
399
  },
398
400
  forceSelection: false,
401
+ saveRemoteData: false,
399
402
  apiSettings: {
400
403
  dataType: 'JSON',
401
404
  cache: false,
@@ -406,12 +409,21 @@ $$1.fn.extend({
406
409
  return settings;
407
410
  },
408
411
  onResponse(response) {
412
+ let results = response.map(item => ({
413
+ name: item[choiceName],
414
+ value: item[choiceValue],
415
+ }));
416
+
417
+ if (!element.hasClass('multiple')) {
418
+ results.unshift({
419
+ name: ' ',
420
+ value: '',
421
+ });
422
+ }
423
+
409
424
  return {
410
425
  success: true,
411
- results: response.map(item => ({
412
- name: item[choiceName],
413
- value: item[choiceValue],
414
- })),
426
+ results: results,
415
427
  };
416
428
  },
417
429
  },
@@ -436,13 +448,12 @@ $$1.fn.extend({
436
448
  $$1(`<div class="item" data-value="${item[choiceValue]}">${item[choiceName]}</div>`)
437
449
  ));
438
450
  });
451
+
452
+ element.dropdown('refresh');
453
+ element.dropdown('set selected', element.find('input.autocomplete').val().split(',').filter(String));
439
454
  },
440
455
  });
441
456
  }
442
-
443
- window.setTimeout(() => {
444
- element.dropdown('set selected', element.find('input.autocomplete').val().split(',').filter(String));
445
- }, 5000);
446
457
  });
447
458
  },
448
459
  });
@@ -473,12 +484,12 @@ const controlAttributesList = function controlAttributesList() {
473
484
  };
474
485
 
475
486
  const modifyAttributesListOnSelectorElementDelete = function modifyAttributesListOnSelectorElementDelete(removedValue) {
476
- $$1(`#attributesContainer .attribute[data-id="${removedValue}"]`).remove();
487
+ $$1(`#attributesContainer .attributes-group[data-attribute-code="${removedValue}"]`).remove();
477
488
  };
478
489
 
479
490
  const modifySelectorOnAttributesListElementDelete = function modifySelectorOnAttributesListElementDelete() {
480
- $$1('.attribute button').off('click').on('click', (event) => {
481
- const attributeId = $$1(event.currentTarget).parents('.attribute').attr('data-id');
491
+ $$1('.attributes-group button[data-attribute="delete"]').off('click').on('click', (event) => {
492
+ const attributeId = $$1(event.currentTarget).parents('.attributes-group').attr('data-attribute-code');
482
493
 
483
494
  $$1('div#attributeChoice > .ui.dropdown.search').dropdown('remove selected', attributeId);
484
495
  modifyAttributesListOnSelectorElementDelete(attributeId);
@@ -507,6 +518,35 @@ const isInTheAttributesContainer = function isInTheAttributesContainer(attribute
507
518
  return result;
508
519
  };
509
520
 
521
+ const copyValueToAllLanguages = function copyValueToAllLanguages() {
522
+ $$1('#attributesContainer').on('click', '.attribute [data-attribute="copy"]', (event) => {
523
+ event.preventDefault();
524
+
525
+ const $attributesContainer = $$1('#attributesContainer');
526
+ const $masterAttribute = $$1(event.currentTarget).closest('.attribute');
527
+ const attributeID = $masterAttribute.attr('data-id');
528
+ const $attributeCollection = $attributesContainer.find(`[data-id="${attributeID}"]`);
529
+
530
+ const $masterAttributeInputs = $masterAttribute.find('input:visible, select, textarea');
531
+
532
+ $attributeCollection.each((index, attr) => {
533
+ const $inputs = $$1(attr).find('input:visible, select, textarea');
534
+
535
+ $inputs.each((i, input) => {
536
+ if (input.getAttribute('type') === 'checkbox') {
537
+ input.checked = $masterAttributeInputs[i].checked;
538
+ } else if (input.nodeName === 'SELECT') {
539
+ for (let x = 0; x < $inputs[i].length; x++) {
540
+ input[x].selected = $masterAttributeInputs[i][x].selected;
541
+ }
542
+ } else {
543
+ input.value = $masterAttributeInputs[i].value;
544
+ }
545
+ });
546
+ });
547
+ });
548
+ };
549
+
510
550
  const setAttributeChoiceListener = function setAttributeChoiceListener() {
511
551
  const $attributeChoice = $$1('#attributeChoice');
512
552
  $attributeChoice.find('button').on('click', (event) => {
@@ -539,8 +579,8 @@ const setAttributeChoiceListener = function setAttributeChoiceListener() {
539
579
  const attributeFormElements = modifyAttributeFormElements($$1(response));
540
580
 
541
581
  attributeFormElements.each((index, element) => {
542
- const localeCode = $$1(element).find('input[type="hidden"]').last().val();
543
- $$1(`#attributesContainer > div[data-tab="${localeCode}"]`).append(element);
582
+ $$1(element).find('input[type="hidden"]').last().val();
583
+ $$1(`#attributesContainer > div`).append(element);
544
584
  });
545
585
 
546
586
  $$1('#sylius_product_attribute_choice').val('');
@@ -567,6 +607,7 @@ $$1.fn.extend({
567
607
 
568
608
  controlAttributesList();
569
609
  modifySelectorOnAttributesListElementDelete();
610
+ copyValueToAllLanguages();
570
611
  },
571
612
  });
572
613
 
@@ -701,6 +742,83 @@ $$1.fn.handlePrototypes = function handlePrototypes(method, ...args) {
701
742
  return undefined;
702
743
  };
703
744
 
745
+ /*
746
+ * This file is part of the Sylius package.
747
+ *
748
+ * (c) Paweł Jędrzejewski
749
+ *
750
+ * For the full copyright and license information, please view the LICENSE
751
+ * file that was distributed with this source code.
752
+ */
753
+
754
+ $$1.fn.extend({
755
+ loadCatalogPromotionActionConfiguration(target) {
756
+ if (target == null || target.querySelector('#sylius_catalog_promotion_actions select[name*="type"]') == null) {
757
+ return;
758
+ }
759
+
760
+ target.querySelector('#sylius_catalog_promotion_actions select[name*="type"]').onchange = function () {
761
+ const parent = this.parentElement;
762
+ const newConfig = document.createElement('div');
763
+ newConfig.innerHTML = this.selectedOptions[0].getAttribute('data-configuration');
764
+ const oldConfig = parent.nextElementSibling;
765
+
766
+ parent.parentElement.replaceChild(newConfig, oldConfig);
767
+
768
+ const oldConfigInputName = oldConfig.querySelector('input').getAttribute('name');
769
+ let newConfigInputs = newConfig.querySelectorAll('input');
770
+
771
+ newConfigInputs.forEach(element => {
772
+ let newConfigInputName = element.getAttribute('name');
773
+
774
+ newConfigInputName = oldConfigInputName.replace(
775
+ oldConfigInputName.substring(oldConfigInputName.indexOf('[configuration]') + 15),
776
+ newConfigInputName.substring(newConfigInputName.indexOf('configuration') + 13),
777
+ );
778
+
779
+ $$1(element).attr('name', newConfigInputName);
780
+ });
781
+ };
782
+ },
783
+ });
784
+
785
+ /*
786
+ * This file is part of the Sylius package.
787
+ *
788
+ * (c) Paweł Jędrzejewski
789
+ *
790
+ * For the full copyright and license information, please view the LICENSE
791
+ * file that was distributed with this source code.
792
+ */
793
+
794
+ $$1.fn.extend({
795
+ loadCatalogPromotionScopeConfiguration(target) {
796
+ if (target == null || target.querySelector('#sylius_catalog_promotion_scopes select[name*="type"]') == null) {
797
+ return;
798
+ }
799
+
800
+ target.querySelector('#sylius_catalog_promotion_scopes select[name*="type"]').onchange = function () {
801
+ const parent = this.parentElement;
802
+ const newConfig = document.createElement('div');
803
+ newConfig.innerHTML = this.selectedOptions[0].getAttribute('data-configuration');
804
+ const oldConfig = parent.nextElementSibling;
805
+
806
+ parent.parentElement.replaceChild(newConfig, oldConfig);
807
+
808
+ const oldConfigInputName = oldConfig.querySelector('input').getAttribute('name');
809
+ let newConfigInputName = newConfig.querySelector('input').getAttribute('name');
810
+
811
+ newConfigInputName = oldConfigInputName.replace(
812
+ oldConfigInputName.substring(oldConfigInputName.lastIndexOf('[') + 1, oldConfigInputName.lastIndexOf(']')),
813
+ newConfigInputName.substring(newConfigInputName.indexOf('[') + 1, newConfigInputName.lastIndexOf(']')),
814
+ );
815
+
816
+ $$1(newConfig).find('input').attr('name', newConfigInputName);
817
+ $$1(newConfig).find('.sylius-autocomplete').autoComplete();
818
+ };
819
+ },
820
+ });
821
+
704
822
  /*
705
823
  * This file is part of the Sylius package.
706
824
  *
@@ -1390,8 +1508,10 @@ const drawChart = function drawChart(canvas, labels = [], values = [], currency)
1390
1508
  },
1391
1509
  responsive: true,
1392
1510
  maintainAspectRatio: false,
1393
- legend: {
1394
- display: false,
1511
+ plugins: {
1512
+ legend: {
1513
+ display: false,
1514
+ },
1395
1515
  },
1396
1516
  },
1397
1517
  });
@@ -1770,18 +1890,26 @@ $$1(document).ready(() => {
1770
1890
  $$1('#sylius_shipping_method_calculator').handlePrototypes({
1771
1891
  prototypePrefix: 'sylius_shipping_method_calculator_calculators',
1772
1892
  containerSelector: '.configuration',
1893
+ }).change(() => {
1894
+ $$1('.ui.tabular.menu .item').tab();
1773
1895
  });
1896
+ setTimeout(() => {
1897
+ $$1('.ui.tabular.menu .item').tab();
1898
+ }, 50);
1774
1899
 
1775
- $$1('#actions a[data-form-collection="add"]').on('click', () => {
1900
+ $$1('#sylius_promotion_actions > a[data-form-collection="add"]').on('click', () => {
1776
1901
  setTimeout(() => {
1777
1902
  $$1('select[name^="sylius_promotion[actions]"][name$="[type]"]').last().change();
1778
1903
  }, 50);
1779
1904
  });
1780
- $$1('#rules a[data-form-collection="add"]').on('click', (event) => {
1781
- const name = $$1(event.target).closest('form').attr('name');
1782
-
1905
+ $$1('#sylius_promotion_rules > a[data-form-collection="add"]').on('click', () => {
1906
+ setTimeout(() => {
1907
+ $$1('select[name^="sylius_promotion[rules]"][name$="[type]"]').last().change();
1908
+ }, 50);
1909
+ });
1910
+ $$1('#sylius_shipping_method_rules > a[data-form-collection="add"]').on('click', () => {
1783
1911
  setTimeout(() => {
1784
- $$1(`select[name^="${name}[rules]"][name$="[type]"]`).last().change();
1912
+ $$1('select[name^="sylius_shipping_method[rules]"][name$="[type]"]').last().change();
1785
1913
  }, 50);
1786
1914
  });
1787
1915
 
@@ -1791,6 +1919,18 @@ $$1(document).ready(() => {
1791
1919
  $$1(element).autoComplete();
1792
1920
  }
1793
1921
  });
1922
+
1923
+ if ($$1('#sylius_catalog_promotion_scopes').length > 0) {
1924
+ $$1(document).loadCatalogPromotionScopeConfiguration(
1925
+ document.querySelector('#sylius_catalog_promotion_scopes [data-form-collection="item"]:last-child')
1926
+ );
1927
+ }
1928
+
1929
+ if ($$1('#sylius_catalog_promotion_actions').length > 0) {
1930
+ $$1(document).loadCatalogPromotionActionConfiguration(
1931
+ document.querySelector('#sylius_catalog_promotion_actions [data-form-collection="item"]:last-child')
1932
+ );
1933
+ }
1794
1934
  });
1795
1935
  $$1(document).on('collection-form-update', () => {
1796
1936
  $$1('.sylius-autocomplete').each((index, element) => {
@@ -1809,12 +1949,21 @@ $$1(document).ready(() => {
1809
1949
  $$1(document).taxonSlugGenerator();
1810
1950
  $$1(document).previewUploadedImage('#sylius_product_images');
1811
1951
  $$1(document).previewUploadedImage('#sylius_taxon_images');
1952
+ if ($$1('#sylius_catalog_promotion_actions').length > 0) {
1953
+ $$1(document).loadCatalogPromotionActionConfiguration(document.querySelector('#sylius_catalog_promotion_actions'));
1954
+ }
1955
+ if ($$1('#sylius_catalog_promotion_scopes').length > 0) {
1956
+ $$1(document).loadCatalogPromotionScopeConfiguration(document.querySelector('#sylius_catalog_promotion_scopes'));
1957
+ }
1812
1958
 
1813
1959
  $$1(document).previewUploadedImage('#add-avatar');
1814
1960
 
1815
1961
  $$1('body').on('DOMNodeInserted', '[data-form-collection="item"]', (event) => {
1816
- if ($$1(event.target).find('.accordion').length > 0) {
1817
- $$1(event.target).find('.accordion').accordion();
1962
+ if ($$1(event.target).find('.ui.accordion').length > 0) {
1963
+ $$1(event.target).find('.ui.accordion').accordion();
1964
+ }
1965
+ if ($$1(event.target).find('.ui.tabular.menu').length > 0) {
1966
+ $$1(event.target).find('.ui.tabular.menu .item').tab();
1818
1967
  }
1819
1968
  });
1820
1969
 
@@ -1901,9 +2050,154 @@ class FeedCategorySelect {
1901
2050
  cache: false,
1902
2051
  },
1903
2052
  minCharacters: 2,
2053
+ clearable: true,
1904
2054
  });
2055
+
2056
+ // Workaround for dropdown clear button not showing after loading initial value from the API
2057
+ setTimeout(() => {
2058
+ $(selectElement).dropdown('restore defaults');
2059
+ }, 0);
2060
+ });
2061
+ }
2062
+ }
2063
+
2064
+ class ProductVariantPricingGraph {
2065
+ constructor(containerSelector) {
2066
+ this.containerSelector = containerSelector;
2067
+ }
2068
+
2069
+ init() {
2070
+ document.querySelectorAll(this.containerSelector).forEach((componentContainer) => {
2071
+ const graphsData = JSON.parse(componentContainer.getAttribute('data-graph'));
2072
+
2073
+ for (const currencyGraphIndex in graphsData) {
2074
+ const currencyGraph = graphsData[currencyGraphIndex];
2075
+
2076
+ const currencyCodeHeader = document.createElement('h4');
2077
+ currencyCodeHeader.classList.add('ui', 'header');
2078
+ currencyCodeHeader.textContent = currencyGraph.currency;
2079
+
2080
+ const graphCanvas = document.createElement('canvas');
2081
+ graphCanvas.width = 400;
2082
+ graphCanvas.height = 200;
2083
+
2084
+ const graphContainer = document.createElement('div');
2085
+ graphContainer.append(currencyCodeHeader);
2086
+ graphContainer.append(graphCanvas);
2087
+
2088
+ componentContainer.append(graphContainer);
2089
+
2090
+ const graphConfig = this.getGraphConfig(currencyGraph.graph);
2091
+ new Chart$1(graphCanvas.getContext('2d'), graphConfig);
2092
+ }
1905
2093
  });
1906
2094
  }
2095
+
2096
+ /** @private */
2097
+ getGraphConfig(rawGraphData) {
2098
+ return {
2099
+ type: 'line',
2100
+ data: {
2101
+ datasets: rawGraphData.datasets.map((rawDataset) => {
2102
+ return {
2103
+ label: rawDataset.label,
2104
+ data: rawDataset.data,
2105
+ borderColor: this.getRandomRgbColor(),
2106
+ fill: false,
2107
+ steppedLine: true,
2108
+ pointRadius: 8,
2109
+ pointHoverRadius: 10,
2110
+ }
2111
+ }),
2112
+ },
2113
+ options: {
2114
+ maintainAspectRatio: true,
2115
+ responsive: true,
2116
+ scales: {
2117
+ xAxes: [
2118
+ {
2119
+ type: 'linear',
2120
+ position: 'bottom',
2121
+ scaleLabel: {
2122
+ display: true,
2123
+ labelString: rawGraphData.xAxisLabel,
2124
+ },
2125
+ },
2126
+ ],
2127
+ yAxes: [
2128
+ {
2129
+ scaleLabel: {
2130
+ display: true,
2131
+ labelString: rawGraphData.yAxisLabel,
2132
+ },
2133
+ },
2134
+ ],
2135
+ },
2136
+ },
2137
+ }
2138
+ }
2139
+
2140
+ /** @private */
2141
+ getRandomRgbColor() {
2142
+ const r = Math.floor(Math.random() * 255);
2143
+ const g = Math.floor(Math.random() * 255);
2144
+ const b = Math.floor(Math.random() * 255);
2145
+ return `rgb(${r},${g},${b})`
2146
+ }
2147
+ }
2148
+
2149
+ class CustomerGroupClientAssigner {
2150
+ constructor(selector, searchSelector = '.ng-client-search-select', submitSelector = '.ng-client-assign-submit') {
2151
+ this.selector = selector;
2152
+ this.searchSelector = searchSelector;
2153
+ this.submitSelector = submitSelector;
2154
+ }
2155
+
2156
+ init() {
2157
+ document.querySelectorAll(this.selector).forEach((containerElement) => {
2158
+ const submitApiEndpoint = containerElement.getAttribute('data-assign-customers-url');
2159
+ const redirectAfterUrl = containerElement.getAttribute('data-redirect-after-url');
2160
+
2161
+ const searchElement = containerElement.querySelector(this.searchSelector);
2162
+ const searchApiEndpoint = searchElement.getAttribute('data-customer-search-url');
2163
+
2164
+ $(searchElement).dropdown({
2165
+ apiSettings: {
2166
+ url: `${searchApiEndpoint}/{query}`,
2167
+ cache: false,
2168
+ },
2169
+
2170
+ minCharacters: 2,
2171
+ });
2172
+
2173
+ const submitElement = containerElement.querySelector(this.submitSelector);
2174
+ submitElement.addEventListener('click', () => {
2175
+ const selectedCustomersIds = this.getSelectValues(searchElement);
2176
+ this.submitCustomers(submitElement, submitApiEndpoint, selectedCustomersIds, redirectAfterUrl);
2177
+ });
2178
+ });
2179
+ }
2180
+
2181
+ getSelectValues(selectElement) {
2182
+ const selected = selectElement.querySelectorAll('option:checked');
2183
+ return Array.from(selected).map((optionElement) => optionElement.value)
2184
+ }
2185
+
2186
+ submitCustomers(submitElement, apiEndpoint, selectedIds, redirectTo) {
2187
+ submitElement.disabled = true;
2188
+
2189
+ axios
2190
+ .post(apiEndpoint, { customers: selectedIds })
2191
+ .then(() => {
2192
+ window.location = redirectTo;
2193
+ })
2194
+ .catch((error) => {
2195
+ console.error(error);
2196
+ })
2197
+ .finally(() => {
2198
+ submitElement.disabled = false;
2199
+ });
2200
+ }
1907
2201
  }
1908
2202
 
1909
2203
  class TooltipHelpers {
@@ -2039,6 +2333,557 @@ class CustomerGroupingRuleConfiguration {
2039
2333
  }
2040
2334
  }
2041
2335
 
2336
+ class ImageInput {
2337
+ constructor(selector) {
2338
+ this.selector = selector;
2339
+ }
2340
+
2341
+ init() {
2342
+ document.querySelectorAll(this.selector).forEach((element) => {
2343
+ element.querySelectorAll('input[type="file"]').forEach((input) => {
2344
+ input.addEventListener('change', () => {
2345
+ this.onImageInputChange(input);
2346
+ });
2347
+ });
2348
+ });
2349
+ }
2350
+
2351
+ onImageInputChange(input) {
2352
+ if (!input.files || !input.files[0]) {
2353
+ return
2354
+ }
2355
+
2356
+ const reader = new FileReader();
2357
+
2358
+ reader.onload = (event) => {
2359
+ const wrapperDiv = input.parentElement.parentElement;
2360
+ const image = wrapperDiv.querySelector('.image');
2361
+
2362
+ if (null === image) {
2363
+ const img = document.createElement('img');
2364
+ img.setAttribute('class', 'ui small bordered image');
2365
+ img.setAttribute('src', event.target.result);
2366
+
2367
+ const inputLabel = wrapperDiv.querySelector(':scope > label');
2368
+ wrapperDiv.insertBefore(img, inputLabel.nextSibling);
2369
+ } else {
2370
+ image.setAttribute('src', event.target.result);
2371
+ }
2372
+ };
2373
+
2374
+ reader.readAsDataURL(input.files[0]);
2375
+ }
2376
+ }
2377
+
2378
+ class ProductVariantPricingSimulation {
2379
+ constructor(selector) {
2380
+ this.selector = selector;
2381
+ }
2382
+
2383
+ init() {
2384
+ document.querySelectorAll(this.selector).forEach((element) => {
2385
+ const productVariantId = element.getAttribute('data-product-variant-id');
2386
+ const channels = JSON.parse(element.getAttribute('data-channels'));
2387
+ const searchApiEndpoint = element.getAttribute('data-customer-search-url');
2388
+ const pricingApiEndpoint = element.getAttribute('data-pricing-url');
2389
+
2390
+ this.initElement(element, productVariantId, channels, searchApiEndpoint, pricingApiEndpoint);
2391
+ });
2392
+ }
2393
+
2394
+ initElement(parentElement, productVariantId, channels, searchApiEndpoint, pricingApiEndpoint) {
2395
+ parentElement.innerHTML = '';
2396
+
2397
+ const simulationData = {
2398
+ productVariantId: productVariantId,
2399
+ channelId: null,
2400
+ currencyId: null,
2401
+ customerId: null,
2402
+ };
2403
+
2404
+ const submitButton = document.createElement('button');
2405
+ const currencySelect = document.createElement('select');
2406
+
2407
+ const onChannelSelect = (event) => {
2408
+ const selectedChannelId = parseInt(event.target.value);
2409
+ simulationData.channelId = selectedChannelId;
2410
+ simulationData.currencyId = null;
2411
+ submitButton.disabled = this.isSubmitButtonDisabled(simulationData);
2412
+
2413
+ const selectedChannel = channels.find((channel) => {
2414
+ return channel.id === selectedChannelId
2415
+ });
2416
+
2417
+ currencySelect.innerHTML = '';
2418
+ this.addSelectOptions(currencySelect, selectedChannel.currencies, 'Select currency');
2419
+ };
2420
+
2421
+ const onCurrencySelect = (event) => {
2422
+ simulationData.currencyId = event.target.value;
2423
+ submitButton.disabled = this.isSubmitButtonDisabled(simulationData);
2424
+ };
2425
+
2426
+ const onCustomerSelect = (event) => {
2427
+ simulationData.customerId = event.target.value;
2428
+ submitButton.disabled = this.isSubmitButtonDisabled(simulationData);
2429
+ };
2430
+
2431
+ const graphWrapper = this.createGraphWrapper();
2432
+
2433
+ const onSubmit = () => {
2434
+ const pricingUrl = `${pricingApiEndpoint}?${this.serializeObjectToQuery(simulationData)}`;
2435
+
2436
+ axios$1
2437
+ .get(pricingUrl)
2438
+ .then((response) => {
2439
+ const chartData = response.data;
2440
+ graphWrapper.setAttribute('data-debug-chart', JSON.stringify(chartData)); // For e2e tests
2441
+ this.renderGraph(graphWrapper, chartData);
2442
+ })
2443
+ .catch((error) => {
2444
+ console.error(error);
2445
+ graphWrapper.innerHTML = 'Pricing simulation error';
2446
+ });
2447
+ };
2448
+
2449
+ const wrapper = document.createElement('div');
2450
+ wrapper.setAttribute('style', 'border: solid 1px #ddd; background-color: #fafafa;');
2451
+
2452
+ const filters = this.createFilters(
2453
+ channels,
2454
+ currencySelect,
2455
+ onChannelSelect,
2456
+ onCurrencySelect,
2457
+ onCustomerSelect,
2458
+ onSubmit,
2459
+ submitButton,
2460
+ searchApiEndpoint
2461
+ );
2462
+ filters.setAttribute(
2463
+ 'style',
2464
+ 'display: grid; grid-template-columns: 1fr 1fr 1fr 60px; grid-gap: 10px; ' +
2465
+ 'padding: 15px; border-bottom: solid 1px #ddd;'
2466
+ );
2467
+
2468
+ const graphFiller = this.createGraphFiller();
2469
+ graphWrapper.append(graphFiller);
2470
+
2471
+ wrapper.append(filters, graphWrapper);
2472
+ parentElement.append(wrapper);
2473
+ }
2474
+
2475
+ createFilters(
2476
+ channels,
2477
+ currencySelect,
2478
+ onChannelSelect,
2479
+ onCurrencySelect,
2480
+ onCustomerSelect,
2481
+ onSubmit,
2482
+ submitButton,
2483
+ searchApiEndpoint
2484
+ ) {
2485
+ const filtersWrapper = document.createElement('div');
2486
+
2487
+ const channelSelect = document.createElement('select');
2488
+ channelSelect.classList.add('dirtyignore');
2489
+ this.addSelectOptions(channelSelect, channels, 'Select channel');
2490
+ channelSelect.addEventListener('change', onChannelSelect);
2491
+
2492
+ currencySelect.classList.add('dirtyignore');
2493
+ currencySelect.addEventListener('change', onCurrencySelect);
2494
+
2495
+ const customerSelect = document.createElement('select');
2496
+ customerSelect.classList.add('dirtyignore');
2497
+ customerSelect.addEventListener('change', onCustomerSelect);
2498
+
2499
+ // this is delayed to avoid racing conditions
2500
+ setTimeout(() => this.hookClientSearchOnSelect(customerSelect, searchApiEndpoint), 600);
2501
+
2502
+ submitButton.disabled = true;
2503
+ submitButton.setAttribute('class', 'ui icon primary button');
2504
+ submitButton.type = 'button';
2505
+ submitButton.addEventListener('click', onSubmit);
2506
+
2507
+ const playIcon = document.createElement('i');
2508
+ playIcon.setAttribute('class', 'icon play');
2509
+ submitButton.append(playIcon);
2510
+
2511
+ filtersWrapper.append(channelSelect, currencySelect, customerSelect, submitButton);
2512
+
2513
+ return filtersWrapper
2514
+ }
2515
+
2516
+ createGraphWrapper() {
2517
+ const wrapper = document.createElement('div');
2518
+ wrapper.setAttribute('style', 'padding: 15px;');
2519
+
2520
+ return wrapper
2521
+ }
2522
+
2523
+ createGraphFiller() {
2524
+ const filler = document.createElement('div');
2525
+ filler.setAttribute(
2526
+ 'style',
2527
+ 'border-radius: 7px; background-color: #eee; height: 350px; display: flex; ' +
2528
+ 'justify-content: space-around; align-items: center; font-size: 4em;'
2529
+ );
2530
+
2531
+ const chartIcon = document.createElement('i');
2532
+ chartIcon.setAttribute('class', 'icon chart line');
2533
+ filler.append(chartIcon);
2534
+
2535
+ return filler
2536
+ }
2537
+
2538
+ addSelectOptions(select, choices, placeholder = null) {
2539
+ if (placeholder !== null) {
2540
+ const placeholderOption = document.createElement('option');
2541
+ placeholderOption.innerHTML = placeholder;
2542
+ placeholderOption.disabled = true;
2543
+ placeholderOption.selected = true;
2544
+ select.append(placeholderOption);
2545
+ }
2546
+
2547
+ for (const property in choices) {
2548
+ const choice = choices[property];
2549
+
2550
+ const channelOption = document.createElement('option');
2551
+ channelOption.innerHTML = choice.name;
2552
+ channelOption.setAttribute('value', choice.id);
2553
+ select.append(channelOption);
2554
+ }
2555
+
2556
+ return select
2557
+ }
2558
+
2559
+ hookClientSearchOnSelect(selectElement, searchApiEndpoint) {
2560
+ selectElement.setAttribute('class', `${selectElement.getAttribute('class')} search dropdown selection`);
2561
+
2562
+ $(selectElement).dropdown({
2563
+ apiSettings: {
2564
+ url: `${searchApiEndpoint}/{query}`,
2565
+ cache: false,
2566
+ },
2567
+
2568
+ minCharacters: 2,
2569
+ });
2570
+ }
2571
+
2572
+ isSubmitButtonDisabled(simulationData) {
2573
+ return (
2574
+ null === simulationData.productVariantId ||
2575
+ null === simulationData.channelId ||
2576
+ null === simulationData.currencyId ||
2577
+ null === simulationData.customerId
2578
+ )
2579
+ }
2580
+
2581
+ serializeObjectToQuery(object) {
2582
+ const query = [];
2583
+
2584
+ for (const part in object) {
2585
+ if (Object.prototype.hasOwnProperty.call(object, part)) {
2586
+ query.push(`${encodeURIComponent(part)}=${encodeURIComponent(object[part])}`);
2587
+ }
2588
+ }
2589
+
2590
+ return query.join('&')
2591
+ }
2592
+
2593
+ renderGraph(graphWrapper, graphData) {
2594
+ graphWrapper.innerHTML = '';
2595
+
2596
+ const graphCanvas = document.createElement('canvas');
2597
+ graphCanvas.width = 600;
2598
+ graphCanvas.height = 200;
2599
+
2600
+ graphWrapper.append(graphCanvas);
2601
+
2602
+ const graphConfig = this.getGraphConfig(graphData);
2603
+ console.log('graphConfig', graphConfig);
2604
+ new Chart$1(graphCanvas.getContext('2d'), graphConfig);
2605
+ }
2606
+
2607
+ /** @private */
2608
+ getGraphConfig(rawGraphData) {
2609
+ return {
2610
+ type: 'line',
2611
+ data: {
2612
+ datasets: rawGraphData.datasets.map((rawDataset) => {
2613
+ return {
2614
+ label: rawDataset.label,
2615
+ data: rawDataset.data,
2616
+ borderColor: '#0000ff',
2617
+ fill: false,
2618
+ steppedLine: true,
2619
+ pointRadius: 8,
2620
+ pointHoverRadius: 10,
2621
+ }
2622
+ }),
2623
+ },
2624
+ options: {
2625
+ maintainAspectRatio: true,
2626
+ responsive: true,
2627
+ scales: {
2628
+ xAxes: [
2629
+ {
2630
+ type: 'linear',
2631
+ position: 'bottom',
2632
+ scaleLabel: {
2633
+ display: true,
2634
+ labelString: rawGraphData.xAxisLabel,
2635
+ },
2636
+ },
2637
+ ],
2638
+ yAxes: [
2639
+ {
2640
+ scaleLabel: {
2641
+ display: true,
2642
+ labelString: rawGraphData.yAxisLabel,
2643
+ },
2644
+ },
2645
+ ],
2646
+ },
2647
+ },
2648
+ }
2649
+ }
2650
+ }
2651
+
2652
+ class DocumentUploadInput {
2653
+ /** @param {string} documentUploadInputSelector */
2654
+ constructor(documentUploadInputSelector) {
2655
+ this.selector = documentUploadInputSelector;
2656
+ }
2657
+
2658
+ init() {
2659
+ const fileInputs = document.querySelectorAll(this.selector);
2660
+
2661
+ Array.prototype.forEach.call(fileInputs, (inputElement) => {
2662
+ const fileUrl = inputElement.getAttribute('data-file-url');
2663
+ const fileTitle = inputElement.getAttribute('data-file-name');
2664
+ const downloadText = inputElement.getAttribute('data-download-translation');
2665
+
2666
+ const iconElement = document.createElement('i');
2667
+ iconElement.classList.add('download', 'icon');
2668
+
2669
+ const buttonElement = document.createElement('button');
2670
+ buttonElement.classList.add('ui', 'compact', 'labeled', 'icon', 'button');
2671
+ buttonElement.setAttribute('type', 'button');
2672
+ buttonElement.append(iconElement);
2673
+ buttonElement.innerHTML += `${downloadText}: ${fileTitle}`;
2674
+
2675
+ const downloadLink = document.createElement('a');
2676
+ downloadLink.setAttribute('style', 'display: inline-block; margin: -5px 0 25px 0;');
2677
+ downloadLink.setAttribute('target', '_blank');
2678
+ downloadLink.setAttribute('href', fileUrl);
2679
+ downloadLink.append(buttonElement);
2680
+
2681
+ inputElement.parentNode.parentNode.append(downloadLink);
2682
+ });
2683
+ }
2684
+ }
2685
+
2686
+ (function ($) {
2687
+
2688
+ $.fn.extend({
2689
+ blogSlugGenerator: function () {
2690
+ let timeout;
2691
+
2692
+ $('[name*="nextgen_cms_bundle_blog[translations]"][name*="[name]"]').on('input', function () {
2693
+ clearTimeout(timeout);
2694
+ let element = $(this);
2695
+
2696
+ timeout = setTimeout(function () {
2697
+ updateSlug(element);
2698
+ }, 1000);
2699
+ });
2700
+
2701
+ $('.toggle-blog-slug-modification').on('click', function (e) {
2702
+ e.preventDefault();
2703
+ toggleSlugModification($(this), $(this).siblings('input'));
2704
+ });
2705
+
2706
+ function updateSlug(element) {
2707
+ let slugInput = element.parents('.content').find('[name*="[slug]"]');
2708
+ let loadableParent = slugInput.parents('.field.loadable');
2709
+
2710
+ if ('readonly' === slugInput.attr('readonly')) {
2711
+ return
2712
+ }
2713
+
2714
+ loadableParent.addClass('loading');
2715
+
2716
+ $.ajax({
2717
+ type: 'GET',
2718
+ url: slugInput.attr('data-url'),
2719
+ data: { name: element.val() },
2720
+ dataType: 'json',
2721
+ accept: 'application/json',
2722
+ success: function (data) {
2723
+ slugInput.val(data.slug);
2724
+ if (slugInput.parents('.field').hasClass('error')) {
2725
+ slugInput.parents('.field').removeClass('error');
2726
+ slugInput.parents('.field').find('.sylius-validation-error').remove();
2727
+ }
2728
+ loadableParent.removeClass('loading');
2729
+ },
2730
+ });
2731
+ }
2732
+
2733
+ function toggleSlugModification(button, slugInput) {
2734
+ if (slugInput.attr('readonly')) {
2735
+ slugInput.removeAttr('readonly');
2736
+ button.html('<i class="unlock icon"></i>');
2737
+ } else {
2738
+ slugInput.attr('readonly', 'readonly');
2739
+ button.html('<i class="lock icon"></i>');
2740
+ }
2741
+ }
2742
+ },
2743
+ });
2744
+ })(jQuery)
2745
+ ;(function ($) {
2746
+ $(document).ready(function () {
2747
+ $(this).blogSlugGenerator();
2748
+ });
2749
+ })(jQuery);
2750
+
2751
+ (function ($) {
2752
+
2753
+ $.fn.extend({
2754
+ articleSlugGenerator: function () {
2755
+ let timeout;
2756
+
2757
+ $('[name*="nextgen_cms_bundle_article[translations]"][name*="[name]"]').on('input', function () {
2758
+ clearTimeout(timeout);
2759
+ let element = $(this);
2760
+
2761
+ timeout = setTimeout(function () {
2762
+ updateSlug(element);
2763
+ }, 1000);
2764
+ });
2765
+
2766
+ $('.toggle-article-slug-modification').on('click', function (e) {
2767
+ e.preventDefault();
2768
+ toggleSlugModification($(this), $(this).siblings('input'));
2769
+ });
2770
+
2771
+ function updateSlug(element) {
2772
+ let slugInput = element.parents('.content').find('[name*="[slug]"]');
2773
+ let loadableParent = slugInput.parents('.field.loadable');
2774
+
2775
+ if ('readonly' === slugInput.attr('readonly')) {
2776
+ return
2777
+ }
2778
+
2779
+ loadableParent.addClass('loading');
2780
+
2781
+ $.ajax({
2782
+ type: 'GET',
2783
+ url: slugInput.attr('data-url'),
2784
+ data: { name: element.val() },
2785
+ dataType: 'json',
2786
+ accept: 'application/json',
2787
+ success: function (data) {
2788
+ slugInput.val(data.slug);
2789
+ if (slugInput.parents('.field').hasClass('error')) {
2790
+ slugInput.parents('.field').removeClass('error');
2791
+ slugInput.parents('.field').find('.sylius-validation-error').remove();
2792
+ }
2793
+ loadableParent.removeClass('loading');
2794
+ },
2795
+ });
2796
+ }
2797
+
2798
+ function toggleSlugModification(button, slugInput) {
2799
+ if (slugInput.attr('readonly')) {
2800
+ slugInput.removeAttr('readonly');
2801
+ button.html('<i class="unlock icon"></i>');
2802
+ } else {
2803
+ slugInput.attr('readonly', 'readonly');
2804
+ button.html('<i class="lock icon"></i>');
2805
+ }
2806
+ }
2807
+ },
2808
+ });
2809
+ })(jQuery)
2810
+ ;(function ($) {
2811
+ $(document).ready(function () {
2812
+ $(this).articleSlugGenerator();
2813
+ });
2814
+ })(jQuery);
2815
+
2816
+ (function ($) {
2817
+
2818
+ $.fn.extend({
2819
+ blogCategorySlugGenerator: function () {
2820
+ let timeout;
2821
+
2822
+ $('[name*="nextgen_cms_bundle_blog_category[translations]"][name*="[name]"]').on('input', function () {
2823
+ clearTimeout(timeout);
2824
+ let element = $(this);
2825
+
2826
+ timeout = setTimeout(function () {
2827
+ updateSlug(element);
2828
+ }, 1000);
2829
+ });
2830
+
2831
+ $('.toggle-blog-category-slug-modification').on('click', function (e) {
2832
+ e.preventDefault();
2833
+ toggleSlugModification($(this), $(this).siblings('input'));
2834
+ });
2835
+
2836
+ function updateSlug(element) {
2837
+ let slugInput = element.parents('.content').find('[name*="[slug]"]');
2838
+ let loadableParent = slugInput.parents('.field.loadable');
2839
+
2840
+ if ('readonly' === slugInput.attr('readonly')) {
2841
+ return
2842
+ }
2843
+
2844
+ loadableParent.addClass('loading');
2845
+
2846
+ let data;
2847
+ data = {
2848
+ name: element.val(),
2849
+ locale: element.closest('[data-locale]').data('locale'),
2850
+ };
2851
+
2852
+ $.ajax({
2853
+ type: 'GET',
2854
+ url: slugInput.attr('data-url'),
2855
+ data: data,
2856
+ dataType: 'json',
2857
+ accept: 'application/json',
2858
+ success: function (data) {
2859
+ slugInput.val(data.slug);
2860
+ if (slugInput.parents('.field').hasClass('error')) {
2861
+ slugInput.parents('.field').removeClass('error');
2862
+ slugInput.parents('.field').find('.sylius-validation-error').remove();
2863
+ }
2864
+ loadableParent.removeClass('loading');
2865
+ },
2866
+ });
2867
+ }
2868
+
2869
+ function toggleSlugModification(button, slugInput) {
2870
+ if (slugInput.attr('readonly')) {
2871
+ slugInput.removeAttr('readonly');
2872
+ button.html('<i class="unlock icon"></i>');
2873
+ } else {
2874
+ slugInput.attr('readonly', 'readonly');
2875
+ button.html('<i class="lock icon"></i>');
2876
+ }
2877
+ }
2878
+ },
2879
+ });
2880
+ })(jQuery)
2881
+ ;(function ($) {
2882
+ $(document).ready(function () {
2883
+ $(this).blogCategorySlugGenerator();
2884
+ });
2885
+ })(jQuery);
2886
+
2042
2887
  /**
2043
2888
  * CKEditor config
2044
2889
  */
@@ -2132,6 +2977,35 @@ vendorDescriptionElements.forEach((element) => {
2132
2977
  CKEDITOR.replace(element.name, ckEditorOptions);
2133
2978
  });
2134
2979
 
2980
+ /**
2981
+ * Blog article
2982
+ */
2983
+ const articleAnnotationElements = document.querySelectorAll(
2984
+ 'form[name="nextgen_cms_bundle_article"] textarea[name$="[annotation]"]'
2985
+ );
2986
+ articleAnnotationElements.forEach((element) => {
2987
+ // eslint-disable-next-line no-undef
2988
+ CKEDITOR.replace(element.name, ckEditorOptions);
2989
+ });
2990
+ const articleContentElements = document.querySelectorAll(
2991
+ 'form[name="nextgen_cms_bundle_article"] textarea[name$="[content]"]'
2992
+ );
2993
+ articleContentElements.forEach((element) => {
2994
+ // eslint-disable-next-line no-undef
2995
+ CKEDITOR.replace(element.name, ckEditorOptions);
2996
+ });
2997
+
2998
+ /**
2999
+ * Blog category
3000
+ */
3001
+ const categoryDescriptionElements = document.querySelectorAll(
3002
+ 'form[name="nextgen_cms_bundle_blog_category"] textarea[name$="[description]"]'
3003
+ );
3004
+ categoryDescriptionElements.forEach((element) => {
3005
+ // eslint-disable-next-line no-undef
3006
+ CKEDITOR.replace(element.name, ckEditorOptions);
3007
+ });
3008
+
2135
3009
  (function ($) {
2136
3010
  $(document).ready(function () {
2137
3011
  $('#sylius_payment_method_calculator').handlePrototypes({
@@ -2141,6 +3015,12 @@ vendorDescriptionElements.forEach((element) => {
2141
3015
  });
2142
3016
  })(jQuery);
2143
3017
 
3018
+ /*
3019
+ This file was created by developers working at BitBag
3020
+ Do you need more information about us and what we do? Visit our https://bitbag.io website!
3021
+ We are hiring developers from all over the world. Join us and start your new, exciting adventure and become part of us: https://bitbag.io/career
3022
+ */
3023
+
2144
3024
  (function ( $ ) {
2145
3025
 
2146
3026
  $.fn.extend({
@@ -2190,6 +3070,12 @@ vendorDescriptionElements.forEach((element) => {
2190
3070
  });
2191
3071
  })(jQuery);
2192
3072
 
3073
+ /*
3074
+ This file was created by developers working at BitBag
3075
+ Do you need more information about us and what we do? Visit our https://bitbag.io website!
3076
+ We are hiring developers from all over the world. Join us and start your new, exciting adventure and become part of us: https://bitbag.io/career
3077
+ */
3078
+
2193
3079
  (function ( $ ) {
2194
3080
 
2195
3081
  $.fn.extend({
@@ -2201,7 +3087,7 @@ vendorDescriptionElements.forEach((element) => {
2201
3087
  if (callback !== undefined) {
2202
3088
  callback();
2203
3089
  }
2204
-
3090
+
2205
3091
  var actionButton = $(this);
2206
3092
  var form = actionButton.closest('form');
2207
3093
  var url = actionButton.data('url');
@@ -2253,6 +3139,12 @@ vendorDescriptionElements.forEach((element) => {
2253
3139
  });
2254
3140
  })(jQuery);
2255
3141
 
3142
+ /*
3143
+ This file was created by developers working at BitBag
3144
+ Do you need more information about us and what we do? Visit our https://bitbag.io website!
3145
+ We are hiring developers from all over the world. Join us and start your new, exciting adventure and become part of us: https://bitbag.io/career
3146
+ */
3147
+
2256
3148
  (function ($) {
2257
3149
 
2258
3150
  $.fn.extend({
@@ -2319,6 +3211,12 @@ vendorDescriptionElements.forEach((element) => {
2319
3211
  });
2320
3212
  })(jQuery);
2321
3213
 
3214
+ /*
3215
+ This file was created by developers working at BitBag
3216
+ Do you need more information about us and what we do? Visit our https://bitbag.io website!
3217
+ We are hiring developers from all over the world. Join us and start your new, exciting adventure and become part of us: https://bitbag.io/career
3218
+ */
3219
+
2322
3220
  (function($) {
2323
3221
  $('.bitbag-cms-import input[type="text"]').click(function() {
2324
3222
  $(this).parent().find('input[type="file"]').click();
@@ -2332,60 +3230,6 @@ vendorDescriptionElements.forEach((element) => {
2332
3230
 
2333
3231
  })( jQuery );
2334
3232
 
2335
- class CustomerGroupClientAssigner {
2336
- constructor(selector, searchSelector = '.ng-client-search-select', submitSelector = '.ng-client-assign-submit') {
2337
- this.selector = selector;
2338
- this.searchSelector = searchSelector;
2339
- this.submitSelector = submitSelector;
2340
- }
2341
-
2342
- init() {
2343
- document.querySelectorAll(this.selector).forEach((containerElement) => {
2344
- const submitApiEndpoint = containerElement.getAttribute('data-assign-customers-url');
2345
- const redirectAfterUrl = containerElement.getAttribute('data-redirect-after-url');
2346
-
2347
- const searchElement = containerElement.querySelector(this.searchSelector);
2348
- const searchApiEndpoint = searchElement.getAttribute('data-customer-search-url');
2349
-
2350
- $(searchElement).dropdown({
2351
- apiSettings: {
2352
- url: `${searchApiEndpoint}/{query}`,
2353
- cache: false,
2354
- },
2355
-
2356
- minCharacters: 2,
2357
- });
2358
-
2359
- const submitElement = containerElement.querySelector(this.submitSelector);
2360
- submitElement.addEventListener('click', () => {
2361
- const selectedCustomersIds = this.getSelectValues(searchElement);
2362
- this.submitCustomers(submitElement, submitApiEndpoint, selectedCustomersIds, redirectAfterUrl);
2363
- });
2364
- });
2365
- }
2366
-
2367
- getSelectValues(selectElement) {
2368
- const selected = selectElement.querySelectorAll('option:checked');
2369
- return Array.from(selected).map((optionElement) => optionElement.value)
2370
- }
2371
-
2372
- submitCustomers(submitElement, apiEndpoint, selectedIds, redirectTo) {
2373
- submitElement.disabled = true;
2374
-
2375
- axios
2376
- .post(apiEndpoint, { customers: selectedIds })
2377
- .then(() => {
2378
- window.location = redirectTo;
2379
- })
2380
- .catch((error) => {
2381
- console.error(error);
2382
- })
2383
- .finally(() => {
2384
- submitElement.disabled = false;
2385
- });
2386
- }
2387
- }
2388
-
2389
3233
  // Scripts
2390
3234
 
2391
3235
  // Components initializations
@@ -2415,7 +3259,21 @@ $(document).ready(() => {
2415
3259
  const adminSidebarScroller = new AdminSidebarScroller(adminSidebarElement, 'a.item');
2416
3260
  adminSidebarScroller.scrollToActiveLink();
2417
3261
 
3262
+ const productVariantPricingGraph = new ProductVariantPricingGraph('.ng-product-variant-pricing-graph');
3263
+ productVariantPricingGraph.init();
3264
+
3265
+ const productVariantPricingSimulation = new ProductVariantPricingSimulation(
3266
+ '.ng-product-variant-pricing-simulation'
3267
+ );
3268
+ productVariantPricingSimulation.init();
3269
+
2418
3270
  // Client search select
2419
3271
  const clientSearchSelect = new CustomerGroupClientAssigner('.ng-customer-group-client-assigner');
2420
3272
  clientSearchSelect.init();
3273
+
3274
+ const imageInput = new ImageInput('.ng-image-input');
3275
+ imageInput.init();
3276
+
3277
+ const documentUploadInput = new DocumentUploadInput('input.ng-document-upload-input');
3278
+ documentUploadInput.init();
2421
3279
  });