@oxyshop/admin 1.3.38 → 1.3.39

Sign up to get free protection for your applications and to get access to all the features.
package/lib/index.js CHANGED
@@ -25,12 +25,14 @@ import 'semantic-ui-css/components/visibility';
25
25
  import 'semantic-ui-css/components/visit';
26
26
  import 'jquery.dirtyforms/jquery.dirtyforms';
27
27
  import 'chart.js/dist/Chart.min';
28
+ import 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
- import { axios } from '@oxyshop/shop/lib/plugins/Axios';
34
36
 
35
37
  window.$ = $$1;
36
38
  window.jQuery = $$1;
@@ -1905,6 +1907,152 @@ class FeedCategorySelect {
1905
1907
  }
1906
1908
  }
1907
1909
 
1910
+ class ProductVariantPricingGraph {
1911
+ constructor(containerSelector) {
1912
+ this.containerSelector = containerSelector;
1913
+ }
1914
+
1915
+ init() {
1916
+ document.querySelectorAll(this.containerSelector).forEach((componentContainer) => {
1917
+ const graphsData = JSON.parse(componentContainer.getAttribute('data-graph'));
1918
+
1919
+ for (const currencyGraphIndex in graphsData) {
1920
+ const currencyGraph = graphsData[currencyGraphIndex];
1921
+
1922
+ const currencyCodeHeader = document.createElement('h4');
1923
+ currencyCodeHeader.classList.add('ui', 'header');
1924
+ currencyCodeHeader.textContent = currencyGraph.currency;
1925
+
1926
+ const graphCanvas = document.createElement('canvas');
1927
+ graphCanvas.width = 400;
1928
+ graphCanvas.height = 200;
1929
+
1930
+ const graphContainer = document.createElement('div');
1931
+ graphContainer.append(currencyCodeHeader);
1932
+ graphContainer.append(graphCanvas);
1933
+
1934
+ componentContainer.append(graphContainer);
1935
+
1936
+ const graphConfig = this.getGraphConfig(currencyGraph.graph);
1937
+ new Chart$1(graphCanvas.getContext('2d'), graphConfig);
1938
+ }
1939
+ });
1940
+ }
1941
+
1942
+ /** @private */
1943
+ getGraphConfig(rawGraphData) {
1944
+ return {
1945
+ type: 'line',
1946
+ data: {
1947
+ datasets: rawGraphData.datasets.map((rawDataset) => {
1948
+ return {
1949
+ label: rawDataset.label,
1950
+ data: rawDataset.data,
1951
+ borderColor: this.getRandomRgbColor(),
1952
+ fill: false,
1953
+ steppedLine: true,
1954
+ pointRadius: 8,
1955
+ pointHoverRadius: 10,
1956
+ }
1957
+ }),
1958
+ },
1959
+ options: {
1960
+ maintainAspectRatio: true,
1961
+ responsive: true,
1962
+ scales: {
1963
+ xAxes: [
1964
+ {
1965
+ type: 'linear',
1966
+ position: 'bottom',
1967
+ scaleLabel: {
1968
+ display: true,
1969
+ labelString: rawGraphData.xAxisLabel,
1970
+ },
1971
+ },
1972
+ ],
1973
+ yAxes: [
1974
+ {
1975
+ scaleLabel: {
1976
+ display: true,
1977
+ labelString: rawGraphData.yAxisLabel,
1978
+ },
1979
+ },
1980
+ ],
1981
+ },
1982
+ },
1983
+ }
1984
+ }
1985
+
1986
+ /** @private */
1987
+ getRandomRgbColor() {
1988
+ const r = Math.floor(Math.random() * 255);
1989
+ const g = Math.floor(Math.random() * 255);
1990
+ const b = Math.floor(Math.random() * 255);
1991
+ return `rgb(${r},${g},${b})`
1992
+ }
1993
+ }
1994
+
1995
+ class CustomerGroupClientAssigner {
1996
+ constructor(selector, searchSelector = '.ng-client-search-select', submitSelector = '.ng-client-assign-submit') {
1997
+ this.selector = selector;
1998
+ this.searchSelector = searchSelector;
1999
+ this.submitSelector = submitSelector;
2000
+
2001
+ this.containerElement = null;
2002
+ this.searchElement = null;
2003
+ this.submitElement = null;
2004
+ }
2005
+
2006
+ init() {
2007
+ this.containerElement = document.querySelector(this.selector);
2008
+ if (null === this.containerElement) {
2009
+ return
2010
+ }
2011
+
2012
+ const submitApiEndpoint = this.containerElement.getAttribute('data-assign-customers-url');
2013
+ const redirectAfterUrl = this.containerElement.getAttribute('data-redirect-after-url');
2014
+
2015
+ this.searchElement = this.containerElement.querySelector(this.searchSelector);
2016
+ const searchApiEndpoint = this.searchElement.getAttribute('data-customer-search-url');
2017
+
2018
+ $(this.searchElement).dropdown({
2019
+ apiSettings: {
2020
+ url: `${searchApiEndpoint}/{query}`,
2021
+ cache: false,
2022
+ },
2023
+
2024
+ minCharacters: 2,
2025
+ });
2026
+
2027
+ this.submitElement = this.containerElement.querySelector(this.submitSelector);
2028
+ this.submitElement.addEventListener('click', () => {
2029
+ const selectedCustomersIds = this.getSelectValues(this.searchElement);
2030
+ this.submitCustomers(submitApiEndpoint, selectedCustomersIds, redirectAfterUrl);
2031
+ });
2032
+ }
2033
+
2034
+ getSelectValues(selectElement) {
2035
+ const selected = selectElement.querySelectorAll('option:checked');
2036
+ return Array.from(selected).map((optionElement) => optionElement.value)
2037
+ }
2038
+
2039
+ submitCustomers(apiEndpoint, selectedIds, redirectTo) {
2040
+ this.submitElement.disabled = true;
2041
+
2042
+ axios
2043
+ .post(apiEndpoint, { customers: selectedIds })
2044
+ .then(() => {
2045
+ window.location = redirectTo;
2046
+ })
2047
+ .catch((error) => {
2048
+ console.error(error);
2049
+ })
2050
+ .finally(() => {
2051
+ this.submitElement.disabled = false;
2052
+ });
2053
+ }
2054
+ }
2055
+
1908
2056
  class TooltipHelpers {
1909
2057
  static init() {
1910
2058
  TooltipHelpers.initSyliusShippingMethodTooltip();
@@ -2038,6 +2186,277 @@ class CustomerGroupingRuleConfiguration {
2038
2186
  }
2039
2187
  }
2040
2188
 
2189
+ class ProductVariantPricingSimulation {
2190
+ constructor(selector) {
2191
+ this.selector = selector;
2192
+ }
2193
+
2194
+ init() {
2195
+ document.querySelectorAll(this.selector).forEach((element) => {
2196
+ const productVariantId = element.getAttribute('data-product-variant-id');
2197
+ const channels = JSON.parse(element.getAttribute('data-channels'));
2198
+ const searchApiEndpoint = element.getAttribute('data-customer-search-url');
2199
+ const pricingApiEndpoint = element.getAttribute('data-pricing-url');
2200
+
2201
+ this.initElement(element, productVariantId, channels, searchApiEndpoint, pricingApiEndpoint);
2202
+ });
2203
+ }
2204
+
2205
+ initElement(parentElement, productVariantId, channels, searchApiEndpoint, pricingApiEndpoint) {
2206
+ parentElement.innerHTML = '';
2207
+
2208
+ const simulationData = {
2209
+ productVariantId: productVariantId,
2210
+ channelId: null,
2211
+ currencyId: null,
2212
+ customerId: null,
2213
+ };
2214
+
2215
+ const submitButton = document.createElement('button');
2216
+ const currencySelect = document.createElement('select');
2217
+
2218
+ const onChannelSelect = (event) => {
2219
+ const selectedChannelId = parseInt(event.target.value);
2220
+ simulationData.channelId = selectedChannelId;
2221
+ simulationData.currencyId = null;
2222
+ submitButton.disabled = this.isSubmitButtonDisabled(simulationData);
2223
+
2224
+ const selectedChannel = channels.find((channel) => {
2225
+ return channel.id === selectedChannelId
2226
+ });
2227
+
2228
+ currencySelect.innerHTML = '';
2229
+ this.addSelectOptions(currencySelect, selectedChannel.currencies, 'Select currency');
2230
+ };
2231
+
2232
+ const onCurrencySelect = (event) => {
2233
+ simulationData.currencyId = event.target.value;
2234
+ submitButton.disabled = this.isSubmitButtonDisabled(simulationData);
2235
+ };
2236
+
2237
+ const onCustomerSelect = (event) => {
2238
+ simulationData.customerId = event.target.value;
2239
+ submitButton.disabled = this.isSubmitButtonDisabled(simulationData);
2240
+ };
2241
+
2242
+ const graphWrapper = this.createGraphWrapper();
2243
+
2244
+ const onSubmit = () => {
2245
+ const pricingUrl = `${pricingApiEndpoint}?${this.serializeObjectToQuery(simulationData)}`;
2246
+
2247
+ axios$1
2248
+ .get(pricingUrl)
2249
+ .then((response) => {
2250
+ const chartData = response.data;
2251
+ graphWrapper.setAttribute('data-debug-chart', JSON.stringify(chartData)); // For e2e tests
2252
+ this.renderGraph(graphWrapper, chartData);
2253
+ })
2254
+ .catch((error) => {
2255
+ console.error(error);
2256
+ graphWrapper.innerHTML = 'Pricing simulation error';
2257
+ });
2258
+ };
2259
+
2260
+ const wrapper = document.createElement('div');
2261
+ wrapper.setAttribute('style', 'border: solid 1px #ddd; background-color: #fafafa;');
2262
+
2263
+ const filters = this.createFilters(
2264
+ channels,
2265
+ currencySelect,
2266
+ onChannelSelect,
2267
+ onCurrencySelect,
2268
+ onCustomerSelect,
2269
+ onSubmit,
2270
+ submitButton,
2271
+ searchApiEndpoint
2272
+ );
2273
+ filters.setAttribute(
2274
+ 'style',
2275
+ 'display: grid; grid-template-columns: 1fr 1fr 1fr 60px; grid-gap: 10px; ' +
2276
+ 'padding: 15px; border-bottom: solid 1px #ddd;'
2277
+ );
2278
+
2279
+ const graphFiller = this.createGraphFiller();
2280
+ graphWrapper.append(graphFiller);
2281
+
2282
+ wrapper.append(filters, graphWrapper);
2283
+ parentElement.append(wrapper);
2284
+ }
2285
+
2286
+ createFilters(
2287
+ channels,
2288
+ currencySelect,
2289
+ onChannelSelect,
2290
+ onCurrencySelect,
2291
+ onCustomerSelect,
2292
+ onSubmit,
2293
+ submitButton,
2294
+ searchApiEndpoint
2295
+ ) {
2296
+ const filtersWrapper = document.createElement('div');
2297
+
2298
+ const channelSelect = document.createElement('select');
2299
+ this.addSelectOptions(channelSelect, channels, 'Select channel');
2300
+ channelSelect.addEventListener('change', onChannelSelect);
2301
+
2302
+ currencySelect.addEventListener('change', onCurrencySelect);
2303
+
2304
+ const customerSelect = document.createElement('select');
2305
+ customerSelect.addEventListener('change', onCustomerSelect);
2306
+
2307
+ // this is delayed to avoid racing conditions
2308
+ setTimeout(() => this.hookClientSearchOnSelect(customerSelect, searchApiEndpoint), 600);
2309
+
2310
+ submitButton.disabled = true;
2311
+ submitButton.setAttribute('class', 'ui icon primary button');
2312
+ submitButton.type = 'button';
2313
+ submitButton.addEventListener('click', onSubmit);
2314
+
2315
+ const playIcon = document.createElement('i');
2316
+ playIcon.setAttribute('class', 'icon play');
2317
+ submitButton.append(playIcon);
2318
+
2319
+ filtersWrapper.append(channelSelect, currencySelect, customerSelect, submitButton);
2320
+
2321
+ return filtersWrapper
2322
+ }
2323
+
2324
+ createGraphWrapper() {
2325
+ const wrapper = document.createElement('div');
2326
+ wrapper.setAttribute('style', 'padding: 15px;');
2327
+
2328
+ return wrapper
2329
+ }
2330
+
2331
+ createGraphFiller() {
2332
+ const filler = document.createElement('div');
2333
+ filler.setAttribute(
2334
+ 'style',
2335
+ 'border-radius: 7px; background-color: #eee; height: 350px; display: flex; ' +
2336
+ 'justify-content: space-around; align-items: center; font-size: 4em;'
2337
+ );
2338
+
2339
+ const chartIcon = document.createElement('i');
2340
+ chartIcon.setAttribute('class', 'icon chart line');
2341
+ filler.append(chartIcon);
2342
+
2343
+ return filler
2344
+ }
2345
+
2346
+ addSelectOptions(select, choices, placeholder = null) {
2347
+ if (placeholder !== null) {
2348
+ const placeholderOption = document.createElement('option');
2349
+ placeholderOption.innerHTML = placeholder;
2350
+ placeholderOption.disabled = true;
2351
+ placeholderOption.selected = true;
2352
+ select.append(placeholderOption);
2353
+ }
2354
+
2355
+ for (const property in choices) {
2356
+ const choice = choices[property];
2357
+
2358
+ const channelOption = document.createElement('option');
2359
+ channelOption.innerHTML = choice.name;
2360
+ channelOption.setAttribute('value', choice.id);
2361
+ select.append(channelOption);
2362
+ }
2363
+
2364
+ return select
2365
+ }
2366
+
2367
+ hookClientSearchOnSelect(selectElement, searchApiEndpoint) {
2368
+ selectElement.setAttribute('class', `${selectElement.getAttribute('class')} search dropdown selection`);
2369
+
2370
+ $(selectElement).dropdown({
2371
+ apiSettings: {
2372
+ url: `${searchApiEndpoint}/{query}`,
2373
+ cache: false,
2374
+ },
2375
+
2376
+ minCharacters: 2,
2377
+ });
2378
+ }
2379
+
2380
+ isSubmitButtonDisabled(simulationData) {
2381
+ return (
2382
+ null === simulationData.productVariantId ||
2383
+ null === simulationData.channelId ||
2384
+ null === simulationData.currencyId ||
2385
+ null === simulationData.customerId
2386
+ )
2387
+ }
2388
+
2389
+ serializeObjectToQuery(object) {
2390
+ const query = [];
2391
+
2392
+ for (const part in object) {
2393
+ if (Object.prototype.hasOwnProperty.call(object, part)) {
2394
+ query.push(`${encodeURIComponent(part)}=${encodeURIComponent(object[part])}`);
2395
+ }
2396
+ }
2397
+
2398
+ return query.join('&')
2399
+ }
2400
+
2401
+ renderGraph(graphWrapper, graphData) {
2402
+ graphWrapper.innerHTML = '';
2403
+
2404
+ const graphCanvas = document.createElement('canvas');
2405
+ graphCanvas.width = 600;
2406
+ graphCanvas.height = 200;
2407
+
2408
+ graphWrapper.append(graphCanvas);
2409
+
2410
+ const graphConfig = this.getGraphConfig(graphData);
2411
+ console.log('graphConfig', graphConfig);
2412
+ new Chart$1(graphCanvas.getContext('2d'), graphConfig);
2413
+ }
2414
+
2415
+ /** @private */
2416
+ getGraphConfig(rawGraphData) {
2417
+ return {
2418
+ type: 'line',
2419
+ data: {
2420
+ datasets: rawGraphData.datasets.map((rawDataset) => {
2421
+ return {
2422
+ label: rawDataset.label,
2423
+ data: rawDataset.data,
2424
+ borderColor: '#0000ff',
2425
+ fill: false,
2426
+ steppedLine: true,
2427
+ pointRadius: 8,
2428
+ pointHoverRadius: 10,
2429
+ }
2430
+ }),
2431
+ },
2432
+ options: {
2433
+ maintainAspectRatio: true,
2434
+ responsive: true,
2435
+ scales: {
2436
+ xAxes: [
2437
+ {
2438
+ type: 'linear',
2439
+ position: 'bottom',
2440
+ scaleLabel: {
2441
+ display: true,
2442
+ labelString: rawGraphData.xAxisLabel,
2443
+ },
2444
+ },
2445
+ ],
2446
+ yAxes: [
2447
+ {
2448
+ scaleLabel: {
2449
+ display: true,
2450
+ labelString: rawGraphData.yAxisLabel,
2451
+ },
2452
+ },
2453
+ ],
2454
+ },
2455
+ },
2456
+ }
2457
+ }
2458
+ }
2459
+
2041
2460
  /**
2042
2461
  * CKEditor config
2043
2462
  */
@@ -2331,63 +2750,6 @@ vendorDescriptionElements.forEach((element) => {
2331
2750
 
2332
2751
  })( jQuery );
2333
2752
 
2334
- class CustomerGroupClientAssigner {
2335
- constructor(selector, searchSelector = '.ng-client-search-select', submitSelector = '.ng-client-assign-submit') {
2336
- this.selector = selector;
2337
- this.searchSelector = searchSelector;
2338
- this.submitSelector = submitSelector;
2339
-
2340
- this.containerElement = null;
2341
- this.searchElement = null;
2342
- this.submitElement = null;
2343
- }
2344
-
2345
- init() {
2346
- this.containerElement = document.querySelector(this.selector);
2347
- const submitApiEndpoint = this.containerElement.getAttribute('data-assign-customers-url');
2348
- const redirectAfterUrl = this.containerElement.getAttribute('data-redirect-after-url');
2349
-
2350
- this.searchElement = this.containerElement.querySelector(this.searchSelector);
2351
- const searchApiEndpoint = this.searchElement.getAttribute('data-customer-search-url');
2352
-
2353
- $(this.searchElement).dropdown({
2354
- apiSettings: {
2355
- url: `${searchApiEndpoint}/{query}`,
2356
- cache: false,
2357
- },
2358
-
2359
- minCharacters: 2,
2360
- });
2361
-
2362
- this.submitElement = this.containerElement.querySelector(this.submitSelector);
2363
- this.submitElement.addEventListener('click', () => {
2364
- const selectedCustomersIds = this.getSelectValues(this.searchElement);
2365
- this.submitCustomers(submitApiEndpoint, selectedCustomersIds, redirectAfterUrl);
2366
- });
2367
- }
2368
-
2369
- getSelectValues(selectElement) {
2370
- const selected = selectElement.querySelectorAll('option:checked');
2371
- return Array.from(selected).map((optionElement) => optionElement.value)
2372
- }
2373
-
2374
- submitCustomers(apiEndpoint, selectedIds, redirectTo) {
2375
- this.submitElement.disabled = true;
2376
-
2377
- axios
2378
- .post(apiEndpoint, { customers: selectedIds })
2379
- .then(() => {
2380
- window.location = redirectTo;
2381
- })
2382
- .catch((error) => {
2383
- console.error(error);
2384
- })
2385
- .finally(() => {
2386
- this.submitElement.disabled = false;
2387
- });
2388
- }
2389
- }
2390
-
2391
2753
  // Scripts
2392
2754
 
2393
2755
  // Components initializations
@@ -2403,20 +2765,28 @@ $(document).ready(() => {
2403
2765
  */
2404
2766
  TooltipHelpers.init();
2405
2767
 
2406
- const feedCategorySelect = new FeedCategorySelect('.ng-feed-category-select');
2407
- feedCategorySelect.init();
2408
-
2409
2768
  const customerGroupingRuleConfiguration = new CustomerGroupingRuleConfiguration(
2410
2769
  'select.ng-grouping-rule-select',
2411
2770
  '.ng-grouping-rule-configuration'
2412
2771
  );
2413
2772
  customerGroupingRuleConfiguration.init();
2414
2773
 
2774
+ const feedCategorySelect = new FeedCategorySelect('.ng-feed-category-select');
2775
+ feedCategorySelect.init();
2776
+
2415
2777
  // Admin sidebar scroller
2416
2778
  const adminSidebarElement = document.getElementById('sidebar');
2417
2779
  const adminSidebarScroller = new AdminSidebarScroller(adminSidebarElement, 'a.item');
2418
2780
  adminSidebarScroller.scrollToActiveLink();
2419
2781
 
2782
+ const productVariantPricingGraph = new ProductVariantPricingGraph('.ng-product-variant-pricing-graph');
2783
+ productVariantPricingGraph.init();
2784
+
2785
+ const productVariantPricingSimulation = new ProductVariantPricingSimulation(
2786
+ '.ng-product-variant-pricing-simulation'
2787
+ );
2788
+ productVariantPricingSimulation.init();
2789
+
2420
2790
  // Client search select
2421
2791
  const clientSearchSelect = new CustomerGroupClientAssigner('.ng-customer-group-client-assigner');
2422
2792
  clientSearchSelect.init();
package/lib/style.css CHANGED
@@ -1,3 +1,217 @@
1
+ .sylius-filters {
2
+ display: flex;
3
+ flex-wrap: wrap;
4
+ margin-left: -10px;
5
+ margin-right: -10px; }
6
+ .sylius-filters__field {
7
+ flex-grow: 1;
8
+ min-width: 360px;
9
+ margin-left: 10px;
10
+ margin-right: 10px; }
11
+ .sylius-filters .sylius-filters__group {
12
+ display: flex;
13
+ flex-wrap: wrap;
14
+ align-items: flex-start; }
15
+ .sylius-filters .sylius-filters__group > .field {
16
+ flex-grow: 1; }
17
+ .sylius-filters .sylius-filters__group > input {
18
+ flex-grow: 1;
19
+ width: auto !important; }
20
+ .sylius-filters .sylius-filters__group > .disabled.field {
21
+ flex-grow: 0; }
22
+ .sylius-filters .sylius-filters__group > .disabled.field input {
23
+ width: 40px !important;
24
+ background: #eeeeee;
25
+ text-align: center; }
26
+ .sylius-filters .field {
27
+ margin-bottom: 22px !important; }
28
+ .sylius-filters .field label {
29
+ font-weight: 700 !important; }
30
+
31
+ .sylius-filters select {
32
+ -webkit-appearance: none;
33
+ -moz-appearance: none;
34
+ appearance: none;
35
+ background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23444444'><polygon points='0,0 100,0 50,50'/></svg>") no-repeat !important;
36
+ background-size: 8px 12px !important;
37
+ background-position: calc(100% - 10px) calc(50% + 3px) !important; }
38
+
39
+ .sylius-filters .sylius-filters__group input, .sylius-filters .sylius-filters__group select {
40
+ border-radius: 0 !important;
41
+ border-right-width: 0 !important; }
42
+
43
+ .sylius-filters .sylius-filters__group .field:last-child input:last-child,
44
+ .sylius-filters .sylius-filters__group .field:last-child select:last-child {
45
+ border-right-width: 1px !important;
46
+ border-radius: 0 .28571429rem .28571429rem 0 !important; }
47
+
48
+ .sylius-filters .sylius-filters__group .field:first-child input:first-of-type,
49
+ .sylius-filters .sylius-filters__group .field:first-child select:first-of-type {
50
+ border-radius: .28571429rem 0 0 .28571429rem !important; }
51
+
52
+ .overflow-x-auto {
53
+ overflow-x: auto; }
54
+
55
+ #wrapper {
56
+ padding: 54px 0 0 0; }
57
+
58
+ #content {
59
+ padding: 1em; }
60
+
61
+ #sidebar {
62
+ font-size: 1.1em;
63
+ padding-bottom: 30px; }
64
+
65
+ #logo {
66
+ margin-bottom: 1em; }
67
+
68
+ body.pushable .pusher {
69
+ background-color: #f9fAfb; }
70
+
71
+ .ui.visible.left.sidebar ~ .fixed.menu,
72
+ .ui.visible.left.sidebar ~ .pusher {
73
+ padding-right: 260px; }
74
+
75
+ body.centered {
76
+ background-color: #f9fAfb; }
77
+ body.centered .grid {
78
+ height: 100%; }
79
+ body.centered .column {
80
+ padding: 1em;
81
+ max-width: 450px; }
82
+
83
+ select.ui.dropdown[multiple="multiple"] {
84
+ height: 100px; }
85
+
86
+ .ui.segments {
87
+ border: 0; }
88
+ .ui.segments .ui.segment {
89
+ border: 1px solid rgba(34, 36, 38, 0.15) !important; }
90
+
91
+ .ui.breadcrumb {
92
+ margin-top: 1em;
93
+ margin-left: 1em;
94
+ margin-bottom: 1em; }
95
+
96
+ th a {
97
+ color: rgba(0, 0, 0, 0.87); }
98
+
99
+ th a:hover {
100
+ color: rgba(0, 0, 0, 0.87); }
101
+
102
+ th a:visited {
103
+ color: rgba(0, 0, 0, 0.87); }
104
+
105
+ .ui.compact.segment .inline.fields {
106
+ margin: 0; }
107
+
108
+ .ui.hidden.element {
109
+ display: none; }
110
+
111
+ .ui.monster.header {
112
+ font-size: 3em; }
113
+
114
+ .ui.styled.header {
115
+ text-transform: uppercase;
116
+ letter-spacing: 1px;
117
+ background-color: #f9fAfb;
118
+ font-size: 0.9em;
119
+ padding-bottom: 7px; }
120
+
121
+ .ui.input input[readonly] {
122
+ color: #aaa; }
123
+
124
+ .field.loading.transition {
125
+ top: auto;
126
+ left: auto; }
127
+
128
+ .ui.floated.dividing.empty {
129
+ top: 100%;
130
+ bottom: auto;
131
+ padding: 0;
132
+ margin: 0; }
133
+
134
+ .ui.left.floated.dividing.empty ~ .ui.dropdown > .menu {
135
+ right: auto;
136
+ left: 0; }
137
+
138
+ .ui.right.floated.dividing.empty ~ .ui.dropdown > .menu {
139
+ right: 0;
140
+ left: auto; }
141
+
142
+ .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__bulk,
143
+ .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__pagination,
144
+ .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__perpage {
145
+ padding-bottom: 1rem; }
146
+
147
+ .sylius-grid-wrapper .sylius-grid-nav__bulk .ui.red.labeled.icon.button:disabled {
148
+ background: #b9babb !important; }
149
+
150
+ .sylius-grid-wrapper .sylius-grid-table-wrapper {
151
+ overflow-x: auto;
152
+ margin-bottom: 1rem; }
153
+ .sylius-grid-wrapper .sylius-grid-table-wrapper .ui.buttons, .sylius-grid-wrapper .sylius-grid-table-wrapper .ui.label {
154
+ white-space: nowrap; }
155
+
156
+ @media only screen and (min-width: 768px) {
157
+ .sylius-grid-wrapper .sylius-grid-nav {
158
+ display: flex;
159
+ flex-wrap: wrap;
160
+ margin-left: -1rem;
161
+ margin-right: -1rem; }
162
+ .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__bulk,
163
+ .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__pagination,
164
+ .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__perpage {
165
+ padding-left: 1rem;
166
+ padding-right: 1rem; }
167
+ .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__bulk {
168
+ display: flex; }
169
+ .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__bulk .button {
170
+ padding-top: 0.99em !important;
171
+ padding-bottom: 0.99em !important; }
172
+ .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__pagination {
173
+ flex-grow: 1; }
174
+ .sylius-grid-wrapper .pagination {
175
+ flex-wrap: wrap; } }
176
+
177
+ #wrapper.full.height {
178
+ position: relative;
179
+ padding-bottom: 80px !important;
180
+ min-height: 100vh; }
181
+ #wrapper.full.height::after {
182
+ content: '';
183
+ display: block;
184
+ position: absolute;
185
+ bottom: 60px;
186
+ right: 30px;
187
+ width: calc(100% - 60px);
188
+ height: 1px;
189
+ background: #ebebeb; }
190
+ #wrapper.full.height .sylius-footer {
191
+ position: absolute;
192
+ bottom: 20px;
193
+ right: 40px;
194
+ font-size: 13px;
195
+ color: #9a9a9a; }
196
+
197
+ input[type="color"] {
198
+ -webkit-appearance: none;
199
+ border: 1px solid rgba(34, 36, 38, 0.15);
200
+ width: 38px;
201
+ height: 38px;
202
+ padding: 3px;
203
+ border-radius: 99px; }
204
+
205
+ input[type="color"]::-webkit-color-swatch,
206
+ input[type="color"]::-webkit-color-swatch-wrapper {
207
+ border-radius: 99px;
208
+ border: 0;
209
+ padding: 3px; }
210
+
211
+ input[type="color"]::-moz-color-swatch {
212
+ border-radius: 99px;
213
+ border: 0; }
214
+
1
215
  .sylius-tree.hidden {
2
216
  display: none; }
3
217
 
@@ -301,217 +515,3 @@ a {
301
515
 
302
516
  .promotion-disabled {
303
517
  color: #a0a0a0; }
304
-
305
- .sylius-filters {
306
- display: flex;
307
- flex-wrap: wrap;
308
- margin-left: -10px;
309
- margin-right: -10px; }
310
- .sylius-filters__field {
311
- flex-grow: 1;
312
- min-width: 360px;
313
- margin-left: 10px;
314
- margin-right: 10px; }
315
- .sylius-filters .sylius-filters__group {
316
- display: flex;
317
- flex-wrap: wrap;
318
- align-items: flex-start; }
319
- .sylius-filters .sylius-filters__group > .field {
320
- flex-grow: 1; }
321
- .sylius-filters .sylius-filters__group > input {
322
- flex-grow: 1;
323
- width: auto !important; }
324
- .sylius-filters .sylius-filters__group > .disabled.field {
325
- flex-grow: 0; }
326
- .sylius-filters .sylius-filters__group > .disabled.field input {
327
- width: 40px !important;
328
- background: #eeeeee;
329
- text-align: center; }
330
- .sylius-filters .field {
331
- margin-bottom: 22px !important; }
332
- .sylius-filters .field label {
333
- font-weight: 700 !important; }
334
-
335
- .sylius-filters select {
336
- -webkit-appearance: none;
337
- -moz-appearance: none;
338
- appearance: none;
339
- background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' fill='%23444444'><polygon points='0,0 100,0 50,50'/></svg>") no-repeat !important;
340
- background-size: 8px 12px !important;
341
- background-position: calc(100% - 10px) calc(50% + 3px) !important; }
342
-
343
- .sylius-filters .sylius-filters__group input, .sylius-filters .sylius-filters__group select {
344
- border-radius: 0 !important;
345
- border-right-width: 0 !important; }
346
-
347
- .sylius-filters .sylius-filters__group .field:last-child input:last-child,
348
- .sylius-filters .sylius-filters__group .field:last-child select:last-child {
349
- border-right-width: 1px !important;
350
- border-radius: 0 .28571429rem .28571429rem 0 !important; }
351
-
352
- .sylius-filters .sylius-filters__group .field:first-child input:first-of-type,
353
- .sylius-filters .sylius-filters__group .field:first-child select:first-of-type {
354
- border-radius: .28571429rem 0 0 .28571429rem !important; }
355
-
356
- .overflow-x-auto {
357
- overflow-x: auto; }
358
-
359
- #wrapper {
360
- padding: 54px 0 0 0; }
361
-
362
- #content {
363
- padding: 1em; }
364
-
365
- #sidebar {
366
- font-size: 1.1em;
367
- padding-bottom: 30px; }
368
-
369
- #logo {
370
- margin-bottom: 1em; }
371
-
372
- body.pushable .pusher {
373
- background-color: #f9fAfb; }
374
-
375
- .ui.visible.left.sidebar ~ .fixed.menu,
376
- .ui.visible.left.sidebar ~ .pusher {
377
- padding-right: 260px; }
378
-
379
- body.centered {
380
- background-color: #f9fAfb; }
381
- body.centered .grid {
382
- height: 100%; }
383
- body.centered .column {
384
- padding: 1em;
385
- max-width: 450px; }
386
-
387
- select.ui.dropdown[multiple="multiple"] {
388
- height: 100px; }
389
-
390
- .ui.segments {
391
- border: 0; }
392
- .ui.segments .ui.segment {
393
- border: 1px solid rgba(34, 36, 38, 0.15) !important; }
394
-
395
- .ui.breadcrumb {
396
- margin-top: 1em;
397
- margin-left: 1em;
398
- margin-bottom: 1em; }
399
-
400
- th a {
401
- color: rgba(0, 0, 0, 0.87); }
402
-
403
- th a:hover {
404
- color: rgba(0, 0, 0, 0.87); }
405
-
406
- th a:visited {
407
- color: rgba(0, 0, 0, 0.87); }
408
-
409
- .ui.compact.segment .inline.fields {
410
- margin: 0; }
411
-
412
- .ui.hidden.element {
413
- display: none; }
414
-
415
- .ui.monster.header {
416
- font-size: 3em; }
417
-
418
- .ui.styled.header {
419
- text-transform: uppercase;
420
- letter-spacing: 1px;
421
- background-color: #f9fAfb;
422
- font-size: 0.9em;
423
- padding-bottom: 7px; }
424
-
425
- .ui.input input[readonly] {
426
- color: #aaa; }
427
-
428
- .field.loading.transition {
429
- top: auto;
430
- left: auto; }
431
-
432
- .ui.floated.dividing.empty {
433
- top: 100%;
434
- bottom: auto;
435
- padding: 0;
436
- margin: 0; }
437
-
438
- .ui.left.floated.dividing.empty ~ .ui.dropdown > .menu {
439
- right: auto;
440
- left: 0; }
441
-
442
- .ui.right.floated.dividing.empty ~ .ui.dropdown > .menu {
443
- right: 0;
444
- left: auto; }
445
-
446
- .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__bulk,
447
- .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__pagination,
448
- .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__perpage {
449
- padding-bottom: 1rem; }
450
-
451
- .sylius-grid-wrapper .sylius-grid-nav__bulk .ui.red.labeled.icon.button:disabled {
452
- background: #b9babb !important; }
453
-
454
- .sylius-grid-wrapper .sylius-grid-table-wrapper {
455
- overflow-x: auto;
456
- margin-bottom: 1rem; }
457
- .sylius-grid-wrapper .sylius-grid-table-wrapper .ui.buttons, .sylius-grid-wrapper .sylius-grid-table-wrapper .ui.label {
458
- white-space: nowrap; }
459
-
460
- @media only screen and (min-width: 768px) {
461
- .sylius-grid-wrapper .sylius-grid-nav {
462
- display: flex;
463
- flex-wrap: wrap;
464
- margin-left: -1rem;
465
- margin-right: -1rem; }
466
- .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__bulk,
467
- .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__pagination,
468
- .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__perpage {
469
- padding-left: 1rem;
470
- padding-right: 1rem; }
471
- .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__bulk {
472
- display: flex; }
473
- .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__bulk .button {
474
- padding-top: 0.99em !important;
475
- padding-bottom: 0.99em !important; }
476
- .sylius-grid-wrapper .sylius-grid-nav .sylius-grid-nav__pagination {
477
- flex-grow: 1; }
478
- .sylius-grid-wrapper .pagination {
479
- flex-wrap: wrap; } }
480
-
481
- #wrapper.full.height {
482
- position: relative;
483
- padding-bottom: 80px !important;
484
- min-height: 100vh; }
485
- #wrapper.full.height::after {
486
- content: '';
487
- display: block;
488
- position: absolute;
489
- bottom: 60px;
490
- right: 30px;
491
- width: calc(100% - 60px);
492
- height: 1px;
493
- background: #ebebeb; }
494
- #wrapper.full.height .sylius-footer {
495
- position: absolute;
496
- bottom: 20px;
497
- right: 40px;
498
- font-size: 13px;
499
- color: #9a9a9a; }
500
-
501
- input[type="color"] {
502
- -webkit-appearance: none;
503
- border: 1px solid rgba(34, 36, 38, 0.15);
504
- width: 38px;
505
- height: 38px;
506
- padding: 3px;
507
- border-radius: 99px; }
508
-
509
- input[type="color"]::-webkit-color-swatch,
510
- input[type="color"]::-webkit-color-swatch-wrapper {
511
- border-radius: 99px;
512
- border: 0;
513
- padding: 3px; }
514
-
515
- input[type="color"]::-moz-color-swatch {
516
- border-radius: 99px;
517
- border: 0; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyshop/admin",
3
- "version": "1.3.38",
3
+ "version": "1.3.39",
4
4
  "author": "oXy Online s.r.o. <info@oxyshop.cz>",
5
5
  "main": "lib/index.js",
6
6
  "sass": "scss/main.scss",
@@ -13,6 +13,10 @@ export default class CustomerGroupClientAssigner {
13
13
 
14
14
  init() {
15
15
  this.containerElement = document.querySelector(this.selector)
16
+ if (null === this.containerElement) {
17
+ return
18
+ }
19
+
16
20
  const submitApiEndpoint = this.containerElement.getAttribute('data-assign-customers-url')
17
21
  const redirectAfterUrl = this.containerElement.getAttribute('data-redirect-after-url')
18
22
 
@@ -0,0 +1,86 @@
1
+ import Chart from 'chart.js'
2
+
3
+ export default class ProductVariantPricingGraph {
4
+ constructor(containerSelector) {
5
+ this.containerSelector = containerSelector
6
+ }
7
+
8
+ init() {
9
+ document.querySelectorAll(this.containerSelector).forEach((componentContainer) => {
10
+ const graphsData = JSON.parse(componentContainer.getAttribute('data-graph'))
11
+
12
+ for (const currencyGraphIndex in graphsData) {
13
+ const currencyGraph = graphsData[currencyGraphIndex]
14
+
15
+ const currencyCodeHeader = document.createElement('h4')
16
+ currencyCodeHeader.classList.add('ui', 'header')
17
+ currencyCodeHeader.textContent = currencyGraph.currency
18
+
19
+ const graphCanvas = document.createElement('canvas')
20
+ graphCanvas.width = 400
21
+ graphCanvas.height = 200
22
+
23
+ const graphContainer = document.createElement('div')
24
+ graphContainer.append(currencyCodeHeader)
25
+ graphContainer.append(graphCanvas)
26
+
27
+ componentContainer.append(graphContainer)
28
+
29
+ const graphConfig = this.getGraphConfig(currencyGraph.graph)
30
+ new Chart(graphCanvas.getContext('2d'), graphConfig)
31
+ }
32
+ })
33
+ }
34
+
35
+ /** @private */
36
+ getGraphConfig(rawGraphData) {
37
+ return {
38
+ type: 'line',
39
+ data: {
40
+ datasets: rawGraphData.datasets.map((rawDataset) => {
41
+ return {
42
+ label: rawDataset.label,
43
+ data: rawDataset.data,
44
+ borderColor: this.getRandomRgbColor(),
45
+ fill: false,
46
+ steppedLine: true,
47
+ pointRadius: 8,
48
+ pointHoverRadius: 10,
49
+ }
50
+ }),
51
+ },
52
+ options: {
53
+ maintainAspectRatio: true,
54
+ responsive: true,
55
+ scales: {
56
+ xAxes: [
57
+ {
58
+ type: 'linear',
59
+ position: 'bottom',
60
+ scaleLabel: {
61
+ display: true,
62
+ labelString: rawGraphData.xAxisLabel,
63
+ },
64
+ },
65
+ ],
66
+ yAxes: [
67
+ {
68
+ scaleLabel: {
69
+ display: true,
70
+ labelString: rawGraphData.yAxisLabel,
71
+ },
72
+ },
73
+ ],
74
+ },
75
+ },
76
+ }
77
+ }
78
+
79
+ /** @private */
80
+ getRandomRgbColor() {
81
+ const r = Math.floor(Math.random() * 255)
82
+ const g = Math.floor(Math.random() * 255)
83
+ const b = Math.floor(Math.random() * 255)
84
+ return `rgb(${r},${g},${b})`
85
+ }
86
+ }
@@ -0,0 +1,273 @@
1
+ import axios from 'axios'
2
+ import Chart from 'chart.js'
3
+
4
+ export default class ProductVariantPricingSimulation {
5
+ constructor(selector) {
6
+ this.selector = selector
7
+ }
8
+
9
+ init() {
10
+ document.querySelectorAll(this.selector).forEach((element) => {
11
+ const productVariantId = element.getAttribute('data-product-variant-id')
12
+ const channels = JSON.parse(element.getAttribute('data-channels'))
13
+ const searchApiEndpoint = element.getAttribute('data-customer-search-url')
14
+ const pricingApiEndpoint = element.getAttribute('data-pricing-url')
15
+
16
+ this.initElement(element, productVariantId, channels, searchApiEndpoint, pricingApiEndpoint)
17
+ })
18
+ }
19
+
20
+ initElement(parentElement, productVariantId, channels, searchApiEndpoint, pricingApiEndpoint) {
21
+ parentElement.innerHTML = ''
22
+
23
+ const simulationData = {
24
+ productVariantId: productVariantId,
25
+ channelId: null,
26
+ currencyId: null,
27
+ customerId: null,
28
+ }
29
+
30
+ const submitButton = document.createElement('button')
31
+ const currencySelect = document.createElement('select')
32
+
33
+ const onChannelSelect = (event) => {
34
+ const selectedChannelId = parseInt(event.target.value)
35
+ simulationData.channelId = selectedChannelId
36
+ simulationData.currencyId = null
37
+ submitButton.disabled = this.isSubmitButtonDisabled(simulationData)
38
+
39
+ const selectedChannel = channels.find((channel) => {
40
+ return channel.id === selectedChannelId
41
+ })
42
+
43
+ currencySelect.innerHTML = ''
44
+ this.addSelectOptions(currencySelect, selectedChannel.currencies, 'Select currency')
45
+ }
46
+
47
+ const onCurrencySelect = (event) => {
48
+ simulationData.currencyId = event.target.value
49
+ submitButton.disabled = this.isSubmitButtonDisabled(simulationData)
50
+ }
51
+
52
+ const onCustomerSelect = (event) => {
53
+ simulationData.customerId = event.target.value
54
+ submitButton.disabled = this.isSubmitButtonDisabled(simulationData)
55
+ }
56
+
57
+ const graphWrapper = this.createGraphWrapper()
58
+
59
+ const onSubmit = () => {
60
+ const pricingUrl = `${pricingApiEndpoint}?${this.serializeObjectToQuery(simulationData)}`
61
+
62
+ axios
63
+ .get(pricingUrl)
64
+ .then((response) => {
65
+ const chartData = response.data
66
+ graphWrapper.setAttribute('data-debug-chart', JSON.stringify(chartData)) // For e2e tests
67
+ this.renderGraph(graphWrapper, chartData)
68
+ })
69
+ .catch((error) => {
70
+ console.error(error)
71
+ graphWrapper.innerHTML = 'Pricing simulation error'
72
+ })
73
+ }
74
+
75
+ const wrapper = document.createElement('div')
76
+ wrapper.setAttribute('style', 'border: solid 1px #ddd; background-color: #fafafa;')
77
+
78
+ const filters = this.createFilters(
79
+ channels,
80
+ currencySelect,
81
+ onChannelSelect,
82
+ onCurrencySelect,
83
+ onCustomerSelect,
84
+ onSubmit,
85
+ submitButton,
86
+ searchApiEndpoint
87
+ )
88
+ filters.setAttribute(
89
+ 'style',
90
+ 'display: grid; grid-template-columns: 1fr 1fr 1fr 60px; grid-gap: 10px; ' +
91
+ 'padding: 15px; border-bottom: solid 1px #ddd;'
92
+ )
93
+
94
+ const graphFiller = this.createGraphFiller()
95
+ graphWrapper.append(graphFiller)
96
+
97
+ wrapper.append(filters, graphWrapper)
98
+ parentElement.append(wrapper)
99
+ }
100
+
101
+ createFilters(
102
+ channels,
103
+ currencySelect,
104
+ onChannelSelect,
105
+ onCurrencySelect,
106
+ onCustomerSelect,
107
+ onSubmit,
108
+ submitButton,
109
+ searchApiEndpoint
110
+ ) {
111
+ const filtersWrapper = document.createElement('div')
112
+
113
+ const channelSelect = document.createElement('select')
114
+ this.addSelectOptions(channelSelect, channels, 'Select channel')
115
+ channelSelect.addEventListener('change', onChannelSelect)
116
+
117
+ currencySelect.addEventListener('change', onCurrencySelect)
118
+
119
+ const customerSelect = document.createElement('select')
120
+ customerSelect.addEventListener('change', onCustomerSelect)
121
+
122
+ // this is delayed to avoid racing conditions
123
+ setTimeout(() => this.hookClientSearchOnSelect(customerSelect, searchApiEndpoint), 600)
124
+
125
+ submitButton.disabled = true
126
+ submitButton.setAttribute('class', 'ui icon primary button')
127
+ submitButton.type = 'button'
128
+ submitButton.addEventListener('click', onSubmit)
129
+
130
+ const playIcon = document.createElement('i')
131
+ playIcon.setAttribute('class', 'icon play')
132
+ submitButton.append(playIcon)
133
+
134
+ filtersWrapper.append(channelSelect, currencySelect, customerSelect, submitButton)
135
+
136
+ return filtersWrapper
137
+ }
138
+
139
+ createGraphWrapper() {
140
+ const wrapper = document.createElement('div')
141
+ wrapper.setAttribute('style', 'padding: 15px;')
142
+
143
+ return wrapper
144
+ }
145
+
146
+ createGraphFiller() {
147
+ const filler = document.createElement('div')
148
+ filler.setAttribute(
149
+ 'style',
150
+ 'border-radius: 7px; background-color: #eee; height: 350px; display: flex; ' +
151
+ 'justify-content: space-around; align-items: center; font-size: 4em;'
152
+ )
153
+
154
+ const chartIcon = document.createElement('i')
155
+ chartIcon.setAttribute('class', 'icon chart line')
156
+ filler.append(chartIcon)
157
+
158
+ return filler
159
+ }
160
+
161
+ addSelectOptions(select, choices, placeholder = null) {
162
+ if (placeholder !== null) {
163
+ const placeholderOption = document.createElement('option')
164
+ placeholderOption.innerHTML = placeholder
165
+ placeholderOption.disabled = true
166
+ placeholderOption.selected = true
167
+ select.append(placeholderOption)
168
+ }
169
+
170
+ for (const property in choices) {
171
+ const choice = choices[property]
172
+
173
+ const channelOption = document.createElement('option')
174
+ channelOption.innerHTML = choice.name
175
+ channelOption.setAttribute('value', choice.id)
176
+ select.append(channelOption)
177
+ }
178
+
179
+ return select
180
+ }
181
+
182
+ hookClientSearchOnSelect(selectElement, searchApiEndpoint) {
183
+ selectElement.setAttribute('class', `${selectElement.getAttribute('class')} search dropdown selection`)
184
+
185
+ $(selectElement).dropdown({
186
+ apiSettings: {
187
+ url: `${searchApiEndpoint}/{query}`,
188
+ cache: false,
189
+ },
190
+
191
+ minCharacters: 2,
192
+ })
193
+ }
194
+
195
+ isSubmitButtonDisabled(simulationData) {
196
+ return (
197
+ null === simulationData.productVariantId ||
198
+ null === simulationData.channelId ||
199
+ null === simulationData.currencyId ||
200
+ null === simulationData.customerId
201
+ )
202
+ }
203
+
204
+ serializeObjectToQuery(object) {
205
+ const query = []
206
+
207
+ for (const part in object) {
208
+ if (Object.prototype.hasOwnProperty.call(object, part)) {
209
+ query.push(`${encodeURIComponent(part)}=${encodeURIComponent(object[part])}`)
210
+ }
211
+ }
212
+
213
+ return query.join('&')
214
+ }
215
+
216
+ renderGraph(graphWrapper, graphData) {
217
+ graphWrapper.innerHTML = ''
218
+
219
+ const graphCanvas = document.createElement('canvas')
220
+ graphCanvas.width = 600
221
+ graphCanvas.height = 200
222
+
223
+ graphWrapper.append(graphCanvas)
224
+
225
+ const graphConfig = this.getGraphConfig(graphData)
226
+ console.log('graphConfig', graphConfig)
227
+ new Chart(graphCanvas.getContext('2d'), graphConfig)
228
+ }
229
+
230
+ /** @private */
231
+ getGraphConfig(rawGraphData) {
232
+ return {
233
+ type: 'line',
234
+ data: {
235
+ datasets: rawGraphData.datasets.map((rawDataset) => {
236
+ return {
237
+ label: rawDataset.label,
238
+ data: rawDataset.data,
239
+ borderColor: '#0000ff',
240
+ fill: false,
241
+ steppedLine: true,
242
+ pointRadius: 8,
243
+ pointHoverRadius: 10,
244
+ }
245
+ }),
246
+ },
247
+ options: {
248
+ maintainAspectRatio: true,
249
+ responsive: true,
250
+ scales: {
251
+ xAxes: [
252
+ {
253
+ type: 'linear',
254
+ position: 'bottom',
255
+ scaleLabel: {
256
+ display: true,
257
+ labelString: rawGraphData.xAxisLabel,
258
+ },
259
+ },
260
+ ],
261
+ yAxes: [
262
+ {
263
+ scaleLabel: {
264
+ display: true,
265
+ labelString: rawGraphData.yAxisLabel,
266
+ },
267
+ },
268
+ ],
269
+ },
270
+ },
271
+ }
272
+ }
273
+ }
package/src/index.js CHANGED
@@ -7,9 +7,12 @@ import 'sylius-bundle/AdminBundle/Resources/private/js/app'
7
7
  // Scripts - components
8
8
  import './components/taxonAttributes'
9
9
  import FeedCategorySelect from './components/feedCategorySelect'
10
+ import ProductVariantPricingGraph from './components/productVariantPricingGraph'
11
+ import CustomerGroupClientAssigner from './components/customerGroupClientAssigner'
10
12
  import TooltipHelpers from './components/tooltipHelpers'
11
13
  import AdminSidebarScroller from './components/adminSidebarScroller'
12
14
  import CustomerGroupingRuleConfiguration from './components/customerGroupingRuleConfiguration'
15
+ import ProductVariantPricingSimulation from './components/productVariantPricingSimulation'
13
16
 
14
17
  // Scripts - plugin
15
18
  import './plugins/ckeditor/index'
@@ -29,7 +32,6 @@ import '@oxyshop/admin/lib/style.css'
29
32
  // Images
30
33
  import '@oxyshop/admin/images/logo.png'
31
34
  import '@oxyshop/admin/images/admin-logo.svg'
32
- import CustomerGroupClientAssigner from './components/customerGroupClientAssigner'
33
35
 
34
36
  // Components initializations
35
37
  $(document).ready(() => {
@@ -44,20 +46,28 @@ $(document).ready(() => {
44
46
  */
45
47
  TooltipHelpers.init()
46
48
 
47
- const feedCategorySelect = new FeedCategorySelect('.ng-feed-category-select')
48
- feedCategorySelect.init()
49
-
50
49
  const customerGroupingRuleConfiguration = new CustomerGroupingRuleConfiguration(
51
50
  'select.ng-grouping-rule-select',
52
51
  '.ng-grouping-rule-configuration'
53
52
  )
54
53
  customerGroupingRuleConfiguration.init()
55
54
 
55
+ const feedCategorySelect = new FeedCategorySelect('.ng-feed-category-select')
56
+ feedCategorySelect.init()
57
+
56
58
  // Admin sidebar scroller
57
59
  const adminSidebarElement = document.getElementById('sidebar')
58
60
  const adminSidebarScroller = new AdminSidebarScroller(adminSidebarElement, 'a.item')
59
61
  adminSidebarScroller.scrollToActiveLink()
60
62
 
63
+ const productVariantPricingGraph = new ProductVariantPricingGraph('.ng-product-variant-pricing-graph')
64
+ productVariantPricingGraph.init()
65
+
66
+ const productVariantPricingSimulation = new ProductVariantPricingSimulation(
67
+ '.ng-product-variant-pricing-simulation'
68
+ )
69
+ productVariantPricingSimulation.init()
70
+
61
71
  // Client search select
62
72
  const clientSearchSelect = new CustomerGroupClientAssigner('.ng-customer-group-client-assigner')
63
73
  clientSearchSelect.init()