@fleetbase/storefront-engine 0.3.18 → 0.3.21

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 (81) hide show
  1. package/addon/components/customer-panel/orders.hbs +107 -104
  2. package/addon/components/customer-panel/orders.js +52 -45
  3. package/addon/components/modals/incoming-order.hbs +208 -199
  4. package/addon/components/modals/order-ready-assign-driver.hbs +1 -1
  5. package/addon/components/order-panel/details.js +0 -2
  6. package/addon/components/order-panel.hbs +314 -1
  7. package/addon/components/order-panel.js +51 -3
  8. package/addon/components/widget/customers.hbs +75 -51
  9. package/addon/components/widget/customers.js +29 -41
  10. package/addon/components/widget/orders.hbs +278 -119
  11. package/addon/components/widget/orders.js +75 -80
  12. package/addon/components/widget/storefront-metrics.hbs +3 -6
  13. package/addon/components/widget/storefront-metrics.js +25 -41
  14. package/addon/controllers/orders/index.js +214 -105
  15. package/addon/controllers/settings/gateways.js +1 -1
  16. package/addon/helpers/get-tip-amount.js +13 -2
  17. package/addon/routes/application.js +2 -4
  18. package/addon/services/order-actions.js +248 -0
  19. package/addon/services/storefront.js +2 -0
  20. package/addon/styles/storefront-engine.css +48 -0
  21. package/addon/templates/home.hbs +2 -1
  22. package/addon/templates/orders/index/view.hbs +1 -1
  23. package/addon/templates/orders/index.hbs +26 -3
  24. package/addon/templates/products/index/index.hbs +28 -28
  25. package/addon/templates/settings.hbs +1 -1
  26. package/app/services/order-actions.js +1 -0
  27. package/composer.json +1 -1
  28. package/extension.json +1 -1
  29. package/package.json +1 -1
  30. package/server/config/storefront.php +20 -0
  31. package/server/migrations/2023_05_03_025307_create_carts_table.php +1 -1
  32. package/server/migrations/2023_05_03_025307_create_checkouts_table.php +1 -1
  33. package/server/migrations/2023_05_03_025307_create_gateways_table.php +1 -1
  34. package/server/migrations/2023_05_03_025307_create_network_stores_table.php +1 -1
  35. package/server/migrations/2023_05_03_025307_create_networks_table.php +1 -1
  36. package/server/migrations/2023_05_03_025307_create_notification_channels_table.php +1 -1
  37. package/server/migrations/2023_05_03_025307_create_payment_methods_table.php +1 -1
  38. package/server/migrations/2023_05_03_025307_create_product_addon_categories_table.php +1 -1
  39. package/server/migrations/2023_05_03_025307_create_product_addons_table.php +1 -1
  40. package/server/migrations/2023_05_03_025307_create_product_hours_table.php +1 -1
  41. package/server/migrations/2023_05_03_025307_create_product_store_locations_table.php +1 -1
  42. package/server/migrations/2023_05_03_025307_create_product_variant_options_table.php +1 -1
  43. package/server/migrations/2023_05_03_025307_create_product_variants_table.php +1 -1
  44. package/server/migrations/2023_05_03_025307_create_products_table.php +1 -1
  45. package/server/migrations/2023_05_03_025307_create_reviews_table.php +1 -1
  46. package/server/migrations/2023_05_03_025307_create_store_hours_table.php +1 -1
  47. package/server/migrations/2023_05_03_025307_create_store_locations_table.php +1 -1
  48. package/server/migrations/2023_05_03_025307_create_stores_table.php +1 -1
  49. package/server/migrations/2023_05_03_025307_create_votes_table.php +1 -1
  50. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_carts_table.php +1 -1
  51. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_checkouts_table.php +1 -1
  52. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_gateways_table.php +1 -1
  53. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_network_stores_table.php +1 -1
  54. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_networks_table.php +1 -1
  55. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_notification_channels_table.php +1 -1
  56. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_payment_methods_table.php +1 -1
  57. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_addon_categories_table.php +1 -1
  58. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_addons_table.php +1 -1
  59. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_hours_table.php +1 -1
  60. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_store_locations_table.php +1 -1
  61. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_variant_options_table.php +1 -1
  62. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_variants_table.php +1 -1
  63. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_products_table.php +1 -1
  64. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_reviews_table.php +1 -1
  65. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_store_hours_table.php +1 -1
  66. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_store_locations_table.php +1 -1
  67. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_stores_table.php +1 -1
  68. package/server/migrations/2023_05_03_025310_add_foreign_keys_to_votes_table.php +1 -1
  69. package/server/src/Http/Controllers/ActionController.php +2 -1
  70. package/server/src/Http/Controllers/OrderController.php +15 -2
  71. package/server/src/Http/Controllers/v1/CheckoutController.php +12 -12
  72. package/server/src/Http/Controllers/v1/CustomerController.php +15 -7
  73. package/server/src/Http/Controllers/v1/ServiceQuoteController.php +5 -5
  74. package/server/src/Http/Requests/CreateCustomerRequest.php +4 -0
  75. package/server/src/Http/Requests/InitializeCheckoutRequest.php +2 -1
  76. package/server/src/Http/Resources/Cart.php +1 -1
  77. package/server/src/Models/Store.php +2 -2
  78. package/server/src/Observers/OrderObserver.php +7 -1
  79. package/server/src/Rules/IsValidLocation.php +2 -2
  80. package/server/src/Support/Storefront.php +34 -0
  81. package/translations/en-us.yaml +6 -1
