@feedmepos/mf-order-setting 0.0.92 → 0.0.94

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 (65) hide show
  1. package/dist/DisplaySystemView-Doh1JUoe.js +8891 -0
  2. package/dist/{KioskDevicesView-d2WLB0-w.js → KioskDevicesView-DvUq9eFa.js} +1 -1
  3. package/dist/{KioskDevicesView.vue_vue_type_script_setup_true_lang-rs-hNWUW.js → KioskDevicesView.vue_vue_type_script_setup_true_lang-Ce-CHsOK.js} +3 -3
  4. package/dist/{KioskSettingView-DFE3_u5c.js → KioskSettingView-Ba1sLolg.js} +3 -3
  5. package/dist/{KioskView-C3Pi3lWW.js → KioskView-CeKSWYbI.js} +5 -5
  6. package/dist/{OrderSettingsView-Dxg9RjSd.js → OrderSettingsView-CdxkPS_V.js} +22200 -22918
  7. package/dist/{app-BFlQtcsd.js → app-BQ0W0_dt.js} +2536 -1818
  8. package/dist/app.js +1 -1
  9. package/dist/featureFlag-C4gAe_F4.js +846 -0
  10. package/dist/frontend/mf-order/src/api/brandkit/index.d.ts +3 -0
  11. package/dist/frontend/mf-order/src/api/native-app/index.d.ts +2 -0
  12. package/dist/frontend/mf-order/src/app.d.ts +716 -0
  13. package/dist/frontend/mf-order/src/composables/featureFlag.d.ts +7 -0
  14. package/dist/frontend/mf-order/src/composables/useBusinessFeatureFlag.d.ts +4 -0
  15. package/dist/frontend/mf-order/src/composables/useLegacyOdsAccess.d.ts +4 -0
  16. package/dist/frontend/mf-order/src/composables/useMiniProgramPermission.d.ts +5 -0
  17. package/dist/frontend/mf-order/src/main.d.ts +716 -0
  18. package/dist/frontend/mf-order/src/modules/display-system/legacy-ods/interface.d.ts +80 -0
  19. package/dist/frontend/mf-order/src/views/display-system/legacy-ods/ColorOverrideDialog.vue.d.ts +26 -0
  20. package/dist/frontend/mf-order/src/views/display-system/legacy-ods/ColorSelection.vue.d.ts +15 -0
  21. package/dist/frontend/mf-order/src/views/display-system/legacy-ods/LegacyOdsEditorDialog.vue.d.ts +24 -0
  22. package/dist/frontend/mf-order/src/views/display-system/legacy-ods/LegacyOdsTemplateList.vue.d.ts +4 -0
  23. package/dist/frontend/mf-order/src/views/display-system/view-selection.d.ts +18 -0
  24. package/dist/frontend/mf-order/src/views/order-settings/components/push-availability.d.ts +13 -0
  25. package/dist/frontend/mf-order/tsconfig.app.tsbuildinfo +1 -1
  26. package/dist/{index-ByiTrmdq.js → index-BFJ4YEfL.js} +2 -2
  27. package/dist/{index-CaO7aaaT.js → index-CGiJXVU3.js} +1 -1
  28. package/dist/{index-s2kWGMtz.js → index-DSB009Br.js} +1 -1
  29. package/dist/{order.dto-C829lA69.js → order.dto-CUp8zhQC.js} +18 -18
  30. package/dist/package/entity/order-platform/tng/tng-menu.do.d.ts +74 -74
  31. package/dist/style.css +1 -1
  32. package/env.d.ts +2 -0
  33. package/package.json +2 -1
  34. package/src/api/brandkit/index.ts +24 -0
  35. package/src/api/native-app/index.ts +26 -0
  36. package/src/api/native-app/native-app.spec.ts +42 -0
  37. package/src/composables/featureFlag.ts +22 -0
  38. package/src/composables/useBusinessFeatureFlag.ts +44 -0
  39. package/src/composables/useLegacyOdsAccess.ts +35 -0
  40. package/src/composables/useMiniProgramPermission.ts +19 -0
  41. package/src/composables/useQrOrderingEnabled.ts +1 -21
  42. package/src/locales/en-US.json +179 -0
  43. package/src/locales/ja-JP.json +179 -0
  44. package/src/locales/th-TH.json +179 -0
  45. package/src/locales/zh-CN.json +179 -0
  46. package/src/modules/display-system/legacy-ods/interface.ts +108 -0
  47. package/src/router/routes.ts +1 -1
  48. package/src/views/display-system/DisplaySystemView.vue +82 -11
  49. package/src/views/display-system/legacy-ods/ColorOverrideDialog.vue +223 -0
  50. package/src/views/display-system/legacy-ods/ColorSelection.vue +67 -0
  51. package/src/views/display-system/legacy-ods/LegacyOdsEditorDialog.spec.ts +185 -0
  52. package/src/views/display-system/legacy-ods/LegacyOdsEditorDialog.vue +1677 -0
  53. package/src/views/display-system/legacy-ods/LegacyOdsTemplateList.spec.ts +124 -0
  54. package/src/views/display-system/legacy-ods/LegacyOdsTemplateList.vue +297 -0
  55. package/src/views/display-system/legacy-ods/brandkit.spec.ts +67 -0
  56. package/src/views/display-system/view-selection.spec.ts +93 -0
  57. package/src/views/display-system/view-selection.ts +54 -0
  58. package/src/views/order-settings/components/NotifyChannelEditor.spec.ts +184 -0
  59. package/src/views/order-settings/components/NotifyChannelEditor.vue +84 -5
  60. package/src/views/order-settings/components/push-availability.spec.ts +59 -0
  61. package/src/views/order-settings/components/push-availability.ts +78 -0
  62. package/src/views/order-settings/queue/QueueSetting.vue +7 -0
  63. package/src/views/order-settings/sms/SmsSetting.vue +11 -0
  64. package/dist/DisplaySystemView-DZS7EVfk.js +0 -6564
  65. package/dist/_plugin-vue_export-helper-CHgC5LLL.js +0 -9
