@feedmepos/mf-order-setting 0.0.56-dev.1 → 0.0.56-dev.2

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 (64) hide show
  1. package/.tsbuildinfo +1 -1
  2. package/dist/{KioskDevicesView-CccsAZqK.js → KioskDevicesView-Qv-xd_kZ.js} +1 -1
  3. package/dist/{KioskDevicesView.vue_vue_type_script_setup_true_lang-dF1jgi53.js → KioskDevicesView.vue_vue_type_script_setup_true_lang-CCF1mKni.js} +2 -2
  4. package/dist/KioskSettingView-CvvrK6Bv.js +643 -0
  5. package/dist/{KioskView-DmaCjLcw.js → KioskView-CppTVBv-.js} +117 -117
  6. package/dist/OrderSettingsView-C38N61dM.js +36564 -0
  7. package/dist/{app-EGmxrjDM.js → app-Bss1GkKY.js} +4 -4
  8. package/dist/app.js +1 -1
  9. package/dist/{dayjs.min-lCwCAXUZ.js → dayjs.min-DZfxGUk4.js} +1 -1
  10. package/dist/frontend/mf-order/src/stores/order-setting/index.d.ts +3 -0
  11. package/dist/frontend/mf-order/src/stores/restaurant/index.d.ts +1 -1
  12. package/dist/frontend/mf-order/src/views/kiosk/settings/KioskPaymentTypeSection.vue.d.ts +13 -3
  13. package/dist/frontend/mf-order/src/views/order-settings/delivery/integrated-delivery/ExternalSetting.vue.d.ts +12 -4
  14. package/dist/frontend/mf-order/src/views/order-settings/dine-in/OfflinePaymentTypeDialog.vue.d.ts +4 -4
  15. package/dist/frontend/mf-order/src/views/order-settings/dine-in/PaymentType.vue.d.ts +38 -4
  16. package/dist/frontend/mf-order/src/views/order-settings/pickup/PaymentSidesheet.vue.d.ts +1 -0
  17. package/dist/frontend/mf-order/src/views/order-settings/reservation/CustomTimePicker.vue.d.ts +1 -0
  18. package/dist/{index-CWrX79Jg.js → index-B6AGCsrw.js} +6 -6
  19. package/dist/index-BpKR-Cxd.js +19757 -0
  20. package/dist/{menu.dto-CgymySda.js → menu.dto-C_B3M2fs.js} +44222 -46755
  21. package/dist/package/entity/incoming-order/incoming-order.do.d.ts +22443 -3
  22. package/dist/package/entity/incoming-order/incoming-order.dto.d.ts +3 -3
  23. package/dist/package/entity/incoming-order/incoming-order.enum.d.ts +1 -1
  24. package/dist/package/entity/index.d.ts +1 -0
  25. package/dist/package/entity/marketing/marketing.dto.d.ts +1 -1
  26. package/dist/package/entity/order/dine-in/qr.dto.d.ts +38 -0
  27. package/dist/package/entity/order/order.do.d.ts +6358 -2
  28. package/dist/package/entity/order/order.dto.d.ts +22 -0
  29. package/dist/package/entity/order-platform/deliveroo/deliveroo-dto.d.ts +3 -0
  30. package/dist/package/entity/order-platform/deliveroo/deliveroo-setting.do.d.ts +3 -0
  31. package/dist/package/entity/order-platform/external/order/external-order.do.d.ts +12 -12
  32. package/dist/package/entity/order-platform/external/order/external-order.dto.d.ts +32 -32
  33. package/dist/package/entity/order-platform/external/setting/external-setting.do.d.ts +21 -3
  34. package/dist/package/entity/order-platform/external/setting/external-setting.dto.d.ts +12 -2
  35. package/dist/package/entity/order-platform/foodpanda/foodpanda-settings.do.d.ts +3 -0
  36. package/dist/package/entity/order-platform/foodpanda/foodpanda-settings.dto.d.ts +3 -0
  37. package/dist/package/entity/order-platform/grabfood/grabfood-edit-order.do.d.ts +9 -1
  38. package/dist/package/entity/order-platform/grabfood/grabfood-settings.do.d.ts +2 -2
  39. package/dist/package/entity/order-platform/grabfood/grabfood.dto.d.ts +3 -3
  40. package/dist/package/entity/order-platform/order-platform.dto.d.ts +2 -2
  41. package/dist/package/entity/order-platform/shopeefood/shopeefood-settings.do.d.ts +3 -0
  42. package/dist/package/entity/order-platform/shopeefood/shopeefood-settings.dto.d.ts +3 -0
  43. package/dist/package/entity/order-setting/order-setting.do.d.ts +3 -0
  44. package/dist/package/entity/order-setting/order-setting.dto.d.ts +6 -0
  45. package/dist/package/entity/queue/queue.do.d.ts +3 -8
  46. package/dist/package/entity/queue/queue.dto.d.ts +10 -0
  47. package/dist/package/entity/reservation/reservation.do.d.ts +4 -0
  48. package/dist/package/entity/reservation/reservation.dto.d.ts +10 -0
  49. package/dist/package/entity/reservation/reservation.utils.d.ts +2 -2
  50. package/dist/style.css +1 -1
  51. package/package.json +1 -1
  52. package/src/views/kiosk/KioskSummary.vue +3 -0
  53. package/src/views/kiosk/settings/KioskPaymentTypeSection.vue +99 -211
  54. package/src/views/kiosk/settings/KioskSettingView.vue +27 -11
  55. package/src/views/order-settings/dine-in/DineInSetting.vue +1 -0
  56. package/src/views/order-settings/dine-in/OfflinePaymentTypeDialog.vue +2 -3
  57. package/src/views/order-settings/dine-in/PaymentType.vue +151 -43
  58. package/src/views/order-settings/pickup/PaymentSidesheet.vue +33 -172
  59. package/src/views/order-settings/pickup/PickUpSettingDialogContent.vue +1 -0
  60. package/src/views/order-settings/reservation/CustomTimePicker.vue +129 -49
  61. package/src/views/order-settings/reservation/ReservationSetting.vue +547 -303
  62. package/dist/KioskSettingView-8GY7AT-N.js +0 -722
  63. package/dist/OrderSettingsView-BZcU4t9L.js +0 -56240
  64. package/dist/index-BXsnV_eO.js +0 -150
@@ -22,7 +22,6 @@ import moment from 'moment'
22
22
  import CopySettingsSheet from './CopySettingsSheet.vue'
23
23
  import notfound from '@/assets/images/not-found.png'
24
24
 
25
-
26
25
  const { t } = useI18n()
27
26
  const { showSuccess } = useSnackbarFunctions()
28
27
  const { currentRestaurant, restaurants } = useCoreStore()
@@ -39,7 +38,8 @@ const generateRangeDefaults = (index = 0) => ({
39
38
  })
40
39
 
41
40
  // Helper function to generate unique capacity tier ID
42
- const generateCapacityTierId = () => new Date().toISOString() + '-' + Math.random().toString(36).substr(2, 9)
41
+ const generateCapacityTierId = () =>
42
+ new Date().toISOString() + '-' + Math.random().toString(36).substr(2, 9)
43
43
 
44
44
  const DEFAULT_GUEST_MESSAGE = `Please take note of the following important details before making a reservation:
45
45
 
@@ -53,21 +53,144 @@ const DEFAULT_CANCELLATION_POLICY = `Cancellation Policy
53
53
 
