@feedmepos/mf-order-setting 0.0.76 → 0.0.77

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 (81) hide show
  1. package/dist/{KioskDevicesView-H7stMDFu.js → KioskDevicesView-Dgs5_UoK.js} +1 -1
  2. package/dist/{KioskDevicesView.vue_vue_type_script_setup_true_lang-DgpV4oKE.js → KioskDevicesView.vue_vue_type_script_setup_true_lang-B4DXPgAV.js} +3 -3
  3. package/dist/KioskSettingView-BUcPNVTc.js +681 -0
  4. package/dist/{KioskView-Cxcc1UL1.js → KioskView-DelVMMj4.js} +137 -127
  5. package/dist/{OrderSettingsView-Ds2L_rbu.js → OrderSettingsView-DE2U7vqW.js} +9232 -8262
  6. package/dist/{app-BDlPjU4y.js → app-BIvt4NBq.js} +1476 -1302
  7. package/dist/app.js +1 -1
  8. package/dist/{dayjs.min-OJf1trOq.js → dayjs.min-B58_jBg3.js} +1 -1
  9. package/dist/frontend/mf-order/src/api/index.d.ts +3 -1
  10. package/dist/frontend/mf-order/src/api/remoteOrder/index.d.ts +65 -2
  11. package/dist/frontend/mf-order/src/app.d.ts +174 -0
  12. package/dist/frontend/mf-order/src/composables/useInternalUser.d.ts +3 -0
  13. package/dist/frontend/mf-order/src/main.d.ts +174 -0
  14. package/dist/frontend/mf-order/src/modules/order-setting/kiosk/interface.d.ts +4 -0
  15. package/dist/frontend/mf-order/src/stores/order-setting/index.d.ts +15 -3
  16. package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/AdditionalStores.vue.d.ts +16 -0
  17. package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/ExternalSetting.vue.d.ts +2 -2
  18. package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/FoodpandaAdditionalStores.vue.d.ts +10 -0
  19. package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/IntegratedDelivery.vue.d.ts +15 -4
  20. package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/IntegrationIdentityDetails.vue.d.ts +10 -0
  21. package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/ShopeefoodAdditionalStores.vue.d.ts +10 -0
  22. package/dist/frontend/mf-order/tsconfig.app.tsbuildinfo +1 -1
  23. package/dist/index-CLS-FSH-.js +762 -0
  24. package/dist/{index-gGOpbnY3.js → index-CahsmFL1.js} +1 -1
  25. package/dist/{lineman-settings.dto-Cny_fF4n.js → lineman-settings.dto-DBDThIb0.js} +8999 -8874
  26. package/dist/package/entity/delivery/delivery.enum.d.ts +1 -1
  27. package/dist/package/entity/incoming-order/incoming-order.do.d.ts +4 -4
  28. package/dist/package/entity/kiosk/marketing/marketing.dto.d.ts +11 -0
  29. package/dist/package/entity/order-platform/base-integration.dto.d.ts +179 -0
  30. package/dist/package/entity/order-platform/deliveroo/deliveroo-dto.d.ts +2 -2
  31. package/dist/package/entity/order-platform/deliveroo/deliveroo-setting.do.d.ts +2 -2
  32. package/dist/package/entity/order-platform/external/order/external-order.dto.d.ts +2 -2
  33. package/dist/package/entity/order-platform/external/setting/external-setting.do.d.ts +4 -4
  34. package/dist/package/entity/order-platform/external/setting/external-setting.dto.d.ts +4 -4
  35. package/dist/package/entity/order-platform/foodpanda/foodpanda-menu.dto.d.ts +1 -1
  36. package/dist/package/entity/order-platform/foodpanda/foodpanda-settings.do.d.ts +105 -4
  37. package/dist/package/entity/order-platform/foodpanda/foodpanda-settings.dto.d.ts +30 -11
  38. package/dist/package/entity/order-platform/gofood/gofood-settings.do.d.ts +2 -2
  39. package/dist/package/entity/order-platform/gofood/gofood-settings.dto.d.ts +2 -2
  40. package/dist/package/entity/order-platform/grabfood/grabfood-order.do.d.ts +10 -10
  41. package/dist/package/entity/order-platform/grabfood/grabfood-settings.do.d.ts +134 -6
  42. package/dist/package/entity/order-platform/grabfood/grabfood.dto.d.ts +42 -20
  43. package/dist/package/entity/order-platform/lineman/lineman-settings.do.d.ts +2 -2
  44. package/dist/package/entity/order-platform/lineman/lineman-settings.dto.d.ts +2 -2
  45. package/dist/package/entity/order-platform/shopeefood/shopeefood-settings.do.d.ts +102 -4
  46. package/dist/package/entity/order-platform/shopeefood/shopeefood-settings.dto.d.ts +66 -5
  47. package/dist/package/entity/order-platform/tng/tng-settings.do.d.ts +2 -2
  48. package/dist/package/entity/order-platform/tng/tng-settings.dto.d.ts +4 -4
  49. package/dist/package/entity/order-setting/dine-in/dine-in.do.d.ts +2 -2
  50. package/dist/package/entity/order-setting/dine-in/dine-in.dto.d.ts +2 -2
  51. package/dist/package/entity/order-setting/kiosk/kiosk.do.d.ts +6 -0
  52. package/dist/package/entity/order-setting/kiosk/kiosk.dto.d.ts +6 -0
  53. package/dist/package/entity/order-setting/order-setting.do.d.ts +14 -4
  54. package/dist/package/entity/order-setting/order-setting.dto.d.ts +28 -8
  55. package/dist/package/entity/restaurant/restaurant.dto.d.ts +10 -0
  56. package/dist/package/entity/websocket/websocket.dto.d.ts +24 -0
  57. package/dist/style.css +1 -1
  58. package/package.json +1 -1
  59. package/src/api/index.ts +8 -2
  60. package/src/api/remoteOrder/index.ts +200 -4
  61. package/src/composables/useInternalUser.ts +14 -0
  62. package/src/locales/en-US.json +43 -0
  63. package/src/locales/ja-JP.json +43 -0
  64. package/src/locales/th-TH.json +90 -45
  65. package/src/locales/zh-CN.json +43 -0
  66. package/src/modules/order-setting/kiosk/interface.ts +29 -19
  67. package/src/stores/order-setting/mapper.ts +65 -55
  68. package/src/views/kiosk/settings/KioskSettingView.vue +33 -0
  69. package/src/views/order-settings/delivery/DeliverySetting.vue +0 -1
  70. package/src/views/order-settings/delivery/delivery.data.ts +3 -0
  71. package/src/views/order-settings/delivery/integrated-delivery/AdditionalStores.vue +472 -0
  72. package/src/views/order-settings/delivery/integrated-delivery/FoodpandaAdditionalStores.vue +314 -0
  73. package/src/views/order-settings/delivery/integrated-delivery/FoodpandaSetting.vue +27 -8
  74. package/src/views/order-settings/delivery/integrated-delivery/GrabfoodSetting.vue +31 -12
  75. package/src/views/order-settings/delivery/integrated-delivery/IntegratedDelivery.vue +23 -11
  76. package/src/views/order-settings/delivery/integrated-delivery/IntegrationIdentityDetails.vue +144 -0
  77. package/src/views/order-settings/delivery/integrated-delivery/ShopeefoodAdditionalStores.vue +335 -0
  78. package/src/views/order-settings/delivery/integrated-delivery/ShopeefoodSetting.vue +29 -8
  79. package/src/views/order-settings/queue/QueueSetting.vue +1 -1
  80. package/dist/KioskSettingView-fF6k9s_q.js +0 -658
  81. package/dist/index-Bid9lO2x.js +0 -665
