@fleetbase/storefront-engine 0.4.1 → 0.4.3

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 (34) hide show
  1. package/addon/components/widget/orders.hbs +1 -1
  2. package/addon/controllers/products/index/category/new.js +13 -2
  3. package/addon/controllers/settings/notifications.js +1 -0
  4. package/addon/templates/home.hbs +2 -2
  5. package/addon/templates/networks/index/network/index.hbs +8 -8
  6. package/addon/templates/products/index/category/new.hbs +149 -134
  7. package/composer.json +1 -1
  8. package/extension.json +1 -1
  9. package/package.json +4 -4
  10. package/server/src/Console/Commands/MigrateStripeSandboxCustomers.php +15 -0
  11. package/server/src/Http/Controllers/FoodTruckController.php +10 -0
  12. package/server/src/Http/Controllers/v1/CheckoutController.php +12 -0
  13. package/server/src/Http/Filter/FoodTruckFilter.php +11 -0
  14. package/server/src/Http/Resources/Product.php +1 -0
  15. package/server/src/Models/FoodTruck.php +14 -2
  16. package/server/src/Notifications/StorefrontOrderAccepted.php +12 -4
  17. package/server/src/Notifications/StorefrontOrderCanceled.php +11 -1
  18. package/server/src/Notifications/StorefrontOrderCompleted.php +11 -1
  19. package/server/src/Notifications/StorefrontOrderDriverAssigned.php +12 -4
  20. package/server/src/Notifications/StorefrontOrderEnroute.php +12 -4
  21. package/server/src/Notifications/StorefrontOrderNearby.php +12 -4
  22. package/server/src/Notifications/StorefrontOrderPreparing.php +12 -4
  23. package/server/src/Notifications/StorefrontOrderReadyForPickup.php +12 -4
  24. package/server/src/Support/PushNotification.php +9 -2
  25. package/server/src/Support/Storefront.php +85 -1
  26. package/translations/{ar-ae.yml → ar-ae.yaml} +313 -253
  27. package/translations/bg-bg.yaml +734 -0
  28. package/translations/es-es.yaml +732 -0
  29. package/translations/fr-fr.yaml +748 -0
  30. package/translations/mn-mn.yaml +725 -0
  31. package/translations/pt-br.yaml +732 -0
  32. package/translations/ru-ru.yaml +726 -0
  33. package/translations/vi-vn.yaml +412 -338
  34. package/translations/zh-cn.yaml +659 -0
@@ -25,7 +25,7 @@
25
25
  @titleStatusRight={{this.orders.length}}
26
26
  @titleStatuRightClass="info-status-badge"
27
27
  @hideStatusDot={{true}}
28
- @open={{gt this.orders.length 0}}
28
+ @open={{true}}
29
29
  @isLoading={{this.loadOrders.isRunning}}
30
30
  @pad={{false}}
31
31
  @wrapperClass={{@wrapperClass}}
