@feedmepos/mf-order-setting 0.0.77 → 0.0.78

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 (55) hide show
  1. package/dist/{KioskDevicesView-Dgs5_UoK.js → KioskDevicesView-Db2DyKc2.js} +1 -1
  2. package/dist/{KioskDevicesView.vue_vue_type_script_setup_true_lang-B4DXPgAV.js → KioskDevicesView.vue_vue_type_script_setup_true_lang-Do-EH0Hn.js} +3 -3
  3. package/dist/{KioskSettingView-BUcPNVTc.js → KioskSettingView-D1JaAjmx.js} +3 -3
  4. package/dist/KioskView-B0jhv4Zp.js +464 -0
  5. package/dist/OrderSettingsView-BPNN4jOB.js +35883 -0
  6. package/dist/{app-BIvt4NBq.js → app-DpdLDlVr.js} +1993 -1954
  7. package/dist/app.js +1 -1
  8. package/dist/{dayjs.min-B58_jBg3.js → dayjs.min-Cs3D4xiZ.js} +1 -1
  9. package/dist/frontend/mf-order/src/app.d.ts +16 -0
  10. package/dist/frontend/mf-order/src/helpers/map.d.ts +12 -1
  11. package/dist/frontend/mf-order/src/main.d.ts +16 -0
  12. package/dist/frontend/mf-order/src/stores/menu/menu.d.ts +28 -0
  13. package/dist/frontend/mf-order/src/stores/restaurant/index.d.ts +9 -0
  14. package/dist/frontend/mf-order/src/views/order-settings/delivery/delivery.d.ts +5 -0
  15. package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/ExternalSetting.vue.d.ts +6 -0
  16. package/dist/frontend/mf-order/tsconfig.app.tsbuildinfo +1 -1
  17. package/dist/{index-CLS-FSH-.js → index-BZL2Hpkn.js} +2 -2
  18. package/dist/{index-CahsmFL1.js → index-DXkcRRAu.js} +1 -1
  19. package/dist/lineman-settings.dto-CtRqCjzQ.js +74920 -0
  20. package/dist/package/entity/booking/booking.do.d.ts +125 -0
  21. package/dist/package/entity/delivery/delivery.dto.d.ts +25 -0
  22. package/dist/package/entity/incoming-order/incoming-order-to-bill.dto.d.ts +87 -0
  23. package/dist/package/entity/member/member.dto.d.ts +38 -0
  24. package/dist/package/entity/order/order.do.d.ts +90 -0
  25. package/dist/package/entity/order/order.dto.d.ts +198 -0
  26. package/dist/package/entity/order-platform/external/menu/external-master-menu.do.d.ts +316 -48
  27. package/dist/package/entity/order-platform/external/menu/external-menu.do.d.ts +1131 -209
  28. package/dist/package/entity/order-platform/external/menu/external-menu.dto.d.ts +3 -3
  29. package/dist/package/entity/order-platform/external/menu/external-menu.enum.d.ts +10 -1
  30. package/dist/package/entity/order-platform/external/order/external-order.do.d.ts +80 -36
  31. package/dist/package/entity/order-platform/external/order/external-order.dto.d.ts +190 -83
  32. package/dist/package/entity/order-platform/external/order/external-order.enum.d.ts +2 -2
  33. package/dist/package/entity/order-platform/external/setting/external-setting.do.d.ts +18 -0
  34. package/dist/package/entity/order-platform/external/setting/external-setting.dto.d.ts +13 -0
  35. package/dist/package/entity/order-platform/foodpanda/foodpanda-order.dto.d.ts +25 -0
  36. package/dist/package/entity/order-platform/grabfood/grabfood-order.do.d.ts +25 -0
  37. package/dist/package/entity/order-platform/order-platform.dto.d.ts +2 -0
  38. package/dist/package/entity/order-platform/shopeefood/shopeefood-order.do.d.ts +25 -0
  39. package/dist/style.css +1 -1
  40. package/package.json +7 -9
  41. package/src/helpers/map.ts +24 -0
  42. package/src/locales/en-US.json +4 -0
  43. package/src/locales/ja-JP.json +4 -0
  44. package/src/locales/th-TH.json +4 -0
  45. package/src/locales/zh-CN.json +4 -0
  46. package/src/views/kiosk/KioskView.vue +51 -7
  47. package/src/views/order-settings/OrderSettingsView.vue +2 -2
  48. package/src/views/order-settings/delivery/DeliverySetting.vue +18 -1
  49. package/src/views/order-settings/delivery/delivery.ts +37 -0
  50. package/src/views/order-settings/delivery/inhouse/DeliveryOrder.vue +24 -8
  51. package/src/views/order-settings/delivery/inhouse/ZoneDialog.vue +14 -2
  52. package/src/views/order-settings/delivery/integrated-delivery/ExternalSetting.vue +136 -27
  53. package/dist/KioskView-DelVMMj4.js +0 -430
  54. package/dist/OrderSettingsView-DE2U7vqW.js +0 -60930
  55. package/dist/lineman-settings.dto-DBDThIb0.js +0 -62793