@@ -0,0 +1,144 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import { useI18n } from '@feedmepos/mf-common'
4
+ import { useSnackbarFunctions } from '@/components/snackbar'
5
+
6
+ const props = defineProps<{
7
+ integrationId?: string | null
8
+ partnerId?: string | null
9
+ partnerLabel?: string
10
+ providerId?: string | null
11
+ providerLabel?: string
12
+ storeLabel?: string
13
+ }>()
14
+
15
+ const { t } = useI18n()
16
+ const { showSuccess, showError } = useSnackbarFunctions()
17
+
18
+ const visiblePartnerId = computed(() => props.partnerId || null)
19
+
20
+ async function copyIntegrationId() {
21
+ if (!props.integrationId) return
22
+ try {
23
+ await navigator.clipboard.writeText(props.integrationId)
24
+ showSuccess(t('order.integrationIdCopied'))
25
+ } catch {
26
+ showError(t('order.integrationIdCopyFailed'))
27
+ }
28
+ }
29
+ </script>
30
+
31
+ <template>
32
+ <div
33
+ v-if="integrationId || partnerId || providerId || storeLabel"
34
+ class="integration-details"
35
+ :class="{ 'integration-details--owned': storeLabel }"
36
+ >
37
+ <div class="integration-details__header">
38
+ <div class="integration-details__title">
39
+ <div class="fm-typo-en-title-sm-600">{{ t('order.integrationDetails') }}</div>
40
+ <FmTooltip :content="t('order.integrationIdGuidance')" :z-index="1000">
41
+ <FmIcon
42
+ name="info"
43
+ size="sm"
44
+ class="cursor-help text-fm-color-neutral-gray-400"
45
+ />
46
+ </FmTooltip>
47
+ </div>
48
+ <span v-if="storeLabel" class="integration-details__store-label fm-typo-en-body-sm-600">
49
+ {{ storeLabel }}
50
+ </span>
51
+ </div>
52
+ <div class="integration-details__row fm-typo-cn-body-md-400">
53
+ <span class="text-fm-color-neutral-gray-400">{{ t('order.feedmeIntegrationId') }}</span>
54
+ <div class="integration-details__value">
55
+ <code>{{ integrationId || t('order.integrationIdNotAssigned') }}</code>
56
+ <FmButton
57
+ v-if="integrationId"
58
+ variant="tertiary"
59
+ size="md"
60
+ :label="t('order.copy')"
61
+ @click="copyIntegrationId"
62
+ />
63
+ </div>
64
+ </div>
65
+ <div v-if="visiblePartnerId" class="integration-details__row fm-typo-cn-body-md-400">
66
+ <span class="text-fm-color-neutral-gray-400">{{ partnerLabel || t('order.partnerId') }}</span>
67
+ <code>{{ visiblePartnerId }}</code>
68
+ </div>
69
+ <div v-if="providerId" class="integration-details__row fm-typo-cn-body-md-400">
70
+ <span class="text-fm-color-neutral-gray-400">{{
71
+ providerLabel || t('order.platformStoreId')
72
+ }}</span>
73
+ <code>{{ providerId }}</code>
74
+ </div>
75
+ </div>
76
+ </template>
77
+
78
+ <style scoped>
79
+ .integration-details {
80
+ display: flex;
81
+ flex-direction: column;
82
+ gap: 0.625rem;
83
+ padding: 1rem;
84
+ margin-top: 1rem;
85
+ border: 1px solid #e5e7eb;
86
+ border-radius: 0.5rem;
87
+ }
88
+
89
+ .integration-details--owned {
90
+ border-color: var(--fm-color-primary-oats);
91
+ box-shadow: inset 0.25rem 0 0 var(--fm-color-primary);
92
+ }
93
+
94
+ .integration-details__header {
95
+ display: flex;
96
+ align-items: center;
97
+ justify-content: space-between;
98
+ flex-wrap: wrap;
99
+ gap: 0.5rem;
100
+ }
101
+
102
+ .integration-details__title {
103
+ display: flex;
104
+ align-items: center;
105
+ gap: 0.375rem;
106
+ }
107
+
108
+ .integration-details__store-label {
109
+ padding: 0.25rem 0.625rem;
110
+ color: var(--fm-color-primary);
111
+ background: var(--fm-color-primary-oats);
112
+ border-radius: 999px;
113
+ }
114
+
115
+ .integration-details__row {
116
+ display: grid;
117
+ grid-template-columns: 10rem minmax(0, 1fr);
118
+ align-items: center;
119
+ gap: 1rem;
120
+ }
121
+
122
+ .integration-details__value {
123
+ display: flex;
124
+ min-width: 0;
125
+ align-items: center;
126
+ gap: 0.5rem;
127
+ }
128
+
129
+ code {
130
+ min-width: 0;
131
+ overflow-wrap: anywhere;
132
+ }
133
+
134
+ @media (max-width: 460px) {
135
+ .integration-details__row {
136
+ grid-template-columns: 1fr;
137
+ gap: 0.25rem;
138
+ }
139
+
140
+ .integration-details__header {
141
+ align-items: flex-start;
142
+ }
143
+ }
144
+ </style>
@@ -0,0 +1,335 @@
1
+ <script setup lang="ts">
2
+ import { computed, onMounted, reactive, ref, watch } from 'vue'
3
+ import Day from 'dayjs'
4
+ import { useI18n } from '@feedmepos/mf-common'
5
+ import { useDialog } from '@feedmepos/ui-library'
6
+ import { remoteOrderApi, type ShopeefoodStoreView } from '@/api/remoteOrder'
7
+ import { useSnackbarFunctions } from '@/components/snackbar'
8
+ import { useLoading } from '@/composables/loading'
9
+ import { useMenuStore } from '@/stores/menu/menu'
10
+ import IntegrationIdentityDetails from './IntegrationIdentityDetails.vue'
11
+ import { useInternalUser } from '@/composables/useInternalUser'
12
+
13
+ const props = defineProps<{ restaurantId: string; primaryEnabled: boolean }>()
14
+ const emits = defineEmits<{ (event: 'syncMenu', storeID?: string): void }>()
15
+ const { t } = useI18n()
16
+ const Dialog = useDialog()
17
+ const menuStore = useMenuStore()
18
+ const { startAsyncCallWithErr } = useLoading()
19
+ const { showError, showSuccess } = useSnackbarFunctions()
20
+ const { isInternal } = useInternalUser()
21
+
22
+ const stores = ref<ShopeefoodStoreView[]>([])
23
+ const editing = ref<null | {
24
+ mode: 'new' | 'edit'
25
+ integrationId: string | null
26
+ routeId: string
27
+ storeID: string
28
+ }>(null)
29
+ const isSaving = ref(false)
30
+ const form = reactive<{ storeID: string; catalogId: string | null; enable: boolean }>({
31
+ storeID: '',
32
+ catalogId: null,
33
+ enable: true
34
+ })
35
+ const originalForm = reactive<{ storeID: string; catalogId: string | null; enable: boolean }>({
36
+ storeID: '',
37
+ catalogId: null,
38
+ enable: true
39
+ })
40
+ const catalogOptions = computed(() => menuStore.catalogOptions ?? [])
41
+ const additionalStores = computed(() => stores.value.filter((store) => !store.isPrimary))
42
+ const showSyncAction = computed(
43
+ () => !props.primaryEnabled && additionalStores.value.some((store) => store.enable === true)
44
+ )
45
+
46
+ function syncMenu() {
47
+ const enabledStore = additionalStores.value.find((store) => store.enable === true)
48
+ emits('syncMenu', enabledStore?.storeID)
49
+ }
50
+
51
+ function catalogLabel(catalogId?: string | null) {
52
+ if (!catalogId) return '—'
53
+ return catalogOptions.value.find((catalog) => catalog.value === catalogId)?.label ?? catalogId
54
+ }
55
+ function formatDate(value?: string | null) {
56
+ return value ? Day(value).format('DD/MM/YYYY hh:mm a') : '—'
57
+ }
58
+ async function load() {
59
+ if (!props.restaurantId) return
60
+ await startAsyncCallWithErr(async () => {
61
+ stores.value = await remoteOrderApi.integratedDelivery.listShopeefoodStores(props.restaurantId)
62
+ })
63
+ }
64
+ onMounted(load)
65
+ watch(() => props.restaurantId, load)
66
+
67
+ function openAdd() {
68
+ editing.value = { mode: 'new', integrationId: null, routeId: '', storeID: '' }
69
+ form.storeID = ''
70
+ form.catalogId = null
71
+ form.enable = true
72
+ }
73
+ function openEdit(store: ShopeefoodStoreView) {
74
+ editing.value = {
75
+ mode: 'edit',
76
+ integrationId: store.integrationId,
77
+ routeId: store.routeId,
78
+ storeID: store.storeID
79
+ }
80
+ form.storeID = store.storeID
81
+ form.catalogId = store.catalogId ?? null
82
+ form.enable = store.enable ?? false
83
+ originalForm.storeID = form.storeID
84
+ originalForm.catalogId = form.catalogId
85
+ originalForm.enable = form.enable
86
+ }
87
+ function cancelEdit() {
88
+ editing.value = null
89
+ }
90
+ function onSheetToggle(open: boolean) {
91
+ if (!open) cancelEdit()
92
+ }
93
+
94
+ async function save() {
95
+ if (isSaving.value) return
96
+
97
+ const storeID = form.storeID.trim()
98
+ if (!storeID) {
99
+ showError(t('order.shopeefoodStoreIdRequired'))
100
+ return
101
+ }
102
+ const editingId = editing.value?.mode === 'edit' ? editing.value.storeID : null
103
+ if (stores.value.some((store) => store.storeID === storeID && store.storeID !== editingId)) {
104
+ showError(t('order.shopeefoodStoreIdAlreadyExists'))
105
+ return
106
+ }
107
+ isSaving.value = true
108
+ try {
109
+ await startAsyncCallWithErr(async () => {
110
+ const payload = { storeID, catalogId: form.catalogId, enable: form.enable }
111
+ if (editing.value?.mode === 'new') {
112
+ await remoteOrderApi.integratedDelivery.addShopeefoodStore(props.restaurantId, payload)
113
+ showSuccess(t('order.storeAdded'))
114
+ } else if (editing.value) {
115
+ const updatePayload =
116
+ form.enable === false &&
117
+ storeID === originalForm.storeID &&
118
+ form.catalogId === originalForm.catalogId
119
+ ? { storeID, enable: false }
120
+ : payload
121
+ await remoteOrderApi.integratedDelivery.updateShopeefoodStore(
122
+ props.restaurantId,
123
+ editing.value.routeId,
124
+ updatePayload
125
+ )
126
+ showSuccess(t('order.storeUpdated'))
127
+ }
128
+ editing.value = null
129
+ await load()
130
+ })
131
+ } finally {
132
+ isSaving.value = false
133
+ }
134
+ }
135
+
136
+ function promptRemove(store: ShopeefoodStoreView) {
137
+ if (store.enable) {
138
+ showError(t('order.disableBeforeRemove'))
139
+ return
140
+ }
141
+ Dialog.open({
142
+ title: t('order.removeStoreConfirm', { merchantID: store.storeID }),
143
+ message: t('order.shopeefoodRemovalWarning'),
144
+ primaryActions: { text: t('order.removeStore'), variant: 'destructive', close: true },
145
+ secondaryActions: { text: t('order.cancel'), variant: 'tertiary', close: true }
146
+ }).onPrimary(async () => {
147
+ await startAsyncCallWithErr(async () => {
148
+ await remoteOrderApi.integratedDelivery.removeShopeefoodStore(
149
+ props.restaurantId,
150
+ store.routeId
151
+ )
152
+ showSuccess(t('order.storeRemoved'))
153
+ await load()
154
+ })
155
+ })
156
+ }
157
+ </script>
158
+
159
+ <template>
160
+ <div class="mt-10 store-section">
161
+ <div class="flex flex-row items-center mb-1">
162
+ <div class="flex-grow fm-typo-en-title-sm-600">{{ t('order.additionalStores') }}</div>
163
+ <div class="store-card__actions">
164
+ <FmButton
165
+ v-if="showSyncAction"
166
+ variant="primary"
167
+ :label="t('order.syncMenu')"
168
+ @click="syncMenu"
169
+ />
170
+ <FmButton variant="secondary" :label="t('order.addStore')" @click="openAdd" />
171
+ </div>
172
+ </div>
173
+ <div class="text-fm-color-neutral-gray-400 fm-typo-cn-body-md-400 mb-3">
174
+ {{ t('order.shopeefoodStoresHint') }}
175
+ </div>
176
+ <div
177
+ v-if="additionalStores.length"
178
+ class="text-fm-color-neutral-gray-400 fm-typo-cn-body-md-400 mb-3"
179
+ >
180
+ {{ t('order.syncAllStoresHint') }}
181
+ </div>
182
+
183
+ <FmCard
184
+ v-for="store in additionalStores"
185
+ :key="store.routeId"
186
+ variant="outlined"
187
+ class="store-card"
188
+ >
189
+ <div class="store-card__top">
190
+ <div class="store-card__title fm-typo-en-title-sm-600">{{ store.storeID }}</div>
191
+ <div class="store-card__actions">
192
+ <FmButton variant="secondary" :label="t('order.edit')" @click="openEdit(store)" />
193
+ <FmButton
194
+ v-if="isInternal"
195
+ variant="secondary"
196
+ :label="t('order.removeStore')"
197
+ @click="promptRemove(store)"
198
+ />
199
+ </div>
200
+ </div>
201
+ <div
202
+ v-if="isInternal && store.enable"
203
+ class="text-fm-color-neutral-gray-400 fm-typo-cn-body-md-400 mb-3"
204
+ >
205
+ {{ t('order.disableBeforeRemove') }}
206
+ </div>
207
+ <div class="store-card__fields fm-typo-cn-body-md-400">
208
+ <div class="store-field">
209
+ <span>{{ t('order.enabled') }}</span
210
+ ><span>{{ store.enable ? '✓' : '✕' }}</span>
211
+ </div>
212
+ <div class="store-field">
213
+ <span>{{ t('order.catalog') }}</span
214
+ ><span>{{ catalogLabel(store.catalogId) }}</span>
215
+ </div>
216
+ <div class="store-field">
217
+ <span>{{ t('order.status') }}</span
218
+ ><span>{{ store.status ?? '—' }}</span>
219
+ </div>
220
+ <div class="store-field">
221
+ <span>{{ t('order.menuSyncError') }}</span
222
+ ><span>{{ store.menuSyncError ?? '—' }}</span>
223
+ </div>
224
+ <div class="store-field">
225
+ <span>{{ t('order.lastSync') }}</span
226
+ ><span>{{ formatDate(store.lastSynchronize) }}</span>
227
+ </div>
228
+ <div class="store-field">
229
+ <span>{{ t('order.updatedAt') }}</span
230
+ ><span>{{ formatDate(store.updatedAt) }}</span>
231
+ </div>
232
+ </div>
233
+ <IntegrationIdentityDetails
234
+ :integration-id="store.integrationId"
235
+ :provider-id="store.providerId ?? store.storeID"
236
+ :provider-label="t('order.shopeefoodStoreId')"
237
+ />
238
+ </FmCard>
239
+
240
+ <FmSideSheet
241
+ :header="editing?.mode === 'new' ? t('order.addStore') : t('order.editStore')"
242
+ dismiss-away
243
+ class="w-full fm-typo-en-title-md-600"
244
+ :max-width="600"
245
+ :model-value="!!editing"
246
+ @update:model-value="onSheetToggle"
247
+ >
248
+ <div class="store-sheet-body">
249
+ <FmTextField v-model="form.storeID" :label="t('order.shopeefoodStoreId')" />
250
+ <FmSelect
251
+ v-model="form.catalogId"
252
+ :label="t('order.catalog')"
253
+ :placeholder="t('order.selectCatalog')"
254
+ :items="catalogOptions"
255
+ />
256
+ <FmSwitch v-model="form.enable" :label="t('order.enabled')" label-placement="right" />
257
+ <IntegrationIdentityDetails
258
+ v-if="editing?.mode === 'edit'"
259
+ :integration-id="editing.integrationId"
260
+ :provider-id="form.storeID"
261
+ :provider-label="t('order.shopeefoodStoreId')"
262
+ />
263
+ </div>
264
+ <template #side-sheet-footer>
265
+ <div class="flex gap-8 items-center justify-start">
266
+ <FmButton
267
+ variant="primary"
268
+ size="lg"
269
+ :label="editing?.mode === 'new' ? t('order.addStore') : t('order.save')"
270
+ :loading="isSaving"
271
+ :disabled="isSaving"
272
+ @click="save"
273
+ />
274
+ <FmButton variant="secondary" size="lg" :label="t('order.cancel')" @click="cancelEdit" />
275
+ </div>
276
+ </template>
277
+ </FmSideSheet>
278
+ </div>
279
+ </template>
280
+
281
+ <style scoped>
282
+ .store-section {
283
+ border-top: 1px solid #e5e7eb;
284
+ padding-top: 1.5rem;
285
+ }
286
+ .store-card {
287
+ padding: 1.25rem;
288
+ margin-bottom: 1rem;
289
+ }
290
+ .store-card__top {
291
+ display: flex;
292
+ align-items: flex-start;
293
+ justify-content: space-between;
294
+ gap: 1rem;
295
+ margin-bottom: 1rem;
296
+ }
297
+ .store-card__title {
298
+ min-width: 0;
299
+ word-break: break-all;
300
+ }
301
+ .store-card__actions {
302
+ display: flex;
303
+ flex-wrap: wrap;
304
+ justify-content: flex-end;
305
+ gap: 0.5rem;
306
+ flex-shrink: 0;
307
+ }
308
+ .store-card__fields {
309
+ display: flex;
310
+ flex-direction: column;
311
+ gap: 0.625rem;
312
+ }
313
+ .store-field {
314
+ display: grid;
315
+ grid-template-columns: 9rem minmax(0, 1fr);
316
+ gap: 1rem;
317
+ }
318
+ .store-field > span:first-child {
319
+ color: var(--fm-color-neutral-gray-400);
320
+ }
321
+ .store-field > span:last-child {
322
+ word-break: break-word;
323
+ }
324
+ .store-sheet-body {
325
+ display: flex;
326
+ flex-direction: column;
327
+ gap: 1rem;
328
+ padding-top: 0.5rem;
329
+ }
330
+ @media (max-width: 460px) {
331
+ .store-field {
332
+ grid-template-columns: 1fr;
333
+ }
334
+ }
335
+ </style>
@@ -7,6 +7,8 @@ import type { IntegratedDeliverySettingData } from './IntegratedDelivery.vue'
7
7
  import { useLoading } from '@/composables/loading'
