@fleetbase/storefront-engine 0.4.0 → 0.4.2

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 (77) hide show
  1. package/addon/components/customer-panel/orders.hbs +2 -2
  2. package/addon/components/modals/create-gateway.hbs +33 -12
  3. package/addon/components/network-category-picker.js +1 -1
  4. package/addon/components/order-panel.hbs +1 -1
  5. package/addon/components/widget/customers.hbs +5 -2
  6. package/addon/components/widget/customers.js +14 -6
  7. package/addon/components/widget/orders.hbs +31 -10
  8. package/addon/components/widget/orders.js +7 -1
  9. package/addon/components/widget/storefront-key-metrics.js +2 -2
  10. package/addon/components/widget/storefront-metrics.hbs +11 -1
  11. package/addon/components/widget/storefront-metrics.js +103 -1
  12. package/addon/controllers/networks/index/network/index.js +2 -0
  13. package/addon/controllers/networks/index/network/stores.js +0 -1
  14. package/addon/controllers/products/index/category/new.js +13 -2
  15. package/addon/controllers/settings/gateways.js +6 -1
  16. package/addon/controllers/settings/index.js +1 -0
  17. package/addon/controllers/settings/notifications.js +4 -5
  18. package/addon/models/network.js +1 -0
  19. package/addon/models/store.js +1 -0
  20. package/addon/routes/networks/index/network/index.js +5 -0
  21. package/addon/routes/settings/index.js +5 -0
  22. package/addon/services/order-actions.js +31 -0
  23. package/addon/styles/storefront-engine.css +22 -0
  24. package/addon/templates/home.hbs +2 -2
  25. package/addon/templates/networks/index/network/index.hbs +21 -8
  26. package/addon/templates/networks/index/network/stores.hbs +8 -1
  27. package/addon/templates/products/index/category/new.hbs +149 -134
  28. package/addon/templates/settings/gateways.hbs +15 -4
  29. package/addon/templates/settings/index.hbs +13 -0
  30. package/addon/templates/settings/notifications.hbs +2 -2
  31. package/addon/utils/commerce-date-ranges.js +263 -0
  32. package/app/utils/commerce-date-ranges.js +1 -0
  33. package/composer.json +1 -1
  34. package/extension.json +1 -1
  35. package/package.json +4 -4
  36. package/server/migrations/2025_09_01_041353_add_default_order_config_column.php +110 -0
  37. package/server/src/Console/Commands/MigrateStripeSandboxCustomers.php +165 -0
  38. package/server/src/Expansions/OrderExpansion.php +43 -0
  39. package/server/src/Http/Controllers/NetworkController.php +1 -1
  40. package/server/src/Http/Controllers/OrderController.php +62 -9
  41. package/server/src/Http/Controllers/v1/CheckoutController.php +57 -48
  42. package/server/src/Http/Controllers/v1/ServiceQuoteController.php +19 -3
  43. package/server/src/Http/Middleware/SetStorefrontSession.php +8 -6
  44. package/server/src/Http/Resources/Customer.php +41 -17
  45. package/server/src/Http/Resources/Gateway.php +16 -11
  46. package/server/src/Http/Resources/Network.php +35 -34
  47. package/server/src/Http/Resources/NotificationChannel.php +17 -10
  48. package/server/src/Http/Resources/Product.php +1 -0
  49. package/server/src/Http/Resources/Store.php +36 -35
  50. package/server/src/Models/Customer.php +18 -2
  51. package/server/src/Models/FoodTruck.php +29 -2
  52. package/server/src/Models/Network.php +63 -1
  53. package/server/src/Models/Store.php +71 -9
  54. package/server/src/Notifications/StorefrontOrderAccepted.php +164 -0
  55. package/server/src/Notifications/StorefrontOrderCanceled.php +11 -1
  56. package/server/src/Notifications/StorefrontOrderCompleted.php +11 -1
  57. package/server/src/Notifications/StorefrontOrderDriverAssigned.php +12 -4
  58. package/server/src/Notifications/StorefrontOrderEnroute.php +12 -4
  59. package/server/src/Notifications/StorefrontOrderNearby.php +12 -4
  60. package/server/src/Notifications/StorefrontOrderPreparing.php +12 -4
  61. package/server/src/Notifications/StorefrontOrderReadyForPickup.php +12 -4
  62. package/server/src/Observers/OrderObserver.php +6 -4
  63. package/server/src/Providers/StorefrontServiceProvider.php +1 -0
  64. package/server/src/Rules/IsValidLocation.php +12 -0
  65. package/server/src/Support/PushNotification.php +20 -4
  66. package/server/src/Support/Storefront.php +283 -37
  67. package/server/src/routes.php +1 -0
  68. package/translations/{ar-ae.yml → ar-ae.yaml} +313 -253
  69. package/translations/bg-bg.yaml +734 -0
  70. package/translations/en-us.yaml +5 -0
  71. package/translations/es-es.yaml +732 -0
  72. package/translations/fr-fr.yaml +748 -0
  73. package/translations/mn-mn.yaml +725 -0
  74. package/translations/pt-br.yaml +732 -0
  75. package/translations/ru-ru.yaml +726 -0
  76. package/translations/vi-vn.yaml +412 -338
  77. package/translations/zh-cn.yaml +659 -0