@@ -2,36 +2,35 @@
2
2
  <Layout::Section::Header @title={{t "storefront.common.orders"}} @onSearch={{this.search}} />
3
3
 
4
4
  <Layout::Section::Body>
5
- <div class="p-4">
6
-
7
- {{#if this.isLoading}}
8
- <div class="px-3 py-2">
9
- <Spinner class="text-sky-400" />
10
- </div>
11
- {{/if}}
12
- <div class="hidden md:flex table-wrapper table-fluid">
13
- <table>
14
- <thead>
15
- <tr class="h-12 text-left py-1">
16
- <th>{{t "storefront.component.widget.orders.id-column"}}</th>
17
- <th>{{t "storefront.common.amount"}}</th>
18
- <th>{{t "storefront.common.driver"}}</th>
19
- <th>{{t "storefront.common.created"}}</th>
20
- <th>{{t "storefront.common.status"}}</th>
21
- <th></th>
22
- </tr>
23
- </thead>
24
- <tbody>
25
- {{#each this.orders as |order|}}
26
- <tr class="h-12">
27
- <td><a href="javascript:;" {{on "click" (fn this.viewOrder order)}}>{{order.public_id}}</a></td>
28
- <td>{{format-currency order.meta.total order.meta.currency}}</td>
29
- <td>{{n-a order.driver_name}}</td>
30
- <td>{{order.createdAgo}}</td>
31
- <td>
32
- <Badge @status={{order.status}} />
33
- </td>
34
- <td>
5
+ {{#if this.loadOrders.isRunning}}
6
+ <div class="px-3 py-2">
7
+ <Spinner class="text-sky-400" />
8
+ </div>
9
+ {{/if}}
10
+ <div class="hidden md:flex table-wrapper table-fluid">
11
+ <table>
12
+ <thead>
13
+ <tr class="h-12 text-left py-1">
14
+ <th>{{t "storefront.component.widget.orders.id-column"}}</th>
15
+ <th>{{t "storefront.common.amount"}}</th>
16
+ <th>{{t "storefront.common.driver"}}</th>
17
+ <th>{{t "storefront.common.created"}}</th>
18
+ <th>{{t "storefront.common.status"}}</th>
19
+ <th></th>
20
+ </tr>
21
+ </thead>
22
+ <tbody>
23
+ {{#each this.orders as |order|}}
24
+ <tr class="h-12">
25
+ <td><a href="javascript:;" {{on "click" (fn this.viewOrder order)}}>{{order.public_id}}</a></td>
26
+ <td>{{format-currency order.meta.total order.meta.currency}}</td>
27
+ <td>{{n-a order.driver_name}}</td>
28
+ <td>{{order.createdAgo}}</td>
29
+ <td>
30
+ <Badge @status={{order.status}} />
31
+ </td>
32
+ <td>
33
+ <div>
35
34
  {{#if order.isFresh}}
36
35
  <Button
37
36
  @size="xs"
@@ -43,7 +42,7 @@
43
42
  />
44
43
  {{/if}}
45
44
  {{#if order.isPreparing}}
46
- <Button @size="xs" @type="success" @icon="bells" @text={{t "storefront.component.widget.orders.mark-as-ready"}} @onClick={{fn this.markAsReady order}} />
45
+ <Button @size="xs" @type="success" @icon="bell-concierge" @text={{t "storefront.component.widget.orders.mark-as-ready"}} @onClick={{fn this.markAsReady order}} />
47
46
  {{/if}}
48
47
  {{#if order.isPickupReady}}
49
48
  <Button
@@ -54,87 +53,91 @@
54
53
  @onClick={{fn this.markAsCompleted order}}
55
54
  />
56
55
  {{/if}}
57
- </td>
58
- </tr>
59
- {{/each}}
60
- </tbody>
61
- </table>
62
- </div>
63
- <div class="flex flex-col md:hidden p-3 space-y-3">
64
- {{#each this.orders as |order|}}
65
- <div class="py-2 px-3 rounded-md border border-gray-400 dark:border-gray-700">
66
- <div class="flex flex-row mb-3">
67
- <div class="flex-1">
68
- <a href="javascript:;" {{on "click" (fn this.viewOrder order)}} class="font-semibold">{{order.public_id}}</a>
69
- <div>{{order.createdAt}}</div>
70
- <div>{{order.createdAgo}}</div>
71
- </div>
72
- <div class="flex-shrink-0 flex flex-col text-right">
73
- <Badge class="mb-1" @status={{order.status}} />
74
- <div>{{format-currency order.meta.total order.meta.currency}}</div>
75
- </div>
56
+ </div>
57
+ <div>
58
+ <Button @size="xs" @type="danger" @icon="ban" @text="Cancel" @onClick={{fn this.cancelOrder order}} />
59
+ </div>
60
+ </td>
61
+ </tr>
62
+ {{/each}}
63
+ </tbody>
64
+ </table>
65
+ </div>
66
+ <div class="flex flex-col md:hidden p-3 space-y-3">
67
+ {{#each this.orders as |order|}}
68
+ <div class="py-2 px-3 rounded-md border border-gray-400 dark:border-gray-700">
69
+ <div class="flex flex-row mb-3">
70
+ <div class="flex-1">
71
+ <a href="javascript:;" {{on "click" (fn this.viewOrder order)}} class="font-semibold">{{order.public_id}}</a>
72
+ <div>{{order.createdAt}}</div>
73
+ <div>{{order.createdAgo}}</div>
74
+ </div>
75
+ <div class="flex-shrink-0 flex flex-col text-right">
76
+ <Badge class="mb-1" @status={{order.status}} />
77
+ <div>{{format-currency order.meta.total order.meta.currency}}</div>
76
78
  </div>
77
- <div class="flex flex-row space-x-2 flex-wrap">
78
- <Button @size="xs" @type="primary" @icon="eye" @text={{t "storefront.common.view"}} @onClick={{fn this.viewOrder order}} />
79
+ </div>
80
+ <div class="flex flex-row space-x-2 flex-wrap">
81
+ <Button @size="xs" @type="primary" @icon="eye" @text={{t "storefront.common.view"}} @onClick={{fn this.viewOrder order}} />
82
+ <Button
83
+ @size="xs"
84
+ @type="default"
85
+ @icon="id-card"
86
+ @text={{if order.has_driver_assigned (t "storefront.component.widget.order.change-driver") (t "storefront.component.widget.order.assign-driver")}}
87
+ @onClick={{fn this.assignDriver order}}
88
+ />
89
+ {{#if order.isFresh}}
79
90
  <Button
80
91
  @size="xs"
81
- @type="default"
82
- @icon="steering-wheel"
83
- @text={{if order.has_driver_assigned (t "storefront.component.widget.order.change-driver") (t "storefront.component.widget.order.assign-driver")}}
84
- @onClick={{fn this.assignDriver order}}
92
+ @type="success"
93
+ @iconPrefix="fas"
94
+ @icon="check"
95
+ @text={{concat (t "storefront.component.widget.orders.accept-order") "!"}}
96
+ @onClick={{fn this.acceptOrder order}}
85
97
  />
86
- {{#if order.isFresh}}
87
- <Button
88
- @size="xs"
89
- @type="success"
90
- @iconPrefix="fas"
91
- @icon="check"
92
- @text={{concat (t "storefront.component.widget.orders.accept-order") "!"}}
93
- @onClick={{fn this.acceptOrder order}}
94
- />
95
- {{/if}}
96
- {{#if order.isPreparing}}
97
- <Button @size="xs" @type="success" @icon="bells" @text={{t "storefront.component.widget.orders.mark-as-mark"}} @onClick={{fn this.markAsReady order}} />
98
- {{/if}}
99
- {{#if order.isPickupReady}}
100
- <Button @size="xs" @type="success" @icon="check" @text={{t "storefront.component.widget.orders.mark-as-completed"}} @onClick={{fn this.markAsCompleted order}} />
101
- {{/if}}
98
+ {{/if}}
99
+ {{#if order.isPreparing}}
100
+ <Button @size="xs" @type="success" @icon="bell-concierge" @text={{t "storefront.component.widget.orders.mark-as-mark"}} @onClick={{fn this.markAsReady order}} />
101
+ {{/if}}
102
+ {{#if order.isPickupReady}}
103
+ <Button @size="xs" @type="success" @icon="check" @text={{t "storefront.component.widget.orders.mark-as-completed"}} @onClick={{fn this.markAsCompleted order}} />
104
+ {{/if}}
105
+ </div>
106
+ <ContentPanel @title={{t "storefront.component.widget.orders.title"}} class="mt-2">
107
+ <div class="flex flex-col py-2 border-t dark:border-gray-800">
108
+ <div>{{t "storefront.component.widget.orders.customer"}}: {{n-a order.customer_name}}</div>
109
+ <div>{{t "storefront.component.widget.orders.driver"}}: {{n-a order.driver_name}}</div>
102
110
  </div>
103
- <ContentPanel @title={{t "storefront.component.widget.orders.title"}} class="mt-2">
104
- <div class="flex flex-col py-2 border-t dark:border-gray-800">
105
- <div>{{t "storefront.component.widget.orders.customer"}}: {{n-a order.customer_name}}</div>
106
- <div>{{t "storefront.component.widget.orders.driver"}}: {{n-a order.driver_name}}</div>
111
+ <div class="py-2 space-y-2 border-t dark:border-gray-800">
112
+ <div class="flex items-center justify-between">
113
+ <span class="dark:text-gray-50">{{t "storefront.component.widget.orders.subtotal"}}</span>
114
+ <span class="dark:text-gray-50">{{format-currency order.meta.subtotal order.meta.currency}}</span>
107
115
  </div>
108
- <div class="py-2 space-y-2 border-t dark:border-gray-800">
116
+ {{#unless order.meta.is_pickup}}
117
+ <div class="flex items-center justify-between">
118
+ <span class="dark:text-gray-50">{{t "storefront.component.widget.orders.delivery-fee"}}</span>
119
+ <span class="dark:text-gray-50">{{format-currency order.meta.delivery_fee order.meta.currency}}</span>
120
+ </div>
121
+ {{/unless}}
122
+ {{#if order.meta.tip}}
109
123
  <div class="flex items-center justify-between">
110
- <span class="dark:text-gray-50">{{t "storefront.component.widget.orders.subtotal"}}</span>
111
- <span class="dark:text-gray-50">{{format-currency order.meta.subtotal order.meta.currency}}</span>
124
+ <span class="dark:text-gray-50">{{t "storefront.component.widget.order.tip"}}</span>
125
+ <span class="dark:text-gray-50">{{get-tip-amount order.meta.tip order.meta.subtotal order.meta.currency}}</span>
112
126
  </div>
113
- {{#unless order.meta.is_pickup}}
114
- <div class="flex items-center justify-between">
115
- <span class="dark:text-gray-50">{{t "storefront.component.widget.orders.delivery-fee"}}</span>
116
- <span class="dark:text-gray-50">{{format-currency order.meta.delivery_fee order.meta.currency}}</span>
117
- </div>
118
- {{/unless}}
119
- {{#if order.meta.tip}}
120
- <div class="flex items-center justify-between">
121
- <span class="dark:text-gray-50">{{t "storefront.component.widget.order.tip"}}</span>
122
- <span class="dark:text-gray-50">{{get-tip-amount order.meta.tip order.meta.subtotal order.meta.currency}}</span>
123
- </div>
124
- {{/if}}
125
- {{#if order.meta.delivery_tip}}
126
- <div class="flex items-center justify-between">
127
- <span class="dark:text-gray-50">{{t "storefront.component.widget.order.delivery-tip"}}</span>
128
- <span class="dark:text-gray-50">{{get-tip-amount order.meta.delivery_tip order.meta.subtotal order.meta.currency}}</span>
129
- </div>
130
- {{/if}}
127
+ {{/if}}
128
+ {{#if order.meta.delivery_tip}}
131
129
  <div class="flex items-center justify-between">
132
- <span class="dark:text-gray-50 font-bold">{{t "storefront.component.widget.order.tip"}}</span>
133
- <span class="dark:text-gray-50 font-bold">{{format-currency order.meta.total order.meta.currency}}</span>
130
+ <span class="dark:text-gray-50">{{t "storefront.component.widget.order.delivery-tip"}}</span>
131
+ <span class="dark:text-gray-50">{{get-tip-amount order.meta.delivery_tip order.meta.subtotal order.meta.currency}}</span>
134
132
  </div>
133
+ {{/if}}
134
+ <div class="flex items-center justify-between">
135
+ <span class="dark:text-gray-50 font-bold">{{t "storefront.component.widget.order.tip"}}</span>
136
+ <span class="dark:text-gray-50 font-bold">{{format-currency order.meta.total order.meta.currency}}</span>
135
137
  </div>
136
- </ContentPanel>
137
- </div>
138
- {{/each}}
139
- </div>
140
- </div></Layout::Section::Body>
138
+ </div>
139
+ </ContentPanel>
140
+ </div>
141
+ {{/each}}
142
+ </div>
143
+ </Layout::Section::Body>
@@ -1,9 +1,10 @@
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 { inject as controller } from '@ember/controller';
5
- import { action, computed, get } from '@ember/object';
4
+ import { action, get } from '@ember/object';
5
+ import { debug } from '@ember/debug';
6
6
  import { task } from 'ember-concurrency-decorators';
7
+
7
8
  export default class CustomerPanelOrdersComponent extends Component {
8
9
  @service store;
9
10
  @service storefront;
@@ -12,67 +13,73 @@ export default class CustomerPanelOrdersComponent extends Component {
12
13
  @service appCache;
13
14
  @service modalsManager;
14
15
  @service contextPanel;
15
- @tracked isLoading = true;
16
+ @service orderActions;
17
+ @tracked loaded = false;
16
18
  @tracked orders = [];
17
19
  @tracked customer;
18
- @controller('orders.index.view') orderDetailsController;
19
-
20
- @computed('args.title') get title() {
21
- return this.args.title ?? this.intl.t('storefront.component.widget.orders.widget-title');
22
- }
23
20
 
24
- constructor() {
21
+ constructor(owner, { customer }) {
25
22
  super(...arguments);
26
- this.customer = this.args.customer;
27
- this.reloadOrders.perform();
23
+ this.customer = customer;
24
+ this.loadOrders.perform();
28
25
  }
29
26
 
30
- @task *reloadOrders(params = {}) {
31
- this.orders = yield this.fetchOrders(params);
27
+ @action search(event) {
28
+ this.loadOrders.perform({ query: event.target.value ?? '' });
32
29
  }
33
30
 
34
- @action fetchOrders(params = {}) {
35
- this.isLoading = true;
31
+ @task *loadOrders(params = {}) {
32
+ const storefront = get(this.storefront, 'activeStore.public_id');
33
+ const queryParams = {
34
+ storefront,
35
+ limit: 14,
36
+ sort: '-created_at',
37
+ customer_uuid: this.customer?.id,
38
+ ...params,
39
+ };
36
40
 
37
- return new Promise((resolve) => {
38
- const storefront = get(this.storefront, 'activeStore.public_id');
41
+ try {
42
+ const orders = yield this.fetch.get('orders', queryParams, { namespace: 'storefront/int/v1', normalizeToEmberData: true });
43
+ this.loaded = true;
44
+ this.orders = orders;
39
45
 
40
- if (!storefront || !this.customer?.id) {
41
- this.isLoading = false;
42
- return resolve([]);
43
- }
46
+ return orders;
47
+ } catch (err) {
48
+ debug('Error loading orders for widget:', err);
49
+ }
50
+ }
44
51
 
45
- const queryParams = {
46
- storefront,
47
- limit: 25,
48
- sort: '-created_at',
49
- customer_uuid: this.customer?.id,
50
- ...params,
51
- };
52
+ @action async viewOrder(order) {
53
+ this.contextPanel.focus(order, 'viewing');
54
+ }
52
55
 
53
- this.fetch
54
- .get('orders', queryParams, {
55
- namespace: 'storefront/int/v1',
56
- normalizeToEmberData: true,
57
- })
58
- .then((orders) => {
59
- this.isLoading = false;
56
+ @action async acceptOrder(order) {
57
+ await this.orderActions.acceptOrder(order, () => {
58
+ this.loadOrders.perform();
59
+ });
60
+ }
60
61
 
61
- resolve(orders);
62
- })
63
- .catch(() => {
64
- this.isLoading = false;
62
+ @action markAsReady(order) {
63
+ this.orderActions.markAsReady(order, () => {
64
+ this.loadOrders.perform();
65
+ });
66
+ }
65
67
 
66
- resolve(this.orders);
67
- });
68
+ @action markAsCompleted(order) {
69
+ this.orderActions.markAsCompleted(order, () => {
70
+ this.loadOrders.perform();
68
71
  });
69
72
  }
70
73
 
71
- @action search(event) {
72
- this.reloadOrders.perform({ query: event.target.value ?? '' });
74
+ @action assignDriver(order) {
75
+ this.orderActions.assignDriver(order, () => {
76
+ this.loadOrders.perform();
77
+ });
73
78
  }
74
79
 
75
- @action async viewOrder(order) {
76
- this.contextPanel.focus(order, 'viewing');
80
+ @action cancelOrder(order) {
81
+ this.orderActions.cancelOrder(order, () => {
82
+ this.loadOrders.perform();
83
+ });
77
84
  }
78
85
  }