8
8
  import { remoteOrderApi } from '@/api/remoteOrder'
9
9
  import IntegratedDelivery from './IntegratedDelivery.vue'
10
+ import ShopeefoodAdditionalStores from './ShopeefoodAdditionalStores.vue'
11
+ import IntegrationIdentityDetails from './IntegrationIdentityDetails.vue'
10
12
  import { clone } from '@/helpers/object'
11
13
  import { useI18n, useCoreStore } from '@feedmepos/mf-common'
12
14
 
@@ -56,10 +58,12 @@ const modelValue = computed<IntegratedDeliverySettingData>(() => {
56
58
  })
57
59
 
58
60
  function updateData({ manual, auto }: IntegratedDeliverySettingData) {
61
+ const { integrationId: storeID, ...autoSettings } = auto
59
62
  data.manual = manual
60
63
  data.integrated = {
61
- ...auto,
62
- storeID: auto.integrationId,
64
+ ...data.integrated,
65
+ ...autoSettings,
66
+ storeID,
63
67
  reportConfig: {
64
68
  discountCampaigns: [],
65
69
  commissionRate: auto.commissionRate
@@ -78,19 +82,21 @@ function updateDataPass({ manual, auto }: IntegratedDeliverySettingData) {
78
82
  }
79
83
 
80
84
  const { startAsyncCallWithErr } = useLoading()
81
- async function syncMenu() {
85
+ async function syncMenu(storeID?: string) {
82
86
  await startAsyncCallWithErr(async () => {
83
- const res = await remoteOrderApi.integratedDelivery.syncShopeefoodMenu(data.integrated.storeID)
84
- const temp = {
85
- ...modelValue.value.auto,
86
- lastSynchronize: res?.lastSynchronize || modelValue.value.auto.lastSynchronize
87
+ const isPrimary = storeID === undefined
88
+ const targetStoreID = storeID ?? data.integrated.storeID
89
+ await remoteOrderApi.integratedDelivery.syncShopeefoodMenu(targetStoreID)
90
+ if (isPrimary) {
91
+ data.integrated.lastSynchronize = new Date().toISOString()
87
92
  }
88
- updateData({ auto: temp, manual: data.manual })
89
93
  showSuccess(t('order.syncMenuSuccess'))
90
94
  })
91
95
  }
92
96
 
93
97
  const { currentRestaurant } = useCoreStore()
98
+ const restaurantId = computed(() => currentRestaurant.value?._id ?? '')
99
+ const primaryIntegrationId = computed(() => data.integrated.integrationId)
94
100
 
95
101
  import { useSnackbarFunctions } from '@/components/snackbar'
96
102
  const { showSuccess } = useSnackbarFunctions()
@@ -124,5 +130,20 @@ async function cancelTestOrder() {
124
130
  @sync-menu="syncMenu"
125
131
  @flow-test-order="flowTestOrder"
126
132
  @cancel-test-order="cancelTestOrder"
133
+ >
134
+ <template #integration-details>
135
+ <IntegrationIdentityDetails
136
+ :integration-id="primaryIntegrationId"
137
+ :provider-id="data.integrated.storeID"
138
+ :provider-label="t('order.shopeefoodStoreId')"
139
+ :store-label="t('order.primaryStore')"
140
+ />
141
+ </template>
142
+ </IntegratedDelivery>
143
+ <ShopeefoodAdditionalStores
144
+ v-if="canUseAutoDeliveryIntegration === true"
145
+ :restaurant-id="restaurantId"
146
+ :primary-enabled="modelValue.auto.enable"
147
+ @sync-menu="syncMenu"
127
148
  />
128
149
  </template>
@@ -317,7 +317,7 @@ async function saveAllowOverrideQueueCode(value: boolean) {
317
317
  />
318
318
  </div>
319
319
  <div class="flex flex-col gap-1">
320
- <span class="text-sm">{{ t('order.current') }}</span>
320
+ <span class="text-sm">{{ t('order.currentNumber') }}</span>
321
321
  <FmTextField
322
322
  type="number"
323
323
  :model-value="codeSetting.current"