@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.
- package/dist/{KioskDevicesView-H7stMDFu.js → KioskDevicesView-Dgs5_UoK.js} +1 -1
- package/dist/{KioskDevicesView.vue_vue_type_script_setup_true_lang-DgpV4oKE.js → KioskDevicesView.vue_vue_type_script_setup_true_lang-B4DXPgAV.js} +3 -3
- package/dist/KioskSettingView-BUcPNVTc.js +681 -0
- package/dist/{KioskView-Cxcc1UL1.js → KioskView-DelVMMj4.js} +137 -127
- package/dist/{OrderSettingsView-Ds2L_rbu.js → OrderSettingsView-DE2U7vqW.js} +9232 -8262
- package/dist/{app-BDlPjU4y.js → app-BIvt4NBq.js} +1476 -1302
- package/dist/app.js +1 -1
- package/dist/{dayjs.min-OJf1trOq.js → dayjs.min-B58_jBg3.js} +1 -1
- package/dist/frontend/mf-order/src/api/index.d.ts +3 -1
- package/dist/frontend/mf-order/src/api/remoteOrder/index.d.ts +65 -2
- package/dist/frontend/mf-order/src/app.d.ts +174 -0
- package/dist/frontend/mf-order/src/composables/useInternalUser.d.ts +3 -0
- package/dist/frontend/mf-order/src/main.d.ts +174 -0
- package/dist/frontend/mf-order/src/modules/order-setting/kiosk/interface.d.ts +4 -0
- package/dist/frontend/mf-order/src/stores/order-setting/index.d.ts +15 -3
- package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/AdditionalStores.vue.d.ts +16 -0
- package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/ExternalSetting.vue.d.ts +2 -2
- package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/FoodpandaAdditionalStores.vue.d.ts +10 -0
- package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/IntegratedDelivery.vue.d.ts +15 -4
- package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/IntegrationIdentityDetails.vue.d.ts +10 -0
- package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/ShopeefoodAdditionalStores.vue.d.ts +10 -0
- package/dist/frontend/mf-order/tsconfig.app.tsbuildinfo +1 -1
- package/dist/index-CLS-FSH-.js +762 -0
- package/dist/{index-gGOpbnY3.js → index-CahsmFL1.js} +1 -1
- package/dist/{lineman-settings.dto-Cny_fF4n.js → lineman-settings.dto-DBDThIb0.js} +8999 -8874
- package/dist/package/entity/delivery/delivery.enum.d.ts +1 -1
- package/dist/package/entity/incoming-order/incoming-order.do.d.ts +4 -4
- package/dist/package/entity/kiosk/marketing/marketing.dto.d.ts +11 -0
- package/dist/package/entity/order-platform/base-integration.dto.d.ts +179 -0
- package/dist/package/entity/order-platform/deliveroo/deliveroo-dto.d.ts +2 -2
- package/dist/package/entity/order-platform/deliveroo/deliveroo-setting.do.d.ts +2 -2
- package/dist/package/entity/order-platform/external/order/external-order.dto.d.ts +2 -2
- package/dist/package/entity/order-platform/external/setting/external-setting.do.d.ts +4 -4
- package/dist/package/entity/order-platform/external/setting/external-setting.dto.d.ts +4 -4
- package/dist/package/entity/order-platform/foodpanda/foodpanda-menu.dto.d.ts +1 -1
- package/dist/package/entity/order-platform/foodpanda/foodpanda-settings.do.d.ts +105 -4
- package/dist/package/entity/order-platform/foodpanda/foodpanda-settings.dto.d.ts +30 -11
- package/dist/package/entity/order-platform/gofood/gofood-settings.do.d.ts +2 -2
- package/dist/package/entity/order-platform/gofood/gofood-settings.dto.d.ts +2 -2
- package/dist/package/entity/order-platform/grabfood/grabfood-order.do.d.ts +10 -10
- package/dist/package/entity/order-platform/grabfood/grabfood-settings.do.d.ts +134 -6
- package/dist/package/entity/order-platform/grabfood/grabfood.dto.d.ts +42 -20
- package/dist/package/entity/order-platform/lineman/lineman-settings.do.d.ts +2 -2
- package/dist/package/entity/order-platform/lineman/lineman-settings.dto.d.ts +2 -2
- package/dist/package/entity/order-platform/shopeefood/shopeefood-settings.do.d.ts +102 -4
- package/dist/package/entity/order-platform/shopeefood/shopeefood-settings.dto.d.ts +66 -5
- package/dist/package/entity/order-platform/tng/tng-settings.do.d.ts +2 -2
- package/dist/package/entity/order-platform/tng/tng-settings.dto.d.ts +4 -4
- package/dist/package/entity/order-setting/dine-in/dine-in.do.d.ts +2 -2
- package/dist/package/entity/order-setting/dine-in/dine-in.dto.d.ts +2 -2
- package/dist/package/entity/order-setting/kiosk/kiosk.do.d.ts +6 -0
- package/dist/package/entity/order-setting/kiosk/kiosk.dto.d.ts +6 -0
- package/dist/package/entity/order-setting/order-setting.do.d.ts +14 -4
- package/dist/package/entity/order-setting/order-setting.dto.d.ts +28 -8
- package/dist/package/entity/restaurant/restaurant.dto.d.ts +10 -0
- package/dist/package/entity/websocket/websocket.dto.d.ts +24 -0
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/api/index.ts +8 -2
- package/src/api/remoteOrder/index.ts +200 -4
- package/src/composables/useInternalUser.ts +14 -0
- package/src/locales/en-US.json +43 -0
- package/src/locales/ja-JP.json +43 -0
- package/src/locales/th-TH.json +90 -45
- package/src/locales/zh-CN.json +43 -0
- package/src/modules/order-setting/kiosk/interface.ts +29 -19
- package/src/stores/order-setting/mapper.ts +65 -55
- package/src/views/kiosk/settings/KioskSettingView.vue +33 -0
- package/src/views/order-settings/delivery/DeliverySetting.vue +0 -1
- package/src/views/order-settings/delivery/delivery.data.ts +3 -0
- package/src/views/order-settings/delivery/integrated-delivery/AdditionalStores.vue +472 -0
- package/src/views/order-settings/delivery/integrated-delivery/FoodpandaAdditionalStores.vue +314 -0
- package/src/views/order-settings/delivery/integrated-delivery/FoodpandaSetting.vue +27 -8
- package/src/views/order-settings/delivery/integrated-delivery/GrabfoodSetting.vue +31 -12
- package/src/views/order-settings/delivery/integrated-delivery/IntegratedDelivery.vue +23 -11
- package/src/views/order-settings/delivery/integrated-delivery/IntegrationIdentityDetails.vue +144 -0
- package/src/views/order-settings/delivery/integrated-delivery/ShopeefoodAdditionalStores.vue +335 -0
- package/src/views/order-settings/delivery/integrated-delivery/ShopeefoodSetting.vue +29 -8
- package/src/views/order-settings/queue/QueueSetting.vue +1 -1
- package/dist/KioskSettingView-fF6k9s_q.js +0 -658
- 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
|
-
...
|
|
62
|
-
|
|
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
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
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.
|
|
320
|
+
<span class="text-sm">{{ t('order.currentNumber') }}</span>
|
|
321
321
|
<FmTextField
|
|
322
322
|
type="number"
|
|
323
323
|
:model-value="codeSetting.current"
|