54
54
  Free cancellation up to 24 hours before your reservation. Please contact the outlet for any last-minute changes.`
55
55
 
56
- const reservationSettings = ref<FdoOrderReservationSettingsV2>({
57
- ranges: [
56
+ function createDefaultCapacityTiers() {
57
+ return [
58
+ {
59
+ _id: generateCapacityTierId(),
60
+ minPax: 1,
61
+ maxPax: 2,
62
+ capacity: 8
63
+ },
64
+ {
65
+ _id: generateCapacityTierId(),
66
+ minPax: 3,
67
+ maxPax: 6,
68
+ capacity: 8
69
+ },
58
70
  {
59
- ...generateRangeDefaults(0),
60
- enable: false,
61
- bookingDuration: 90,
62
- enablePreorder: true,
63
- minLeadDuration: {
64
- value: 0,
65
- unit: 'day'
71
+ _id: generateCapacityTierId(),
72
+ minPax: 5,
73
+ maxPax: 7,
74
+ capacity: 8
75
+ }
76
+ ]
77
+ }
78
+
79
+ function createDefaultRange(index = 0): FdoReservationRange {
80
+ return {
81
+ ...generateRangeDefaults(index),
82
+ enable: false,
83
+ bookingDuration: 90,
84
+ enablePreorder: true,
85
+ minLeadDuration: {
86
+ value: 0,
87
+ unit: 'day'
88
+ },
89
+ maxLeadDuration: {
90
+ value: 30,
91
+ unit: 'day'
92
+ },
93
+ operatingHours: {
94
+ 0: {
95
+ enable: false,
96
+ hours: []
97
+ },
98
+ 1: {
99
+ enable: true,
100
+ hours: [
101
+ { start: '09:00', end: '14:00' },
102
+ { start: '17:00', end: '22:00' }
103
+ ]
104
+ },
105
+ 2: {
106
+ enable: true,
107
+ hours: [
108
+ { start: '09:00', end: '14:00' },
109
+ { start: '17:00', end: '22:00' }
110
+ ]
66
111
  },
67
- maxLeadDuration: {
68
- value: 30,
69
- unit: 'day'
112
+ 3: {
113
+ enable: true,
114
+ hours: [
115
+ { start: '09:00', end: '14:00' },
116
+ { start: '17:00', end: '22:00' }
117
+ ]
70
118
  },
119
+ 4: {
120
+ enable: true,
121
+ hours: [
122
+ { start: '09:00', end: '14:00' },
123
+ { start: '17:00', end: '22:00' }
124
+ ]
125
+ },
126
+ 5: {
127
+ enable: true,
128
+ hours: [
129
+ { start: '09:00', end: '14:00' },
130
+ { start: '17:00', end: '22:00' }
131
+ ]
132
+ },
133
+ 6: {
134
+ enable: true,
135
+ hours: []
136
+ }
137
+ },
138
+ preferences: [],
139
+ capacityTiers: createDefaultCapacityTiers(),
140
+ slotInterval: 30,
141
+ guestMessage: DEFAULT_GUEST_MESSAGE,
142
+ cancellationPolicy: DEFAULT_CANCELLATION_POLICY
143
+ }
144
+ }
145
+
146
+ function parseTimeToMinutes(time: string) {
147
+ const [hours, minutes] = time.split(':').map(Number)
148
+ return hours * 60 + minutes
149
+ }
150
+
151
+ function isOvernightRange(range: { start: string; end: string }) {
152
+ return parseTimeToMinutes(range.end) <= parseTimeToMinutes(range.start)
153
+ }
154
+
155
+ function normalizeRange<T extends Partial<FdoReservationRange>>(range: T, index = 0): T {
156
+ const defaults = generateRangeDefaults(index)
157
+ return {
158
+ ...range,
159
+ _id: range._id || defaults._id,
160
+ name: range.name || defaults.name,
161
+ capacityTiers: range.capacityTiers?.length ? range.capacityTiers : createDefaultCapacityTiers()
162
+ }
163
+ }
164
+
165
+ function getPreviewHoursForDay(day: 0 | 1 | 2 | 3 | 4 | 5 | 6) {
166
+ const operatingHours = rangeSetting.value.operatingHours
167
+ const previousDay = ((day + 6) % 7) as 0 | 1 | 2 | 3 | 4 | 5 | 6
168
+ const currentDayHours = operatingHours[day]
169
+ const previousDayHours = operatingHours[previousDay]
170
+
171
+ const spilloverHours = previousDayHours?.enable
172
+ ? previousDayHours.hours
173
+ .filter((hour) => isOvernightRange(hour))
174
+ .map((hour) => ({ start: '00:00', end: hour.end }))
175
+ : []
176
+
177
+ const currentHours = currentDayHours?.enable ? currentDayHours.hours : []
178
+
179
+ return [...spilloverHours, ...currentHours]
180
+ }
181
+
182
+ function getPreviewOperatingHours(day: 0 | 1 | 2 | 3 | 4 | 5 | 6) {
183
+ const hours = getPreviewHoursForDay(day)
184
+ return {
185
+ enable: hours.length > 0,
186
+ hours
187
+ }
188
+ }
189
+
190
+ const reservationSettings = ref<FdoOrderReservationSettingsV2>({
191
+ ranges: [
192
+ {
193
+ ...createDefaultRange(0),
71
194
  operatingHours: {
72
195
  0: {
73
196
  enable: false,
@@ -97,12 +220,7 @@ const reservationSettings = ref<FdoOrderReservationSettingsV2>({
97
220
  enable: false,
98
221
  hours: []
99
222
  }
100
- },
101
- preferences: [],
102
- capacityTiers: [],
103
- slotInterval: 30,
104
- guestMessage: DEFAULT_GUEST_MESSAGE,
105
- cancellationPolicy: DEFAULT_CANCELLATION_POLICY
223
+ }
106
224
  }
107
225
  ],
108
226
  posCanOverbook: false,
@@ -113,95 +231,7 @@ const reservationSettings = ref<FdoOrderReservationSettingsV2>({
113
231
  notifyOnCancel: true
114
232
  })
115
233
 
116
- const rangeSetting = ref<FdoReservationRange>({
117
- ...generateRangeDefaults(0),
118
- enable: false,
119
- bookingDuration: 90,
120
- enablePreorder: true,
121
- minLeadDuration: {
122
- value: 0,
123
- unit: 'day'
124
- },
125
- maxLeadDuration: {
126
- value: 30,
127
- unit: 'day'
128
- },
129
- operatingHours: {
130
- 0: {
131
- enable: true,
132
- hours: []
133
- },
134
- 1: {
135
- enable: true,
136
- hours: [
137
- { start: '09:00', end: '14:00' },
138
- { start: '17:00', end: '22:00' }
139
- ]
140
- },
141
- 2: {
142
- enable: true,
143
- hours: [
144
- { start: '09:00', end: '14:00' },
145
- { start: '17:00', end: '22:00' }
146
- ]
147
- },
148
- 3: {
149
- enable: true,
150
- hours: [
151
- { start: '09:00', end: '14:00' },
152
- { start: '17:00', end: '22:00' }
153
- ]
154
- },
155
- 4: {
156
- enable: true,
157
- hours: [
158
- { start: '09:00', end: '14:00' },
159
- { start: '17:00', end: '22:00' }
160
- ]
161
- },
162
- 5: {
163
- enable: true,
164
- hours: [
165
- { start: '09:00', end: '14:00' },
166
- { start: '17:00', end: '22:00' }
167
- ]
168
- },
169
- 6: {
170
- enable: true,
171
- hours: []
172
- }
173
- },
174
- preferences: [],
175
- capacityTiers: [
176
- {
177
- _id: generateCapacityTierId(),
178
- minPax: 1,
179
- maxPax: 2,
180
- capacity: 10
181
- },
182
- {
183
- _id: generateCapacityTierId(),
184
- minPax: 3,
185
- maxPax: 4,
186
- capacity: 8
187
- },
188
- {
189
- _id: generateCapacityTierId(),
190
- minPax: 5,
191
- maxPax: 6,
192
- capacity: 5
193
- },
194
- {
195
- _id: generateCapacityTierId(),
196
- minPax: 7,
197
- maxPax: null,
198
- capacity: 3
199
- }
200
- ],
201
- slotInterval: 30,
202
- guestMessage: DEFAULT_GUEST_MESSAGE,
203
- cancellationPolicy: DEFAULT_CANCELLATION_POLICY
204
- })
234
+ const rangeSetting = ref<FdoReservationRange>(createDefaultRange(0))
205
235
 
206
236
  const isSaving = ref(false)
207
237
 
@@ -281,9 +311,10 @@ const selectedPreset = computed(() => {
281
311
  // Now includes unavailable slots (between operating hour gaps)
282
312
  const availableSlots = computed(() => {
283
313
  const day = selectedPreviewDay.value as 0 | 1 | 2 | 3 | 4 | 5 | 6
284
- const { operatingHours, slotInterval, bookingDuration } = rangeSetting.value
314
+ const { slotInterval, bookingDuration } = rangeSetting.value
315
+ const previewOperatingHours = getPreviewOperatingHours(day)
285
316
 
286
- if (!operatingHours[day]?.enable || !operatingHours[day].hours.length) {
317
+ if (!previewOperatingHours.enable) {
287
318
  return { morning: [], afternoon: [], evening: [] }
288
319
  }
289
320
 
@@ -291,7 +322,7 @@ const availableSlots = computed(() => {
291
322
  // This generates slots only from earliest to latest operating hour (not full 24h)
292
323
  // Example: If hours are 10:00-12:00, 15:00-21:00, shows 10:00-21:00 range
293
324
  const slotsWithStatus = generateDayTimeSlotsWithStatus(
294
- operatingHours[day],
325
+ previewOperatingHours,
295
326
  slotInterval,
296
327
  bookingDuration
297
328
  )
@@ -333,15 +364,13 @@ const hasMoreItems = computed(() => {
333
364
 
334
365
  const reservationPreview = computed(() => {
335
366
  const today = moment()
336
- const { minLeadDuration, maxLeadDuration, operatingHours } = rangeSetting.value
367
+ const { minLeadDuration, maxLeadDuration } = rangeSetting.value
337
368
  const startDate = today.clone().add(minLeadDuration.value, minLeadDuration.unit).startOf('d')
338
369
  const endDate = today.clone().add(maxLeadDuration.value, maxLeadDuration.unit).startOf('d')
339
370
 
340
- type Day = keyof typeof operatingHours
341
-
342
371
  // Get the hours for start and end days
343
- const startDayHours = operatingHours[startDate.day() as Day].hours
344
- const endDayHours = operatingHours[endDate.day() as Day].hours
372
+ const startDayHours = getPreviewHoursForDay(startDate.day() as 0 | 1 | 2 | 3 | 4 | 5 | 6)
373
+ const endDayHours = getPreviewHoursForDay(endDate.day() as 0 | 1 | 2 | 3 | 4 | 5 | 6)
345
374
 
346
375
  // Check if hours exist for both days
347
376
  if (!startDayHours || startDayHours.length === 0 || !endDayHours || endDayHours.length === 0) {
@@ -354,11 +383,14 @@ const reservationPreview = computed(() => {
354
383
  }
355
384
 
356
385
  // use operatingHours and get the earlier starting hour to return a start&end for the preview, return the formatted time
357
- const startHour = [...startDayHours].sort((a, b) =>
358
- moment(a.start, 'HH:mm').diff(moment(b.start, 'HH:mm'))
386
+ const startHour = [...startDayHours].sort(
387
+ (a, b) => parseTimeToMinutes(a.start) - parseTimeToMinutes(b.start)
359
388
  )[0]
360
- const endHour = [...endDayHours].sort((a, b) =>
361
- moment(b.end, 'HH:mm').diff(moment(a.end, 'HH:mm'))
389
+ const endHour = [...endDayHours].sort(
390
+ (a, b) =>
391
+ parseTimeToMinutes(b.end) +
392
+ (isOvernightRange(b) ? 24 * 60 : 0) -
393
+ (parseTimeToMinutes(a.end) + (isOvernightRange(a) ? 24 * 60 : 0))
362
394
  )[0]
363
395
 
364
396
  return {
@@ -431,7 +463,7 @@ async function updateReservationSetting() {
431
463
 
432
464
  // Validate with Zod schema
433
465
  const validated = ReservationSettingsSchema.parse(reservationSettings.value)
434
- console.log(validated);
466
+ console.log(validated)
435
467
  await ReservationApi.updateReservationSetting(currentRestaurant.value._id, validated)
436
468
  await init()
437
469
  })
@@ -445,7 +477,7 @@ async function init() {
445
477
  if (currentRestaurant.value) {
446
478
  const settings = await readReservationSetting()
447
479
  reservationSettings.value = {
448
- ranges: settings.ranges || [],
480
+ ranges: (settings.ranges || []).map((range, index) => normalizeRange(range, index)),
449
481
  posCanOverbook: settings.posCanOverbook || false,
450
482
  draftHoldTimeMinutes: settings.draftHoldTimeMinutes || 15,
451
483
  smsEnabled: settings.smsEnabled ?? true,
@@ -455,17 +487,11 @@ async function init() {
455
487
  }
456
488
  // Sync rangeSetting with the first range if it exists, otherwise reset to default
457
489
  if (settings.ranges && settings.ranges.length > 0) {
458
- rangeSetting.value = settings.ranges[0]
490
+ rangeSetting.value = normalizeRange(settings.ranges[0], 0)
459
491
  } else {
460
492
  // Reset to default state when no ranges exist (fresh restaurant)
461
493
  rangeSetting.value = {
462
- _id: new Date().toISOString(),
463
- name: 'Dining Area 1',
464
- enable: false,
465
- bookingDuration: 90,
466
- enablePreorder: true,
467
- minLeadDuration: { value: 0, unit: 'day' },
468
- maxLeadDuration: { value: 30, unit: 'day' },
494
+ ...createDefaultRange(0),
469
495
  operatingHours: {
470
496
  0: { enable: false, hours: [] },
471
497
  1: { enable: false, hours: [] },
@@ -474,12 +500,7 @@ async function init() {
474
500
  4: { enable: false, hours: [] },
475
501
  5: { enable: false, hours: [] },
476
502
  6: { enable: false, hours: [] }
477
- },
478
- preferences: [],
479
- capacityTiers: [],
480
- slotInterval: 30,
481
- guestMessage: DEFAULT_GUEST_MESSAGE,
482
- cancellationPolicy: DEFAULT_CANCELLATION_POLICY
503
+ }
483
504
  }
484
505
  }
485
506
 
@@ -632,7 +653,7 @@ function validateTimeRange(day: 0 | 1 | 2 | 3 | 4 | 5 | 6, hourIndex: number): s
632
653
 
633
654
  // Validate same day time range (end > start)
634
655
  if (!validateSameDayTimeRange(range)) {
635
- return 'End time must be after start time'
656
+ return 'Start and end time cannot be the same'
636
657
  }
637
658
 
638
659
  // Check for overlaps with other time ranges
@@ -736,9 +757,13 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
736
757
  <div class="flex-grow fm-typo-en-title-sm-600 mb-16">
737
758
  {{ t('order.reservationStatus') }}
738
759
  </div>
739
- <FmSwitch label-placement="right" :label="'Enable reservation'"
760
+ <FmSwitch
761
+ label-placement="right"
762
+ :label="'Enable reservation'"
740
763
  :sublabel="'Enable this to make the outlet available for reservations. This setting does not impact walk-in dining.'"
741
- :model-value="rangeSetting.enable ?? false" @update:model-value="(v: boolean) => (rangeSetting.enable = v)" />
764
+ :model-value="rangeSetting.enable ?? false"
765
+ @update:model-value="(v: boolean) => (rangeSetting.enable = v)"
766
+ />
742
767
 
743
768
  <div v-if="rangeSetting.enable && isMultiOutlet" class="ml-56 my-8">
744
769
  <CopySettingsSheet :current-settings="reservationSettings" @apply="handleCopySettings" />
@@ -791,21 +816,31 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
791
816
  <div class="mb-5">
792
817
  <div class="mb-8 fm-typo-en-body-md-600 flex items-center gap-8">
793
818
  {{ t('order.draftHoldTimeMinutes') }}
794
- <FmTooltip :content="'The amount of time a reservation is held before it is automatically released.'">
819
+ <FmTooltip
820
+ :content="'The amount of time a reservation is held before it is automatically released.'"
821
+ >
795
822
  <FmIcon name="info" outline size="sm" class="cursor-pointer" />
796
823
  </FmTooltip>
797
824
  </div>
798
- <FmTextField type="number" :model-value="reservationSettings.draftHoldTimeMinutes" @update:model-value="
799
- (v: string | number) =>
800
- updateSetting('draftHoldTimeMinutes', v === '' ? 15 : Number(v))
801
- " suffix="minutes"
802
- class="max-w-md" />
825
+ <FmTextField
826
+ type="number"
827
+ :model-value="reservationSettings.draftHoldTimeMinutes"
828
+ @update:model-value="
829
+ (v: string | number) =>
830
+ updateSetting('draftHoldTimeMinutes', v === '' ? 15 : Number(v))
831
+ "
832
+ suffix="minutes"
833
+ class="max-w-md"
834
+ />
803
835
  </div>
804
836
  <div class="mb-5">
805
- <FmSwitch :model-value="reservationSettings.posCanOverbook"
837
+ <FmSwitch
838
+ :model-value="reservationSettings.posCanOverbook"
806
839
  @update:model-value="(v: boolean) => updateSetting('posCanOverbook', v)"
807
- :label="t('order.posCanOverbook')" label-placement="right"
808
- :sublabel="t('order.posCanOverbookDescription')" />
840
+ :label="t('order.posCanOverbook')"
841
+ label-placement="right"
842
+ :sublabel="t('order.posCanOverbookDescription')"
843
+ />
809
844
  </div>
810
845
  </FmCard>
811
846
  </div>
@@ -823,7 +858,8 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
823
858
  <div class="mb-8">Preview</div>
824
859
  <div class="flex items-center gap-4 mb-8">
825
860
  <div
826
- class="w-fit border-1 border-fm-color-neutral-gray-200 rounded-md py-4 px-8 bg-fm-color-neutral-gray-100 flex items-center gap-8 text-fm-color-typo-tertiary">
861
+ class="w-fit border-1 border-fm-color-neutral-gray-200 rounded-md py-4 px-8 bg-fm-color-neutral-gray-100 flex items-center gap-8 text-fm-color-typo-tertiary"
862
+ >
827
863
  <FmIcon name="calendar_month" outline />
828
864
  <div class="pr-6">
829
865
  {{ reservationPreview.start + ' ' + reservationPreview.startHour }}
@@ -831,7 +867,8 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
831
867
  </div>
832
868
  <div>to</div>
833
869
  <div
834
- class="w-fit border-1 border-fm-color-neutral-gray-200 rounded-md py-4 px-8 bg-fm-color-neutral-gray-100 flex items-center gap-8 text-fm-color-typo-tertiary">
870
+ class="w-fit border-1 border-fm-color-neutral-gray-200 rounded-md py-4 px-8 bg-fm-color-neutral-gray-100 flex items-center gap-8 text-fm-color-typo-tertiary"
871
+ >
835
872
  <FmIcon name="calendar_month" outline />
836
873
  <div class="pr-6">
837
874
  {{ reservationPreview.end + ' ' + reservationPreview.endHour }}
@@ -847,8 +884,10 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
847
884
 
848
885
  <div class="mb-24">
849
886
  <div class="mb-8">Presets</div>
850
- <FmRadioGroup :model-value="selectedPreset"
851
- @update:model-value="(v: number | 'custom') => updateMaxLeadPreset(v)">
887
+ <FmRadioGroup
888
+ :model-value="selectedPreset"
889
+ @update:model-value="(v: number | 'custom') => updateMaxLeadPreset(v)"
890
+ >
852
891
  <FmRadio label="30 days" :value="30">
853
892
  <template #label>
854
893
  <div>30 days <span class="text-fm-color-typo-secondary">(default)</span></div>
@@ -860,24 +899,35 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
860
899
  </FmRadioGroup>
861
900
 
862
901
  <!-- Custom preset fields -->
863
- <div v-if="selectedPreset === 'custom'"
864
- class="ml-32 mt-12 p-16 border rounded-md bg-fm-color-neutral-gray-50">
902
+ <div
903
+ v-if="selectedPreset === 'custom'"
904
+ class="ml-32 mt-12 p-16 border rounded-md bg-fm-color-neutral-gray-50"
905
+ >
865
906
  <div class="mb-16">
866
907
  <div class="mb-8 fm-typo-en-body-md-600 flex items-center gap-8">
867
908
  Minimum Lead Time
868
909
  <FmTooltip
869
- :content="'The earliest time a guest can make a reservation. For example, if you set this to 1 day, guests can only make reservations from tomorrow onwards.'">
910
+ :content="'The earliest time a guest can make a reservation. For example, if you set this to 1 day, guests can only make reservations from tomorrow onwards.'"
911
+ >
870
912
  <FmIcon name="info" outline size="sm" class="cursor-pointer" />
871
913
  </FmTooltip>
872
914
  </div>
873
915
  <div class="flex items-center gap-8">
874
- <FmStepperField :model-value="rangeSetting.minLeadDuration.value"
875
- @update:model-value="(v: number) => updateMinLeadValue(v)" :min="0" class="" />
876
- <FmSelect :model-value="rangeSetting.minLeadDuration.unit"
877
- @update:model-value="(v: 'hour' | 'day') => updateMinLeadUnit(v)" :items="[
916
+ <FmStepperField
917
+ :model-value="rangeSetting.minLeadDuration.value"
918
+ @update:model-value="(v: number) => updateMinLeadValue(v)"
919
+ :min="0"
920
+ class=""
921
+ />
922
+ <FmSelect
923
+ :model-value="rangeSetting.minLeadDuration.unit"
924
+ @update:model-value="(v: 'hour' | 'day') => updateMinLeadUnit(v)"
925
+ :items="[
878
926
  { label: 'Hours', value: 'hour' },
879
927
  { label: 'Days', value: 'day' }
880
- ]" class="w-120" />
928
+ ]"
929
+ class="w-120"
930
+ />
881
931
  </div>
882
932
  </div>
883
933
 
@@ -885,18 +935,27 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
885
935
  <div class="mb-8 fm-typo-en-body-md-600 flex items-center gap-8">
886
936
  Maximum Lead Time
887
937
  <FmTooltip
888
- :content="'The furthest in advance a guest can make a reservation. For example, if you set this to 30 days, guests can only make reservations up to 30 days from today.'">
938
+ :content="'The furthest in advance a guest can make a reservation. For example, if you set this to 30 days, guests can only make reservations up to 30 days from today.'"
939
+ >
889
940
  <FmIcon name="info" outline size="sm" class="cursor-pointer" />
890
941
  </FmTooltip>
891
942
  </div>
892
943
  <div class="flex items-center gap-8">
893
- <FmStepperField :model-value="rangeSetting.maxLeadDuration.value"
894
- @update:model-value="(v: number) => updateMaxLeadValue(v)" :min="0" class="" />
895
- <FmSelect :model-value="rangeSetting.maxLeadDuration.unit"
896
- @update:model-value="(v: 'hour' | 'day') => updateMaxLeadUnit(v)" :items="[
944
+ <FmStepperField
945
+ :model-value="rangeSetting.maxLeadDuration.value"
946
+ @update:model-value="(v: number) => updateMaxLeadValue(v)"
947
+ :min="0"
948
+ class=""
949
+ />
950
+ <FmSelect
951
+ :model-value="rangeSetting.maxLeadDuration.unit"
952
+ @update:model-value="(v: 'hour' | 'day') => updateMaxLeadUnit(v)"
953
+ :items="[
897
954
  { label: 'Hours', value: 'hour' },
898
955
  { label: 'Days', value: 'day' }
899
- ]" class="w-120" />
956
+ ]"
957
+ class="w-120"
958
+ />
900
959
  </div>
901
960
  </div>
902
961
 
@@ -909,9 +968,7 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
909
968
  </div>
910
969
 
911
970
  <div class="flex flex-col">
912
- <div class="flex-grow fm-typo-en-title-sm-600 mb-4">
913
- Time Settings
914
- </div>
971
+ <div class="flex-grow fm-typo-en-title-sm-600 mb-4">Time Settings</div>
915
972
  <div class="fm-typo-en-body-lg-400 text-fm-color-typo-secondary mb-12">
916
973
  Choose the start and end time for reservations, and the interval between each time slot.
917
974
  Available time slots will be generated automatically.
@@ -920,13 +977,19 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
920
977
  <!-- Operating hour setting -->
921
978
  <div class="mb-32">
922
979
  <div class="grid grid-cols-[1fr_1fr_3fr] items-start">
923
- <div class="p-12 fm-typo-en-body-md-600 text-fm-color-typo-secondary bg-fm-color-neutral-gray-100">
980
+ <div
981
+ class="p-12 fm-typo-en-body-md-600 text-fm-color-typo-secondary bg-fm-color-neutral-gray-100"
982
+ >
924
983
  Day
925
984
  </div>
926
- <div class="p-12 fm-typo-en-body-md-600 text-fm-color-typo-secondary bg-fm-color-neutral-gray-100">
985
+ <div
986
+ class="p-12 fm-typo-en-body-md-600 text-fm-color-typo-secondary bg-fm-color-neutral-gray-100"
987
+ >
927
988
  Open / Closed
928
989
  </div>
929
- <div class="p-12 fm-typo-en-body-md-600 text-fm-color-typo-secondary bg-fm-color-neutral-gray-100">
990
+ <div
991
+ class="p-12 fm-typo-en-body-md-600 text-fm-color-typo-secondary bg-fm-color-neutral-gray-100"
992
+ >
930
993
  Reservation Time Range
931
994
  </div>
932
995
  <template v-for="day in [1, 2, 3, 4, 5, 6, 0] as const" :key="day">
@@ -934,40 +997,63 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
934
997
  {{ moment().day(day).format('dddd') }}
935
998
  </div>
936
999
  <template v-if="rangeSetting.operatingHours[day as 0 | 1 | 2 | 3 | 4 | 5 | 6]">
937
- <template v-for="hours in [rangeSetting.operatingHours[day as 0 | 1 | 2 | 3 | 4 | 5 | 6]]"
938
- :key="`hours-${day}`">
1000
+ <template
1001
+ v-for="hours in [rangeSetting.operatingHours[day as 0 | 1 | 2 | 3 | 4 | 5 | 6]]"
1002
+ :key="`hours-${day}`"
1003
+ >
939
1004
  <div class="px-12 py-8">
940
- <FmSwitch label-placement="right" :model-value="hours.enable" @update:model-value="
941
- (v) => {
942
- rangeSetting.operatingHours[day].enable = v
943
- rangeSetting.operatingHours[day].hours = v
944
- ? [
945
- {
946
- start: '00:00',
947
- end: '23:59'
948
- }
949
- ]
950
- : []
951
- }
952
- " :label="hours.enable ? 'Open' : 'Closed'" />
1005
+ <FmSwitch
1006
+ label-placement="right"
1007
+ :model-value="hours.enable"
1008
+ @update:model-value="
1009
+ (v) => {
1010
+ rangeSetting.operatingHours[day].enable = v
1011
+ rangeSetting.operatingHours[day].hours = v
1012
+ ? [
1013
+ {
1014
+ start: '00:00',
1015
+ end: '23:59'
1016
+ }
1017
+ ]
1018
+ : []
1019
+ }
1020
+ "
1021
+ :label="hours.enable ? 'Open' : 'Closed'"
1022
+ />
953
1023
  </div>
954
1024
  <div class="px-12 self-center">
955
1025
  <div v-if="!hours.enable" class="">-</div>
956
1026
  <div v-else class="flex flex-col">
957
1027
  <div v-for="(hour, hi) in hours.hours" :key="hi" class="flex flex-col gap-4">
958
1028
  <div class="flex gap-4 items-center justify-between">
959
- <div class="flex gap-12 items-center flex-1 justify-between py-8">
960
- <CustomTimePicker v-model="hour.start" :min-time="hours.hours[hi - 1]?.end ?? '00:00'"
961
- class="grow" />
1029
+ <div class="flex gap-12 items-center flex-1 justify-start py-8">
1030
+ <CustomTimePicker
1031
+ v-model="hour.start"
1032
+ :min-time="hours.hours[hi - 1]?.end ?? '00:00'"
1033
+ />
962
1034
  <div class="text-center w-16 flex-shrink-0">to</div>
963
- <CustomTimePicker v-model="hour.end" :min-time="hour.start" class="grow" />
1035
+ <CustomTimePicker
1036
+ v-model="hour.end"
1037
+ :min-time="hour.start"
1038
+ :restrict-min-time="false"
1039
+ />
964
1040
  </div>
965
1041
  <div class="mr-8 w-32 flex-shrink">
966
- <FmButton variant="plain" icon="add" v-if="hi == 0" :disabled="hours.hours.length >= 2"
967
- @click="hours.hours.push({ start: hour.end, end: '23:59' })" />
968
- <FmButton variant="plain" icon="delete" v-if="hi > 0" @click="
969
- deleteTimeRange(day as unknown as 0 | 1 | 2 | 3 | 4 | 5 | 6, hi)
970
- " />
1042
+ <FmButton
1043
+ variant="plain"
1044
+ icon="add"
1045
+ v-if="hi == 0"
1046
+ :disabled="hours.hours.length >= 2"
1047
+ @click="hours.hours.push({ start: hour.end, end: '23:59' })"
1048
+ />
1049
+ <FmButton
1050
+ variant="plain"
1051
+ icon="delete"
1052
+ v-if="hi > 0"
1053
+ @click="
1054
+ deleteTimeRange(day as unknown as 0 | 1 | 2 | 3 | 4 | 5 | 6, hi)
1055
+ "
1056
+ />
971
1057
  </div>
972
1058
  </div>
973
1059
  <div v-if="getTimeRangeError(day, hi)" class="text-sm text-red-600 ml-4">
@@ -991,11 +1077,15 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
991
1077
  <FmIcon name="info" outline size="sm" class="cursor-pointer" />
992
1078
  </FmTooltip>
993
1079
  </div>
994
- <FmRadioGroup :model-value="rangeSetting.slotInterval"
995
- @update:model-value="(v: number) => updateSlotInterval(v)">
1080
+ <FmRadioGroup
1081
+ :model-value="rangeSetting.slotInterval"
1082
+ @update:model-value="(v: number) => updateSlotInterval(v)"
1083
+ >
996
1084
  <FmRadio label="15 min" :value="15" />
997
1085
  <FmRadio label="30 min (default)" :value="30">
998
- <template #label>30 min <span class="text-fm-color-typo-secondary">(default)</span></template>
1086
+ <template #label
1087
+ >30 min <span class="text-fm-color-typo-secondary">(default)</span></template
1088
+ >
999
1089
  </FmRadio>
1000
1090
  <FmRadio label="60 min" :value="60" />
1001
1091
  </FmRadioGroup>
@@ -1008,11 +1098,15 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
1008
1098
  <FmIcon name="info" outline size="sm" class="cursor-pointer" />
1009
1099
  </FmTooltip>
1010
1100
  </div>
1011
- <FmRadioGroup :model-value="rangeSetting.bookingDuration"
1012
- @update:model-value="(v: number) => updateBookingDuration(v)">
1101
+ <FmRadioGroup
1102
+ :model-value="rangeSetting.bookingDuration"
1103
+ @update:model-value="(v: number) => updateBookingDuration(v)"
1104
+ >
1013
1105
  <FmRadio label="60 min" :value="60" />
1014
1106
  <FmRadio label="90 min" :value="90">
1015
- <template #label>90 min <span class="text-fm-color-typo-secondary">(default)</span></template>
1107
+ <template #label
1108
+ >90 min <span class="text-fm-color-typo-secondary">(default)</span></template
1109
+ >
1016
1110
  </FmRadio>
1017
1111
 
1018
1112
  <FmRadio label="120 min" :value="120" />
@@ -1023,30 +1117,39 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
1023
1117
  <div class="p-16 flex flex-col gap-16">
1024
1118
  <div class="flex items-center justify-between w-full">
1025
1119
  <div class="fm-typo-en-body-lg-600">Available reservation slots (preview)</div>
1026
- <FmSelect v-model="selectedPreviewDay" :items="[
1027
- { label: 'Monday', value: 1 },
1028
- { label: 'Tuesday', value: 2 },
1029
- { label: 'Wednesday', value: 3 },
1030
- { label: 'Thursday', value: 4 },
1031
- { label: 'Friday', value: 5 },
1032
- { label: 'Saturday', value: 6 },
1033
- { label: 'Sunday', value: 0 }
1034
- ]" />
1120
+ <FmSelect
1121
+ v-model="selectedPreviewDay"
1122
+ :items="[
1123
+ { label: 'Monday', value: 1 },
1124
+ { label: 'Tuesday', value: 2 },
1125
+ { label: 'Wednesday', value: 3 },
1126
+ { label: 'Thursday', value: 4 },
1127
+ { label: 'Friday', value: 5 },
1128
+ { label: 'Saturday', value: 6 },
1129
+ { label: 'Sunday', value: 0 }
1130
+ ]"
1131
+ />
1035
1132
  </div>
1036
1133
 
1037
1134
  <template v-if="availableSlots.morning.length > 0">
1038
1135
  <div class="fm-typo-en-body-md-600 text-[#4B4B4B]">Morning</div>
1039
1136
  <div class="grid grid-cols-5 gap-8">
1040
- <div v-for="slot in displayedSlots.morning" :key="slot.time"
1041
- class="border-1 rounded-md text-center p-8 transition-colors" :class="{
1137
+ <div
1138
+ v-for="slot in displayedSlots.morning"
1139
+ :key="slot.time"
1140
+ class="border-1 rounded-md text-center p-8 transition-colors"
1141
+ :class="{
1042
1142
  'bg-[#fafafa] text-fm-color-typo-primary': slot.available,
1043
1143
  'bg-[#f0f0f0] text-fm-color-typo-disabled border-dashed': !slot.available
1044
- }">
1144
+ }"
1145
+ >
1045
1146
  {{ slot.time }}
1046
1147
  </div>
1047
- <div v-if="hasMoreItems.morning && !expandedSegments.morning"
1148
+ <div
1149
+ v-if="hasMoreItems.morning && !expandedSegments.morning"
1048
1150
  class="border-2 rounded-md text-center p-8 transition-colors cursor-pointer border-fm-color-primary text-fm-color-primary"
1049
- @click="toggleSegmentExpansion('morning')">
1151
+ @click="toggleSegmentExpansion('morning')"
1152
+ >
1050
1153
  more
1051
1154
  </div>
1052
1155
  </div>
@@ -1055,16 +1158,22 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
1055
1158
  <template v-if="availableSlots.afternoon.length > 0">
1056
1159
  <div class="fm-typo-en-body-md-600 text-[#4B4B4B]">Afternoon</div>
1057
1160
  <div class="grid grid-cols-5 gap-8">
1058
- <div v-for="slot in displayedSlots.afternoon" :key="slot.time"
1059
- class="border-1 rounded-md text-center p-8 transition-colors" :class="{
1161
+ <div
1162
+ v-for="slot in displayedSlots.afternoon"
1163
+ :key="slot.time"
1164
+ class="border-1 rounded-md text-center p-8 transition-colors"
1165
+ :class="{
1060
1166
  'bg-[#fafafa] text-fm-color-typo-primary': slot.available,
1061
1167
  'bg-[#f0f0f0] text-fm-color-typo-disabled border-dashed': !slot.available
1062
- }">
1168
+ }"
1169
+ >
1063
1170
  {{ slot.time }}
1064
1171
  </div>
1065
- <div v-if="hasMoreItems.afternoon && !expandedSegments.afternoon"
1172
+ <div
1173
+ v-if="hasMoreItems.afternoon && !expandedSegments.afternoon"
1066
1174
  class="border-2 rounded-md text-center p-8 transition-colors cursor-pointer border-fm-color-primary text-fm-color-primary"
1067
- @click="toggleSegmentExpansion('afternoon')">
1175
+ @click="toggleSegmentExpansion('afternoon')"
1176
+ >
1068
1177
  more
1069
1178
  </div>
1070
1179
  </div>
@@ -1073,27 +1182,37 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
1073
1182
  <template v-if="availableSlots.evening.length > 0">
1074
1183
  <div class="fm-typo-en-body-md-600 text-[#4B4B4B]">Evening</div>
1075
1184
  <div class="grid grid-cols-5 gap-8">
1076
- <div v-for="slot in displayedSlots.evening" :key="slot.time"
1077
- class="border-1 rounded-md text-center p-8 transition-colors" :class="{
1185
+ <div
1186
+ v-for="slot in displayedSlots.evening"
1187
+ :key="slot.time"
1188
+ class="border-1 rounded-md text-center p-8 transition-colors"
1189
+ :class="{
1078
1190
  'bg-[#fafafa] text-fm-color-typo-primary': slot.available,
1079
1191
  'bg-[#f0f0f0] text-fm-color-typo-disabled border-dashed': !slot.available
1080
- }">
1192
+ }"
1193
+ >
1081
1194
  {{ slot.time }}
1082
1195
  </div>
1083
- <div v-if="hasMoreItems.evening && !expandedSegments.evening"
1196
+ <div
1197
+ v-if="hasMoreItems.evening && !expandedSegments.evening"
1084
1198
  class="border-2 rounded-md text-center p-8 transition-colors cursor-pointer border-fm-color-primary text-fm-color-primary"
1085
- @click="toggleSegmentExpansion('evening')">
1199
+ @click="toggleSegmentExpansion('evening')"
1200
+ >
1086
1201
  more
1087
1202
  </div>
1088
1203
  </div>
1089
1204
  </template>
1090
1205
 
1091
- <div v-if="
1092
- !rangeSetting.operatingHours[selectedPreviewDay as 0 | 1 | 2 | 3 | 4 | 5 | 6]
1093
- ?.enable
1094
- " class="text-center text-fm-color-typo-secondary flex flex-col items-center gap-16 p-24">
1206
+ <div
1207
+ v-if="
1208
+ !availableSlots.morning.length &&
1209
+ !availableSlots.afternoon.length &&
1210
+ !availableSlots.evening.length
1211
+ "
1212
+ class="text-center text-fm-color-typo-secondary flex flex-col items-center gap-16 p-24"
1213
+ >
1095
1214
  <img :src="notfound" class="aspect-square w-[150px]" />
1096
- Uh-oh! This outlet is closed on the selected day. <br>
1215
+ Uh-oh! This outlet is closed on the selected day. <br />
1097
1216
  Please select another day to view available time slots.
1098
1217
  </div>
1099
1218
  </div>
@@ -1101,11 +1220,10 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
1101
1220
  </div>
1102
1221
 
1103
1222
  <div class="flex flex-col">
1104
- <div class="flex-grow fm-typo-en-title-sm-600 mb-4">
1105
- Table Capacity Settings
1106
- </div>
1223
+ <div class="flex-grow fm-typo-en-title-sm-600 mb-4">Table Capacity Settings</div>
1107
1224
  <div class="fm-typo-en-body-lg-400 text-fm-color-typo-secondary mb-24">
1108
- Set how many tables are available for reservation per time slot. You can reduce availability to keep tables for walk-ins.
1225
+ Set how many tables are available for reservation per time slot. You can reduce
1226
+ availability to keep tables for walk-ins.
1109
1227
  </div>
1110
1228
 
1111
1229
  <!-- Table Capacity Settings -->
@@ -1121,44 +1239,74 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
1121
1239
  </div>
1122
1240
  <div class="bg-fm-color-neutral-gray-100 p-12"></div>
1123
1241
  </div>
1124
- <div class="grid grid-cols-[4fr_4fr_4fr_1fr] items-center gap-8" v-for="tier in rangeSetting.capacityTiers"
1125
- :key="tier._id">
1242
+ <div
1243
+ class="grid grid-cols-[4fr_4fr_4fr_1fr] items-center gap-8"
1244
+ v-for="tier in rangeSetting.capacityTiers"
1245
+ :key="tier._id"
1246
+ >
1126
1247
  <div class="p-8">{{ tier.minPax }}{{ tier.maxPax ? `-${tier.maxPax}` : '+' }} pax</div>
1127
- <div class="flex items-center gap-4">
1248
+ <div class="flex items-center gap-4 pr-24">
1128
1249
  <FmStepperField v-model="tier.minPax" :min="1" />
1129
1250
  <div>to</div>
1130
- <FmStepperField :model-value="tier.maxPax ?? null" @update:model-value="(v) => (tier.maxPax = v)" :min="tier.minPax" />
1251
+ <FmStepperField
1252
+ :model-value="tier.maxPax ?? null"
1253
+ @update:model-value="(v) => (tier.maxPax = v)"
1254
+ :min="tier.minPax"
1255
+ />
1131
1256
  </div>
1132
1257
  <div class="flex items-center gap-8">
1133
- <FmButton variant="tertiary" icon="remove" @click="tier.capacity--" :disabled="tier.capacity <= 1" class="!rounded-full !w-10 !h-10 !bg-fm-color-neutral-gray-100" />
1258
+ <FmButton
1259
+ variant="tertiary"
1260
+ icon="remove"
1261
+ @click="tier.capacity--"
1262
+ :disabled="tier.capacity <= 1"
1263
+ class="!rounded-full !w-10 !h-10 !bg-fm-color-neutral-gray-100"
1264
+ />
1134
1265
  <div class="w-32 text-center">{{ tier.capacity }}</div>
1135
- <FmButton variant="tertiary" icon="add" @click="tier.capacity++" class="!rounded-full !w-10 !h-10 !bg-fm-color-neutral-gray-100" />
1266
+ <FmButton
1267
+ variant="tertiary"
1268
+ icon="add"
1269
+ @click="tier.capacity++"
1270
+ class="!rounded-full !w-10 !h-10 !bg-fm-color-neutral-gray-100"
1271
+ />
1136
1272
 
1137
1273
  <!-- <FmStepperField :model-value="tier.capacity ?? null" @update:model-value="(v) => (tier.capacity = v)" /> -->
1138
1274
  </div>
1139
- <FmButton icon="delete" variant="plain" @click="
1140
- rangeSetting.capacityTiers.splice(rangeSetting.capacityTiers.indexOf(tier), 1)
1141
- " />
1275
+ <FmButton
1276
+ icon="delete"
1277
+ variant="plain"
1278
+ @click="
1279
+ rangeSetting.capacityTiers.splice(rangeSetting.capacityTiers.indexOf(tier), 1)
1280
+ "
1281
+ />
1142
1282
  </div>
1143
1283
  <div>
1144
- <FmButton label="Add table type" icon="add" variant="plain" @click="
1145
- rangeSetting.capacityTiers.push({
1146
- _id: generateCapacityTierId(),
1147
- minPax: Math.max(1, ([...rangeSetting.capacityTiers].pop()?.maxPax ?? 0) + 1),
1148
- maxPax: null,
1149
- capacity: 0
1150
- })
1151
- " />
1284
+ <FmButton
1285
+ label="Add table type"
1286
+ icon="add"
1287
+ variant="plain"
1288
+ @click="
1289
+ rangeSetting.capacityTiers.push({
1290
+ _id: generateCapacityTierId(),
1291
+ minPax: Math.max(1, ([...rangeSetting.capacityTiers].pop()?.maxPax ?? 0) + 1),
1292
+ maxPax: null,
1293
+ capacity: 0
1294
+ })
1295
+ "
1296
+ />
1152
1297
  </div>
1153
1298
  </div>
1154
1299
  </div>
1155
1300
 
1156
1301
  <div>
1157
1302
  <div class="flex-grow fm-typo-en-title-sm-600 mb-16">Preorder</div>
1158
- <FmSwitch label-placement="right" :label="'Enable preorder'"
1303
+ <FmSwitch
1304
+ label-placement="right"
1305
+ :label="'Enable preorder'"
1159
1306
  :sublabel="'Enable this to allow guests to place preorders when making a reservation. This allows them to order food in advance.'"
1160
1307
  :model-value="rangeSetting.enablePreorder"
1161
- @update:model-value="(v: boolean) => (rangeSetting.enablePreorder = v)" />
1308
+ @update:model-value="(v: boolean) => (rangeSetting.enablePreorder = v)"
1309
+ />
1162
1310
  </div>
1163
1311
 
1164
1312
  <div class="flex flex-col">
@@ -1168,8 +1316,12 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
1168
1316
  allergies, or other notes.
1169
1317
  </div>
1170
1318
 
1171
- <FmSwitch class="mb-8" label="Enable preferences" label-placement="right"
1172
- :model-value="rangeSetting.preferences.length > 0" @update:model-value="
1319
+ <FmSwitch
1320
+ class="mb-8"
1321
+ label="Enable preferences"
1322
+ label-placement="right"
1323
+ :model-value="rangeSetting.preferences.length > 0"
1324
+ @update:model-value="
1173
1325
  (v) => {
1174
1326
  if (v == true) {
1175
1327
  rangeSetting.preferences = [
@@ -1183,10 +1335,15 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
1183
1335
  rangeSetting.preferences = []
1184
1336
  }
1185
1337
  }
1186
- " />
1187
-
1188
- <FmCard v-for="(preference, pIndex) in rangeSetting.preferences" class="p-16 mb-12" variant="outlined"
1189
- :key="pIndex">
1338
+ "
1339
+ />
1340
+
1341
+ <FmCard
1342
+ v-for="(preference, pIndex) in rangeSetting.preferences"
1343
+ class="p-16 mb-12"
1344
+ variant="outlined"
1345
+ :key="pIndex"
1346
+ >
1190
1347
  <div class="fm-typo-en-body-lg-600 mb-8">Category title</div>
1191
1348
  <div class="grid grid-cols-[6fr_3fr_1fr] items-start gap-24 mb-24">
1192
1349
  <div>
@@ -1195,66 +1352,125 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
1195
1352
  This title will be shown to guests during reservation.
1196
1353
  </div>
1197
1354
  </div>
1198
- <CustomSelect v-model="preference.type" :items="[
1199
- { label: 'Single choice', value: 'radio', icon: 'radio' },
1200
- { label: 'Multiple choice', value: 'checkbox', icon: 'checkbox' }
1201
- ]" />
1355
+ <CustomSelect
1356
+ v-model="preference.type"
1357
+ :items="[
1358
+ { label: 'Single choice', value: 'radio', icon: 'radio' },
1359
+ { label: 'Multiple choice', value: 'checkbox', icon: 'checkbox' }
1360
+ ]"
1361
+ />
1202
1362
  <FmButton variant="tertiary" icon="delete" @click="removePreference(pIndex)" />
1203
1363
  </div>
1204
1364
 
1205
1365
  <div v-if="preference.type == 'checkbox' || preference.type == 'radio'">
1206
1366
  <div class="mb-8 fm-typo-en-body-md-600">Options</div>
1207
- <div v-for="(option, oIndex) in preference.options" :key="oIndex"
1208
- class="flex items-center gap-4 gap-y-8 mb-8">
1367
+ <div
1368
+ v-for="(option, oIndex) in preference.options"
1369
+ :key="oIndex"
1370
+ class="flex items-center gap-4 gap-y-8 mb-8"
1371
+ >
1209
1372
  <div class="flex items-center w-full">
1210
- <FmCheckbox v-if="preference.type == 'checkbox'" disabled :value="option" :model-value="false" readonly
1211
- class="mr-8" />
1212
- <FmRadio v-if="preference.type == 'radio'" disabled :value="option" :model-value="false" readonly />
1373
+ <FmCheckbox
1374
+ v-if="preference.type == 'checkbox'"
1375
+ disabled
1376
+ :value="option"
1377
+ :model-value="false"
1378
+ readonly
1379
+ class="mr-8"
1380
+ />
1381
+ <FmRadio
1382
+ v-if="preference.type == 'radio'"
1383
+ disabled
1384
+ :value="option"
1385
+ :model-value="false"
1386
+ readonly
1387
+ />
1213
1388
 
1214
1389
  <!-- Editable option label -->
1215
- <input v-if="isEditingOption(pIndex, oIndex)" type="text"
1216
- class="flex-1 outline-none border-b-2 border-fm-color-primary px-4 py-2" :value="option" @blur="
1390
+ <input
1391
+ v-if="isEditingOption(pIndex, oIndex)"
1392
+ type="text"
1393
+ class="flex-1 outline-none border-b-2 border-fm-color-primary px-4 py-2"
1394
+ :value="option"
1395
+ @blur="
1217
1396
  (e) => saveOptionEdit(pIndex, oIndex, (e.target as HTMLInputElement).value)
1218
- " @keyup.enter="
1397
+ "
1398
+ @keyup.enter="
1219
1399
  (e) => saveOptionEdit(pIndex, oIndex, (e.target as HTMLInputElement).value)
1220
- " ref="optionInput" />
1221
- <div v-else-if="option != 'Other'"
1400
+ "
1401
+ ref="optionInput"
1402
+ />
1403
+ <div
1404
+ v-else-if="option != 'Other'"
1222
1405
  class="flex-1 cursor-pointer hover:bg-fm-color-neutral-gray-100 px-4 py-2 rounded transition-colors"
1223
- @click="startEditingOption(pIndex, oIndex)" title="Click to edit">
1406
+ @click="startEditingOption(pIndex, oIndex)"
1407
+ title="Click to edit"
1408
+ >
1224
1409
  {{ option }}
1225
1410
  </div>
1226
- <div v-else-if="option == 'Other'" class="flex-1 px-4 py-2 border-b border-fm-color-neutral-gray-200">
1411
+ <div
1412
+ v-else-if="option == 'Other'"
1413
+ class="flex-1 px-4 py-2 border-b border-fm-color-neutral-gray-200"
1414
+ >
1227
1415
  Other:
1228
1416
  </div>
1229
1417
  </div>
1230
- <FmButton variant="plain" icon="close" :class="{ 'opacity-0 pointer-events-nonex': oIndex == 0 }"
1231
- @click="oIndex != 0 && removePreferenceOption(preference, option)" />
1418
+ <FmButton
1419
+ variant="plain"
1420
+ icon="close"
1421
+ :class="{ 'opacity-0 pointer-events-nonex': oIndex == 0 }"
1422
+ @click="oIndex != 0 && removePreferenceOption(preference, option)"
1423
+ />
1232
1424
  </div>
1233
1425
  <div class="flex items-center">
1234
- <FmCheckbox v-if="preference.type == 'checkbox'" disabled :value="null" :model-value="false" readonly />
1426
+ <FmCheckbox
1427
+ v-if="preference.type == 'checkbox'"
1428
+ disabled
1429
+ :value="null"
1430
+ :model-value="false"
1431
+ readonly
1432
+ />
1235
1433
  <div v-if="preference.type == 'radio'" class="flex items-center">
1236
1434
  <FmRadio disabled :value="null" :model-value="false" readonly />
1237
1435
  </div>
1238
1436
  <div class="flex items-center w-full">
1239
- <FmButton variant="tertiary" class="text-fm-color-typo-secondary" label="add option" @click="
1240
- addPreferenceOption(preference, `Option ${preference.options.length + 1}`)
1241
- ">
1437
+ <FmButton
1438
+ variant="tertiary"
1439
+ class="text-fm-color-typo-secondary"
1440
+ label="add option"
1441
+ @click="
1442
+ addPreferenceOption(preference, `Option ${preference.options.length + 1}`)
1443
+ "
1444
+ >
1242
1445
  <template #default>
1243
1446
  <div>Add option</div>
1244
1447
  </template>
1245
1448
  </FmButton>
1246
1449
  <template v-if="!preference.options.includes('Other')">
1247
1450
  <div>or</div>
1248
- <FmButton variant="plain" label='add "Other"' @click="addPreferenceOption(preference, 'Other')" />
1451
+ <FmButton
1452
+ variant="plain"
1453
+ label='add "Other"'
1454
+ @click="addPreferenceOption(preference, 'Other')"
1455
+ />
1249
1456
  </template>
1250
1457
  </div>
1251
1458
  </div>
1252
1459
  </div>
1253
1460
  </FmCard>
1254
1461
 
1255
- <FmCard variant="outlined" class="border-dashed p-16" v-if="rangeSetting.preferences.length">
1256
- <FmButton label="Add another preference category" icon="add" variant="plain"
1257
- class="border-1 border-fm-color-primary rounded-lg" @click="addPreference" />
1462
+ <FmCard
1463
+ variant="outlined"
1464
+ class="border-dashed p-16"
1465
+ v-if="rangeSetting.preferences.length"
1466
+ >
1467
+ <FmButton
1468
+ label="Add another preference category"
1469
+ icon="add"
1470
+ variant="plain"
1471
+ class="border-1 border-fm-color-primary rounded-lg"
1472
+ @click="addPreference"
1473
+ />
1258
1474
  </FmCard>
1259
1475
  </div>
1260
1476
 
@@ -1264,14 +1480,24 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
1264
1480
  Add important information or notes guests should know before their visit.
1265
1481
  </div>
1266
1482
 
1267
- <FmSwitch class="mb-16" label="Enable guest message" label-placement="right" :model-value="rangeSetting.guestMessage !== null && rangeSetting.guestMessage !== undefined
1268
- " @update:model-value="toggleGuestMessage" />
1483
+ <FmSwitch
1484
+ class="mb-16"
1485
+ label="Enable guest message"
1486
+ label-placement="right"
1487
+ :model-value="
1488
+ rangeSetting.guestMessage !== null && rangeSetting.guestMessage !== undefined
1489
+ "
1490
+ @update:model-value="toggleGuestMessage"
1491
+ />
1269
1492
 
1270
1493
  <div v-if="rangeSetting.guestMessage !== null && rangeSetting.guestMessage !== undefined">
1271
1494
  <div class="mb-8 fm-typo-en-body-md-600">Message</div>
1272
- <FmTextarea v-model="rangeSetting.guestMessage" :maxLength="600"
1495
+ <FmTextarea
1496
+ v-model="rangeSetting.guestMessage"
1497
+ :maxLength="600"
1273
1498
  placeholder="Please take note of the following important details before making a reservation:"
1274
- class="mb-4" />
1499
+ class="mb-4"
1500
+ />
1275
1501
  <div class="text-right text-fm-color-typo-tertiary fm-typo-en-body-sm-400">
1276
1502
  {{ rangeSetting.guestMessage?.length || 0 }} / 600 characters
1277
1503
  </div>
@@ -1284,17 +1510,30 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
1284
1510
  Set the rules guests should follow when cancelling a reservation.
1285
1511
  </div>
1286
1512
 
1287
- <FmSwitch class="mb-16" label="Enable cancellation policy" label-placement="right" :model-value="rangeSetting.cancellationPolicy !== null &&
1288
- rangeSetting.cancellationPolicy !== undefined
1289
- " @update:model-value="toggleCancellationPolicy" />
1290
-
1291
- <div v-if="
1292
- rangeSetting.cancellationPolicy !== null &&
1293
- rangeSetting.cancellationPolicy !== undefined
1294
- ">
1513
+ <FmSwitch
1514
+ class="mb-16"
1515
+ label="Enable cancellation policy"
1516
+ label-placement="right"
1517
+ :model-value="
1518
+ rangeSetting.cancellationPolicy !== null &&
1519
+ rangeSetting.cancellationPolicy !== undefined
1520
+ "
1521
+ @update:model-value="toggleCancellationPolicy"
1522
+ />
1523
+
1524
+ <div
1525
+ v-if="
1526
+ rangeSetting.cancellationPolicy !== null &&
1527
+ rangeSetting.cancellationPolicy !== undefined
1528
+ "
1529
+ >
1295
1530
  <div class="mb-8 fm-typo-en-body-md-600">Message</div>
1296
- <FmTextarea v-model="rangeSetting.cancellationPolicy" :maxLength="200" placeholder="Cancellation Policy"
1297
- class="mb-4" />
1531
+ <FmTextarea
1532
+ v-model="rangeSetting.cancellationPolicy"
1533
+ :maxLength="200"
1534
+ placeholder="Cancellation Policy"
1535
+ class="mb-4"
1536
+ />
1298
1537
  <div class="text-right text-fm-color-typo-tertiary fm-typo-en-body-sm-400">
1299
1538
  {{ rangeSetting.cancellationPolicy?.length || 0 }} / 200 characters
1300
1539
  </div>
@@ -1304,8 +1543,13 @@ function handleCopySettings(copiedSettings: Partial<FdoOrderReservationSettingsV
1304
1543
 
1305
1544
  <!-- Save Button -->
1306
1545
  <div class="flex mt-5">
1307
- <FmButton variant="primary" :label="t('order.saveAllChanges')" class="mr-auto" @click="updateReservationSetting"
1308
- :loading="isSaving" />
1546
+ <FmButton
1547
+ variant="primary"
1548
+ :label="t('order.saveAllChanges')"
1549
+ class="mr-auto"
1550
+ @click="updateReservationSetting"
1551
+ :loading="isSaving"
1552
+ />
1309
1553
  </div>
1310
1554
  </div>
1311
1555
  </template>