@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.
- 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/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/settings/gateways.js +1 -1
- package/addon/helpers/get-tip-amount.js +13 -2
- 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 +48 -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/index.hbs +28 -28
- 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/config/storefront.php +20 -0
- 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/v1/CheckoutController.php +12 -12
- package/server/src/Http/Controllers/v1/CustomerController.php +15 -7
- package/server/src/Http/Controllers/v1/ServiceQuoteController.php +5 -5
- package/server/src/Http/Requests/CreateCustomerRequest.php +4 -0
- package/server/src/Http/Requests/InitializeCheckoutRequest.php +2 -1
- package/server/src/Http/Resources/Cart.php +1 -1
- 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/Storefront.php +34 -0
- package/translations/en-us.yaml +6 -1
|
@@ -1 +1,314 @@
|
|
|
1
|
-
<
|
|
1
|
+
<Overlay position="right" @noBackdrop={{true}} @width="550px" @fullHeight={{true}} @isResizable={{true}} as |overlay|>
|
|
2
|
+
<Overlay::Header
|
|
3
|
+
@overlay={{overlay}}
|
|
4
|
+
@title={{this.order.public_id}}
|
|
5
|
+
@status={{this.order.status}}
|
|
6
|
+
@dispatched={{this.order.dispatched}}
|
|
7
|
+
@createdAt={{this.order.createdAt}}
|
|
8
|
+
@onPressCancel={{@onPressCancel}}
|
|
9
|
+
>
|
|
10
|
+
<div class="flex flex-row justify-end space-x-2">
|
|
11
|
+
{{#if this.order.isFresh}}
|
|
12
|
+
<Button
|
|
13
|
+
@size="xs"
|
|
14
|
+
@type="success"
|
|
15
|
+
@iconPrefix="fas"
|
|
16
|
+
@icon="check"
|
|
17
|
+
@text={{t "storefront.component.widget.orders.accept-order"}}
|
|
18
|
+
@onClick={{fn this.acceptOrder this.order}}
|
|
19
|
+
/>
|
|
20
|
+
{{/if}}
|
|
21
|
+
{{#if this.order.isPreparing}}
|
|
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
|
+
{{/if}}
|
|
24
|
+
{{#if this.order.isPickupReady}}
|
|
25
|
+
<Button @size="xs" @type="success" @icon="check" @text={{t "storefront.component.widget.orders.mark-as-completed"}} @onClick={{fn this.markAsCompleted this.order}} />
|
|
26
|
+
{{/if}}
|
|
27
|
+
{{#unless this.order.isCanceled}}
|
|
28
|
+
<Button @size="xs" @type="danger" @icon="ban" @helpText={{t "storefront.component.widget.orders.cancel-order"}} @onClick={{fn this.cancelOrder this.order}} />
|
|
29
|
+
{{/unless}}
|
|
30
|
+
</div>
|
|
31
|
+
</Overlay::Header>
|
|
32
|
+
<Overlay::Body>
|
|
33
|
+
<div class="py-4">
|
|
34
|
+
<div>
|
|
35
|
+
<div class="flex flex-col items-center justify-center">
|
|
36
|
+
<div class="p-2 rounded-md bg-white">
|
|
37
|
+
<Image src={{concat "data:image/png;base64," this.order.tracking_number.qr_code}} class="w-18 h-18" alt={{this.order.public_id}} />
|
|
38
|
+
</div>
|
|
39
|
+
<div class="text-center">
|
|
40
|
+
<h2 class="dark:text-gray-100 font-semibold">{{this.order.public_id}}</h2>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="text-xs">
|
|
43
|
+
{{this.order.createdAt}}
|
|
44
|
+
</div>
|
|
45
|
+
<div>
|
|
46
|
+
<Badge @status={{this.order.status}} />
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="grid grid-cols-2 lg:grid-cols-1 gap-3 justify-items-stretch auto-rows-max p-4">
|
|
51
|
+
{{#if this.order.tracking_statuses}}
|
|
52
|
+
<div class="col-span-2">
|
|
53
|
+
<Timeline @activity={{this.order.tracking_statuses}} @arrowClass="bg-gray-600 border border-gray-900 shadow-md" as |TimelineItem|>
|
|
54
|
+
<TimelineItem @activeStatus={{this.order.status}} as |trackingStatus|>
|
|
55
|
+
<div class="flex flex-col px-3 py-2 rounded text-sm leading-4 space-y-2 bg-gray-200 dark:bg-gray-800 dark:text-white">
|
|
56
|
+
<div class="flex flex-col space-y-1">
|
|
57
|
+
<div class="text-xs font-semibold truncate">{{trackingStatus.status}}</div>
|
|
58
|
+
<div class="text-xs truncate">{{n-a trackingStatus.details}}</div>
|
|
59
|
+
<div class="text-xs">{{trackingStatus.createdAtShortWithTime}}</div>
|
|
60
|
+
</div>
|
|
61
|
+
<Attach::Tooltip @class="clean" @animation="scale" @placement="top">
|
|
62
|
+
<InputInfo>
|
|
63
|
+
<div class="text-xs">{{or trackingStatus.details trackingStatus.status}}</div>
|
|
64
|
+
<div class="text-xs">{{trackingStatus.createdAtShortWithTime}}</div>
|
|
65
|
+
</InputInfo>
|
|
66
|
+
</Attach::Tooltip>
|
|
67
|
+
</div>
|
|
68
|
+
</TimelineItem>
|
|
69
|
+
</Timeline>
|
|
70
|
+
</div>
|
|
71
|
+
{{/if}}
|
|
72
|
+
<div class="col-span-2">
|
|
73
|
+
<div class="bg-gray-100 border border-gray-200 dark:bg-gray-800 dark:border-gray-700 rounded-md px-4 py-2 space-y-2">
|
|
74
|
+
<h5 class="dark:text-gray-100 font-semibold">{{t "storefront.common.store"}}</h5>
|
|
75
|
+
<div class="flex items-start space-x-4">
|
|
76
|
+
<Image src={{this.store.logo_url}} class="w-12 h-12 rounded-md shadow-sm" alt={{this.store.name}} />
|
|
77
|
+
<div>
|
|
78
|
+
<h5 class="font-semibold dark:text-white text-base">{{this.store.name}}</h5>
|
|
79
|
+
<DisplayPlace @place={{this.order.payload.pickup}} @type="store location" @addressClass="text-xs dark:text-gray-100" @noAddressClass="text-xs" />
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
<div class="col-span-2">
|
|
85
|
+
<div class="flex {{if (media 'isMobile') 'flex-col space-y-3' 'flex-row space-x-3'}} items-stretch">
|
|
86
|
+
{{#unless this.order.meta.is_pickup}}
|
|
87
|
+
<div class="flex-1 self-stretch">
|
|
88
|
+
<div class="bg-gray-100 border border-gray-200 dark:bg-gray-800 dark:border-gray-700 rounded-md px-4 py-2 space-y-2 h-full">
|
|
89
|
+
<h5 class="dark:text-gray-100 font-semibold">{{t "storefront.component.modals.incoming-order.assigned"}}</h5>
|
|
90
|
+
<div class="flex flex-col space-y-4">
|
|
91
|
+
{{#if this.order.driver_assigned.id}}
|
|
92
|
+
<div class="flex items-center">
|
|
93
|
+
<Image src={{this.order.driver_assigned.photoUrl}} class="w-12 h-12 rounded-md shadow-sm mr-4" alt={{this.order.driver_assigned.name}} />
|
|
94
|
+
<div>
|
|
95
|
+
<h5 class="font-semibold dark:text-white text-xs">{{n-a this.order.driver_assigned.displayName}}</h5>
|
|
96
|
+
<div class="font-semibold dark:text-gray-100 text-xs">{{n-a
|
|
97
|
+
this.order.driver_assigned.phone
|
|
98
|
+
(t "storefront.component.modals.incoming-order.no-phone")
|
|
99
|
+
}}</div>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
{{else}}
|
|
103
|
+
<div>
|
|
104
|
+
<h5 class="text-red-500 text-sm">{{t "storefront.component.modals.incoming-order.not-assigned"}}</h5>
|
|
105
|
+
</div>
|
|
106
|
+
{{/if}}
|
|
107
|
+
{{#if @options.assignDriver}}
|
|
108
|
+
<div>
|
|
109
|
+
<Button
|
|
110
|
+
@size="xs"
|
|
111
|
+
@type="default"
|
|
112
|
+
@icon="id-card"
|
|
113
|
+
@text={{if
|
|
114
|
+
this.order.has_driver_assigned
|
|
115
|
+
(t "storefront.component.modals.incoming-order.change-driver")
|
|
116
|
+
(t "storefront.component.modals.incoming-order.assign-driver")
|
|
117
|
+
}}
|
|
118
|
+
@onClick={{@options.assignDriver}}
|
|
119
|
+
/>
|
|
120
|
+
</div>
|
|
121
|
+
{{/if}}
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
{{/unless}}
|
|
126
|
+
<div class="flex-1 self-stretch">
|
|
127
|
+
<div class="bg-gray-100 border border-gray-200 dark:bg-gray-800 dark:border-gray-700 rounded-md px-4 py-2 space-y-2 h-full">
|
|
128
|
+
<h5 class="dark:text-gray-100 font-semibold">{{t "storefront.common.customer"}}</h5>
|
|
129
|
+
<div class="">
|
|
130
|
+
<div class="flex flex-row">
|
|
131
|
+
<div>
|
|
132
|
+
<Image src={{avatar-url this.order.customer.photo_url}} class="w-12 h-12 rounded-md shadow-sm mr-4" alt={{this.order.customer.name}} />
|
|
133
|
+
</div>
|
|
134
|
+
<div>
|
|
135
|
+
<div class="text-xs font-bold dark:text-gray-100">{{this.order.customer.name}}</div>
|
|
136
|
+
<div class="text-xs dark:text-gray-100">{{this.order.customer.email}}</div>
|
|
137
|
+
<div class="text-xs dark:text-gray-100">{{this.order.customer.phone}}</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
{{#unless this.order.meta.is_pickup}}
|
|
141
|
+
<div class="mt-2">
|
|
142
|
+
<h5 class="dark:text-gray-100 font-semibold text-xs truncate">{{t "storefront.component.modals.incoming-order.address"}}</h5>
|
|
143
|
+
<div class="flex flex-row mt-1">
|
|
144
|
+
<div class="flex items-center justify-center rounded-full bg-blue-500 w-8 h-8 mr-3">
|
|
145
|
+
<FaIcon @icon="map-marker-alt" class="text-white" />
|
|
146
|
+
</div>
|
|
147
|
+
<div class="truncate">
|
|
148
|
+
<DisplayPlace
|
|
149
|
+
@place={{this.order.payload.dropoff}}
|
|
150
|
+
@type="dropoff"
|
|
151
|
+
@addressClass="text-xs dark:text-gray-100"
|
|
152
|
+
@noAddressClass="text-xs"
|
|
153
|
+
/>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
{{/unless}}
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
<div class="col-span-2">
|
|
164
|
+
<div class="bg-gray-100 border border-gray-200 dark:bg-gray-800 dark:border-gray-700 rounded-md px-4 py-2 space-y-2">
|
|
165
|
+
{{#if this.order.meta.is_pickup}}
|
|
166
|
+
<h5 class="dark:text-gray-100 font-semibold">{{t "storefront.common.pickup"}}</h5>
|
|
167
|
+
{{else}}
|
|
168
|
+
<h5 class="dark:text-gray-100 font-semibold">{{t "storefront.common.delivery"}}</h5>
|
|
169
|
+
{{/if}}
|
|
170
|
+
<div>
|
|
171
|
+
{{#if this.order.meta.is_pickup}}
|
|
172
|
+
<div class="flex-1">
|
|
173
|
+
<InfoBlock @size="xs" class="mb-3">{{t "storefront.component.modals.incoming-order.pickup-order"}}</InfoBlock>
|
|
174
|
+
<div class="flex flex-row">
|
|
175
|
+
<div class="flex items-center justify-center rounded-full bg-blue-500 w-8 h-8 mr-3">
|
|
176
|
+
<FaIcon @icon="store-alt" class="text-white" />
|
|
177
|
+
</div>
|
|
178
|
+
<DisplayPlace @place={{this.order.payload.pickup}} @type="pickup" @addressClass="text-xs dark:text-gray-100" @noAddressClass="text-xs" />
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
{{else if this.order.payload.hasWaypoints}}
|
|
182
|
+
<RouteList @order={{this.order}} />
|
|
183
|
+
{{else}}
|
|
184
|
+
<div class="order-route-list storefront flex-1">
|
|
185
|
+
<div class="order-route-stop">
|
|
186
|
+
<div class="order-route-stop-index">
|
|
187
|
+
<div class="index-count">
|
|
188
|
+
<FaIcon @prefix="fas" @icon="store-alt" />
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
<div class="order-route-location dark:text-gray-100">
|
|
192
|
+
<DisplayPlace @place={{this.order.payload.pickup}} @type="pickup" @addressClass="text-xs dark:text-gray-100" @noAddressClass="text-xs" />
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
<div class="order-route-stop">
|
|
196
|
+
<div class="order-route-stop-index">
|
|
197
|
+
<div class="index-count">
|
|
198
|
+
<FaIcon @prefix="fas" @icon="map-marker-alt" />
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
<div class="order-route-location dark:text-gray-100">
|
|
202
|
+
<DisplayPlace @place={{this.order.payload.dropoff}} @type="dropoff" @addressClass="text-xs dark:text-gray-100" @noAddressClass="text-xs" />
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
{{/if}}
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
<div class="col-span-2">
|
|
211
|
+
<div class="bg-gray-100 border border-gray-200 dark:bg-gray-800 dark:border-gray-700 rounded-md px-4 py-2 space-y-2">
|
|
212
|
+
<div class="flex flex-row items-center space-x-2">
|
|
213
|
+
<h5 class="dark:text-gray-100 font-semibold">{{t "storefront.component.modals.incoming-order.tracking"}}</h5>
|
|
214
|
+
<h5 class="dark:text-gray-100 font-semibold">({{this.order.tracking}})</h5>
|
|
215
|
+
</div>
|
|
216
|
+
<div class="flex flex-row items-center justify-center space-x-4">
|
|
217
|
+
<div class="p-2 rounded-md bg-white">
|
|
218
|
+
<Image src={{concat "data:image/png;base64," this.order.tracking_number.qr_code}} class="w-14 h-14" alt={{this.order.public_id}} />
|
|
219
|
+
</div>
|
|
220
|
+
<div class="p-2 rounded-md bg-white">
|
|
221
|
+
<Image src={{concat "data:image/png;base64," this.order.tracking_number.barcode}} class="w-40 h-14" alt={{this.order.public_id}} />
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
<div class="col-span-2">
|
|
227
|
+
<div class="bg-gray-100 border border-gray-200 dark:bg-gray-800 dark:border-gray-700 rounded-md px-4 py-2 space-y-2">
|
|
228
|
+
<div class="flex flex-row items-center justify-between">
|
|
229
|
+
<h5 class="dark:text-gray-100 font-semibold">{{t "storefront.component.modals.incoming-order.summary"}}</h5>
|
|
230
|
+
{{#if this.order.payload.cod_amount}}
|
|
231
|
+
<div>
|
|
232
|
+
<FaIcon @icon="money-bill-wave" @size="sm" class="text-green-400 mr-1" />
|
|
233
|
+
<span class="font-semibold text-green-400 text-sm">{{t "storefront.common.cash"}}</span>
|
|
234
|
+
</div>
|
|
235
|
+
{{/if}}
|
|
236
|
+
</div>
|
|
237
|
+
<div>
|
|
238
|
+
<div class="flex flex-col space-y-4 overflow-hidden py-4">
|
|
239
|
+
{{#each this.order.payload.entities as |entity|}}
|
|
240
|
+
<div class="flex flex-1">
|
|
241
|
+
<div class="mr-2">
|
|
242
|
+
<div class="flex items-center justify-center w-5 h-5 border border-gray-100 dark:border-blue-400 rounded-md">
|
|
243
|
+
<span class="text-blue-400 text-xs">{{entity.meta.quantity}}x</span>
|
|
244
|
+
</div>
|
|
245
|
+
</div>
|
|
246
|
+
<div class="flex-1 flex">
|
|
247
|
+
<div class="mr-4">
|
|
248
|
+
<img src={{entity.photo_url}} class="w-12 h-12 rounded-md shadow-sm" alt={{entity.name}} />
|
|
249
|
+
</div>
|
|
250
|
+
<div>
|
|
251
|
+
<h4 class="font-semibold dark:text-gray-100 mb-1 text-sm">{{entity.name}}</h4>
|
|
252
|
+
<div class="flex flex-wrap truncate w-44">
|
|
253
|
+
<p class="dark:text-gray-50 text-xs truncate">{{entity.description}}</p>
|
|
254
|
+
</div>
|
|
255
|
+
<div>
|
|
256
|
+
{{#each entity.meta.variants as |variant|}}
|
|
257
|
+
<div>
|
|
258
|
+
<span class="text-xs dark:text-gray-50">{{variant.name}}</span>
|
|
259
|
+
</div>
|
|
260
|
+
{{/each}}
|
|
261
|
+
</div>
|
|
262
|
+
<div>
|
|
263
|
+
{{#each entity.meta.addons as |addon|}}
|
|
264
|
+
<div>
|
|
265
|
+
<span class="text-xs dark:text-gray-50">+ {{addon.name}}</span>
|
|
266
|
+
</div>
|
|
267
|
+
{{/each}}
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
</div>
|
|
271
|
+
<div class="px-6">
|
|
272
|
+
<span class="dark:text-gray-50 text-sm">{{format-currency entity.meta.subtotal entity.currency}}</span>
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
{{/each}}
|
|
276
|
+
</div>
|
|
277
|
+
<div class="px-6 py-2.5 space-y-2 border-t border-b border-gray-200 dark:border-gray-700">
|
|
278
|
+
<div class="flex items-center justify-between">
|
|
279
|
+
<span class="dark:text-gray-50 text-sm">{{t "storefront.component.modals.incoming-order.subtotal"}}</span>
|
|
280
|
+
<span class="dark:text-gray-50 text-sm">{{format-currency this.order.meta.subtotal this.order.meta.currency}}</span>
|
|
281
|
+
</div>
|
|
282
|
+
{{#unless this.order.meta.is_pickup}}
|
|
283
|
+
<div class="flex items-center justify-between">
|
|
284
|
+
<span class="dark:text-gray-50 text-sm">{{t "storefront.component.modals.incoming-order.fee"}}</span>
|
|
285
|
+
<span class="dark:text-gray-50 text-sm">{{format-currency this.order.meta.delivery_fee this.order.meta.currency}}</span>
|
|
286
|
+
</div>
|
|
287
|
+
{{/unless}}
|
|
288
|
+
{{#if this.order.meta.tip}}
|
|
289
|
+
<div class="flex items-center justify-between">
|
|
290
|
+
<span class="dark:text-gray-50 text-sm">{{t "storefront.component.modals.incoming-order.tip"}}</span>
|
|
291
|
+
<span class="dark:text-gray-50 text-sm">{{get-tip-amount this.order.meta.tip this.order.meta.subtotal this.order.meta.currency}}</span>
|
|
292
|
+
</div>
|
|
293
|
+
{{/if}}
|
|
294
|
+
{{#if this.order.meta.delivery_tip}}
|
|
295
|
+
<div class="flex items-center justify-between">
|
|
296
|
+
<span class="dark:text-gray-50 text-sm">{{t "storefront.component.modals.incoming-order.delivery-tip"}}</span>
|
|
297
|
+
<span class="dark:text-gray-50 text-sm">{{get-tip-amount this.order.meta.delivery_tip this.order.meta.subtotal this.order.meta.currency}}</span>
|
|
298
|
+
</div>
|
|
299
|
+
{{/if}}
|
|
300
|
+
</div>
|
|
301
|
+
<div class="px-6 py-2">
|
|
302
|
+
<div class="flex items-center justify-between">
|
|
303
|
+
<span class="dark:text-gray-50 font-bold text-sm">{{t "storefront.common.total"}}</span>
|
|
304
|
+
<span class="dark:text-gray-50 font-bold text-sm">{{format-currency this.order.meta.total this.order.meta.currency}}</span>
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
307
|
+
</div>
|
|
308
|
+
</div>
|
|
309
|
+
</div>
|
|
310
|
+
</div>
|
|
311
|
+
</div>
|
|
312
|
+
<Spacer @height="300px" />
|
|
313
|
+
</Overlay::Body>
|
|
314
|
+
</Overlay>
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import Component from '@glimmer/component';
|
|
2
|
-
import { tracked } from '@glimmer/tracking';
|
|
3
|
-
import { action } from '@ember/object';
|
|
4
2
|
import applyContextComponentArguments from '@fleetbase/ember-core/utils/apply-context-component-arguments';
|
|
5
3
|
import contextComponentCallback from '@fleetbase/ember-core/utils/context-component-callback';
|
|
4
|
+
import { tracked } from '@glimmer/tracking';
|
|
5
|
+
import { action } from '@ember/object';
|
|
6
|
+
import { inject as service } from '@ember/service';
|
|
7
|
+
import { debug } from '@ember/debug';
|
|
8
|
+
import { task } from 'ember-concurrency';
|
|
6
9
|
|
|
7
10
|
export default class OrderPanelComponent extends Component {
|
|
11
|
+
@service storefront;
|
|
12
|
+
@service orderActions;
|
|
8
13
|
@tracked context = null;
|
|
14
|
+
@tracked store = null;
|
|
9
15
|
|
|
10
16
|
constructor() {
|
|
11
17
|
super(...arguments);
|
|
12
18
|
applyContextComponentArguments(this);
|
|
19
|
+
this.loadActiveStore.perform();
|
|
13
20
|
}
|
|
14
21
|
|
|
15
22
|
/**
|
|
@@ -31,6 +38,47 @@ export default class OrderPanelComponent extends Component {
|
|
|
31
38
|
* @returns {Boolean} Indicates whether the cancel action was overridden.
|
|
32
39
|
*/
|
|
33
40
|
@action onPressCancel() {
|
|
34
|
-
return contextComponentCallback(this, 'onPressCancel', this.
|
|
41
|
+
return contextComponentCallback(this, 'onPressCancel', this.order);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@action acceptOrder(order) {
|
|
45
|
+
this.orderActions.acceptOrder(order);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@action markAsReady(order) {
|
|
49
|
+
this.orderActions.markAsReady(order);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@action markAsCompleted(order) {
|
|
53
|
+
this.orderActions.markAsCompleted(order);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@action assignDriver(order) {
|
|
57
|
+
this.orderActions.assignDriver(order);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@action cancelOrder(order) {
|
|
61
|
+
this.orderActions.cancelOrder(order);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@task *loadActiveStore() {
|
|
65
|
+
const storefrontId = this.order.meta.storefront_id;
|
|
66
|
+
if (!storefrontId) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const currentStore = this.storefront.activeStore;
|
|
71
|
+
if (storefrontId === currentStore.public_id) {
|
|
72
|
+
this.store = currentStore;
|
|
73
|
+
return currentStore;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const store = yield this.store.findRecord('store', storefrontId);
|
|
78
|
+
this.store = store;
|
|
79
|
+
return store;
|
|
80
|
+
} catch (err) {
|
|
81
|
+
debug(`Unable to load store for ${this.order.public_id}:`, err);
|
|
82
|
+
}
|
|
35
83
|
}
|
|
36
84
|
}
|
|
@@ -1,55 +1,79 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
{{#if (and this.loadCustomers.isRunning (not this.loaded))}}
|
|
2
|
+
<div class="next-content-panel-wrapper">
|
|
3
|
+
<div class="next-content-panel-container">
|
|
4
|
+
<div class="next-content-panel next-content-panel-is-closed">
|
|
5
|
+
<div class="next-content-panel-header next-content-panel-toggle next-content-panel-is-closed">
|
|
6
|
+
<a href="javascript:;" class="next-content-panel-header-left">
|
|
7
|
+
<span class="icon-container">
|
|
8
|
+
<Spinner class="text-sky-400" @height="13" @width="13" />
|
|
9
|
+
</span>
|
|
10
|
+
<div class="next-content-panel-title-container">
|
|
11
|
+
<div class="panel-title flex-shrink-0">
|
|
12
|
+
<div class="flex flex-col">
|
|
13
|
+
<span>{{this.title}}</span>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
</a>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
14
20
|
</div>
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<
|
|
21
|
+
</div>
|
|
22
|
+
{{else}}
|
|
23
|
+
<ContentPanel
|
|
24
|
+
@title={{this.title}}
|
|
25
|
+
@titleStatusRight={{this.customers.length}}
|
|
26
|
+
@titleStatusRightClass="info-status-badge"
|
|
27
|
+
@hideStatusDot={{true}}
|
|
28
|
+
@open={{gt this.customers.length 0}}
|
|
29
|
+
@isLoading={{this.loadCustomers.isRunning}}
|
|
30
|
+
@pad={{false}}
|
|
31
|
+
@wrapperClass={{@wrapperClass}}
|
|
32
|
+
>
|
|
33
|
+
{{#if (media "isMobile")}}
|
|
34
|
+
<div class="flex flex-col p-3 space-y-3">
|
|
29
35
|
{{#each this.customers as |customer|}}
|
|
30
|
-
<
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
<div class="py-2 px-3 rounded-md border border-gray-400 dark:border-gray-700">
|
|
37
|
+
<div class="flex flex-row">
|
|
38
|
+
<div>
|
|
39
|
+
<Image src={{avatar-url customer.photo_url}} class="w-12 h-12 rounded-md shadow-sm mr-4" alt={{customer.name}} />
|
|
40
|
+
</div>
|
|
41
|
+
<div>
|
|
42
|
+
<div class="text-xs font-bold dark:text-gray-100">{{customer.name}}</div>
|
|
43
|
+
<div class="text-xs dark:text-gray-100">{{customer.email}}</div>
|
|
44
|
+
<div class="text-xs dark:text-gray-100">{{customer.phone}}</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
38
48
|
{{/each}}
|
|
39
|
-
</tbody>
|
|
40
|
-
</table>
|
|
41
|
-
</div>
|
|
42
|
-
<div class="flex flex-col md:hidden p-3 space-y-3">
|
|
43
|
-
{{#each this.customers as |customer|}}
|
|
44
|
-
<div class="py-2 px-3 rounded-md border border-gray-400 dark:border-gray-700">
|
|
45
|
-
<div class="flex flex-row">
|
|
46
|
-
<div class="flex-1 font-semibold">{{customer.name}}</div>
|
|
47
|
-
</div>
|
|
48
|
-
<div class="flex flex-col">
|
|
49
|
-
<div class="text-xs">{{t "storefront.component.widget.customers.phone"}}{{n-a customer.phone}}</div>
|
|
50
|
-
<div class="text-xs">{{t "storefront.component.widget.customers.email"}} {{n-a customer.email}}</div>
|
|
51
|
-
</div>
|
|
52
49
|
</div>
|
|
53
|
-
{{
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
{{else}}
|
|
51
|
+
<div class="table-wrapper table-fluid">
|
|
52
|
+
<table class="storefront-widget-table">
|
|
53
|
+
<thead>
|
|
54
|
+
<tr class="h-12 text-left py-1">
|
|
55
|
+
<th>{{t "storefront.common.id"}}</th>
|
|
56
|
+
<th>{{t "storefront.common.name"}}</th>
|
|
57
|
+
<th>{{t "storefront.common.phone"}}</th>
|
|
58
|
+
<th>{{t "storefront.common.email"}}</th>
|
|
59
|
+
<th>{{t "storefront.common.orders"}}</th>
|
|
60
|
+
<th></th>
|
|
61
|
+
</tr>
|
|
62
|
+
</thead>
|
|
63
|
+
<tbody>
|
|
64
|
+
{{#each this.customers as |customer|}}
|
|
65
|
+
<tr class="h-12">
|
|
66
|
+
<td><a href="javascript:;" {{on "click" (fn this.viewCustomer customer)}}>{{customer.customerId}}</a></td>
|
|
67
|
+
<td>{{n-a customer.name}}</td>
|
|
68
|
+
<td>{{n-a customer.phone}}</td>
|
|
69
|
+
<td>{{n-a customer.email}}</td>
|
|
70
|
+
<td></td>
|
|
71
|
+
<td></td>
|
|
72
|
+
</tr>
|
|
73
|
+
{{/each}}
|
|
74
|
+
</tbody>
|
|
75
|
+
</table>
|
|
76
|
+
</div>
|
|
77
|
+
{{/if}}
|
|
78
|
+
</ContentPanel>
|
|
79
|
+
{{/if}}
|
|
@@ -1,62 +1,50 @@
|
|
|
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 { action } from '@ember/object';
|
|
5
|
-
import
|
|
4
|
+
import { action, get } from '@ember/object';
|
|
5
|
+
import { debug } from '@ember/debug';
|
|
6
|
+
import { task } from 'ember-concurrency';
|
|
6
7
|
|
|
7
8
|
export default class WidgetCustomersComponent extends Component {
|
|
8
9
|
@service store;
|
|
9
10
|
@service storefront;
|
|
10
11
|
@service intl;
|
|
11
12
|
@service contextPanel;
|
|
12
|
-
@tracked
|
|
13
|
+
@tracked loaded = false;
|
|
13
14
|
@tracked customers = [];
|
|
14
15
|
@tracked title = this.intl.t('storefront.component.widget.customers.widget-title');
|
|
15
16
|
|
|
16
17
|
constructor(owner, { title }) {
|
|
17
18
|
super(...arguments);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
this.storefront.on('storefront.changed', this.reloadCustomers);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@action async reloadCustomers() {
|
|
29
|
-
this.customers = await this.fetchCustomers();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
@action fetchCustomers() {
|
|
33
|
-
this.isLoading = true;
|
|
34
|
-
|
|
35
|
-
return new Promise((resolve) => {
|
|
36
|
-
const storefront = this.storefront.getActiveStore('public_id');
|
|
37
|
-
|
|
38
|
-
if (!storefront) {
|
|
39
|
-
this.isLoading = false;
|
|
40
|
-
return resolve([]);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
this.store
|
|
44
|
-
.query('customer', {
|
|
45
|
-
storefront,
|
|
46
|
-
limit: 14,
|
|
47
|
-
})
|
|
48
|
-
.then((customers) => {
|
|
49
|
-
this.isLoading = false;
|
|
50
|
-
resolve(customers);
|
|
51
|
-
})
|
|
52
|
-
.catch(() => {
|
|
53
|
-
this.isLoading = false;
|
|
54
|
-
resolve(this.customers);
|
|
55
|
-
});
|
|
19
|
+
this.title = title ?? this.intl.t('storefront.component.widget.customers.widget-title');
|
|
20
|
+
this.loadCustomers.perform();
|
|
21
|
+
this.storefront.on('order.broadcasted', () => {
|
|
22
|
+
this.loadCustomers.perform();
|
|
23
|
+
});
|
|
24
|
+
this.storefront.on('storefront.changed', () => {
|
|
25
|
+
this.loadCustomers.perform();
|
|
56
26
|
});
|
|
57
27
|
}
|
|
58
28
|
|
|
59
29
|
@action viewCustomer(customer) {
|
|
60
30
|
this.contextPanel.focus(customer, 'viewing');
|
|
61
31
|
}
|
|
32
|
+
|
|
33
|
+
@task *loadCustomers(params = {}) {
|
|
34
|
+
const storefront = get(this.storefront, 'activeStore.public_id');
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const customers = yield this.store.query('customer', {
|
|
38
|
+
storefront,
|
|
39
|
+
limit: 14,
|
|
40
|
+
...params,
|
|
41
|
+
});
|
|
42
|
+
this.loaded = true;
|
|
43
|
+
this.customers = customers;
|
|
44
|
+
|
|
45
|
+
return customers;
|
|
46
|
+
} catch (err) {
|
|
47
|
+
debug('Error loading customers for widget:', err);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
62
50
|
}
|