@fleetbase/storefront-engine 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/addon/components/context-panel.hbs +5 -0
  2. package/addon/components/context-panel.js +6 -0
  3. package/addon/components/customer-panel/details.hbs +34 -0
  4. package/addon/components/customer-panel/details.js +3 -0
  5. package/addon/components/customer-panel/orders.hbs +140 -0
  6. package/addon/components/customer-panel/orders.js +78 -0
  7. package/addon/components/customer-panel.hbs +70 -0
  8. package/addon/components/customer-panel.js +171 -0
  9. package/addon/components/display-place.hbs +52 -0
  10. package/addon/components/display-place.js +11 -0
  11. package/addon/components/modals/manage-addons.hbs +15 -52
  12. package/addon/components/modals/manage-addons.js +93 -43
  13. package/addon/components/modals/select-addon-category.hbs +1 -1
  14. package/addon/components/order-panel/details.hbs +245 -0
  15. package/addon/components/order-panel/details.js +189 -0
  16. package/addon/components/order-panel.hbs +1 -0
  17. package/addon/components/order-panel.js +38 -0
  18. package/addon/components/storefront-order-summary.hbs +9 -2
  19. package/addon/components/widget/customers.hbs +3 -1
  20. package/addon/components/widget/customers.js +5 -0
  21. package/addon/components/widget/orders.js +8 -146
  22. package/addon/controllers/customers/index/view.js +43 -0
  23. package/addon/controllers/customers/index.js +10 -6
  24. package/addon/controllers/networks/index/network/customers.js +68 -2
  25. package/addon/controllers/networks/index/network/orders.js +324 -1
  26. package/addon/controllers/networks/index/network/stores.js +0 -2
  27. package/addon/controllers/orders/index/view.js +13 -0
  28. package/addon/controllers/orders/index.js +10 -7
  29. package/addon/controllers/products/index/category/edit.js +12 -16
  30. package/addon/controllers/products/index/category/new.js +40 -45
  31. package/addon/controllers/products/index.js +8 -2
  32. package/addon/helpers/avatar-url.js +9 -0
  33. package/addon/models/product-variant-option.js +8 -1
  34. package/addon/models/product-variant.js +12 -2
  35. package/addon/models/product.js +62 -0
  36. package/addon/routes/customers/index/view.js +14 -0
  37. package/addon/routes/networks/index/network/customers.js +29 -0
  38. package/addon/routes/networks/index/network/orders.js +5 -0
  39. package/addon/routes/networks/index.js +1 -1
  40. package/addon/routes/orders/index/view.js +22 -1
  41. package/addon/routes/products/index/category/edit.js +6 -0
  42. package/addon/routes/products/index/category/new.js +3 -1
  43. package/addon/routes.js +1 -0
  44. package/addon/serializers/product-variant-option.js +14 -0
  45. package/addon/serializers/product-variant.js +27 -0
  46. package/addon/serializers/product.js +26 -4
  47. package/addon/services/context-panel.js +210 -0
  48. package/addon/styles/storefront-engine.css +6 -0
  49. package/addon/templates/application.hbs +3 -1
  50. package/addon/templates/customers/index/view.hbs +1 -0
  51. package/addon/templates/networks/index/network/customers.hbs +18 -1
  52. package/addon/templates/networks/index/network/orders.hbs +18 -1
  53. package/addon/templates/networks/index/network.hbs +1 -1
  54. package/addon/templates/orders/index/view.hbs +1 -1
  55. package/addon/templates/products/index/category/new.hbs +12 -67
  56. package/app/components/context-panel.js +1 -0
  57. package/app/components/customer-panel/details.js +1 -0
  58. package/app/components/customer-panel/orders.js +1 -0
  59. package/app/components/customer-panel.js +1 -0
  60. package/app/components/display-place.js +1 -0
  61. package/app/components/order-panel/details.js +1 -0
  62. package/app/components/order-panel.js +1 -0
  63. package/app/controllers/customers/index/view.js +1 -0
  64. package/app/controllers/orders/index/view.js +1 -0
  65. package/app/helpers/avatar-url.js +1 -0
  66. package/app/routes/customers/index/view.js +1 -0
  67. package/app/serializers/product-variant-option.js +1 -0
  68. package/app/services/context-panel.js +1 -0
  69. package/app/templates/customers/index/view.js +1 -0
  70. package/composer.json +4 -4
  71. package/extension.json +1 -1
  72. package/package.json +9 -3
  73. package/server/seeders/OrderConfigSeeder.php +2 -249
  74. package/server/src/Http/Controllers/AddonCategoryController.php +90 -0
  75. package/server/src/Http/Controllers/v1/ReviewController.php +43 -52
  76. package/server/src/Http/Controllers/v1/ServiceQuoteController.php +7 -9
  77. package/server/src/Http/Resources/Network.php +34 -32
  78. package/server/src/Http/Resources/NotificationChannel.php +32 -0
  79. package/server/src/Http/Resources/Product.php +10 -8
  80. package/server/src/Models/AddonCategory.php +37 -0
  81. package/server/src/Models/Product.php +6 -7
  82. package/server/src/Models/ProductAddon.php +3 -0
  83. package/server/src/Models/ProductAddonCategory.php +12 -2
  84. package/server/src/Observers/CompanyObserver.php +20 -0
  85. package/server/src/Providers/StorefrontServiceProvider.php +2 -1
  86. package/server/src/Support/Storefront.php +249 -0
  87. package/translations/en-us.yaml +101 -39
  88. package/server/src/Support/OrderConfig.php +0 -14
