@fleetbase/storefront-engine 0.3.17 → 0.3.20
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 +107 -104
- package/addon/components/customer-panel/orders.js +52 -45
- package/addon/components/modals/incoming-order.hbs +208 -199
- package/addon/components/modals/manage-addons.js +6 -2
- package/addon/components/modals/order-ready-assign-driver.hbs +1 -1
- package/addon/components/order-panel/details.js +0 -2
- package/addon/components/order-panel.hbs +314 -1
- package/addon/components/order-panel.js +51 -3
- package/addon/components/widget/customers.hbs +75 -51
- package/addon/components/widget/customers.js +29 -41
- package/addon/components/widget/orders.hbs +278 -119
- package/addon/components/widget/orders.js +75 -80
- package/addon/components/widget/storefront-metrics.hbs +3 -6
- package/addon/components/widget/storefront-metrics.js +25 -41
- package/addon/controllers/orders/index.js +214 -105
- package/addon/controllers/products/index/category/new.js +2 -1
- package/addon/controllers/products/index/index.js +0 -23
- package/addon/controllers/settings/gateways.js +14 -18
- package/addon/helpers/get-tip-amount.js +13 -2
- package/addon/models/product-addon-category.js +3 -0
- package/addon/routes/application.js +2 -4
- package/addon/services/order-actions.js +248 -0
- package/addon/services/storefront.js +2 -0
- package/addon/styles/storefront-engine.css +55 -0
- package/addon/templates/home.hbs +2 -1
- package/addon/templates/orders/index/view.hbs +1 -1
- package/addon/templates/orders/index.hbs +26 -3
- package/addon/templates/products/index/category/new.hbs +4 -1
- package/addon/templates/products/index/index.hbs +28 -28
- package/addon/templates/settings/gateways.hbs +1 -1
- package/addon/templates/settings/index.hbs +2 -2
- package/addon/templates/settings.hbs +1 -1
- package/app/services/order-actions.js +1 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +1 -1
- package/server/migrations/2023_05_03_025307_create_carts_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_checkouts_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_gateways_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_network_stores_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_networks_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_notification_channels_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_payment_methods_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_product_addon_categories_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_product_addons_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_product_hours_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_product_store_locations_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_product_variant_options_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_product_variants_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_products_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_reviews_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_store_hours_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_store_locations_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_stores_table.php +1 -1
- package/server/migrations/2023_05_03_025307_create_votes_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_carts_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_checkouts_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_gateways_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_network_stores_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_networks_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_notification_channels_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_payment_methods_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_addon_categories_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_addons_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_hours_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_store_locations_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_variant_options_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_product_variants_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_products_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_reviews_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_store_hours_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_store_locations_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_stores_table.php +1 -1
- package/server/migrations/2023_05_03_025310_add_foreign_keys_to_votes_table.php +1 -1
- package/server/src/Http/Controllers/ActionController.php +2 -1
- package/server/src/Http/Controllers/OrderController.php +15 -2
- package/server/src/Http/Controllers/ProductController.php +2 -0
- package/server/src/Http/Controllers/v1/CheckoutController.php +337 -40
- package/server/src/Http/Controllers/v1/CustomerController.php +88 -3
- package/server/src/Http/Controllers/v1/ServiceQuoteController.php +5 -5
- package/server/src/Http/Controllers/v1/StoreController.php +35 -5
- package/server/src/Http/Requests/CreateCustomerRequest.php +4 -0
- package/server/src/Http/Requests/CreateStripeSetupIntentRequest.php +31 -0
- package/server/src/Http/Requests/CustomerRequest.php +31 -0
- package/server/src/Http/Requests/InitializeCheckoutRequest.php +2 -1
- package/server/src/Http/Resources/Cart.php +18 -1
- package/server/src/Http/Resources/Customer.php +19 -14
- package/server/src/Http/Resources/Store.php +5 -1
- package/server/src/Models/AddonCategory.php +14 -16
- package/server/src/Models/Cart.php +10 -5
- package/server/src/Models/Customer.php +2 -2
- package/server/src/Models/Gateway.php +9 -4
- package/server/src/Models/Product.php +9 -10
- package/server/src/Models/ProductAddonCategory.php +2 -0
- package/server/src/Models/Store.php +2 -2
- package/server/src/Observers/OrderObserver.php +7 -1
- package/server/src/Rules/IsValidLocation.php +2 -2
- package/server/src/Support/QPay.php +35 -1
- package/server/src/Support/Storefront.php +34 -0
- package/server/src/Support/StripeUtils.php +38 -0
- package/server/src/routes.php +19 -0
- package/translations/en-us.yaml +8 -2
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { helper } from '@ember/component/helper';
|
|
2
|
+
import formatCurrency from '@fleetbase/ember-ui/utils/format-currency';
|
|
3
|
+
import numbersOnly from '@fleetbase/ember-ui/utils/numbers-only';
|
|
4
|
+
import calculatePercentage from '@fleetbase/ember-core/utils/calculate-percentage';
|
|
2
5
|
|
|
3
|
-
export default helper(function getTipAmount(
|
|
4
|
-
|
|
6
|
+
export default helper(function getTipAmount([tip, subtotal, currency]) {
|
|
7
|
+
let amount = tip;
|
|
8
|
+
if (typeof tip === 'string' && tip.endsWith('%')) {
|
|
9
|
+
amount = calculatePercentage(numbersOnly(tip), subtotal);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
amount = parseInt(amount);
|
|
13
|
+
amount = isNaN(amount) ? 0 : amount;
|
|
14
|
+
|
|
15
|
+
return formatCurrency(amount, currency);
|
|
5
16
|
});
|
|
@@ -12,6 +12,8 @@ export default class ProductAddonCategoryModel extends Model {
|
|
|
12
12
|
|
|
13
13
|
/** @attributes */
|
|
14
14
|
@attr('string') name;
|
|
15
|
+
@attr('number') max_selectable;
|
|
16
|
+
@attr('boolean') is_required;
|
|
15
17
|
@attr('raw') excluded_addons;
|
|
16
18
|
|
|
17
19
|
/** @dates */
|
|
@@ -25,6 +27,7 @@ export default class ProductAddonCategoryModel extends Model {
|
|
|
25
27
|
category_uuid: this.category_uuid,
|
|
26
28
|
product_uuid: this.product_uuid,
|
|
27
29
|
name: this.name,
|
|
30
|
+
max_selectable: this.max_selectable,
|
|
28
31
|
excluded_addons: getWithDefault(this, 'excluded_addons', []),
|
|
29
32
|
updated_at: this.updated_at,
|
|
30
33
|
created_at: this.created_at,
|
|
@@ -45,10 +45,8 @@ export default class ApplicationRoute extends Route {
|
|
|
45
45
|
return this.store.query('store', { limit: 300, sort: '-updated_at' });
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
afterModel(
|
|
49
|
-
|
|
50
|
-
// this.storefront.listenForIncomingOrders();
|
|
51
|
-
}
|
|
48
|
+
afterModel() {
|
|
49
|
+
this.storefront.listenForIncomingOrders();
|
|
52
50
|
}
|
|
53
51
|
|
|
54
52
|
disableSandbox() {
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import Service, { inject as service } from '@ember/service';
|
|
2
|
+
import toBoolean from '@fleetbase/ember-core/utils/to-boolean';
|
|
3
|
+
|
|
4
|
+
export default class OrderActionsService extends Service {
|
|
5
|
+
@service intl;
|
|
6
|
+
@service notifications;
|
|
7
|
+
@service fetch;
|
|
8
|
+
@service store;
|
|
9
|
+
@service modalsManager;
|
|
10
|
+
@service storefront;
|
|
11
|
+
|
|
12
|
+
cancelOrder(order, callback) {
|
|
13
|
+
this.modalsManager.confirm({
|
|
14
|
+
title: this.intl.t('fleet-ops.operations.orders.index.cancel-title'),
|
|
15
|
+
body: this.intl.t('fleet-ops.operations.orders.index.cancel-body'),
|
|
16
|
+
order,
|
|
17
|
+
confirm: async (modal) => {
|
|
18
|
+
modal.startLoading();
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
await this.fetch.patch('orders/cancel', { order: order.id });
|
|
22
|
+
order.set('status', 'canceled');
|
|
23
|
+
this.notifications.success('Order canceled.');
|
|
24
|
+
modal.done();
|
|
25
|
+
if (typeof callback === 'function') {
|
|
26
|
+
callback(order);
|
|
27
|
+
}
|
|
28
|
+
} catch (error) {
|
|
29
|
+
this.notifications.serverError(error);
|
|
30
|
+
} finally {
|
|
31
|
+
modal.stopLoading();
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
decline: async (modal) => {
|
|
35
|
+
if (typeof callback === 'function') {
|
|
36
|
+
callback(order);
|
|
37
|
+
}
|
|
38
|
+
modal.done();
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async assignDriver(order, callback) {
|
|
44
|
+
await order.loadDriver();
|
|
45
|
+
|
|
46
|
+
this.modalsManager.show('modals/assign-driver', {
|
|
47
|
+
title: this.intl.t('storefront.component.widget.orders.assign-driver-modal-title'),
|
|
48
|
+
acceptButtonText: this.intl.t('storefront.component.widget.orders.assign-driver-modal-accept-button-text'),
|
|
49
|
+
acceptButtonScheme: 'success',
|
|
50
|
+
acceptButtonIcon: 'check',
|
|
51
|
+
driver: order.driver_assigned,
|
|
52
|
+
order,
|
|
53
|
+
confirm: async (modal) => {
|
|
54
|
+
modal.startLoading();
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
await order.save();
|
|
58
|
+
this.notifications.success('Driver assigned to order.');
|
|
59
|
+
modal.done();
|
|
60
|
+
if (typeof callback === 'function') {
|
|
61
|
+
callback(order);
|
|
62
|
+
}
|
|
63
|
+
} catch (err) {
|
|
64
|
+
this.notifications.serverError(err);
|
|
65
|
+
} finally {
|
|
66
|
+
modal.stopLoading();
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
decline: async (modal) => {
|
|
70
|
+
if (typeof callback === 'function') {
|
|
71
|
+
callback(order);
|
|
72
|
+
}
|
|
73
|
+
modal.done();
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async acceptOrder(order, callback) {
|
|
79
|
+
const store = this.storefront.activeStore;
|
|
80
|
+
|
|
81
|
+
await order.loadPayload();
|
|
82
|
+
await order.loadCustomer();
|
|
83
|
+
|
|
84
|
+
this.modalsManager.show('modals/incoming-order', {
|
|
85
|
+
title: this.intl.t('storefront.component.widget.orders.accept-order'),
|
|
86
|
+
acceptButtonText: this.intl.t('storefront.component.widget.orders.accept-order'),
|
|
87
|
+
acceptButtonScheme: 'success',
|
|
88
|
+
acceptButtonIcon: 'check',
|
|
89
|
+
modalClass: 'scrollable-height-dialog',
|
|
90
|
+
order,
|
|
91
|
+
store,
|
|
92
|
+
assignDriver: async () => {
|
|
93
|
+
await this.modalsManager.done();
|
|
94
|
+
this.assignDriver(order, (order) => {
|
|
95
|
+
this.acceptOrder(order);
|
|
96
|
+
});
|
|
97
|
+
},
|
|
98
|
+
confirm: async (modal) => {
|
|
99
|
+
modal.startLoading();
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
await this.fetch.post('orders/accept', { order: order.id }, { namespace: 'storefront/int/v1' });
|
|
103
|
+
modal.done();
|
|
104
|
+
if (typeof callback === 'function') {
|
|
105
|
+
callback(order);
|
|
106
|
+
}
|
|
107
|
+
} catch (err) {
|
|
108
|
+
this.notifications.serverError(err);
|
|
109
|
+
} finally {
|
|
110
|
+
modal.stopLoading();
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
decline: async (modal) => {
|
|
114
|
+
if (typeof callback === 'function') {
|
|
115
|
+
callback(order);
|
|
116
|
+
}
|
|
117
|
+
modal.done();
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
markAsReady(order, callback) {
|
|
123
|
+
// for pickup orders
|
|
124
|
+
if (order.meta && toBoolean(order.meta.is_pickup) === true) {
|
|
125
|
+
return this.modalsManager.confirm({
|
|
126
|
+
title: this.intl.t('storefront.component.widget.orders.mark-as-ready-modal-pickup-title'),
|
|
127
|
+
body: this.intl.t('storefront.component.widget.orders.mark-as-ready-modal-pickup-body'),
|
|
128
|
+
acceptButtonText: this.intl.t('storefront.component.widget.orders.mark-as-ready-modal-pickup-accept-button-text'),
|
|
129
|
+
acceptButtonIcon: 'check',
|
|
130
|
+
acceptButtonScheme: 'success',
|
|
131
|
+
confirm: async (modal) => {
|
|
132
|
+
modal.startLoading();
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
await this.fetch.post('orders/ready', { order: order.id }, { namespace: 'storefront/int/v1' });
|
|
136
|
+
modal.done();
|
|
137
|
+
if (typeof callback === 'function') {
|
|
138
|
+
callback(order);
|
|
139
|
+
}
|
|
140
|
+
} catch (err) {
|
|
141
|
+
this.notifications.serverError(err);
|
|
142
|
+
} finally {
|
|
143
|
+
modal.stopLoading();
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
decline: async (modal) => {
|
|
147
|
+
if (typeof callback === 'function') {
|
|
148
|
+
callback(order);
|
|
149
|
+
}
|
|
150
|
+
modal.done();
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (!order.adhoc) {
|
|
156
|
+
// prompt to assign driver then dispatch
|
|
157
|
+
return this.modalsManager.show('modals/order-ready-assign-driver', {
|
|
158
|
+
title: this.intl.t('storefront.component.widget.orders.mark-as-ready-modal-not-adhoc-title'),
|
|
159
|
+
acceptButtonText: this.intl.t('storefront.component.widget.orders.mark-as-ready-modal-not-adhoc-accept-button-text'),
|
|
160
|
+
acceptButtonScheme: 'success',
|
|
161
|
+
acceptButtonIcon: 'check',
|
|
162
|
+
adhoc: false,
|
|
163
|
+
driver: null,
|
|
164
|
+
order,
|
|
165
|
+
confirm: async (modal) => {
|
|
166
|
+
modal.startLoading();
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
await this.fetch.post('orders/ready', { order: order.id, driver: modal.getOption('driver.id'), adhoc: modal.getOption('adhoc') }, { namespace: 'storefront/int/v1' });
|
|
170
|
+
modal.done();
|
|
171
|
+
if (typeof callback === 'function') {
|
|
172
|
+
callback(order);
|
|
173
|
+
}
|
|
174
|
+
} catch (err) {
|
|
175
|
+
this.notifications.serverError(err);
|
|
176
|
+
} finally {
|
|
177
|
+
modal.stopLoading();
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
decline: async (modal) => {
|
|
181
|
+
if (typeof callback === 'function') {
|
|
182
|
+
callback(order);
|
|
183
|
+
}
|
|
184
|
+
modal.done();
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
this.modalsManager.confirm({
|
|
190
|
+
title: this.intl.t('storefront.component.widget.orders.mark-as-ready-modal-title'),
|
|
191
|
+
body: this.intl.t('storefront.component.widget.orders.mark-as-ready-modal-body'),
|
|
192
|
+
acceptButtonText: this.intl.t('storefront.component.widget.orders.mark-as-ready-modal-accept-button-text'),
|
|
193
|
+
acceptButtonIcon: 'check',
|
|
194
|
+
acceptButtonScheme: 'success',
|
|
195
|
+
confirm: async (modal) => {
|
|
196
|
+
modal.startLoading();
|
|
197
|
+
try {
|
|
198
|
+
await this.fetch.post('orders/ready', { order: order.id }, { namespace: 'storefront/int/v1' });
|
|
199
|
+
modal.done();
|
|
200
|
+
if (typeof callback === 'function') {
|
|
201
|
+
callback(order);
|
|
202
|
+
}
|
|
203
|
+
} catch (err) {
|
|
204
|
+
this.notifications.serverError(err);
|
|
205
|
+
} finally {
|
|
206
|
+
modal.stopLoading();
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
decline: async (modal) => {
|
|
210
|
+
if (typeof callback === 'function') {
|
|
211
|
+
callback(order);
|
|
212
|
+
}
|
|
213
|
+
modal.done();
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
markAsCompleted(order, callback) {
|
|
219
|
+
this.modalsManager.confirm({
|
|
220
|
+
title: this.intl.t('storefront.component.widget.orders.mark-as-completed-modal-title'),
|
|
221
|
+
body: this.intl.t('storefront.component.widget.orders.mark-as-completed-modal-body'),
|
|
222
|
+
acceptButtonText: this.intl.t('storefront.component.widget.orders.mark-as-completed-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/completed', { 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
|
+
}
|
|
@@ -15,6 +15,7 @@ export default class StorefrontService extends Service.extend(Evented) {
|
|
|
15
15
|
@service modalsManager;
|
|
16
16
|
@service hostRouter;
|
|
17
17
|
@service abilities;
|
|
18
|
+
@service socket;
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Gets the active store.
|
|
@@ -102,6 +103,7 @@ export default class StorefrontService extends Service.extend(Evented) {
|
|
|
102
103
|
declineButtonScheme: 'danger',
|
|
103
104
|
closeButton: false,
|
|
104
105
|
backdropClose: false,
|
|
106
|
+
modalClass: 'scrollable-height-dialog',
|
|
105
107
|
order,
|
|
106
108
|
store,
|
|
107
109
|
confirm: async (modal) => {
|
|
@@ -4,3 +4,58 @@
|
|
|
4
4
|
.ui-combo-box .selected-list a.combo-box-option.selected:hover {
|
|
5
5
|
background-color: #76a9fa !important;
|
|
6
6
|
}
|
|
7
|
+
|
|
8
|
+
/** hotfix tag input */
|
|
9
|
+
.emberTagInput.form-input {
|
|
10
|
+
flex-wrap: wrap !important;
|
|
11
|
+
gap: 0.35rem !important;
|
|
12
|
+
height: auto !important;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.scrollable-height-dialog {
|
|
16
|
+
display: flex !important;
|
|
17
|
+
padding: 0;
|
|
18
|
+
min-width: 100%;
|
|
19
|
+
min-height: 100%;
|
|
20
|
+
height: 100%;
|
|
21
|
+
width: 100%;
|
|
22
|
+
margin: 0;
|
|
23
|
+
align-items: center;
|
|
24
|
+
justify-content: center;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.scrollable-height-dialog > .flb--modal-dialog {
|
|
28
|
+
padding: 25rem 0 5rem;
|
|
29
|
+
height: 100%;
|
|
30
|
+
overflow-y: scroll;
|
|
31
|
+
width: 100%;
|
|
32
|
+
margin: 1rem 0 0;
|
|
33
|
+
min-width: 100%;
|
|
34
|
+
min-height: 100%;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.storefront-widget-table {
|
|
38
|
+
table-layout: fixed;
|
|
39
|
+
width: 100%;
|
|
40
|
+
max-width: 100%;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.status-badge.pickup-ready-status-badge > span {
|
|
44
|
+
background-color: #166534;
|
|
45
|
+
border: 1px solid #15803d;
|
|
46
|
+
color: #dcfce7;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.status-badge.pickup-ready-status-badge > span svg {
|
|
50
|
+
color: #86efac;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.status-badge.order-canceled-status-badge > span {
|
|
54
|
+
background-color: #991b1b;
|
|
55
|
+
border: 1px solid #b91c1c;
|
|
56
|
+
color: #fee2e2;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.status-badge.order-canceled-status-badge > span svg {
|
|
60
|
+
color: #fca5a5;
|
|
61
|
+
}
|
package/addon/templates/home.hbs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<Layout::Section::Header @title={{t "storefront.home.title"}} @hideActions={{true}} />
|
|
2
2
|
|
|
3
|
-
<Layout::Section::Body class="space-y-4" @padded={{true}}>
|
|
3
|
+
<Layout::Section::Body class="space-y-4 h-full overflow-y-scroll" @padded={{true}}>
|
|
4
4
|
<Widget::StorefrontMetrics />
|
|
5
5
|
<Widget::Orders />
|
|
6
6
|
<Widget::Customers />
|
|
7
|
+
<Spacer @height="300px" />
|
|
7
8
|
</Layout::Section::Body>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<OrderPanel
|
|
1
|
+
<OrderPanel @context={{@model}} @onPressCancel={{this.transitionBack}} />
|
|
@@ -9,11 +9,34 @@
|
|
|
9
9
|
/>
|
|
10
10
|
<VisibleColumnPicker @columns={{this.columns}} @onChange={{fn (mut this.columns)}} class="mr-2" />
|
|
11
11
|
{{#if (safe-has this.table "selectedRows")}}
|
|
12
|
-
<DropdownButton
|
|
12
|
+
<DropdownButton
|
|
13
|
+
@icon="layer-group"
|
|
14
|
+
@text={{t "storefront.common.bulk-action"}}
|
|
15
|
+
@type="magic"
|
|
16
|
+
@size="sm"
|
|
17
|
+
@buttonWrapperClass="mr-2"
|
|
18
|
+
@contentClass="dropdown-menu"
|
|
19
|
+
@permission="storefront delete order"
|
|
20
|
+
as |dd|
|
|
21
|
+
>
|
|
13
22
|
<div class="next-dd-menu mt-2 mx-0">
|
|
14
23
|
<div class="px-1">
|
|
15
|
-
<a href="
|
|
16
|
-
|
|
24
|
+
<a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.bulkCancelOrders)}} disabled={{cannot "fleet-ops cancel order"}}>
|
|
25
|
+
<div class="w-6"><FaIcon @icon="ban" @size="sm" /></div>
|
|
26
|
+
<div>{{t "fleet-ops.operations.orders.index.cancel-orders"}}</div>
|
|
27
|
+
</a>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="px-1">
|
|
30
|
+
<a href="javascript:;" class="text-red-500 next-dd-item" {{on "click" (dropdown-fn dd this.bulkDeleteOrders)}} disabled={{cannot "fleet-ops delete order"}}>
|
|
31
|
+
<div class="w-6"><FaIcon @icon="trash" @size="sm" /></div>
|
|
32
|
+
<div>{{t "fleet-ops.operations.orders.index.delete-orders"}}</div>
|
|
33
|
+
</a>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="next-dd-menu-seperator"></div>
|
|
36
|
+
<div class="px-1">
|
|
37
|
+
<a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd this.bulkDispatchOrders)}} disabled={{cannot "fleet-ops dispatch order"}}>
|
|
38
|
+
<div class="w-6"><FaIcon @icon="rocket" @size="sm" /></div>
|
|
39
|
+
<div>{{t "fleet-ops.operations.orders.index.dispatch-orders"}}</div>
|
|
17
40
|
</a>
|
|
18
41
|
</div>
|
|
19
42
|
</div>
|
|
@@ -23,6 +23,9 @@
|
|
|
23
23
|
<InputGroup @name="Product Description" @helpText="Enter a description of your product">
|
|
24
24
|
<Textarea @value={{this.product.description}} class="form-input w-full" placeholder="Enter a description of your product...." disabled={{unauthorized}} rows={{4}} />
|
|
25
25
|
</InputGroup>
|
|
26
|
+
<InputGroup @name="Product Status">
|
|
27
|
+
<Select class="w-full" @value={{this.product.status}} @placeholder="Select product status" @options={{this.statusOptions}} @onSelect={{fn (mut this.product.status)}} @humanize={{true}} />
|
|
28
|
+
</InputGroup>
|
|
26
29
|
<InputGroup @name="Product Tags">
|
|
27
30
|
<TagInput
|
|
28
31
|
class="form-input"
|
|
@@ -261,7 +264,7 @@
|
|
|
261
264
|
{{addon.description}}
|
|
262
265
|
</div>
|
|
263
266
|
<div class="col-span-2">
|
|
264
|
-
{{format-currency addon.price}}
|
|
267
|
+
{{format-currency addon.price this.product.currency}}
|
|
265
268
|
</div>
|
|
266
269
|
</div>
|
|
267
270
|
{{/each}}
|
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
<Layout::Section::Header @title="All Products" @searchQuery={{this.query}} @onSearch={{perform this.search}} />
|
|
2
2
|
|
|
3
|
-
<Layout::Section::Body>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
</div>
|
|
3
|
+
<Layout::Section::Body class="h-full overflow-y-scroll p-6">
|
|
4
|
+
|
|
5
|
+
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
6
|
+
{{#each @model as |product|}}
|
|
7
|
+
<div class="border border-gray-200 bg-white dark:bg-gray-900 dark:text-gray-100 dark:border-gray-700 text-center rounded-md px-2 py-3">
|
|
8
|
+
<div class="flex flex-col items-center justify-center overflow-hidden">
|
|
9
|
+
<div class="mb-3 flex items-center justify-center">
|
|
10
|
+
<img src={{product.primary_image_url}} alt={{product.name}} class="w-24 h-24" />
|
|
11
|
+
</div>
|
|
12
|
+
<h4 class="font-semibold mb-1">{{product.name}}</h4>
|
|
13
|
+
<p class="text-sm truncate">{{product.description}}</p>
|
|
14
|
+
<p class="mb-2 text-sm text-green-400">{{format-currency product.price product.currency}}</p>
|
|
15
|
+
<div class="flex items-center justify-evenly space-x-4">
|
|
16
|
+
<LinkTo @route="products.index.index.edit" @model={{product}} disabled={{cannot "storefront update product"}} class="text-sm">
|
|
17
|
+
<FaIcon @icon="pencil" class="mr-1" />
|
|
18
|
+
<span class="destroy-action">Edit</span>
|
|
19
|
+
</LinkTo>
|
|
20
|
+
<a href="javascript:;" class="destroy-action text-sm" disabled={{cannot "storefront delete product"}} {{on "click" (fn this.deleteProduct product)}}>
|
|
21
|
+
<FaIcon @icon="trash" class="text-red-500 mr-1" />
|
|
22
|
+
<span class="destroy-action">Delete</span>
|
|
23
|
+
</a>
|
|
25
24
|
</div>
|
|
26
25
|
</div>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
</
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
</div>
|
|
27
|
+
{{else}}
|
|
28
|
+
<div>
|
|
29
|
+
<h3 class="dark:text-gray-100 text-opacity-75 text-sm">No products</h3>
|
|
30
|
+
</div>
|
|
31
|
+
{{/each}}
|
|
33
32
|
</div>
|
|
33
|
+
<Spacer @height="400px" />
|
|
34
34
|
</Layout::Section::Body>
|
|
35
35
|
|
|
36
36
|
<Layout::Section::Footer>
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
</div>
|
|
16
16
|
</div>
|
|
17
17
|
|
|
18
|
-
{{#each
|
|
18
|
+
{{#each @model as |gateway|}}
|
|
19
19
|
<ContentPanel @title={{gateway.name}} @open={{true}} @pad={{true}}>
|
|
20
20
|
<InputGroup @name={{t "storefront.settings.gateways.gateway-name"}} @value={{gateway.name}} @helpText={{t "storefront.settings.gateways.helpText"}} />
|
|
21
21
|
<InputGroup
|
|
@@ -293,14 +293,14 @@
|
|
|
293
293
|
<div class="input-group">
|
|
294
294
|
<Toggle @isToggled={{@model.options.tips_enabled}} @onToggle={{fn (mut @model.options.tips_enabled)}}>
|
|
295
295
|
<FaIcon @icon="cash-register" class="text-gray-600 dark:text-gray-400 mx-2" /><span class="dark:text-gray-100 text-sm">{{t
|
|
296
|
-
"storefront.settings.index.enable-
|
|
296
|
+
"storefront.settings.index.enable-tips"
|
|
297
297
|
}}</span>
|
|
298
298
|
</Toggle>
|
|
299
299
|
</div>
|
|
300
300
|
<div class="input-group">
|
|
301
301
|
<Toggle @isToggled={{@model.options.delivery_tips_enabled}} @onToggle={{fn (mut @model.options.delivery_tips_enabled)}}>
|
|
302
302
|
<FaIcon @icon="face-smile" class="text-gray-600 dark:text-gray-400 mx-2" /><span class="dark:text-gray-100 text-sm">{{t
|
|
303
|
-
"storefront.settings.index.enable-
|
|
303
|
+
"storefront.settings.index.enable-delivery-tips"
|
|
304
304
|
}}</span>
|
|
305
305
|
</Toggle>
|
|
306
306
|
</div>
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
<span>{{t "storefront.common.api"}}</span>
|
|
19
19
|
</LinkTo>
|
|
20
20
|
<LinkTo @route="settings.notifications" class="ui-tab">
|
|
21
|
-
<FaIcon @icon="
|
|
21
|
+
<FaIcon @icon="bell-concierge" class="mr-1" />
|
|
22
22
|
<span>{{t "storefront.common.notification"}}</span>
|
|
23
23
|
</LinkTo>
|
|
24
24
|
</nav>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/storefront-engine/services/order-actions';
|
package/composer.json
CHANGED
package/extension.json
CHANGED
package/package.json
CHANGED