@fleetbase/storefront-engine 0.4.0 → 0.4.1
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.
- package/addon/components/customer-panel/orders.hbs +2 -2
- package/addon/components/modals/create-gateway.hbs +33 -12
- package/addon/components/network-category-picker.js +1 -1
- package/addon/components/order-panel.hbs +1 -1
- package/addon/components/widget/customers.hbs +5 -2
- package/addon/components/widget/customers.js +14 -6
- package/addon/components/widget/orders.hbs +30 -9
- package/addon/components/widget/orders.js +7 -1
- package/addon/components/widget/storefront-key-metrics.js +2 -2
- package/addon/components/widget/storefront-metrics.hbs +11 -1
- package/addon/components/widget/storefront-metrics.js +103 -1
- package/addon/controllers/networks/index/network/index.js +2 -0
- package/addon/controllers/networks/index/network/stores.js +0 -1
- package/addon/controllers/settings/gateways.js +6 -1
- package/addon/controllers/settings/index.js +1 -0
- package/addon/controllers/settings/notifications.js +3 -5
- package/addon/models/network.js +1 -0
- package/addon/models/store.js +1 -0
- package/addon/routes/networks/index/network/index.js +5 -0
- package/addon/routes/settings/index.js +5 -0
- package/addon/services/order-actions.js +31 -0
- package/addon/styles/storefront-engine.css +22 -0
- package/addon/templates/networks/index/network/index.hbs +13 -0
- package/addon/templates/networks/index/network/stores.hbs +8 -1
- package/addon/templates/settings/gateways.hbs +15 -4
- package/addon/templates/settings/index.hbs +13 -0
- package/addon/templates/settings/notifications.hbs +2 -2
- package/addon/utils/commerce-date-ranges.js +263 -0
- package/app/utils/commerce-date-ranges.js +1 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +1 -1
- package/server/migrations/2025_09_01_041353_add_default_order_config_column.php +110 -0
- package/server/src/Console/Commands/MigrateStripeSandboxCustomers.php +150 -0
- package/server/src/Expansions/OrderExpansion.php +43 -0
- package/server/src/Http/Controllers/NetworkController.php +1 -1
- package/server/src/Http/Controllers/OrderController.php +62 -9
- package/server/src/Http/Controllers/v1/CheckoutController.php +45 -48
- package/server/src/Http/Controllers/v1/ServiceQuoteController.php +19 -3
- package/server/src/Http/Middleware/SetStorefrontSession.php +8 -6
- package/server/src/Http/Resources/Customer.php +41 -17
- package/server/src/Http/Resources/Gateway.php +16 -11
- package/server/src/Http/Resources/Network.php +35 -34
- package/server/src/Http/Resources/NotificationChannel.php +17 -10
- package/server/src/Http/Resources/Store.php +36 -35
- package/server/src/Models/Customer.php +18 -2
- package/server/src/Models/FoodTruck.php +15 -0
- package/server/src/Models/Network.php +63 -1
- package/server/src/Models/Store.php +71 -9
- package/server/src/Notifications/StorefrontOrderAccepted.php +154 -0
- package/server/src/Observers/OrderObserver.php +6 -4
- package/server/src/Providers/StorefrontServiceProvider.php +1 -0
- package/server/src/Rules/IsValidLocation.php +12 -0
- package/server/src/Support/PushNotification.php +13 -4
- package/server/src/Support/Storefront.php +199 -37
- package/server/src/routes.php +1 -0
- package/translations/en-us.yaml +5 -0
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
@onClick={{fn this.acceptOrder order}}
|
|
42
42
|
/>
|
|
43
43
|
{{/if}}
|
|
44
|
-
{{#if order.
|
|
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.
|
|
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
|
|
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
|
-
{{#
|
|
34
|
-
{{#
|
|
35
|
-
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
}
|
|
@@ -30,7 +30,8 @@
|
|
|
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.
|
|
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-
|
|
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:
|
|
230
|
-
<th style={{"width:
|
|
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:
|
|
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.
|
|
279
|
+
{{#if (eq order.status "started")}}
|
|
268
280
|
<Button
|
|
269
281
|
@size="xs"
|
|
270
282
|
@type="success"
|
|
271
|
-
@icon="
|
|
272
|
-
@text={{t "storefront.component.widget.orders.mark-as-
|
|
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',
|
|
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
|
-
|
|
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
|
}
|
|
@@ -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';
|
|
@@ -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
|
|
54
|
+
schema,
|
|
50
55
|
schemas,
|
|
51
56
|
schemaOptions,
|
|
52
57
|
gateway,
|
|
@@ -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';
|
|
@@ -14,7 +13,6 @@ export default class SettingsNotificationsController extends Controller {
|
|
|
14
13
|
@service crud;
|
|
15
14
|
@service storefront;
|
|
16
15
|
@alias('storefront.activeStore') activeStore;
|
|
17
|
-
@tracked channels = [];
|
|
18
16
|
|
|
19
17
|
@action createChannel() {
|
|
20
18
|
const channel = this.store.createRecord('notification-channel', {
|
|
@@ -71,9 +69,9 @@ export default class SettingsNotificationsController extends Controller {
|
|
|
71
69
|
|
|
72
70
|
return channel
|
|
73
71
|
.save()
|
|
74
|
-
.then((
|
|
72
|
+
.then(() => {
|
|
75
73
|
this.notifications.success(this.intl.t('storefront.settings.notification.new-notification-channel-added'));
|
|
76
|
-
this.
|
|
74
|
+
this.hostRouter.refresh();
|
|
77
75
|
})
|
|
78
76
|
.catch((error) => {
|
|
79
77
|
// gateway.rollbackAttributes();
|
|
@@ -94,7 +92,7 @@ export default class SettingsNotificationsController extends Controller {
|
|
|
94
92
|
|
|
95
93
|
return channel.destroyRecord().then(() => {
|
|
96
94
|
// justincase
|
|
97
|
-
this.
|
|
95
|
+
this.hostRouter.refresh();
|
|
98
96
|
modal.stopLoading();
|
|
99
97
|
});
|
|
100
98
|
},
|
package/addon/models/network.js
CHANGED
package/addon/models/store.js
CHANGED
|
@@ -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'),
|
|
@@ -40,12 +40,14 @@
|
|
|
40
40
|
max-width: 100%;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
.status-badge.accepted-status-badge > span,
|
|
43
44
|
.status-badge.pickup-ready-status-badge > span {
|
|
44
45
|
background-color: #166534;
|
|
45
46
|
border: 1px solid #15803d;
|
|
46
47
|
color: #dcfce7;
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
.status-badge.accepted-status-badge > span svg,
|
|
49
51
|
.status-badge.pickup-ready-status-badge > span svg {
|
|
50
52
|
color: #86efac;
|
|
51
53
|
}
|
|
@@ -60,12 +62,16 @@
|
|
|
60
62
|
color: #fca5a5;
|
|
61
63
|
}
|
|
62
64
|
|
|
65
|
+
.status-badge.driver-picked-up-status-badge > span,
|
|
66
|
+
.status-badge.driver-enroute-to-store-status-badge > span,
|
|
63
67
|
.status-badge.draft-status-badge > span {
|
|
64
68
|
background-color: #a16207;
|
|
65
69
|
border: 1px solid #a16207;
|
|
66
70
|
color: #fef9c3;
|
|
67
71
|
}
|
|
68
72
|
|
|
73
|
+
.status-badge.driver-picked-up-status-badge > span svg,
|
|
74
|
+
.status-badge.driver-enroute-to-store-status-badge > span svg,
|
|
69
75
|
.status-badge.draft-status-badge > span svg {
|
|
70
76
|
color: #fef9c3;
|
|
71
77
|
}
|
|
@@ -84,3 +90,19 @@ td.network-store-name-column > div > svg {
|
|
|
84
90
|
height: 0.5rem;
|
|
85
91
|
width: 0.5rem;
|
|
86
92
|
}
|
|
93
|
+
|
|
94
|
+
.storefront-datepicker .air-datepicker-buttons {
|
|
95
|
+
animation: slideIn 0.3s ease-out;
|
|
96
|
+
display: flex;
|
|
97
|
+
flex-wrap: wrap;
|
|
98
|
+
gap: 8px;
|
|
99
|
+
padding: 0.5rem;
|
|
100
|
+
max-height: 235px;
|
|
101
|
+
overflow-y: auto;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.storefront-datepicker .air-datepicker-buttons .quick-select-btn {
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
width: 48%;
|
|
108
|
+
}
|