@@ -41,7 +41,7 @@
41
41
  @onClick={{fn this.acceptOrder order}}
42
42
  />
43
43
  {{/if}}
44
- {{#if order.isPreparing}}
44
+ {{#if (eq order.status "accepted")}}
45
45
  <Button
46
46
  @size="xs"
47
47
  @type="success"
@@ -102,7 +102,7 @@
102
102
  @onClick={{fn this.acceptOrder order}}
103
103
  />
104
104
  {{/if}}
105
- {{#if order.isPreparing}}
105
+ {{#if (eq order.status "accepted")}}
106
106
  <Button @size="xs" @type="success" @icon="bell-concierge" @text={{t "storefront.component.widget.orders.mark-as-mark"}} @onClick={{fn this.markAsReady order}} />
107
107
  {{/if}}
108
108
  {{#if order.isPickupReady}}
@@ -2,7 +2,14 @@
2
2
  <div class="modal-body-container">
3
3
  <div class="mb-4 w-full">
4
4
  <InputGroup @name={{t "storefront.component.modals.create-getaway.getaway"}} @helpText={{t "storefront.component.modals.create-getaway.getaway-text"}}>
5
- <Select class="w-full" @placeholder="Select gateway type" @options={{@options.schemaOptions}} @onSelect={{@options.selectSchema}} @humanize={{true}} />
5
+ <Select
6
+ @value={{@options.gateway.code}}
7
+ class="w-full"
8
+ @placeholder="Select gateway type"
9
+ @options={{@options.schemaOptions}}
10
+ @onSelect={{@options.selectSchema}}
11
+ @humanize={{true}}
12
+ />
6
13
  </InputGroup>
7
14
  </div>
8
15
 
@@ -30,17 +37,31 @@
30
37
  </div>
31
38
  <div class="p-2 rounded-md my-2 border border-gray-200 dark:border-gray-800">
32
39
  <h4 class="mb-2 font-semibold text-sm dark:text-white">Config</h4>
33
- {{#each-in @options.schema as |key value|}}
34
- {{#if (is-bool-value value)}}
35
- <div class="input-group">
36
- <Checkbox @value={{value}} @label={{humanize key}} @onToggle={{fn @options.setConfigKey key}} />
37
- </div>
38
- {{else}}
39
- <InputGroup @name={{humanize key}}>
40
- <Input class="form-input w-full" placeholder={{humanize key}} @value={{value}} {{on "blur" (fn @options.setConfigKey key)}} />
41
- </InputGroup>
42
- {{/if}}
43
- {{/each-in}}
40
+ {{#if @options.gateway.isNew}}
41
+ {{#each-in @options.schema as |key value|}}
42
+ {{#if (is-bool-value value)}}
43
+ <div class="input-group">
44
+ <Checkbox @value={{value}} @label={{humanize key}} @onToggle={{fn @options.setConfigKey key}} />
45
+ </div>
46
+ {{else}}
47
+ <InputGroup @name={{humanize key}}>
48
+ <Input class="form-input w-full" placeholder={{humanize key}} @value={{value}} {{on "blur" (fn @options.setConfigKey key)}} />
49
+ </InputGroup>
50
+ {{/if}}
51
+ {{/each-in}}
52
+ {{else}}
53
+ {{#each-in @options.gateway.config as |key value|}}
54
+ {{#if (is-bool-value value)}}
55
+ <div class="input-group">
56
+ <Checkbox @value={{value}} @label={{humanize key}} @onToggle={{fn @options.setConfigKey key}} />
57
+ </div>
58
+ {{else}}
59
+ <InputGroup @name={{humanize key}}>
60
+ <Input class="form-input w-full" placeholder={{humanize key}} @value={{value}} {{on "blur" (fn @options.setConfigKey key)}} />
61
+ </InputGroup>
62
+ {{/if}}
63
+ {{/each-in}}
64
+ {{/if}}
44
65
  </div>
45
66
  {{/if}}
46
67
  </div>
@@ -58,7 +58,7 @@ export default class NetworkCategoryPickerComponent extends Component {
58
58
  const categories = yield this.store.query('category', queryParams);
59
59
  this.categories = categories.toArray();
60
60
  } catch (error) {
61
- debug(`Unable to load categories : ${error.message}`)
61
+ debug(`Unable to load categories : ${error.message}`);
62
62
  }
63
63
  }
64
64
 
@@ -18,7 +18,7 @@
18
18
  @onClick={{fn this.acceptOrder this.order}}
19
19
  />
20
20
  {{/if}}
21
- {{#if this.order.isPreparing}}
21
+ {{#if (eq this.order.status "accepted")}}
22
22
  <Button @size="xs" @type="success" @icon="bell-concierge" @text={{t "storefront.component.widget.orders.mark-as-ready"}} @onClick={{fn this.markAsReady this.order}} />
23
23
  {{/if}}
24
24
  {{#if this.order.isPickupReady}}
@@ -30,6 +30,9 @@
30
30
  @pad={{false}}
31
31
  @wrapperClass={{@wrapperClass}}
32
32
  >
33
+ <div class="flex justify-end px-4 py-2 space-x-2">
34
+ <Button @icon="refresh" @size="xs" @onClick={{perform this.loadCustomers}} />
35
+ </div>
33
36
  {{#if (media "isMobile")}}
34
37
  <div class="flex flex-col p-3 space-y-3">
35
38
  {{#each this.customers as |customer|}}
@@ -63,11 +66,11 @@
63
66
  <tbody>
64
67
  {{#each this.customers as |customer|}}
65
68
  <tr class="h-12">
66
- <td><a href="javascript:;" {{on "click" (fn this.viewCustomer customer)}}>{{customer.customerId}}</a></td>
69
+ <td><a href="javascript:;" {{on "click" (fn this.viewCustomer customer)}}>{{customer.public_id}}</a></td>
67
70
  <td>{{n-a customer.name}}</td>
68
71
  <td>{{n-a customer.phone}}</td>
69
72
  <td>{{n-a customer.email}}</td>
70
- <td></td>
73
+ <td>{{n-a customer.orders 0}}</td>
71
74
  <td></td>
72
75
  </tr>
73
76
  {{/each}}
@@ -7,6 +7,7 @@ import { task } from 'ember-concurrency';
7
7
 
8
8
  export default class WidgetCustomersComponent extends Component {
9
9
  @service store;
10
+ @service fetch;
10
11
  @service storefront;
11
12
  @service intl;
12
13
  @service contextPanel;
@@ -34,17 +35,24 @@ export default class WidgetCustomersComponent extends Component {
34
35
  const storefront = get(this.storefront, 'activeStore.public_id');
35
36
 
36
37
  try {
37
- const customers = yield this.store.query('customer', {
38
- storefront,
39
- limit: 14,
40
- ...params,
41
- });
38
+ const { customers } = yield this.fetch.get(
39
+ 'customers',
40
+ {
41
+ storefront,
42
+ limit: 14,
43
+ ...params,
44
+ },
45
+ {
46
+ namespace: 'storefront/int/v1',
47
+ }
48
+ );
49
+
42
50
  this.loaded = true;
43
51
  this.customers = customers;
44
52
 
45
53
  return customers;
46
54
  } catch (err) {
47
- debug('Error loading customers for widget:', err);
55
+ debug('Error loading customers for widget:', err.message);
48
56
  }
49
57
  }
50
58
  }
@@ -25,12 +25,13 @@
25
25
  @titleStatusRight={{this.orders.length}}
26
26
  @titleStatuRightClass="info-status-badge"
27
27
  @hideStatusDot={{true}}
28
- @open={{gt this.orders.length 0}}
28
+ @open={{true}}
29
29
  @isLoading={{this.loadOrders.isRunning}}
30
30
  @pad={{false}}
31
31
  @wrapperClass={{@wrapperClass}}
32
32
  >
33
- <div class="flex justify-end px-4 py-2">
33
+ <div class="flex justify-end px-4 py-2 space-x-2">
34
+ <Button @icon="refresh" @size="xs" @onClick={{perform this.loadOrders}} />
34
35
  <Toggle @label="Active Orders Filter" @isToggled={{this.activeFilter}} @onToggle={{this.toggleActiveFilter}} />
35
36
  </div>
36
37
  {{#if (media "isMobile")}}
@@ -86,14 +87,25 @@
86
87
  @onClick={{fn this.acceptOrder order}}
87
88
  />
88
89
  {{/if}}
89
- {{#if order.isPreparing}}
90
+ {{#if (eq order.status "started")}}
90
91
  <Button
91
92
  @wrapperClass="w-full"
92
93
  class="btn-block w-full"
93
94
  @size="xs"
94
95
  @type="success"
95
96
  @icon="bell-concierge"
96
- @text={{t "storefront.component.widget.orders.mark-as-ready"}}
97
+ @text={{t "storefront.component.widget.orders.mark-as-preparing"}}
98
+ @onClick={{fn this.markAsPreparing order}}
99
+ />
100
+ {{/if}}
101
+ {{#if (eq order.status "accepted")}}
102
+ <Button
103
+ @wrapperClass="w-full"
104
+ class="btn-block w-full"
105
+ @size="xs"
106
+ @type={{if order.meta.is_pickup "success" "magic"}}
107
+ @icon={{if order.meta.is_pickup "bell-concierge" "paper-plane"}}
108
+ @text={{if order.meta.is_pickup (t "storefront.component.widget.orders.mark-as-ready") (t "storefront.component.widget.orders.dispatch")}}
97
109
  @onClick={{fn this.markAsReady order}}
98
110
  />
99
111
  {{/if}}
@@ -226,11 +238,11 @@
226
238
  <tr class="h-12 text-left py-1">
227
239
  <th style={{"width: 15%"}}>{{t "storefront.component.widget.orders.id-column"}}</th>
228
240
  <th style={{"width: 10%"}}>{{t "storefront.common.amount"}}</th>
229
- <th style={{"width: 15%"}}>{{t "storefront.common.customer"}}</th>
230
- <th style={{"width: 15%"}}>{{t "storefront.common.driver"}}</th>
241
+ <th style={{"width: 14%"}}>{{t "storefront.common.customer"}}</th>
242
+ <th style={{"width: 14%"}}>{{t "storefront.common.driver"}}</th>
231
243
  <th style={{"width: 10%"}}>{{t "storefront.common.created"}}</th>
232
244
  <th style={{"width: 15%"}}>{{t "storefront.common.status"}}</th>
233
- <th style={{"width: 22%"}}></th>
245
+ <th style={{"width: 24%"}}></th>
234
246
  </tr>
235
247
  </thead>
236
248
  <tbody>
@@ -264,12 +276,21 @@
264
276
  @onClick={{fn this.acceptOrder order}}
265
277
  />
266
278
  {{/if}}
267
- {{#if order.isPreparing}}
279
+ {{#if (eq order.status "started")}}
268
280
  <Button
269
281
  @size="xs"
270
282
  @type="success"
271
- @icon="bell-concierge"
272
- @text={{t "storefront.component.widget.orders.mark-as-ready"}}
283
+ @icon="hourglass-start"
284
+ @text={{t "storefront.component.widget.orders.mark-as-preparing"}}
285
+ @onClick={{fn this.markAsPreparing order}}
286
+ />
287
+ {{/if}}
288
+ {{#if (eq order.status "accepted")}}
289
+ <Button
290
+ @size="xs"
291
+ @type={{if order.meta.is_pickup "success" "magic"}}
292
+ @icon={{if order.meta.is_pickup "bell-concierge" "paper-plane"}}
293
+ @text={{if order.meta.is_pickup (t "storefront.component.widget.orders.mark-as-ready") (t "storefront.component.widget.orders.dispatch")}}
273
294
  @onClick={{fn this.markAsReady order}}
274
295
  />
275
296
  {{/if}}
@@ -66,7 +66,7 @@ export default class WidgetOrdersComponent extends Component {
66
66
 
67
67
  return orders;
68
68
  } catch (err) {
69
- debug('Error loading orders for widget:', err);
69
+ debug('Error loading orders for widget:', err.message);
70
70
  }
71
71
  }
72
72
 
@@ -113,6 +113,12 @@ export default class WidgetOrdersComponent extends Component {
113
113
  });
114
114
  }
115
115
 
116
+ @action markAsPreparing(order) {
117
+ this.orderActions.markAsPreparing(order, () => {
118
+ this.loadOrders.perform();
119
+ });
120
+ }
121
+
116
122
  @action markAsCompleted(order) {
117
123
  this.orderActions.markAsCompleted(order, () => {
118
124
  this.loadOrders.perform();
@@ -39,8 +39,8 @@ export default class WidgetStorefrontKeyMetricsComponent extends Component {
39
39
  *
40
40
  * @memberof WidgetKeyMetricsComponent
41
41
  */
42
- @task *getDashboardMetrics() {
43
- this.metrics = yield this.fetch.get('metrics', {}, { namespace: 'storefront/int/v1' }).then((response) => {
42
+ @task *getDashboardMetrics(params = {}) {
43
+ this.metrics = yield this.fetch.get('metrics', params, { namespace: 'storefront/int/v1' }).then((response) => {
44
44
  return this.createMetricsMapFromResponse(response);
45
45
  });
46
46
  }
@@ -2,7 +2,7 @@
2
2
  <div class="flex items-center justify-between">
3
3
  <div class="flex items-center">
4
4
  <h3 class="text-lg leading-6 font-medium text-gray-900 dark:text-gray-100 mr-2">
5
- {{t "storefront.component.widget.storefront-metrics.last-day"}}
5
+ Metrics
6
6
  </h3>
7
7
  {{#if this.loadMetrics.isRunning}}
8
8
  <div>
@@ -10,6 +10,16 @@
10
10
  </div>
11
11
  {{/if}}
12
12
  </div>
13
+ <div class="storefront-datepicker">
14
+ <DatePicker
15
+ @value={{concat this.start "," this.end}}
16
+ @range={{true}}
17
+ @buttons={{this.datePickerButtons}}
18
+ @onSelect={{this.selectDates}}
19
+ placeholder="Select date range"
20
+ class="min-w-250px"
21
+ />
22
+ </div>
13
23
  </div>
14
24
  <dl class="mt-4 grid grid-cols-2 gap-5 sm:grid-cols-4">
15
25
  <div class="px-4 py-5 border border-gray-200 dark:border-gray-900 bg-gray-50 dark:bg-gray-700 shadow-sm dark:shadow rounded-lg overflow-hidden sm:p-6">
@@ -1,10 +1,11 @@
1
1
  import Component from '@glimmer/component';
2
2
  import { tracked } from '@glimmer/tracking';
3
3
  import { inject as service } from '@ember/service';
4
- import { get } from '@ember/object';
4
+ import { get, action } from '@ember/object';
5
5
  import { debug } from '@ember/debug';
6
6
  import { startOfMonth, endOfMonth, format } from 'date-fns';
7
7
  import { task } from 'ember-concurrency';
8
+ import { getDateRangeByLabel } from '../../utils/commerce-date-ranges';
8
9
 
9
10
  export default class WidgetStorefrontMetricsComponent extends Component {
10
11
  @service fetch;
@@ -18,6 +19,98 @@ export default class WidgetStorefrontMetricsComponent extends Component {
18
19
  stores_count: 0,
19
20
  earnings_sum: 0,
20
21
  };
22
+ @tracked datePickerButtons = [
23
+ {
24
+ content: 'Yesterday',
25
+ className: 'quick-select-btn',
26
+ onClick: (datepicker) => {
27
+ const thisMonthRange = getDateRangeByLabel('Yesterday');
28
+ if (thisMonthRange) {
29
+ datepicker.selectDate(thisMonthRange);
30
+ }
31
+ },
32
+ },
33
+ {
34
+ content: 'Last 7 Days',
35
+ className: 'quick-select-btn',
36
+ onClick: (datepicker) => {
37
+ const thisMonthRange = getDateRangeByLabel('Last 7 Days');
38
+ if (thisMonthRange) {
39
+ datepicker.selectDate(thisMonthRange);
40
+ }
41
+ },
42
+ },
43
+ {
44
+ content: 'Last Week',
45
+ className: 'quick-select-btn',
46
+ onClick: (datepicker) => {
47
+ const thisMonthRange = getDateRangeByLabel('Last Week');
48
+ if (thisMonthRange) {
49
+ datepicker.selectDate(thisMonthRange);
50
+ }
51
+ },
52
+ },
53
+ {
54
+ content: 'This Month',
55
+ className: 'quick-select-btn',
56
+ onClick: (datepicker) => {
57
+ const thisMonthRange = getDateRangeByLabel('This Month');
58
+ if (thisMonthRange) {
59
+ datepicker.selectDate(thisMonthRange);
60
+ }
61
+ },
62
+ },
63
+ {
64
+ content: 'Last Month',
65
+ className: 'quick-select-btn',
66
+ onClick: (datepicker) => {
67
+ const thisMonthRange = getDateRangeByLabel('Last Month');
68
+ if (thisMonthRange) {
69
+ datepicker.selectDate(thisMonthRange);
70
+ }
71
+ },
72
+ },
73
+ {
74
+ content: 'This Quarter',
75
+ className: 'quick-select-btn',
76
+ onClick: (datepicker) => {
77
+ const thisMonthRange = getDateRangeByLabel('This Quarter');
78
+ if (thisMonthRange) {
79
+ datepicker.selectDate(thisMonthRange);
80
+ }
81
+ },
82
+ },
83
+ {
84
+ content: 'Last Quarter',
85
+ className: 'quick-select-btn',
86
+ onClick: (datepicker) => {
87
+ const thisMonthRange = getDateRangeByLabel('Last Quarter');
88
+ if (thisMonthRange) {
89
+ datepicker.selectDate(thisMonthRange);
90
+ }
91
+ },
92
+ },
93
+ {
94
+ content: 'This Year',
95
+ className: 'quick-select-btn',
96
+ onClick: (datepicker) => {
97
+ const thisMonthRange = getDateRangeByLabel('This Year');
98
+ if (thisMonthRange) {
99
+ datepicker.selectDate(thisMonthRange);
100
+ }
101
+ },
102
+ },
103
+ {
104
+ content: 'Last Year',
105
+ className: 'quick-select-btn',
106
+ onClick: (datepicker) => {
107
+ const thisMonthRange = getDateRangeByLabel('Last Year');
108
+ if (thisMonthRange) {
109
+ datepicker.selectDate(thisMonthRange);
110
+ }
111
+ },
112
+ },
113
+ ];
21
114
 
22
115
  constructor(owner, { title = 'This Month' }) {
23
116
  super(...arguments);
@@ -42,4 +135,13 @@ export default class WidgetStorefrontMetricsComponent extends Component {
42
135
  debug('Error loading storefront metrics:', err);
43
136
  }
44
137
  }
138
+
139
+ @action selectDates({ formattedDate }) {
140
+ const [start, end] = formattedDate;
141
+ this.start = start;
142
+ this.end = end;
143
+ if (start && end) {
144
+ this.loadMetrics.perform(start, end);
145
+ }
146
+ }
45
147
  }
@@ -70,6 +70,8 @@ export default class NetworksIndexNetworkIndexController extends Controller {
70
70
  */
71
71
  @tracked isLoading = false;
72
72
 
73
+ @tracked orderConfigs = [];
74
+
73
75
  /**
74
76
  * Alias for model.gateways, representing the gateways associated with the network.
75
77
  *
@@ -3,7 +3,6 @@ import { tracked } from '@glimmer/tracking';
3
3
  import { inject as service } from '@ember/service';
4
4
  import { action, set } from '@ember/object';
5
5
  import { isBlank } from '@ember/utils';
6
- import { debug } from '@ember/debug';
7
6
  import { timeout, task } from 'ember-concurrency';
8
7
  import createShareableLink from '../../../../utils/create-shareable-link';
9
8
  import isEmail from '@fleetbase/ember-core/utils/is-email';
@@ -21,7 +21,14 @@ export default class ProductsIndexCategoryNewController extends BaseController {
21
21
  @service crud;
22
22
  @service hostRouter;
23
23
  @alias('storefront.activeStore') activeStore;
24
- @tracked product = this.store.createRecord('product', { store_uuid: this.activeStore.id, currency: this.activeStore.currency, tags: [], meta_array: [], status: 'published' });
24
+ @tracked product = this.store.createRecord('product', {
25
+ store_uuid: this.activeStore.id,
26
+ currency: this.activeStore.currency,
27
+ tags: [],
28
+ meta_array: [],
29
+ category: this.category,
30
+ status: 'published',
31
+ });
25
32
  @tracked uploadQueue = [];
26
33
  @tracked uploadedFiles = [];
27
34
  @tracked primaryFile = null;
@@ -29,6 +36,10 @@ export default class ProductsIndexCategoryNewController extends BaseController {
29
36
  @tracked statusOptions = ['published', 'draft'];
30
37
  abilityPermission = 'storefront create product';
31
38
 
39
+ get category() {
40
+ return this.productsIndexCategoryController?.category ?? null;
41
+ }
42
+
32
43
  /** overlay options */
33
44
  @tracked overlayTitle = 'New Product';
34
45
  @tracked overlayActionButtonTitle = 'Create Product';
@@ -47,7 +58,7 @@ export default class ProductsIndexCategoryNewController extends BaseController {
47
58
  @tracked acceptedFileTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'video/mp4', 'video/quicktime', 'video/x-msvideo', 'video/x-flv', 'video/x-ms-wmv'];
48
59
 
49
60
  @action reset() {
50
- this.product = this.store.createRecord('product', { store_uuid: this.activeStore.id, currency: this.activeStore.currency });
61
+ this.product = this.store.createRecord('product', { store_uuid: this.activeStore.id, category: this.category, currency: this.activeStore.currency });
51
62
  this.uploadQueue = [];
52
63
  this.uploadedFiles = [];
53
64
  }
@@ -43,10 +43,15 @@ export default class SettingsGatewaysController extends Controller {
43
43
  const schemas = getGatewaySchemas();
44
44
  const schemaOptions = Object.keys(schemas);
45
45
 
46
+ let schema = null;
47
+ if (!gateway.get('isNew')) {
48
+ schema = schemas[gateway.code];
49
+ }
50
+
46
51
  this.modalsManager.show('modals/create-gateway', {
47
52
  title: this.intl.t('storefront.settings.gateways.edit-payment-gateway'),
48
53
  acceptButtonText: this.intl.t('storefront.settings.gateways.save-changes'),
49
- schema: null,
54
+ schema,
50
55
  schemas,
51
56
  schemaOptions,
52
57
  gateway,
@@ -17,6 +17,7 @@ export default class SettingsIndexController extends Controller {
17
17
  @tracked isLoading = false;
18
18
  @tracked uploadQueue = [];
19
19
  @tracked uploadedFiles = [];
20
+ @tracked orderConfigs = [];
20
21
 
21
22
  @action addTag(tag) {
22
23
  if (!isArray(this.model.tags)) {
@@ -1,5 +1,4 @@
1
1
  import Controller from '@ember/controller';
2
- import { tracked } from '@glimmer/tracking';
3
2
  import { inject as service } from '@ember/service';
4
3
  import { alias } from '@ember/object/computed';
5
4
  import { action, set } from '@ember/object';
@@ -13,8 +12,8 @@ export default class SettingsNotificationsController extends Controller {
13
12
  @service intl;
14
13
  @service crud;
15
14
  @service storefront;
15
+ @service hostRouter;
16
16
  @alias('storefront.activeStore') activeStore;
17
- @tracked channels = [];
18
17
 
19
18
  @action createChannel() {
20
19
  const channel = this.store.createRecord('notification-channel', {
@@ -71,9 +70,9 @@ export default class SettingsNotificationsController extends Controller {
71
70
 
72
71
  return channel
73
72
  .save()
74
- .then((channel) => {
73
+ .then(() => {
75
74
  this.notifications.success(this.intl.t('storefront.settings.notification.new-notification-channel-added'));
76
- this.channels.pushObject(channel);
75
+ this.hostRouter.refresh();
77
76
  })
78
77
  .catch((error) => {
79
78
  // gateway.rollbackAttributes();
@@ -94,7 +93,7 @@ export default class SettingsNotificationsController extends Controller {
94
93
 
95
94
  return channel.destroyRecord().then(() => {
96
95
  // justincase
97
- this.channels.removeObject(channel);
96
+ this.hostRouter.refresh();
98
97
  modal.stopLoading();
99
98
  });
100
99
  },
@@ -10,6 +10,7 @@ export default class NetworkModel extends Model {
10
10
  @attr('string') company_uuid;
11
11
  @attr('string') logo_uuid;
12
12
  @attr('string') backdrop_uuid;
13
+ @attr('string') order_config_uuid;
13
14
 
14
15
  /** @relationships */
15
16
  @hasMany('store') stores;
@@ -11,6 +11,7 @@ export default class StoreModel extends Model {
11
11
  @attr('string') company_uuid;
12
12
  @attr('string') logo_uuid;
13
13
  @attr('string') backdrop_uuid;
14
+ @attr('string') order_config_uuid;
14
15
 
15
16
  /** @relationships */
16
17
  @hasMany('notification-channel') notification_channels;
@@ -7,4 +7,9 @@ export default class NetworksIndexNetworkIndexRoute extends Route {
7
7
  model() {
8
8
  return this.modelFor('networks.index.network');
9
9
  }
10
+
11
+ async setupController(controller) {
12
+ super.setupController(...arguments);
13
+ controller.orderConfigs = await this.store.findAll('order-config');
14
+ }
10
15
  }
@@ -24,4 +24,9 @@ export default class SettingsIndexRoute extends Route {
24
24
  afterModel(model) {
25
25
  model?.loadFiles();
26
26
  }
27
+
28
+ async setupController(controller) {
29
+ super.setupController(...arguments);
30
+ controller.orderConfigs = await this.store.findAll('order-config');
31
+ }
27
32
  }
@@ -215,6 +215,37 @@ export default class OrderActionsService extends Service {
215
215
  });
216
216
  }
217
217
 
218
+ markAsPreparing(order, callback) {
219
+ this.modalsManager.confirm({
220
+ title: this.intl.t('storefront.component.widget.orders.mark-as-preparing-modal-title'),
221
+ body: this.intl.t('storefront.component.widget.orders.mark-as-preparing-modal-body'),
222
+ acceptButtonText: this.intl.t('storefront.component.widget.orders.mark-as-preparing-accept-button-text'),
223
+ acceptButtonIcon: 'check',
224
+ acceptButtonScheme: 'success',
225
+ confirm: async (modal) => {
226
+ modal.startLoading();
227
+
228
+ try {
229
+ await this.fetch.post('orders/preparing', { order: order.id }, { namespace: 'storefront/int/v1' });
230
+ modal.done();
231
+ if (typeof callback === 'function') {
232
+ callback(order);
233
+ }
234
+ } catch (err) {
235
+ this.notifications.serverError(err);
236
+ } finally {
237
+ modal.stopLoading();
238
+ }
239
+ },
240
+ decline: async (modal) => {
241
+ if (typeof callback === 'function') {
242
+ callback(order);
243
+ }
244
+ modal.done();
245
+ },
246
+ });
247
+ }
248
+
218
249
  markAsCompleted(order, callback) {
219
250
  this.modalsManager.confirm({
220
251
  title: this.intl.t('storefront.component.widget.orders.mark-as-completed-modal-title'),