@@ -1,3 +1,326 @@
1
1
  import Controller from '@ember/controller';
2
+ import { inject as service } from '@ember/service';
3
+ import { tracked } from '@glimmer/tracking';
4
+ import { isBlank } from '@ember/utils';
5
+ import { timeout } from 'ember-concurrency';
6
+ import { task } from 'ember-concurrency-decorators';
7
+ import { action } from '@ember/object';
2
8
 
3
- export default class NetworksIndexNetworkOrdersController extends Controller {}
9
+ export default class NetworksIndexNetworkOrdersController extends Controller {
10
+ /**
11
+ * Inject the `notifications` service
12
+ *
13
+ * @var {Service}
14
+ */
15
+ @service notifications;
16
+
17
+ /**
18
+ * Inject the `intl` service
19
+ *
20
+ * @var {Service}
21
+ */
22
+ @service intl;
23
+
24
+ /**
25
+ * Inject the `modals-manager` service
26
+ *
27
+ * @var {Service}
28
+ */
29
+ @service modalsManager;
30
+
31
+ /**
32
+ * Inject the `crud` service
33
+ *
34
+ * @var {Service}
35
+ */
36
+ @service crud;
37
+
38
+ /**
39
+ * Inject the `fetch` service
40
+ *
41
+ * @var {Service}
42
+ */
43
+ @service fetch;
44
+
45
+ /**
46
+ * Inject the `filters` service
47
+ *
48
+ * @var {Service}
49
+ */
50
+ @service filters;
51
+
52
+ @service contextPanel;
53
+
54
+ /**
55
+ * Queryable parameters for this controller's model
56
+ *
57
+ * @var {Array}
58
+ */
59
+ queryParams = [];
60
+
61
+ @tracked page = 1;
62
+ @tracked limit;
63
+ @tracked query;
64
+ @tracked sort = '-created_at';
65
+ @tracked public_id;
66
+ @tracked internal_id;
67
+ @tracked tracking;
68
+ @tracked facilitator;
69
+ @tracked customer;
70
+ @tracked driver;
71
+ @tracked payload;
72
+ @tracked pickup;
73
+ @tracked dropoff;
74
+ @tracked updated_by;
75
+ @tracked created_by;
76
+ @tracked status;
77
+
78
+ @tracked columns = [
79
+ {
80
+ label: this.intl.t('storefront.common.id'),
81
+ valuePath: 'public_id',
82
+ width: '150px',
83
+ cellComponent: 'table/cell/anchor',
84
+ action: this.viewOrder,
85
+ resizable: true,
86
+ sortable: true,
87
+ filterable: true,
88
+ filterComponent: 'filter/string',
89
+ },
90
+ {
91
+ label: this.intl.t('storefront.orders.index.internal-id'),
92
+ valuePath: 'internal_id',
93
+ width: '125px',
94
+ resizable: true,
95
+ sortable: true,
96
+ filterable: true,
97
+ filterComponent: 'filter/string',
98
+ },
99
+ {
100
+ label: this.intl.t('storefront.orders.index.customer'),
101
+ valuePath: 'customer.name',
102
+ cellComponent: 'table/cell/base',
103
+ width: '125px',
104
+ resizable: true,
105
+ sortable: true,
106
+ hidden: true,
107
+ filterable: true,
108
+ filterComponent: 'filter/model',
109
+ filterComponentPlaceholder: this.intl.t('storefront.orders.index.select-order-customer'),
110
+ filterParam: 'customer',
111
+ model: 'customer',
112
+ },
113
+ {
114
+ label: this.intl.t('storefront.common.pickup'),
115
+ valuePath: 'pickupName',
116
+ cellComponent: 'table/cell/base',
117
+ width: '160px',
118
+ resizable: true,
119
+ sortable: true,
120
+ filterable: true,
121
+ filterComponent: 'filter/model',
122
+ filterComponentPlaceholder: this.intl.t('storefront.orders.index.select-order-pickup-location'),
123
+ filterParam: 'pickup',
124
+ model: 'place',
125
+ },
126
+ {
127
+ label: this.intl.t('storefront.common.dropoff'),
128
+ valuePath: 'dropoffName',
129
+ cellComponent: 'table/cell/base',
130
+ width: '160px',
131
+ resizable: true,
132
+ sortable: true,
133
+ filterable: true,
134
+ filterComponent: 'filter/model',
135
+ filterComponentPlaceholder: this.intl.t('storefront.orders.index.select-order-dropoff-location'),
136
+ filterParam: 'dropoff',
137
+ model: 'place',
138
+ },
139
+ {
140
+ label: this.intl.t('storefront.orders.index.scheduled-at'),
141
+ valuePath: 'scheduledAt',
142
+ sortParam: 'scheduled_at',
143
+ filterParam: 'scheduled_at',
144
+ width: '150px',
145
+ resizable: true,
146
+ sortable: true,
147
+ filterable: true,
148
+ filterComponent: 'filter/date',
149
+ },
150
+ {
151
+ label: '# Items',
152
+ cellComponent: 'table/cell/base',
153
+ valuePath: 'item_count',
154
+ resizable: true,
155
+ hidden: true,
156
+ width: '50px',
157
+ },
158
+ {
159
+ label: this.intl.t('storefront.orders.index.transaction-total'),
160
+ cellComponent: 'table/cell/base',
161
+ valuePath: 'transaction_amount',
162
+ width: '50px',
163
+ resizable: true,
164
+ hidden: true,
165
+ sortable: true,
166
+ },
167
+ {
168
+ label: this.intl.t('storefront.orders.index.tracking-number'),
169
+ cellComponent: 'table/cell/base',
170
+ valuePath: 'tracking_number.tracking_number',
171
+ width: '170px',
172
+ resizable: true,
173
+ sortable: true,
174
+ filterable: true,
175
+ filterComponent: 'filter/string',
176
+ },
177
+ {
178
+ label: this.intl.t('storefront.orders.index.driver-assigned'),
179
+ cellComponent: 'table/cell/driver-name',
180
+ valuePath: 'driver_assigned',
181
+ modelPath: 'driver_assigned',
182
+ width: '170px',
183
+ resizable: true,
184
+ sortable: true,
185
+ filterable: true,
186
+ filterComponent: 'filter/model',
187
+ filterComponentPlaceholder: this.intl.t('storefront.orders.index.select-driver-for-order'),
188
+ filterParam: 'driver',
189
+ model: 'driver',
190
+ query: {
191
+ // no model, serializer, adapter for relations
192
+ without: ['fleets', 'vendor', 'vehicle', 'currentJob'],
193
+ },
194
+ },
195
+ {
196
+ label: this.intl.t('storefront.common.type'),
197
+ cellComponent: 'cell/humanize',
198
+ valuePath: 'type',
199
+ width: '100px',
200
+ resizable: true,
201
+ hidden: true,
202
+ sortable: true,
203
+ },
204
+ {
205
+ label: this.intl.t('storefront.common.status'),
206
+ valuePath: 'status',
207
+ cellComponent: 'table/cell/status',
208
+ width: '120px',
209
+ resizable: true,
210
+ sortable: true,
211
+ filterable: true,
212
+ filterComponent: 'filter/multi-option',
213
+ // filterOptions: this.statusOptions,
214
+ },
215
+ {
216
+ label: this.intl.t('storefront.orders.index.created-at'),
217
+ valuePath: 'createdAt',
218
+ sortParam: 'created_at',
219
+ filterParam: 'created_at',
220
+ width: '140px',
221
+ resizable: true,
222
+ sortable: true,
223
+ filterable: true,
224
+ filterComponent: 'filter/date',
225
+ },
226
+ {
227
+ label: this.intl.t('storefront.orders.index.updated-at'),
228
+ valuePath: 'updatedAt',
229
+ sortParam: 'updated_at',
230
+ filterParam: 'updated_at',
231
+ width: '125px',
232
+ resizable: true,
233
+ sortable: true,
234
+ hidden: true,
235
+ filterable: true,
236
+ filterComponent: 'filter/date',
237
+ },
238
+ {
239
+ label: this.intl.t('storefront.orders.index.created-by'),
240
+ valuePath: 'created_by_name',
241
+ width: '125px',
242
+ resizable: true,
243
+ hidden: true,
244
+ filterable: true,
245
+ filterComponent: 'filter/model',
246
+ filterComponentPlaceholder: 'Select user',
247
+ filterParam: 'created_by',
248
+ model: 'user',
249
+ },
250
+ {
251
+ label: this.intl.t('storefront.orders.index.updated-by'),
252
+ valuePath: 'updated_by_name',
253
+ width: '125px',
254
+ resizable: true,
255
+ hidden: true,
256
+ filterable: true,
257
+ filterComponent: 'filter/model',
258
+ filterComponentPlaceholder: this.intl.t('storefront.orders.index.select-user'),
259
+ filterParam: 'updated_by',
260
+ model: 'user',
261
+ },
262
+ {
263
+ label: '',
264
+ cellComponent: 'table/cell/dropdown',
265
+ ddButtonText: false,
266
+ ddButtonIcon: 'ellipsis-h',
267
+ ddButtonIconPrefix: 'fas',
268
+ ddMenuLabel: 'Order Actions',
269
+ cellClassNames: 'overflow-visible',
270
+ wrapperClass: 'flex items-center justify-end mx-2',
271
+ width: '12%',
272
+ actions: [
273
+ {
274
+ label: this.intl.t('storefront.orders.index.view-order'),
275
+ icon: 'eye',
276
+ fn: this.viewOrder,
277
+ },
278
+ {
279
+ label: this.intl.t('storefront.orders.index.cancel-order'),
280
+ icon: 'ban',
281
+ fn: this.cancelOrder,
282
+ },
283
+ {
284
+ separator: true,
285
+ },
286
+ {
287
+ label: this.intl.t('storefront.orders.index.delete-order'),
288
+ icon: 'trash',
289
+ fn: this.deleteOrder,
290
+ },
291
+ ],
292
+ sortable: false,
293
+ filterable: false,
294
+ resizable: false,
295
+ searchable: false,
296
+ },
297
+ ];
298
+
299
+ /**
300
+ * The search task.
301
+ *
302
+ * @void
303
+ */
304
+ @task({ restartable: true }) *search({ target: { value } }) {
305
+ // if no query don't search
306
+ if (isBlank(value)) {
307
+ this.query = null;
308
+ return;
309
+ }
310
+
311
+ // timeout for typing
312
+ yield timeout(250);
313
+
314
+ // reset page for results
315
+ if (this.page > 1) {
316
+ this.page = 1;
317
+ }
318
+
319
+ // update the query param
320
+ this.query = value;
321
+ }
322
+
323
+ @action viewOrder(order) {
324
+ this.contextPanel.focus(order, 'viewing');
325
+ }
326
+ }
@@ -568,8 +568,6 @@ export default class NetworksIndexNetworkStoresController extends Controller {
568
568
  confirm: (modal) => {
569
569
  modal.startLoading();
570
570
 
571
- console.log('saving store', store);
572
-
573
571
  return store
574
572
  .save()
575
573
  .then(() => {
@@ -0,0 +1,13 @@
1
+ import { action } from '@ember/object';
2
+ import BaseController from '../../base-controller';
3
+
4
+ export default class OrdersIndexViewController extends BaseController {
5
+ /**
6
+ * Uses router service to transition back to `orders.index`
7
+ *
8
+ * @void
9
+ */
10
+ @action transitionBack() {
11
+ return this.transitionToRoute('orders.index');
12
+ }
13
+ }
@@ -1,11 +1,12 @@
1
- import Controller from '@ember/controller';
1
+ import { action } from '@ember/object';
2
2
  import { inject as service } from '@ember/service';
3
- import { tracked } from '@glimmer/tracking';
4
3
  import { isBlank } from '@ember/utils';
4
+ import BaseController from '@fleetbase/storefront-engine/controllers/base-controller';
5
+ import { tracked } from '@glimmer/tracking';
5
6
  import { timeout } from 'ember-concurrency';
6
7
  import { task } from 'ember-concurrency-decorators';
7
8
 
8
- export default class OrdersIndexController extends Controller {
9
+ export default class OrdersIndexController extends BaseController {
9
10
  /**
10
11
  * Inject the `notifications` service
11
12
  *
@@ -94,13 +95,11 @@ export default class OrdersIndexController extends Controller {
94
95
  label: this.intl.t('storefront.common.id'),
95
96
  valuePath: 'public_id',
96
97
  width: '150px',
97
- cellComponent: 'table/cell/link-to',
98
- route: 'orders.index.view',
99
- // onLinkClick: this.viewOrder,
98
+ cellComponent: 'table/cell/anchor',
99
+ onClick: this.viewOrder,
100
100
  resizable: true,
101
101
  sortable: true,
102
102
  filterable: true,
103
- filterComponent: 'filter/string',
104
103
  },
105
104
  {
106
105
  label: this.intl.t('storefront.orders.index.internal-id'),
@@ -334,4 +333,8 @@ export default class OrdersIndexController extends Controller {
334
333
  // update the query param
335
334
  this.query = value;
336
335
  }
336
+
337
+ @action viewOrder(order) {
338
+ return this.transitionToRoute('orders.index.view', order);
339
+ }
337
340
  }
@@ -1,12 +1,13 @@
1
1
  import ProductsIndexCategoryNewController from './new';
2
2
  import { tracked } from '@glimmer/tracking';
3
- import { alias } from '@ember/object/computed';
4
3
  import { action } from '@ember/object';
5
4
  import { inject as service } from '@ember/service';
5
+ import { task } from 'ember-concurrency';
6
+ import { filterHasManyForNewRecords } from '../../../../serializers/product';
6
7
 
7
8
  export default class ProductsIndexCategoryEditController extends ProductsIndexCategoryNewController {
8
- @alias('model') product;
9
9
  @service intl;
10
+ @tracked product;
10
11
  @tracked overlayActionButtonTitle = 'Save Changes';
11
12
  @tracked overlayActionButtonIcon = 'save';
12
13
  @tracked overlayExitButtonTitle = 'Done';
@@ -15,20 +16,15 @@ export default class ProductsIndexCategoryEditController extends ProductsIndexCa
15
16
  return `Edit ${this.product.name}`;
16
17
  }
17
18
 
18
- @action saveProduct() {
19
- this.isSaving = true;
20
-
21
- this.product
22
- .serializeMeta()
23
- .save()
24
- .then(() => {
25
- this.isSaving = false;
26
- this.notifications.success(this.intl.t('storefront.products.index.edit.changes-saved'));
27
- })
28
- .catch((error) => {
29
- this.isSaving = false;
30
- this.notifications.serverError(error);
31
- });
19
+ @task *saveProduct() {
20
+ let savedProduct;
21
+ try {
22
+ savedProduct = yield this.product.serializeMeta().save();
23
+ } catch (error) {
24
+ return this.notifications.serverError(error);
25
+ }
26
+ this.product = filterHasManyForNewRecords(savedProduct, ['variants', 'addon_categories', 'hours']);
27
+ this.notifications.success(this.intl.t('storefront.products.index.edit.changes-saved'));
32
28
  }
33
29
 
34
30
  @action transitionBack({ closeOverlay }) {
@@ -6,6 +6,7 @@ import { action } from '@ember/object';
6
6
  import { alias } from '@ember/object/computed';
7
7
  import { underscore } from '@ember/string';
8
8
  import { inject as service } from '@ember/service';
9
+ import { task } from 'ember-concurrency';
9
10
 
10
11
  export default class ProductsIndexCategoryNewController extends BaseController {
11
12
  @controller('products.index.category') productsIndexCategoryController;
@@ -40,6 +41,7 @@ export default class ProductsIndexCategoryNewController extends BaseController {
40
41
  onClick: this.addMetaField,
41
42
  },
42
43
  ];
44
+
43
45
  @tracked acceptedFileTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'video/mp4', 'video/quicktime', 'video/x-msvideo', 'video/x-flv', 'video/x-ms-wmv'];
44
46
 
45
47
  @action reset() {
@@ -48,32 +50,24 @@ export default class ProductsIndexCategoryNewController extends BaseController {
48
50
  this.uploadedFiles = [];
49
51
  }
50
52
 
51
- @action saveProduct() {
52
- const { category } = this.productsIndexCategoryController;
53
+ @task *saveProduct() {
53
54
  const loader = this.loader.showLoader('body', { loadingMessage: 'Creating new product...' });
54
- this.isSaving = true;
55
-
55
+ const { category } = this.productsIndexCategoryController;
56
56
  if (category) {
57
57
  this.product.set('category_uuid', category.id);
58
58
  }
59
59
 
60
- this.product
61
- .serializeMeta()
62
- .save()
63
- .then(() => {
64
- this.loader.removeLoader(loader);
65
- this.isSaving = false;
66
- this.notifications.success(this.intl.t('storefront.products.index.new.new-product-created-success'));
67
-
68
- this.transitionToRoute('products.index.category', category.slug).finally(() => {
69
- this.reset();
70
- });
71
- })
72
- .catch((error) => {
73
- this.loader.removeLoader(loader);
74
- this.isSaving = false;
75
- this.notifications.serverError(error);
76
- });
60
+ try {
61
+ yield this.product.serializeMeta().save();
62
+ } catch (error) {
63
+ this.loader.removeLoader(loader);
64
+ return this.notifications.serverError(error);
65
+ }
66
+
67
+ this.loader.removeLoader(loader);
68
+ this.notifications.success(this.intl.t('storefront.products.index.new.new-product-created-success'));
69
+ yield this.transitionToRoute('products.index.category', category.slug);
70
+ this.reset();
77
71
  }
78
72
 
79
73
  @action addTag(tag) {
@@ -166,7 +160,6 @@ export default class ProductsIndexCategoryNewController extends BaseController {
166
160
  }
167
161
 
168
162
  @action exit(closeOverlay) {
169
- console.log(closeOverlay, 'closeOverlay');
170
163
  return closeOverlay(() => {
171
164
  return this.transitionToRoute('products.index.category').then(() => {
172
165
  this.reset();
@@ -174,32 +167,34 @@ export default class ProductsIndexCategoryNewController extends BaseController {
174
167
  });
175
168
  }
176
169
 
177
- @action async selectAddonCategory() {
178
- this.modalsManager.displayLoader();
179
-
180
- const { product } = this;
181
- const addonCategories = await this.store.findAll('addon-category');
182
-
183
- return this.modalsManager.done().then(() => {
184
- this.modalsManager.show('modals/select-addon-category', {
185
- title: this.intl.t('storefront.products.index.new.select-addon-categories'),
186
- addonCategories,
187
- product,
188
- updateProductAddonCategories: (categories) => {
189
- this.product.addon_categories = categories.map((category) => {
190
- return this.store.createRecord('product-addon-category', {
191
- product_uuid: product.id,
192
- category_uuid: category.id,
193
- name: category.name,
194
- excluded_addons: [],
195
- category,
196
- });
197
- });
198
- },
199
- });
170
+ @task *promptSelectAddonCategories() {
171
+ const addonCategories = yield this.store.findAll('addon-category');
172
+ const selectedAddonCategories = this.product.addon_categories;
173
+ this.modalsManager.show('modals/select-addon-category', {
174
+ title: this.intl.t('storefront.products.index.new.select-addon-categories'),
175
+ selectedAddonCategories,
176
+ addonCategories,
177
+ updateProductAddonCategories: (addonCategories) => {
178
+ this.product.syncProductAddonCategories(addonCategories);
179
+ },
200
180
  });
201
181
  }
202
182
 
183
+ // @action selectAddonCategory() {
184
+ // this.store.findAll('addon-category')
185
+ // const addonCategories = await this.store.findAll('addon-category');
186
+
187
+ // await this.modalsManager.done();
188
+ // this.modalsManager.show('modals/select-addon-category', {
189
+ // title: this.intl.t('storefront.products.index.new.select-addon-categories'),
190
+ // addonCategories,
191
+ // selectedAddonCategories: this.product.addon_categories,
192
+ // updateProductAddonCategories: (addonCategories) => {
193
+ // this.product.syncProductAddonCategories(addonCategories);
194
+ // },
195
+ // });
196
+ // }
197
+
203
198
  @action createProductVariant() {
204
199
  const { product } = this;
205
200
  const productVariant = this.store.createRecord('product-variant');
@@ -33,11 +33,17 @@ export default class ProductsIndexController extends BaseController {
33
33
  return this.transitionToRoute('products.index.category.new');
34
34
  }
35
35
 
36
+ /**
37
+ * Toggles a dialog which allows user to manage addon categories and options.
38
+ *
39
+ * @memberof ProductsIndexController
40
+ */
36
41
  @action manageAddons() {
37
42
  this.modalsManager.show('modals/manage-addons', {
38
- title: this.intl.t('storefront.products.index.aside-scroller.title'),
43
+ title: this.intl.t('storefront.products.index.manage-addons-dialog.manage-addons-title'),
44
+ acceptButtonText: this.intl.t('storefront.products.index.manage-addons-dialog.manage-addons-accept-button'),
45
+ acceptButtonIcon: 'save',
39
46
  modalClass: 'modal-lg',
40
- acceptButtonText: this.intl.t('storefront.products.index.done'),
41
47
  store: this.activeStore,
42
48
  });
43
49
  }
@@ -0,0 +1,9 @@
1
+ import { helper } from '@ember/component/helper';
2
+
3
+ export default helper(function avatarUrl([url, defaultUrl = 'https://s3.ap-southeast-1.amazonaws.com/flb-assets/static/no-avatar.png']) {
4
+ if (typeof url === 'string') {
5
+ return url;
6
+ }
7
+
8
+ return defaultUrl;
9
+ });
@@ -17,7 +17,14 @@ export default class ProductVariantOptionModel extends Model {
17
17
 
18
18
  /** @methods */
19
19
  toJSON() {
20
- return this.serialize();
20
+ return {
21
+ uuid: this.id,
22
+ product_variant_uuid: this.product_variant_uuid,
23
+ name: this.name,
24
+ description: this.description,
25
+ additional_cost: this.additional_cost,
26
+ translations: this.additional_cost,
27
+ };
21
28
  }
22
29
 
23
30
  /** @computed */
@@ -1,12 +1,13 @@
1
1
  import Model, { attr, hasMany } from '@ember-data/model';
2
2
  import { format, formatDistanceToNow } from 'date-fns';
3
+ import { isArray } from '@ember/array';
3
4
 
4
5
  export default class ProductVariantModel extends Model {
5
6
  /** @ids */
6
7
  @attr('string') product_uuid;
7
8
 
8
9
  /** @relationships */
9
- @hasMany('product-variant-option') options;
10
+ @hasMany('product-variant-option', { async: false }) options;
10
11
 
11
12
  /** @attributes */
12
13
  @attr('string', { defaultValue: '' }) name;
@@ -21,7 +22,16 @@ export default class ProductVariantModel extends Model {
21
22
 
22
23
  /** @methods */
23
24
  toJSON() {
24
- return this.serialize();
25
+ return {
26
+ uuid: this.id,
27
+ product_uuid: this.product_uuid,
28
+ name: this.name,
29
+ description: this.description,
30
+ is_multiselect: this.is_multiselect,
31
+ is_required: this.is_required,
32
+ translations: this.translations,
33
+ options: isArray(this.options) ? Array.from(this.options) : [],
34
+ };
25
35
  }
26
36
 
27
37
  /** @computed */