@@ -21,7 +21,14 @@ export default class ProductsIndexCategoryNewController extends BaseController {
21
21
  @service crud;
22
22
  @service hostRouter;
23
23
  @alias('storefront.activeStore') activeStore;
24
- @tracked product = this.store.createRecord('product', { store_uuid: this.activeStore.id, currency: this.activeStore.currency, tags: [], meta_array: [], status: 'published' });
24
+ @tracked product = this.store.createRecord('product', {
25
+ store_uuid: this.activeStore.id,
26
+ currency: this.activeStore.currency,
27
+ tags: [],
28
+ meta_array: [],
29
+ category: this.category,
30
+ status: 'published',
31
+ });
25
32
  @tracked uploadQueue = [];
26
33
  @tracked uploadedFiles = [];
27
34
  @tracked primaryFile = null;
@@ -29,6 +36,10 @@ export default class ProductsIndexCategoryNewController extends BaseController {
29
36
  @tracked statusOptions = ['published', 'draft'];
30
37
  abilityPermission = 'storefront create product';
31
38
 
39
+ get category() {
40
+ return this.productsIndexCategoryController?.category ?? null;
41
+ }
42
+
32
43
  /** overlay options */
33
44
  @tracked overlayTitle = 'New Product';
34
45
  @tracked overlayActionButtonTitle = 'Create Product';
@@ -47,7 +58,7 @@ export default class ProductsIndexCategoryNewController extends BaseController {
47
58
  @tracked acceptedFileTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'video/mp4', 'video/quicktime', 'video/x-msvideo', 'video/x-flv', 'video/x-ms-wmv'];
48
59
 
49
60
  @action reset() {
50
- this.product = this.store.createRecord('product', { store_uuid: this.activeStore.id, currency: this.activeStore.currency });
61
+ this.product = this.store.createRecord('product', { store_uuid: this.activeStore.id, category: this.category, currency: this.activeStore.currency });
51
62
  this.uploadQueue = [];
52
63
  this.uploadedFiles = [];
53
64
  }
@@ -12,6 +12,7 @@ export default class SettingsNotificationsController extends Controller {
12
12
  @service intl;
13
13
  @service crud;
14
14
  @service storefront;
15
+ @service hostRouter;
15
16
  @alias('storefront.activeStore') activeStore;
16
17
 
17
18
  @action createChannel() {
@@ -2,7 +2,7 @@
2
2
 
3
3
  <Layout::Section::Body class="space-y-4 h-full overflow-y-scroll" @padded={{true}}>
4
4
  <Widget::StorefrontMetrics />
5
- <Widget::Orders />
6
- <Widget::Customers />
5
+ <Widget::Orders @wrapperClass="bordered-classic" />
6
+ <Widget::Customers @wrapperClass="bordered-classic" />
7
7
  <Spacer @height="300px" />
8
8
  </Layout::Section::Body>
@@ -1,5 +1,5 @@
1
- <div class="space-y-4 px-6 py-4">
2
- <ContentPanel @title={{t "storefront.networks.index.network.index.general-network-settings-title"}} @open={{true}} @pad={{true}}>
1
+ <div class="space-y-2">
2
+ <ContentPanel @title={{t "storefront.networks.index.network.index.general-network-settings-title"}} @open={{true}} @pad={{false}} @wrapperClass="bordered-top">
3
3
  <div class="space-y-4">
4
4
  <div>
5
5
  <h1 class="text-lg leading-6 font-bold text-gray-900 dark:text-gray-100">
@@ -39,7 +39,7 @@
39
39
  />
40
40
  </InputGroup>
41
41
 
42
- <ContentPanel @title={{t "storefront.networks.index.network.index.general-network-settings-form.contact-social-panel.panel-title"}} @open={{false}} @pad={{true}}>
42
+ <ContentPanel @title={{t "storefront.networks.index.network.index.general-network-settings-form.contact-social-panel.panel-title"}} @open={{false}} @pad={{false}} @wrapperClass="bordered-top">
43
43
  <InputGroup @name={{t "storefront.networks.index.network.index.general-network-settings-form.contact-social-panel.phone"}}>
44
44
  <PhoneInput @value={{@model.phone}} @onInput={{fn (mut @model.phone)}} class="form-input w-full" />
45
45
  </InputGroup>
@@ -75,7 +75,7 @@
75
75
  />
76
76
  </ContentPanel>
77
77
 
78
- <ContentPanel @title={{t "storefront.networks.index.network.index.general-network-settings-form.logo-backdrop-panel.panel-title"}} @open={{false}} @pad={{true}}>
78
+ <ContentPanel @title={{t "storefront.networks.index.network.index.general-network-settings-form.logo-backdrop-panel.panel-title"}} @open={{false}} @pad={{false}} @wrapperClass="bordered-top">
79
79
  <InputGroup
80
80
  @name={{t "storefront.networks.index.network.index.general-network-settings-form.logo-backdrop-panel.logo-label"}}
81
81
  @helpText={{t "storefront.networks.index.network.index.general-network-settings-form.logo-backdrop-panel.logo-help-text"}}
@@ -268,7 +268,7 @@
268
268
  </div>
269
269
  </ContentPanel>
270
270
 
271
- <ContentPanel @title={{t "storefront.networks.index.network.index.api-panel.panel-title"}} @open={{false}} @pad={{true}}>
271
+ <ContentPanel @title={{t "storefront.networks.index.network.index.api-panel.panel-title"}} @open={{false}} @pad={{false}} @wrapperClass="bordered-top">
272
272
  <div class="space-y-6">
273
273
  <div>
274
274
  <h1 class="text-lg leading-6 font-bold text-gray-900 dark:text-gray-100">
@@ -288,7 +288,7 @@
288
288
  </div>
289
289
  </ContentPanel>
290
290
 
291
- <ContentPanel @title={{t "storefront.networks.index.network.index.payment-gateways-panel.panel-title"}} @open={{false}} @pad={{true}}>
291
+ <ContentPanel @title={{t "storefront.networks.index.network.index.payment-gateways-panel.panel-title"}} @open={{false}} @pad={{false}} @wrapperClass="bordered-top">
292
292
  <div class="space-y-6">
293
293
  <div class="flex justify-between">
294
294
  <div>
@@ -311,7 +311,7 @@
311
311
  </div>
312
312
 
313
313
  {{#each this.gateways as |gateway|}}
314
- <ContentPanel @title={{gateway.name}} @open={{true}} @pad={{true}}>
314
+ <ContentPanel @title={{gateway.name}} @open={{true}} @pad={{false}} @wrapperClass="bordered-top">
315
315
  <InputGroup
316
316
  @name={{t "storefront.networks.index.network.index.payment-gateways-panel.gateway-form.name"}}
317
317
  @value={{gateway.name}}
@@ -368,7 +368,7 @@
368
368
  </div>
369
369
  </ContentPanel>
370
370
 
371
- <ContentPanel @title={{t "storefront.networks.index.network.index.notification-channels-panel.panel-title"}} @open={{false}} @pad={{true}}>
371
+ <ContentPanel @title={{t "storefront.networks.index.network.index.notification-channels-panel.panel-title"}} @open={{false}} @pad={{false}} @wrapperClass="bordered-top">
372
372
  <div class="space-y-6">
373
373
  <div class="flex justify-between">
374
374
  <div class="w-3/4">
@@ -7,79 +7,100 @@
7
7
  @headerLeftInnerClass="w-full flex-1"
8
8
  @onPressCancel={{this.transitionBack}}
9
9
  >
10
- <Button
11
- @icon={{this.overlayActionButtonIcon}}
12
- @type="primary"
13
- @text={{this.overlayActionButtonTitle}}
14
- @onClick={{perform this.saveProduct}}
15
- @isLoading={{not this.saveProduct.isIdle}}
16
- @permission={{this.abilityPermission}}
17
- />
10
+ <:actions>
11
+ <Button
12
+ @icon={{this.overlayActionButtonIcon}}
13
+ @type="primary"
14
+ @text={{this.overlayActionButtonTitle}}
15
+ @onClick={{perform this.saveProduct}}
16
+ @isLoading={{not this.saveProduct.isIdle}}
17
+ @permission={{this.abilityPermission}}
18
+ />
19
+ </:actions>
18
20
  </Overlay::Header>
19
21
 
20
- <Overlay::Body @increaseInnerBodyHeightBy="0" @wrapperClass="new-order-overlay-body px-4 space-y-4 pt-4">
22
+ <Overlay::Body>
21
23
  {{#let (cannot this.abilityPermission) as |unauthorized|}}
22
- <InputGroup @name="Product Name" @value={{this.product.name}} @helpText="Enter your product's name" @disabled={{unauthorized}} />
23
- <InputGroup @name="Product Description" @helpText="Enter a description of your product">
24
- <Textarea @value={{this.product.description}} class="form-input w-full" placeholder="Enter a description of your product...." disabled={{unauthorized}} rows={{4}} />
25
- </InputGroup>
26
- <InputGroup @name="Product Status">
27
- <Select
28
- class="w-full"
29
- @value={{this.product.status}}
30
- @placeholder="Select product status"
31
- @options={{this.statusOptions}}
32
- @onSelect={{fn (mut this.product.status)}}
33
- @humanize={{true}}
34
- />
35
- </InputGroup>
36
- <InputGroup @name="Product Tags">
37
- <TagInput
38
- class="form-input"
39
- @placeholder="Add tags"
40
- @allowSpacesInTags={{true}}
41
- @tags={{this.product.tags}}
42
- @addTag={{this.addTag}}
43
- @removeTagAtIndex={{this.removeTag}}
44
- @disabled={{unauthorized}}
45
- as |tag|
46
- >
47
- {{tag}}
48
- </TagInput>
49
- </InputGroup>
50
- <InputGroup @name="Product SKU" @value={{this.product.sku}} @helpText="Enter product SKU if applicable" @disabled={{unauthorized}} />
51
- <div class="grid grid-cols-2 gap-2">
52
- <InputGroup @name="Price" @helpText="Enter a price users will pay to purchase this product">
53
- <MoneyInput
24
+ <ContentPanel @title={{t "common.details"}} @open={{true}} @wrapperClass="bordered-top">
25
+ <InputGroup @name="Product Name" @value={{this.product.name}} @helpText="Enter your product's name" @disabled={{unauthorized}} />
26
+ <InputGroup @name="Product Description" @helpText="Enter a description of your product">
27
+ <Textarea @value={{this.product.description}} class="form-input w-full" placeholder="Enter a description of your product...." disabled={{unauthorized}} rows={{4}} />
28
+ </InputGroup>
29
+ <InputGroup @name="Product Category">
30
+ <ModelSelect
31
+ @modelName="category"
32
+ @selectedModel={{this.product.category}}
33
+ @query={{hash for="storefront_product" owner_uuid=this.activeStore.id}}
34
+ @placeholder="Select Product Category"
35
+ @triggerClass="form-select form-input"
36
+ @infiniteScroll={{false}}
37
+ @renderInPlace={{true}}
38
+ @allowClear={{true}}
39
+ @onChange={{fn (mut this.product.category)}}
40
+ @onChangeId={{fn (mut this.product.category_uuid)}}
41
+ as |model|
42
+ >
43
+ <div class="flex items-center">
44
+ <span class="uppercase">
45
+ {{model.name}}
46
+ </span>
47
+ </div>
48
+ </ModelSelect>
49
+ </InputGroup>
50
+ <InputGroup @name="Product Status">
51
+ <Select
54
52
  class="w-full"
55
- @currency={{if this.product.currency this.product.currency this.activeStore.currency}}
56
- @value={{this.product.price}}
57
- @canSelectCurrency={{false}}
58
- @onCurrencyChange={{fn (mut this.product.currency)}}
59
- @disabled={{unauthorized}}
53
+ @value={{this.product.status}}
54
+ @placeholder="Select product status"
55
+ @options={{this.statusOptions}}
56
+ @onSelect={{fn (mut this.product.status)}}
57
+ @humanize={{true}}
60
58
  />
61
59
  </InputGroup>
62
- <InputGroup @name="Sale Price" @helpText="Optionally add a sale price for the product if the product is put on sale">
63
- <MoneyInput
64
- class="w-full"
65
- @currency={{if this.product.currency this.product.currency this.activeStore.currency}}
66
- @value={{this.product.sale_price}}
67
- @canSelectCurrency={{false}}
68
- @onCurrencyChange={{fn (mut this.product.currency)}}
60
+ <InputGroup @name="Product Tags">
61
+ <TagInput
62
+ class="form-input"
63
+ @placeholder="Add tags"
64
+ @allowSpacesInTags={{true}}
65
+ @tags={{this.product.tags}}
66
+ @addTag={{this.addTag}}
67
+ @removeTagAtIndex={{this.removeTag}}
69
68
  @disabled={{unauthorized}}
70
- />
69
+ as |tag|
70
+ >
71
+ {{tag}}
72
+ </TagInput>
71
73
  </InputGroup>
72
- </div>
74
+ <InputGroup @name="Product SKU" @value={{this.product.sku}} @helpText="Enter product SKU if applicable" @disabled={{unauthorized}} />
75
+ <div class="grid grid-cols-2 gap-2">
76
+ <InputGroup @name="Price" @helpText="Enter a price users will pay to purchase this product">
77
+ <MoneyInput
78
+ class="w-full"
79
+ @currency={{if this.product.currency this.product.currency this.activeStore.currency}}
80
+ @value={{this.product.price}}
81
+ @canSelectCurrency={{false}}
82
+ @onCurrencyChange={{fn (mut this.product.currency)}}
83
+ @disabled={{unauthorized}}
84
+ />
85
+ </InputGroup>
86
+ <InputGroup @name="Sale Price" @helpText="Optionally add a sale price for the product if the product is put on sale">
87
+ <MoneyInput
88
+ class="w-full"
89
+ @currency={{if this.product.currency this.product.currency this.activeStore.currency}}
90
+ @value={{this.product.sale_price}}
91
+ @canSelectCurrency={{false}}
92
+ @onCurrencyChange={{fn (mut this.product.currency)}}
93
+ @disabled={{unauthorized}}
94
+ />
95
+ </InputGroup>
96
+ </div>
97
+ </ContentPanel>
73
98
 
74
- <ContentPanel
75
- @title="Metadata"
76
- @open={{this.product.meta_array.length}}
77
- @actionButtons={{this.metadataButtons}}
78
- @pad={{true}}
79
- @panelBodyWrapperClass="px-0 py-4"
80
- @panelBodyClass="bg-white dark:bg-gray-800"
81
- >
82
- {{#each this.product.meta_array as |metaField index|}}
99
+ <ContentPanel @title={{t "common.metadata"}} @open={{true}} @wrapperClass="bordered-top">
100
+ <div>
101
+ <MetadataEditor @value={{this.product.meta}} @onChange={{fn (mut this.product.meta)}} />
102
+ </div>
103
+ {{!-- {{#each this.product.meta_array as |metaField index|}}
83
104
  <div class="px-4 py-3 border-b border-gray-200 dark:border-gray-700">
84
105
  <div class="input-group">
85
106
  <div class="flex justify-between items-center mb-1">
@@ -97,7 +118,7 @@
97
118
  <Input class="w-full form-input" @value={{metaField.value}} placeholder={{metaField.label}} disabled={{unauthorized}} />
98
119
  </div>
99
120
  </div>
100
- {{/each}}
121
+ {{/each}} --}}
101
122
  </ContentPanel>
102
123
 
103
124
  <InputGroup>
@@ -143,11 +164,9 @@
143
164
  </div>
144
165
  </div>
145
166
 
146
- <ContentPanel @title="Variants" @open={{true}} @pad={{false}} @panelBodyWrapperClass="px-0 py-4" @panelBodyClass="bg-white dark:bg-gray-800">
147
- <div class="content-panel-body p-4">
148
- <div class="flex items-center justify-end">
149
- <Button @text="New Variant" @icon="plus" @iconPrefix="fas" @onClick={{this.createProductVariant}} @permission="storefront create product-variant" />
150
- </div>
167
+ <ContentPanel @title="Variants" @open={{true}} @wrapperClass="bordered-top">
168
+ <div class="flex items-center justify-end">
169
+ <Button @text="New Variant" @icon="plus" @iconPrefix="fas" @onClick={{this.createProductVariant}} @permission="storefront create product-variant" />
151
170
  </div>
152
171
  <Tabs class="overlay-content-panel" as |Tab|>
153
172
  {{#each this.product.variants as |variant|}}
@@ -224,78 +243,74 @@
224
243
  </Tabs>
225
244
  </ContentPanel>
226
245
 
227
- <ContentPanel @title="Add-Ons" @open={{true}} @pad={{false}} @panelBodyWrapperClass="px-0 py-4" @panelBodyClass="bg-white dark:bg-gray-800">
228
- <div class="px-4">
229
- <div class="flex items-center justify-end mb-3">
230
- <Button
231
- @text="Select Addon Categories"
232
- @icon="plus"
233
- @iconPrefix="fas"
234
- @onClick={{perform this.promptSelectAddonCategories}}
235
- @permission="storefront list product-addon"
236
- />
237
- </div>
238
- <div class="space-y-2">
239
- {{#each this.product.addon_categories as |addonCategory index|}}
240
- <div>
241
- <div class="flex items-center rounded-md shadow-sm px-3 py-2 font-semibold bg-gray-200 dark:bg-gray-900 dark:text-gray-100 mb-2">
242
- <div class="flex-1 flex items-center">
243
- <FaIcon @icon="pencil" class="mr-1 dark:text-gray-100" />
244
- <div class="w-full px-2 m-0 border-none bg-transparent dark:text-gray-100">
245
- {{addonCategory.name}}
246
- </div>
247
- </div>
248
- <div class="flex items-center">
249
- <a
250
- href="javascript:;"
251
- class="destroy-action opacity-50 hover:opacity-100 text-sm"
252
- {{on "click" (fn this.removeAddonCategory index)}}
253
- disabled={{cannot "storefront delete product-addon"}}
254
- >Remove</a>
246
+ <ContentPanel @title="Add-Ons" @open={{true}} @wrapperClass="bordered-top">
247
+ <div class="flex items-center justify-end mb-2">
248
+ <Button
249
+ @text="Select Addon Categories"
250
+ @icon="plus"
251
+ @iconPrefix="fas"
252
+ @onClick={{perform this.promptSelectAddonCategories}}
253
+ @permission="storefront list product-addon"
254
+ />
255
+ </div>
256
+ <div class="space-y-2">
257
+ {{#each this.product.addon_categories as |addonCategory index|}}
258
+ <div>
259
+ <div class="flex items-center rounded-md shadow-sm px-3 py-2 font-semibold bg-gray-200 dark:bg-gray-900 dark:text-gray-100 mb-2">
260
+ <div class="flex-1 flex items-center">
261
+ <FaIcon @icon="pencil" class="mr-1 dark:text-gray-100" />
262
+ <div class="w-full px-2 m-0 border-none bg-transparent dark:text-gray-100">
263
+ {{addonCategory.name}}
255
264
  </div>
256
265
  </div>
257
- <div class="space-y-2 mb-2">
258
- {{#each addonCategory.category.addons as |addon|}}
259
- <div class="grid grid-cols-10 gap-1 px-3 py-2 rounded-md border border-gray-200 dark:border-gray-900 dark:text-gray-100 dark:bg-gray-800 bg-gray-200">
260
- <div class="flex items-center">
261
- <Checkbox
262
- @value={{not (in-array addon.id addonCategory.excluded_addons)}}
263
- @onToggle={{fn this.excludeAddon index addon}}
264
- disabled={{cannot "storefront update product-addon"}}
265
- />
266
- </div>
267
- <div class="col-span-3 flex items-center">
268
- {{addon.name}}
269
- </div>
270
- <div class="col-span-4">
271
- {{addon.description}}
272
- </div>
273
- <div class="col-span-2">
274
- {{format-currency addon.price this.product.currency}}
275
- </div>
276
- </div>
277
- {{/each}}
266
+ <div class="flex items-center">
267
+ <a
268
+ href="javascript:;"
269
+ class="destroy-action opacity-50 hover:opacity-100 text-sm"
270
+ {{on "click" (fn this.removeAddonCategory index)}}
271
+ disabled={{cannot "storefront delete product-addon"}}
272
+ >Remove</a>
278
273
  </div>
279
274
  </div>
280
- {{/each}}
281
- </div>
275
+ <div class="space-y-2 mb-2">
276
+ {{#each addonCategory.category.addons as |addon|}}
277
+ <div class="grid grid-cols-10 gap-1 px-3 py-2 rounded-md border border-gray-200 dark:border-gray-900 dark:text-gray-100 dark:bg-gray-800 bg-gray-200">
278
+ <div class="flex items-center">
279
+ <Checkbox
280
+ @value={{not (in-array addon.id addonCategory.excluded_addons)}}
281
+ @onToggle={{fn this.excludeAddon index addon}}
282
+ disabled={{cannot "storefront update product-addon"}}
283
+ />
284
+ </div>
285
+ <div class="col-span-3 flex items-center">
286
+ {{addon.name}}
287
+ </div>
288
+ <div class="col-span-4">
289
+ {{addon.description}}
290
+ </div>
291
+ <div class="col-span-2">
292
+ {{format-currency addon.price this.product.currency}}
293
+ </div>
294
+ </div>
295
+ {{/each}}
296
+ </div>
297
+ </div>
298
+ {{/each}}
282
299
  </div>
283
300
  </ContentPanel>
284
301
 
285
- <ContentPanel @title="Availability" @open={{this.product.hours.length}} @pad={{false}} @panelBodyClass="bg-white dark:bg-gray-800">
286
- <div class="p-2">
287
- <ScheduleManager
288
- @subject={{this.product}}
289
- @subjectKey="product_uuid"
290
- @hourModelType="product-hour"
291
- @disabled={{unauthorized}}
292
- class="grid grid-cols-1 gap-4 lg:grid-cols-2 lg:gap-2"
293
- />
294
- </div>
302
+ <ContentPanel @title="Availability" @open={{true}} @wrapperClass="bordered-top">
303
+ <ScheduleManager
304
+ @subject={{this.product}}
305
+ @subjectKey="product_uuid"
306
+ @hourModelType="product-hour"
307
+ @disabled={{unauthorized}}
308
+ class="grid grid-cols-1 gap-4 lg:grid-cols-2 lg:gap-2"
309
+ />
295
310
  </ContentPanel>
296
311
 
297
- <ContentPanel @title="Images & Videos" @open={{this.product.files.length}} @pad={{false}} @panelBodyWrapperClass="px-0 py-4" @panelBodyClass="bg-white dark:bg-gray-800">
298
- <div class="px-6 space-y-4">
312
+ <ContentPanel @title="Images & Videos" @open={{true}} @wrapperClass="bordered-top">
313
+ <div class="space-y-2">
299
314
  {{#if this.isUploading}}
300
315
  <div
301
316
  class="min-h-56 dropzone w-full rounded-lg px-4 py-8 min-h bg-gray-50 dark:bg-gray-900 bg-opacity-25 text-gray-900 dark:text-white text-center flex flex-col items-center justify-center border-2 border-dashed border-gray-200 dark:border-indigo-500"
@@ -382,7 +397,7 @@
382
397
  </div>
383
398
  </ContentPanel>
384
399
 
385
- <ContentPanel @title="Youtube Videos" @open={{this.product.youtube_urls.length}} @wrapperClass="mb-12" @panelBodyWrapperClass="p-4" @panelBodyClass="bg-white dark:bg-gray-800">
400
+ <ContentPanel @title="Youtube Videos" @open={{true}} @wrapperClass="bordered-top">
386
401
  <p class="text-sm">Add YouTube video urls to assosciate with this product or service.</p>
387
402
  <div class="input-group">
388
403
  <ArrayInput @data={{this.product.youtube_urls}} @placeholder="Enter youtube video url" @onDataChanged={{fn (mut this.product.youtube_urls)}} @disabled={{unauthorized}}>
package/composer.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbase/storefront-api",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "Headless Commerce & Marketplace Extension for Fleetbase",
5
5
  "keywords": [
6
6
  "fleetbase-extension",
package/extension.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "Storefront",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "Headless Commerce & Marketplace Extension for Fleetbase",
5
5
  "repository": "https://github.com/fleetbase/storefront",
6
6
  "license": "AGPL-3.0-or-later",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleetbase/storefront-engine",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "Headless Commerce & Marketplace Extension for Fleetbase",
5
5
  "fleetbase": {
6
6
  "route": "storefront",
@@ -44,9 +44,9 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@babel/core": "^7.23.2",
47
- "@fleetbase/ember-core": "latest",
48
- "@fleetbase/ember-ui": "latest",
49
- "@fleetbase/fleetops-data": "^0.1.19",
47
+ "@fleetbase/ember-core": "^0.3.4",
48
+ "@fleetbase/ember-ui": "^0.3.6",
49
+ "@fleetbase/fleetops-data": "^0.1.20",
50
50
  "@fortawesome/ember-fontawesome": "^2.0.0",
51
51
  "@fortawesome/fontawesome-svg-core": "6.4.0",
52
52
  "@fortawesome/free-brands-svg-icons": "6.4.0",
@@ -6,6 +6,9 @@ use Fleetbase\Storefront\Models\Customer;
6
6
  use Fleetbase\Storefront\Models\Gateway;
7
7
  use Fleetbase\Storefront\Models\Store;
8
8
  use Illuminate\Console\Command;
9
+ use Illuminate\Http\Request;
10
+ use Illuminate\Support\Facades\App;
11
+ use Illuminate\Support\Facades\Session;
9
12
  use Stripe\Customer as StripeCustomer;
10
13
  use Stripe\Exception\InvalidRequestException;
11
14
  use Stripe\Stripe;
@@ -30,6 +33,7 @@ class MigrateStripeSandboxCustomers extends Command
30
33
  $dryRun = $this->option('dry-run');
31
34
  $storeInput = $this->option('store');
32
35
 
36
+ $this->startSession();
33
37
  $this->info('Starting Stripe customer migration...');
34
38
 
35
39
  // If a single store is specified, load that store by UUID or public_id.
@@ -147,4 +151,15 @@ class MigrateStripeSandboxCustomers extends Command
147
151
 
148
152
  return Command::SUCCESS;
149
153
  }
154
+
155
+ private function startSession()
156
+ {
157
+ if (!App::bound('request')) {
158
+ App::instance('request', Request::create('/'));
159
+ }
160
+ if (!Session::isStarted()) {
161
+ Session::start();
162
+ request()->setLaravelSession(Session::getFacadeRoot());
163
+ }
164
+ }
150
165
  }
@@ -2,6 +2,8 @@
2
2
 
3
3
  namespace Fleetbase\Storefront\Http\Controllers;
4
4
 
5
+ use Illuminate\Database\Eloquent\Builder;
6
+
5
7
  class FoodTruckController extends StorefrontController
6
8
  {
7
9
  /**
@@ -10,4 +12,12 @@ class FoodTruckController extends StorefrontController
10
12
  * @var string
11
13
  */
12
14
  public $resource = 'food_truck';
15
+
16
+ /**
17
+ * Additional query hook.
18
+ */
19
+ public function onQueryRecord(Builder $builder)
20
+ {
21
+ $builder->with(['vehicle']);
22
+ }
13
23
  }
@@ -901,13 +901,22 @@ class CheckoutController extends Controller
901
901
  ...$transactionDetails,
902
902
  ]);
903
903
 
904
+ // Create order input here
905
+ $orderInput = [];
906
+
904
907
  // if there is a food truck include it in the order meta
905
908
  if ($foodTruck) {
906
909
  $orderMeta['food_truck_id'] = $foodTruck->public_id;
910
+ // assign the driver to the food truck driver
911
+ $driverAssigned = $foodTruck->getDriverAssigned();
912
+ if ($driverAssigned) {
913
+ $orderInput['driver_assigned_uuid'] = $driverAssigned->uuid;
914
+ }
907
915
  }
908
916
 
909
917
  // initialize order creation input
910
918
  $orderInput = [
919
+ ...$orderInput,
911
920
  'company_uuid' => $store->company_uuid ?? session('company'),
912
921
  'payload_uuid' => $payload->uuid,
913
922
  'customer_uuid' => $customer->uuid,
@@ -933,6 +942,9 @@ class CheckoutController extends Controller
933
942
  // create order
934
943
  $order = Order::create($orderInput);
935
944
 
945
+ // notify driver if assigned
946
+ $order->notifyDriverAssigned();
947
+
936
948
  // notify order creation
937
949
  Storefront::alertNewOrder($order);
938
950
 
@@ -12,6 +12,12 @@ class FoodTruckFilter extends FleetOpsOrderFilter
12
12
  $this->builder->where('company_uuid', $this->session->get('company'));
13
13
  }
14
14
 
15
+ public function queryForPublic()
16
+ {
17
+ $this->builder->where('company_uuid', $this->session->get('company'));
18
+ $this->builder->whereHas('vehicle');
19
+ }
20
+
15
21
  public function storefront($storefront)
16
22
  {
17
23
  $this->builder->whereHas(
@@ -34,4 +40,9 @@ class FoodTruckFilter extends FleetOpsOrderFilter
34
40
 
35
41
  $this->builder->whereIn('service_area_uuid', $matchingServiceAreaIds);
36
42
  }
43
+
44
+ public function withDeleted()
45
+ {
46
+ $this->builder->withTrashed();
47
+ }
37
48
  }
@@ -31,6 +31,7 @@ class Product extends FleetbaseResource
31
31
  'primary_image_uuid' => $this->when(Http::isInternalRequest(), $this->primary_image_uuid),
32
32
  'name' => $this->name,
33
33
  'description' => $this->description,
34
+ 'category' => $this->when(Http::isInternalRequest(), $this->category),
34
35
  'sku' => $this->sku,
35
36
  'primary_image_url' => $this->primary_image_url,
36
37
  'price' => $this->price,