@@ -7,7 +7,7 @@ import { clone } from '@/helpers/object'
7
7
  import type { FdoAddress, FdoDeliveryArea } from '@feedmepos/core/entity'
8
8
  import GoogleMap from '@/components/GoogleMap.vue'
9
9
  import ZoneDialog from './ZoneDialog.vue'
10
- import { type PropType, computed, onMounted, ref } from 'vue'
10
+ import { type PropType, computed, onMounted, ref, watch } from 'vue'
11
11
  import { useSnackbar, SnackbarPosition } from '@feedmepos/ui-library'
12
12
  import { useI18n } from '@feedmepos/mf-common'
13
13
 
@@ -97,13 +97,12 @@ const deliveryArea = ref<FdoDeliveryArea>()
97
97
  function editZone(index: number) {
98
98
  currentIndex.value = index
99
99
  deliveryArea.value = props.modelValue[index]
100
- openSideSheet()
100
+ sideSheet.value = true
101
101
  }
102
102
 
103
103
  const Snackbar = useSnackbar()
104
104
 
105
105
  function addZone() {
106
- sideSheet.value = false
107
106
  if (savedZone.value) {
108
107
  emits('update:model-value', [...props.modelValue, savedZone.value])
109
108
  Snackbar.open({
@@ -112,12 +111,15 @@ function addZone() {
112
111
  position: 'bottom' as SnackbarPosition
113
112
  })
114
113
  }
114
+ closeSideSheet()
115
115
  }
116
116
 
117
117
  const savedZone = ref<FdoDeliveryArea>()
118
118
 
119
119
  function handleZoneUpdate(v: FdoDeliveryArea) {
120
- savedZone.value = v
120
+ // Clone: `v` is the dialog's own reactive state, so storing it directly would make the saved
121
+ // zone keep mutating with the dialog (and make two zones share one object).
122
+ savedZone.value = clone(v)
121
123
  }
122
124
 
123
125
  function updateZone(index: number) {
@@ -131,8 +133,8 @@ function updateZone(index: number) {
131
133
  message: 'Zone updated successfully.',
132
134
  position: 'bottom' as SnackbarPosition
133
135
  })
134
- sideSheet.value = false
135
136
  }
137
+ closeSideSheet()
136
138
  }
137
139
 
138
140
  const center = ref<{
@@ -167,15 +169,29 @@ async function getCenter() {
167
169
  }
168
170
  }
169
171
 
170
- function openSideSheet() {
172
+ function openAddZone() {
173
+ // currentIndex selects the edit branch of the side sheet, so it has to be cleared here —
174
+ // otherwise "Add Delivery Zone" right after an edit reopens the sheet in edit mode and Save
175
+ // overwrites the zone that was just edited instead of appending a new one.
176
+ currentIndex.value = null
177
+ deliveryArea.value = undefined
171
178
  sideSheet.value = true
172
179
  }
173
180
 
174
181
  function closeSideSheet() {
175
182
  sideSheet.value = false
176
- currentIndex.value = null
177
183
  }
178
184
 
185
+ // Reset on every close, not just in closeSideSheet: dismiss-away and the sheet's own X button
186
+ // close it without going through here. A zone left in savedZone by a cancelled "Add" would
187
+ // otherwise be written over the next zone that is edited and saved.
188
+ watch(sideSheet, (open) => {
189
+ if (open) return
190
+ currentIndex.value = null
191
+ deliveryArea.value = undefined
192
+ savedZone.value = undefined
193
+ })
194
+
179
195
  onMounted(getCenter)
180
196
  </script>
181
197
 
@@ -183,7 +199,7 @@ onMounted(getCenter)
183
199
  <GoogleMap ref="gmRef" class="full-width" style="height: 500px" :center="center" :polygons="polygons" :zoom="10" />
184
200
 
185
201
  <div class=" mt-5 mb-5">
186
- <FmButton class="mt-3" @click="openSideSheet" icon="add" :label="t('order.addDeliveryZone')" variant="plain" />
202
+ <FmButton class="mt-3" @click="openAddZone" icon="add" :label="t('order.addDeliveryZone')" variant="plain" />
187
203
  </div>
188
204
 
189
205
  <FmSideSheet :header="t('order.addDeliveryZone')" dismiss-away :maxWidth="600" v-model="sideSheet">
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import GoogleMap from '@/components/GoogleMap.vue'
3
3
  import type { InputModel, MapCoordinate, MapPolygon } from '@/components/type'
4
- import { arrayToCoordinate, coordinates, coordinateToArray, generateAreaPaths, getDefaultCoordinates } from '@/helpers/map'
4
+ import { arrayToCoordinate, coordinates, coordinateToArray, generateAreaPaths, getDefaultCoordinates, getPolygonDistanceInKM } from '@/helpers/map'
5
5
  import { clone } from '@/helpers/object'
6
6
  import { Country, Dinero } from '@feedmepos/core'
7
7
  import { F_COUNTRY, type FCurrency, type FdoCountry, type FdoDeliveryArea, type FdoDinero } from '@feedmepos/core/entity'
@@ -36,7 +36,15 @@ const props = defineProps({
36
36
  }
37
37
  })