@@ -0,0 +1,185 @@
1
+ // @vitest-environment happy-dom
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
3
+ import { mount, type VueWrapper } from '@vue/test-utils'
4
+ import { ref } from 'vue'
5
+ import type { OdsConfigEntry } from '@/modules/display-system/legacy-ods/interface'
6
+
7
+ const access = {
8
+ canAccessOdsTemplateSettings: ref(true),
9
+ isAdvancedCustomizationEnabled: ref(false)
10
+ }
11
+ vi.mock('@/composables/useLegacyOdsAccess', () => ({ useLegacyOdsAccess: () => access }))
12
+ vi.mock('@feedmepos/media-picker', () => ({
13
+ MediaPickerModal: {
14
+ name: 'MediaPickerModal',
15
+ props: ['open', 'businessId', 'kinds', 'zIndex'],
16
+ template: '<div />'
17
+ }
18
+ }))
19
+ vi.mock('@feedmepos/mf-common', () => ({
20
+ RestaurantSelector: { name: 'RestaurantSelector', template: '<div />' },
21
+ useCoreStore: () => ({ currentBusiness: ref({ _id: 'business' }), namespace: ref('dev') }),
22
+ useI18n: () => ({ t: (key: string) => key })
23
+ }))
24
+ vi.mock('./ColorOverrideDialog.vue', () => ({ default: { template: '<div />' } }))
25
+ import Editor from './LegacyOdsEditorDialog.vue'
26
+
27
+ const wrappers: VueWrapper[] = []
28
+ beforeEach(() => {
29
+ access.canAccessOdsTemplateSettings.value = true
30
+ access.isAdvancedCustomizationEnabled.value = false
31
+ vi.stubGlobal(
32
+ 'ResizeObserver',
33
+ class {
34
+ observe() {}
35
+ disconnect() {}
36
+ }
37
+ )
38
+ })
39
+ afterEach(() => {
40
+ wrappers.forEach((wrapper) => wrapper.unmount())
41
+ wrappers.length = 0
42
+ vi.unstubAllGlobals()
43
+ })
44
+
45
+ async function editor(entry: OdsConfigEntry = { isDefault: true, label: '默认 🍵' }) {
46
+ const wrapper = mount(Editor, {
47
+ props: {
48
+ modelValue: false,
49
+ entry,
50
+ editingIndex: 0,
51
+ allEntries: [entry],
52
+ brandkit: { colors: { primary: '#123456' } } as never,
53
+ colorFields: []
54
+ },
55
+ global: {
56
+ stubs: {
57
+ Teleport: true,
58
+ FmButton: {
59
+ props: ['label', 'disabled'],
60
+ template: '<button :disabled="disabled">{{ label }}</button>'
61
+ },
62
+ FmIcon: true,
63
+ FmTextField: true,
64
+ FmSwitch: true,
65
+ FmButtonGroup: true,
66
+ FmStepperField: true,
67
+ FmRadio: true
68
+ }
69
+ }
70
+ })
71
+ wrappers.push(wrapper)
72
+ await wrapper.setProps({ modelValue: true })
73
+ return wrapper
74
+ }
75
+ async function confirm(wrapper: VueWrapper) {
76
+ await wrapper
77
+ .findAll('button')
78
+ .find((button) => button.text().endsWith('.confirm'))!
79
+ .trigger('click')
80
+ // The list closes the editor only once the save has landed.
81
+ expect(wrapper.emitted('update:modelValue')).toBeUndefined()
82
+ return wrapper.emitted('save')![0][0] as OdsConfigEntry
83
+ }
84
+
85
+ function previewBrandKit(wrapper: VueWrapper) {
86
+ const url = new URL(wrapper.get('iframe').attributes('src'))
87
+ expect(url.origin).toBe('https://v2-dev.feedme-ods.pages.dev')
88
+ expect(url.searchParams.get('preview')).toBe('1')
89
+ return JSON.parse(Buffer.from(url.searchParams.get('brandKit')!, 'base64url').toString('utf8'))
90
+ }
91
+
92
+ describe('legacy ODS editor', () => {
93
+ it('keeps collected-order hiding across preset changes and previews the draft as default', async () => {
94
+ const wrapper = await editor({
95
+ isDefault: false,
96
+ label: '默认 🍵',
97
+ restaurantIds: ['outlet'],
98
+ display: { hideCompletedOrders: true } as never
99
+ })
100
+ const presets = wrapper.findAllComponents({ name: 'FmButtonGroup' })[0]
101
+ presets.vm.$emit('update:modelValue', { value: 'preset2' })
102
+ await wrapper.vm.$nextTick()
103
+ const preview = previewBrandKit(wrapper)
104
+ expect(preview.colors.primary).toBe('#123456')
105
+ expect(preview.ods[0]).toMatchObject({
106
+ isDefault: true,
107
+ layout: { background: null, sidePanel: { url: '/images/feedme-side.png' } },
108
+ display: { groupBy: 'status', hideCompletedOrders: true }
109
+ })
110
+ const saved = await confirm(wrapper)
111
+ expect(saved.label).toBe('默认 🍵')
112
+ expect(saved.restaurantIds).toEqual(['outlet'])
113
+ expect(saved.isDefault).toBe(false)
114
+ expect(saved.display?.hideCompletedOrders).toBe(true)
115
+ })
116
+
117
+ it('leaves metadata, outlet selection and presets editable without the template flag', async () => {
118
+ access.canAccessOdsTemplateSettings.value = false
119
+ const wrapper = await editor({ isDefault: false, label: 'Existing', restaurantIds: ['outlet'] })
120
+ const label = wrapper.findComponent({ name: 'FmTextField' })
121
+ expect(label.attributes('disabled')).toBeUndefined()
122
+ label.vm.$emit('update:modelValue', 'Renamed')
123
+ const selector = wrapper.findComponent({ name: 'RestaurantSelector' })
124
+ expect(selector.attributes('disabled')).toBeUndefined()
125
+ expect(selector.attributes('managable-only')).toBe('false')
126
+ selector.vm.$emit('update:modelValue', ['other-outlet'])
127
+ const defaultSwitch = wrapper
128
+ .findAllComponents({ name: 'FmSwitch' })
129
+ .find((item) => item.attributes('label')?.endsWith('.defaultConfiguration'))!
130
+ expect(defaultSwitch.attributes('disabled')).toBeUndefined()
131
+ defaultSwitch.vm.$emit('update:modelValue', true)
132
+ const presets = wrapper.findComponent({ name: 'FmButtonGroup' })
133
+ expect(presets.attributes('disabled')).toBeUndefined()
134
+ presets.vm.$emit('update:modelValue', { value: 'preset2' })
135
+ const hide = wrapper
136
+ .findAllComponents({ name: 'FmSwitch' })
137
+ .find((item) => item.attributes('label')?.endsWith('.hideCollectedOrders'))!
138
+ hide.vm.$emit('update:modelValue', true)
139
+ const saved = await confirm(wrapper)
140
+ expect(saved).toMatchObject({
141
+ label: 'Renamed',
142
+ isDefault: true,
143
+ restaurantIds: ['other-outlet'],
144
+ layout: { background: null, sidePanel: { url: '/images/feedme-side.png' } },
145
+ display: { groupBy: 'status', hideCompletedOrders: true }
146
+ })
147
+ expect(wrapper.text()).not.toContain('order.displaySystem.legacyOds.displaySettingsDescription')
148
+ expect(wrapper.text()).not.toContain('order.displaySystem.legacyOds.layoutSettingsDescription')
149
+ })
150
+
151
+ it('replaces a custom image with one picked from the media library', async () => {
152
+ const media = 'https://image.feedmedev.vip/media-image/business/asset/a1/main'
153
+ const wrapper = await editor({
154
+ isDefault: true,
155
+ layout: {
156
+ background: { url: 'https://image.feedmedev.vip/business/business/ods/background/old.png' },
157
+ sidePanel: null
158
+ }
159
+ })
160
+ const picker = () => wrapper.findComponent({ name: 'MediaPickerModal' })
161
+ expect(picker().props()).toMatchObject({ open: false, businessId: 'business', kinds: ['image'] })
162
+ await wrapper
163
+ .findAll('button')
164
+ .find((button) => button.text().endsWith('.changeImage'))!
165
+ .trigger('click')
166
+ expect(picker().props('open')).toBe(true)
167
+ picker().vm.$emit('select', { url: media, kind: 'image' })
168
+ await wrapper.vm.$nextTick()
169
+ expect(picker().props('open')).toBe(false)
170
+ const saved = await confirm(wrapper)
171
+ expect(saved.layout?.background).toMatchObject({
172
+ url: media,
173
+ size: 'cover',
174
+ position: 'center'
175
+ })
176
+ })
177
+
178
+ it('shows advanced controls only when the advanced flag is enabled', async () => {
179
+ const wrapper = await editor()
180
+ expect(wrapper.text()).not.toContain('order.displaySystem.legacyOds.footerModeDescription')
181
+ access.isAdvancedCustomizationEnabled.value = true
182
+ await wrapper.vm.$nextTick()
183
+ expect(wrapper.text()).toContain('order.displaySystem.legacyOds.footerModeDescription')
184
+ })
185
+ })