38
38
 
39
- const distanceInKM = ref(10)
39
+ const DEFAULT_DISTANCE_IN_KM = 10
40
+
41
+ // FmSideSheet renders its slot inside a v-if, so this dialog is remounted on every open. The
42
+ // distance has to be recovered from the zone being edited, otherwise the field always reads the
43
+ // default and the merchant sees their saved zone as DEFAULT_DISTANCE_IN_KM.
44
+ const distanceInKM = ref(
45
+ (props.initialValue ? getPolygonDistanceInKM(props.initialValue.polygon) : undefined) ??
46
+ DEFAULT_DISTANCE_IN_KM
47
+ )
40
48
  const data = reactive<FdoDeliveryArea>(
41
49
  props.initialValue
42
50
  ? clone(props.initialValue)
@@ -94,6 +102,10 @@ function updateFreeAfterTotal(v: FdoDinero) {
94
102
 
95
103
  onMounted(() => {
96
104
  if (!props.initialValue) generatePolygon()
105
+ // The watcher below only fires once `data` is mutated, and editing an existing zone mutates
106
+ // nothing on mount. Emit once so the parent always holds THIS zone instead of whichever zone
107
+ // was last emitted by a previous open of the dialog.
108
+ emits('update:model-value', data)
97
109
  })
98
110
 
99
111
  watch(
@@ -44,23 +44,40 @@
44
44
  @update:model-value="updatePlatform"
45
45
  />
46
46
 
47
- <FmSelect
48
- class="mt-5"
49
- :placeholder="t('order.selectItem')"
50
- :model-value="data.delivery!.catalogId"
51
- :label="t('order.deliveryCatalog')"
52
- :items="menuStore.catalogOptions"
53
- @update:model-value="updateDeliveryMenuCatalog"
54
- />
55
-
56
- <FmSelect
57
- class="mt-5"
58
- :placeholder="t('order.selectItem')"
59
- :model-value="data.pickup!.catalogId"
60
- :label="t('order.pickupCatalog')"
61
- :items="menuStore.catalogOptions"
62
- @update:model-value="updatePickupMenuCatalog"
63
- />
47
+ <div class="fm-typo-en-title-sm-600 mb-3 mt-5">{{ t('order.orderType') }}</div>
48
+ <div
49
+ v-for="section in menuOrderTypeSections"
50
+ :key="section.key"
51
+ :class="menuOrderTypeEnabled[section.key] ? 'mb-5' : 'mb-3'"
52
+ >
53
+ <FmCheckbox
54
+ :model-value="menuOrderTypeEnabled[section.key]"
55
+ :label="section.label"
56
+ :value="section.key"
57
+ @update:model-value="(enabled: boolean) => toggleMenuOrderType(section.key, enabled)"
58
+ />
59
+ <FmCard
60
+ v-if="menuOrderTypeEnabled[section.key]"
61
+ variant="outlined"
62
+ class="mt-2 p-5"
63
+ >
64
+ <FmSelect
65
+ :placeholder="t('order.selectItem')"
66
+ :model-value="data[section.key]?.catalogId ?? null"
67
+ :label="section.catalogLabel"
68
+ :items="catalogOptionsFor(section.key)"
69
+ @update:model-value="
70
+ (catalogId: string | null) => updateMenuCatalog(section.key, catalogId)
71
+ "
72
+ />
73
+ <div
74
+ v-if="isMenuCatalogInvalid(section.key)"
75
+ class="text-fm-color-typo-error fm-typo-en-body-sm-400 mt-3"
76
+ >
77
+ {{ menuCatalogValidationMessage([section.key]) }}
78
+ </div>
79
+ </FmCard>
80
+ </div>
64
81
  </div>
65
82
 
66
83
  <div class="text-fm-color-neutral-gray-400 fm-typo-cn-body-md-400 mb-5 mt-5">
@@ -86,7 +103,7 @@
86
103
  </template>
87
104
 
88
105
  <script setup lang="ts">
89
- import { type PropType, reactive, ref } from 'vue'
106
+ import { computed, onMounted, type PropType, reactive, ref } from 'vue'
90
107
  import { F_ORDER_PLATFORM, type FdoExternalSetting } from '@entity'
91
108
  import { useI18n } from '@feedmepos/mf-common'
92
109
  import Day from 'dayjs'
@@ -95,8 +112,13 @@ import { useMenuStore } from '@/stores/menu/menu'
95
112
  import { useLoading } from '@/composables/loading'
96
113
  import { remoteOrderApi } from '@/api/remoteOrder'
97
114
  import { useSnackbarFunctions } from '@/components/snackbar'
115
+ import {
116
+ externalMenuOrderTypeRequiresCatalog,
117
+ getInvalidExternalMenuCatalogOrderTypes,
118
+ type ExternalMenuOrderType
119
+ } from '../delivery'
98
120
 
99
- const { showSuccess } = useSnackbarFunctions()
121
+ const { showError, showSuccess } = useSnackbarFunctions()
100
122
  const { t } = useI18n()
101
123
  const menuStore = useMenuStore()
102
124
 
@@ -107,11 +129,33 @@ const props = defineProps({
107
129
  }
108
130
  })
109
131
 
132
+ type MenuOrderType = ExternalMenuOrderType
133
+ type MenuOrderTypeSetting = NonNullable<FdoExternalSetting[MenuOrderType]>
134
+
135
+ function cloneMenuOrderTypeSetting(
136
+ setting: MenuOrderTypeSetting | null | undefined
137
+ ): MenuOrderTypeSetting | null {
138
+ return setting == null ? null : clone(setting)
139
+ }
140
+
110
141
  const data = reactive<FdoExternalSetting>({
111
- ...clone(props.initialValue),
112
- platform: props.initialValue.platform ?? 'ZUS',
113
- delivery: props.initialValue.delivery ?? { catalogId: null },
114
- pickup: props.initialValue.pickup ?? { catalogId: null }
142
+ _id: props.initialValue._id ?? '',
143
+ enable: props.initialValue.enable ?? false,
144
+ config: {
145
+ autoAccept: props.initialValue.config?.autoAccept ?? true,
146
+ autoSend: props.initialValue.config?.autoSend ?? true,
147
+ autoCloseBill: props.initialValue.config?.autoCloseBill ?? false,
148
+ printReceiptAfterClose: props.initialValue.config?.printReceiptAfterClose,
149
+ bypass: props.initialValue.config?.bypass,
150
+ skipAllocateTax: props.initialValue.config?.skipAllocateTax,
151
+ groupItemsBySubCategory: props.initialValue.config?.groupItemsBySubCategory
152
+ },
153
+ platform: props.initialValue.platform ?? F_ORDER_PLATFORM.enum.ZUS,
154
+ delivery: cloneMenuOrderTypeSetting(props.initialValue.delivery),
155
+ pickup: cloneMenuOrderTypeSetting(props.initialValue.pickup),
156
+ dineIn: cloneMenuOrderTypeSetting(props.initialValue.dineIn),
157
+ updatedAt: props.initialValue.updatedAt,
158
+ lastSynchronize: props.initialValue.lastSynchronize
115
159
  })
116
160
 
117
161
  const platformOptions = ref([
@@ -120,6 +164,28 @@ const platformOptions = ref([
120
164
  { label: 'US Pizza', value: F_ORDER_PLATFORM.enum.US_PIZZA }
121
165
  ])
122
166
 
167
+ const menuOrderTypeSections = computed<
168
+ Array<{ key: MenuOrderType; label: string; catalogLabel: string }>
169
+ >(() => [
170
+ { key: 'delivery', label: t('order.delivery'), catalogLabel: t('order.deliveryCatalog') },
171
+ { key: 'pickup', label: t('order.pickup'), catalogLabel: t('order.pickupCatalog') },
172
+ { key: 'dineIn', label: t('order.dineIn'), catalogLabel: t('order.dineInCatalog') }
173
+ ])
174
+
175
+ const menuOrderTypeEnabled = reactive<Record<MenuOrderType, boolean>>({
176
+ delivery: data.delivery != null,
177
+ pickup: data.pickup != null,
178
+ dineIn: data.dineIn != null
179
+ })
180
+
181
+ const menuOrderTypeDrafts = reactive<Record<MenuOrderType, MenuOrderTypeSetting | null>>({
182
+ delivery: cloneMenuOrderTypeSetting(data.delivery),
183
+ pickup: cloneMenuOrderTypeSetting(data.pickup),
184
+ dineIn: cloneMenuOrderTypeSetting(data.dineIn)
185
+ })
186
+
187
+ const invalidMenuCatalogOrderTypes = computed(() => getInvalidExternalMenuCatalogOrderTypes(data))
188
+
123
189
  const emits = defineEmits<{
124
190
  (event: 'update:model-value', v: FdoExternalSetting): void
125
191
  }>()
@@ -128,6 +194,8 @@ function emitUpdatedValue() {
128
194
  emits('update:model-value', { ...data })
129
195
  }
130
196
 
197
+ onMounted(emitUpdatedValue)
198
+
131
199
  function updateAutoSend(value: boolean) {
132
200
  data.config.autoSend = value
133
201
  emitUpdatedValue()
@@ -148,13 +216,49 @@ function updateEnable(value: boolean) {
148
216
  emitUpdatedValue()
149
217
  }
150
218
 
151
- function updateDeliveryMenuCatalog(catalogId: string) {
152
- data.delivery!.catalogId = catalogId
219
+ function menuOrderTypeLabel(type: MenuOrderType) {
220
+ return t(`order.${type}`)
221
+ }
222
+
223
+ function menuCatalogValidationMessage(orderTypes: MenuOrderType[]) {
224
+ const platform =
225
+ platformOptions.value.find(({ value }) => value === data.platform)?.label ?? data.platform
226
+
227
+ return t('order.externalCatalogRequired', {
228
+ orderTypes: orderTypes.map(menuOrderTypeLabel).join(', '),
229
+ platform
230
+ })
231
+ }
232
+
233
+ function isMenuCatalogInvalid(type: MenuOrderType) {
234
+ return invalidMenuCatalogOrderTypes.value.some((invalidType) => invalidType === type)
235
+ }
236
+
237
+ function catalogOptionsFor(type: MenuOrderType) {
238
+ if (!externalMenuOrderTypeRequiresCatalog(data.platform, type)) {
239
+ return menuStore.catalogOptions
240
+ }
241
+
242
+ return menuStore.catalogOptions.filter(({ value }) => value !== null)
243
+ }
244
+
245
+ function toggleMenuOrderType(type: MenuOrderType, enabled: boolean) {
246
+ menuOrderTypeEnabled[type] = enabled
247
+
248
+ if (enabled) {
249
+ data[type] = cloneMenuOrderTypeSetting(menuOrderTypeDrafts[type]) ?? { catalogId: null }
250
+ } else {
251
+ menuOrderTypeDrafts[type] = cloneMenuOrderTypeSetting(data[type])
252
+ data[type] = null
253
+ }
254
+
153
255
  emitUpdatedValue()
154
256
  }
155
257
 
156
- function updatePickupMenuCatalog(catalogId: string) {
157
- data.pickup!.catalogId = catalogId
258
+ function updateMenuCatalog(type: MenuOrderType, catalogId: string | null) {
259
+ const setting = data[type] ?? menuOrderTypeDrafts[type] ?? { catalogId: null }
260
+ data[type] = { ...setting, catalogId }
261
+ menuOrderTypeEnabled[type] = true
158
262
  emitUpdatedValue()
159
263
  }
160
264
 
@@ -165,6 +269,11 @@ function updatePlatform(platform: F_ORDER_PLATFORM) {
165
269
 
166
270
  const { startAsyncCallWithErr } = useLoading()
167
271
  async function syncMenu() {
272
+ if (invalidMenuCatalogOrderTypes.value.length > 0) {
273
+ showError(menuCatalogValidationMessage(invalidMenuCatalogOrderTypes.value))
274
+ return
275
+ }
276
+
168
277
  await startAsyncCallWithErr(async () => {
169
278
  const res = await remoteOrderApi.integratedDelivery.syncExternalMenu(data._id ?? '')
170
279
  if (res?.lastSynchronize) {