pukaad-ui-lib 1.370.0 → 1.372.0
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/module.json +1 -1
- package/dist/runtime/components/card/card-opening-hours.d.vue.ts +16 -0
- package/dist/runtime/components/card/card-opening-hours.vue +90 -0
- package/dist/runtime/components/card/card-opening-hours.vue.d.ts +16 -0
- package/dist/runtime/components/card/card-place-detail.vue +28 -85
- package/dist/runtime/components/card/card-profile-header.d.vue.ts +1 -1
- package/dist/runtime/components/card/card-profile-header.vue.d.ts +1 -1
- package/dist/runtime/components/card/card-reaction.d.vue.ts +1 -1
- package/dist/runtime/components/card/card-reaction.vue.d.ts +1 -1
- package/dist/runtime/components/card/card-review.d.vue.ts +5 -5
- package/dist/runtime/components/card/card-review.vue.d.ts +5 -5
- package/dist/runtime/components/display/display-image-place.d.vue.ts +1 -1
- package/dist/runtime/components/display/display-image-place.vue.d.ts +1 -1
- package/dist/runtime/components/drawer/drawer-profile-network.d.vue.ts +1 -1
- package/dist/runtime/components/drawer/drawer-profile-network.vue.d.ts +1 -1
- package/dist/runtime/components/input/input-autocomplete.d.vue.ts +1 -1
- package/dist/runtime/components/input/input-autocomplete.vue.d.ts +1 -1
- package/dist/runtime/components/input/input-file.d.vue.ts +1 -1
- package/dist/runtime/components/input/input-file.vue.d.ts +1 -1
- package/dist/runtime/components/input/input-localized-name.d.vue.ts +1 -1
- package/dist/runtime/components/input/input-localized-name.vue.d.ts +1 -1
- package/dist/runtime/components/input/input-tag.d.vue.ts +1 -1
- package/dist/runtime/components/input/input-tag.vue.d.ts +1 -1
- package/dist/runtime/components/input/input-typed-field.d.vue.ts +1 -1
- package/dist/runtime/components/input/input-typed-field.vue.d.ts +1 -1
- package/dist/runtime/components/modal/modal-media-view.d.vue.ts +1 -1
- package/dist/runtime/components/modal/modal-media-view.vue.d.ts +1 -1
- package/dist/runtime/components/modal/suggest-edit-place/modal-suggest-edit-place.vue +154 -69
- package/dist/runtime/components/modal/suggest-edit-place/place-dateopening.vue +5 -78
- package/dist/runtime/components/timeline.d.vue.ts +14 -0
- package/dist/runtime/components/timeline.vue +29 -10
- package/dist/runtime/components/timeline.vue.d.ts +14 -0
- package/dist/runtime/utils/opening-hours.d.ts +21 -0
- package/dist/runtime/utils/opening-hours.js +20 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OpeningHour, SpecialDay } from "#pukaad-ui/runtime/utils/opening-hours";
|
|
2
|
+
export type { OpeningHour, SpecialDay, TimeSlot, } from "#pukaad-ui/runtime/utils/opening-hours";
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
items?: OpeningHour[];
|
|
5
|
+
specialDays?: SpecialDay[];
|
|
6
|
+
openStatus?: string;
|
|
7
|
+
filterUpcomingSpecialDays?: boolean;
|
|
8
|
+
};
|
|
9
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
10
|
+
items: OpeningHour[];
|
|
11
|
+
specialDays: SpecialDay[];
|
|
12
|
+
openStatus: string;
|
|
13
|
+
filterUpcomingSpecialDays: boolean;
|
|
14
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
+
declare const _default: typeof __VLS_export;
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="font-body-large flex flex-col gap-[4px] w-full">
|
|
3
|
+
<!-- สถานะปิดชั่วคราว -->
|
|
4
|
+
<div
|
|
5
|
+
v-if="props.openStatus === 'temporarily_closed'"
|
|
6
|
+
class="font-body-large-prominent text-error"
|
|
7
|
+
>
|
|
8
|
+
ปิดชั่วคราว
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<!-- เวลาทำการปกติ -->
|
|
12
|
+
<div
|
|
13
|
+
v-for="(line, index) in lines"
|
|
14
|
+
:key="index"
|
|
15
|
+
class="flex items-start justify-between"
|
|
16
|
+
>
|
|
17
|
+
<span>{{ line.day }}</span>
|
|
18
|
+
<div class="flex flex-col items-end">
|
|
19
|
+
<span v-for="(time, timeIndex) in line.time_lines" :key="timeIndex">
|
|
20
|
+
{{ time }}
|
|
21
|
+
</span>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<!-- วันทำการพิเศษ -->
|
|
26
|
+
<template v-if="formattedSpecialDays.length">
|
|
27
|
+
<div class="font-body-large-prominent text-warning">วันทำการพิเศษ</div>
|
|
28
|
+
<div
|
|
29
|
+
v-for="(special, index) in formattedSpecialDays"
|
|
30
|
+
:key="index"
|
|
31
|
+
class="flex items-start justify-between text-warning"
|
|
32
|
+
>
|
|
33
|
+
<span>{{ special.date_label }}</span>
|
|
34
|
+
<div class="flex flex-col items-end">
|
|
35
|
+
<span
|
|
36
|
+
v-for="(time, timeIndex) in special.time_lines"
|
|
37
|
+
:key="timeIndex"
|
|
38
|
+
>
|
|
39
|
+
{{ time }}
|
|
40
|
+
</span>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<div
|
|
46
|
+
v-if="
|
|
47
|
+
!lines.length && !formattedSpecialDays.length && props.openStatus !== 'temporarily_closed'
|
|
48
|
+
"
|
|
49
|
+
class="text-cloud"
|
|
50
|
+
>
|
|
51
|
+
ไม่มีข้อมูลเวลาทำการ
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<script setup>
|
|
57
|
+
import { computed } from "vue";
|
|
58
|
+
import dayjs from "#pukaad-ui/runtime/utils/dayjs";
|
|
59
|
+
import { useConvert } from "#pukaad-ui/runtime/composables/useConvert";
|
|
60
|
+
import {
|
|
61
|
+
toDayLines,
|
|
62
|
+
getTimeLines
|
|
63
|
+
} from "#pukaad-ui/runtime/utils/opening-hours";
|
|
64
|
+
const props = defineProps({
|
|
65
|
+
items: { type: Array, required: false, default: () => [] },
|
|
66
|
+
specialDays: { type: Array, required: false, default: () => [] },
|
|
67
|
+
openStatus: { type: String, required: false, default: void 0 },
|
|
68
|
+
filterUpcomingSpecialDays: { type: Boolean, required: false, default: true }
|
|
69
|
+
});
|
|
70
|
+
const { convertDate } = useConvert();
|
|
71
|
+
const toArray = (value) => Array.isArray(value) ? value : [];
|
|
72
|
+
const lines = computed(() => toDayLines(props.items));
|
|
73
|
+
const sortedSpecialDays = computed(() => {
|
|
74
|
+
const allSpecial = toArray(props.specialDays).filter(
|
|
75
|
+
(s) => !!s?.date
|
|
76
|
+
);
|
|
77
|
+
if (!props.filterUpcomingSpecialDays) return allSpecial;
|
|
78
|
+
const today = dayjs().startOf("day");
|
|
79
|
+
const maxDate = today.add(30, "day").endOf("day");
|
|
80
|
+
return allSpecial.map((s) => ({ ...s, parsedDate: dayjs(s.date) })).filter((s) => s.parsedDate.isValid()).filter(
|
|
81
|
+
(s) => !s.parsedDate.isBefore(today) && !s.parsedDate.isAfter(maxDate)
|
|
82
|
+
).sort((a, b) => a.parsedDate.valueOf() - b.parsedDate.valueOf());
|
|
83
|
+
});
|
|
84
|
+
const formattedSpecialDays = computed(
|
|
85
|
+
() => sortedSpecialDays.value.map((s) => ({
|
|
86
|
+
date_label: convertDate(s.date),
|
|
87
|
+
time_lines: getTimeLines(s.isOpen, s.timeSlots)
|
|
88
|
+
}))
|
|
89
|
+
);
|
|
90
|
+
</script>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OpeningHour, SpecialDay } from "#pukaad-ui/runtime/utils/opening-hours";
|
|
2
|
+
export type { OpeningHour, SpecialDay, TimeSlot, } from "#pukaad-ui/runtime/utils/opening-hours";
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
items?: OpeningHour[];
|
|
5
|
+
specialDays?: SpecialDay[];
|
|
6
|
+
openStatus?: string;
|
|
7
|
+
filterUpcomingSpecialDays?: boolean;
|
|
8
|
+
};
|
|
9
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
10
|
+
items: OpeningHour[];
|
|
11
|
+
specialDays: SpecialDay[];
|
|
12
|
+
openStatus: string;
|
|
13
|
+
filterUpcomingSpecialDays: boolean;
|
|
14
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
+
declare const _default: typeof __VLS_export;
|
|
16
|
+
export default _default;
|
|
@@ -30,50 +30,13 @@
|
|
|
30
30
|
props.item.open_status === 'temporarily_closed' ? 'text-destructive' : 'text-primary '
|
|
31
31
|
]"
|
|
32
32
|
/>
|
|
33
|
-
<div
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
</div>
|
|
40
|
-
<div
|
|
41
|
-
v-for="(hour, index) in businessHours"
|
|
42
|
-
:key="index"
|
|
43
|
-
class="flex items-start justify-between"
|
|
44
|
-
>
|
|
45
|
-
<span>{{ hour.day }}</span>
|
|
46
|
-
<div class="flex flex-col items-end">
|
|
47
|
-
<span v-for="(line, li) in hour.time_lines" :key="li">{{
|
|
48
|
-
line
|
|
49
|
-
}}</span>
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
|
|
53
|
-
<template v-if="upcomingSpecialDays.length">
|
|
54
|
-
<div class="font-body-large-prominent text-warning">
|
|
55
|
-
วันทำการพิเศษ
|
|
56
|
-
</div>
|
|
57
|
-
<div
|
|
58
|
-
v-for="(special, index) in upcomingSpecialDays"
|
|
59
|
-
:key="index"
|
|
60
|
-
class="flex items-start justify-between text-warning"
|
|
61
|
-
>
|
|
62
|
-
<span>{{ special.date_label }}</span>
|
|
63
|
-
<div class="flex flex-col items-end">
|
|
64
|
-
<span v-for="(line, li) in special.time_lines" :key="li">{{
|
|
65
|
-
line
|
|
66
|
-
}}</span>
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
</template>
|
|
70
|
-
</div>
|
|
71
|
-
<div v-else-if="props.item.open_status === 'temporarily_closed'">
|
|
72
|
-
<div class="font-body-large-prominent text-destructive">
|
|
73
|
-
ปิดชั่วคราว
|
|
74
|
-
</div>
|
|
33
|
+
<div class="flex-1 min-w-0">
|
|
34
|
+
<CardOpeningHours
|
|
35
|
+
:items="props.item.opening_hours"
|
|
36
|
+
:special-days="props.item.special_days"
|
|
37
|
+
:open-status="props.item.open_status"
|
|
38
|
+
/>
|
|
75
39
|
</div>
|
|
76
|
-
<div v-else class="text-cloud">ไม่มีข้อมูลเวลาทำการ</div>
|
|
77
40
|
</div>
|
|
78
41
|
|
|
79
42
|
<div class="flex gap-[12px]">
|
|
@@ -85,25 +48,27 @@
|
|
|
85
48
|
<div v-if="props.item.phone">{{ props.item.phone }}</div>
|
|
86
49
|
<div v-else class="text-cloud">ไม่มีข้อมูลเบอร์โทรศัพท์</div>
|
|
87
50
|
</div>
|
|
88
|
-
<
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
51
|
+
<template v-if="!props.item.owner_profile_id">
|
|
52
|
+
<div class="flex gap-[12px]">
|
|
53
|
+
<Icon
|
|
54
|
+
name="lucide:shield-check"
|
|
55
|
+
:size="20"
|
|
56
|
+
class="text-primary shrink-0 mt-[2px]"
|
|
57
|
+
/>
|
|
58
|
+
<div class="font-body-large">หากคุณเป็นเจ้าของธุรกิจนี้</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div
|
|
61
|
+
class="flex gap-[12px] hover:cursor-pointer"
|
|
62
|
+
@click="isOpenModalSuggestEdit = true"
|
|
63
|
+
>
|
|
64
|
+
<Icon
|
|
65
|
+
name="lucide:square-pen"
|
|
66
|
+
:size="20"
|
|
67
|
+
class="text-primary shrink-0 mt-[2px]"
|
|
68
|
+
/>
|
|
69
|
+
<div class="font-body-large">แนะนำให้แก้ไข</div>
|
|
70
|
+
</div>
|
|
71
|
+
</template>
|
|
107
72
|
<Divider />
|
|
108
73
|
|
|
109
74
|
<div v-if="socialLinks.length" class="flex flex-col gap-[8px]">
|
|
@@ -127,6 +92,7 @@
|
|
|
127
92
|
</div>
|
|
128
93
|
</div>
|
|
129
94
|
<ModalSuggestEditPlace
|
|
95
|
+
v-if="!props.item.owner_profile_id"
|
|
130
96
|
v-model="isOpenModalSuggestEdit"
|
|
131
97
|
:item="props.item"
|
|
132
98
|
/>
|
|
@@ -153,35 +119,12 @@ const toArray = (value) => Array.isArray(value) ? value : [];
|
|
|
153
119
|
const categoryText = computed(
|
|
154
120
|
() => props.item.categories?.map((c) => c.category_name).join(", ") ?? ""
|
|
155
121
|
);
|
|
156
|
-
const getTimeLines = (isOpen, timeSlots, isAllDay) => {
|
|
157
|
-
if (!isOpen) return ["\u0E2B\u0E22\u0E38\u0E14\u0E17\u0E33\u0E01\u0E32\u0E23"];
|
|
158
|
-
const slots = toArray(timeSlots);
|
|
159
|
-
if (isAllDay || slots.length === 0) return ["\u0E40\u0E1B\u0E34\u0E14\u0E15\u0E25\u0E2D\u0E14 24 \u0E0A\u0E21."];
|
|
160
|
-
return slots.map((t) => `${t.start} - ${t.end} \u0E19.`);
|
|
161
|
-
};
|
|
162
|
-
const businessHours = computed(
|
|
163
|
-
() => toArray(props.item.opening_hours).filter((h) => !!h).map((h) => ({
|
|
164
|
-
day: DAY_NAMES[h.day] ?? "",
|
|
165
|
-
time_lines: getTimeLines(h.isOpen, h.timeSlots, h.isAllDay)
|
|
166
|
-
}))
|
|
167
|
-
);
|
|
168
122
|
const socialLinks = computed(
|
|
169
123
|
() => toArray(props.item.contact_channels).filter((ch) => ch?.value).map((ch) => ({
|
|
170
124
|
name: ch.channel_type ?? "link",
|
|
171
125
|
link: ch.value
|
|
172
126
|
}))
|
|
173
127
|
);
|
|
174
|
-
const sortedSpecialDays = computed(() => {
|
|
175
|
-
const today = dayjs().startOf("day");
|
|
176
|
-
const maxDate = today.add(30, "day").endOf("day");
|
|
177
|
-
return toArray(props.item.special_days).filter((s) => !!s?.date).map((s) => ({ ...s, date: dayjs(s.date) })).filter((s) => s.date.isValid()).filter((s) => !s.date.isBefore(today) && !s.date.isAfter(maxDate)).sort((a, b) => a.date.valueOf() - b.date.valueOf());
|
|
178
|
-
});
|
|
179
|
-
const upcomingSpecialDays = computed(
|
|
180
|
-
() => sortedSpecialDays.value.map((s) => ({
|
|
181
|
-
date_label: s.date.locale("th").format("D MMMM BBBB"),
|
|
182
|
-
time_lines: getTimeLines(s.isOpen, s.timeSlots)
|
|
183
|
-
}))
|
|
184
|
-
);
|
|
185
128
|
const onClickLink = (link) => {
|
|
186
129
|
window.open(link, "_blank");
|
|
187
130
|
};
|
|
@@ -7,9 +7,9 @@ declare const __VLS_export: import("vue").DefineComponent<CardProfileAboutProps,
|
|
|
7
7
|
onChat?: (() => any) | undefined;
|
|
8
8
|
}>, {
|
|
9
9
|
type: "article" | "media" | "sale-info";
|
|
10
|
+
preview: boolean;
|
|
10
11
|
optionMenuButtonType: "solid" | "text";
|
|
11
12
|
actionsHidden: boolean;
|
|
12
|
-
preview: boolean;
|
|
13
13
|
disabledPadding: boolean;
|
|
14
14
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
15
|
declare const _default: typeof __VLS_export;
|
|
@@ -7,9 +7,9 @@ declare const __VLS_export: import("vue").DefineComponent<CardProfileAboutProps,
|
|
|
7
7
|
onChat?: (() => any) | undefined;
|
|
8
8
|
}>, {
|
|
9
9
|
type: "article" | "media" | "sale-info";
|
|
10
|
+
preview: boolean;
|
|
10
11
|
optionMenuButtonType: "solid" | "text";
|
|
11
12
|
actionsHidden: boolean;
|
|
12
|
-
preview: boolean;
|
|
13
13
|
disabledPadding: boolean;
|
|
14
14
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
15
|
declare const _default: typeof __VLS_export;
|
|
@@ -24,8 +24,8 @@ type __VLS_Props = {
|
|
|
24
24
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
25
25
|
disabled: boolean;
|
|
26
26
|
id: string;
|
|
27
|
-
disabledPadding: boolean;
|
|
28
27
|
state: string;
|
|
28
|
+
disabledPadding: boolean;
|
|
29
29
|
itemCount: Count;
|
|
30
30
|
itemActive: Reacted;
|
|
31
31
|
padding: string | number;
|
|
@@ -24,8 +24,8 @@ type __VLS_Props = {
|
|
|
24
24
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
25
25
|
disabled: boolean;
|
|
26
26
|
id: string;
|
|
27
|
-
disabledPadding: boolean;
|
|
28
27
|
state: string;
|
|
28
|
+
disabledPadding: boolean;
|
|
29
29
|
itemCount: Count;
|
|
30
30
|
itemActive: Reacted;
|
|
31
31
|
padding: string | number;
|
|
@@ -36,17 +36,17 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
36
36
|
"onReply-delete"?: ((item: CardReviewProps) => any) | undefined;
|
|
37
37
|
}>, {
|
|
38
38
|
item: CardReviewProps;
|
|
39
|
-
disabledMenu: boolean;
|
|
40
|
-
isProfile: boolean;
|
|
41
|
-
disabledLike: boolean;
|
|
42
|
-
allowReply: boolean;
|
|
43
|
-
replyAvatar: string;
|
|
44
39
|
place: {
|
|
45
40
|
id: string | number;
|
|
46
41
|
name?: string;
|
|
47
42
|
address?: string;
|
|
48
43
|
cover?: string;
|
|
49
44
|
};
|
|
45
|
+
disabledMenu: boolean;
|
|
46
|
+
isProfile: boolean;
|
|
47
|
+
disabledLike: boolean;
|
|
48
|
+
allowReply: boolean;
|
|
49
|
+
replyAvatar: string;
|
|
50
50
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
51
51
|
declare const _default: typeof __VLS_export;
|
|
52
52
|
export default _default;
|
|
@@ -36,17 +36,17 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
36
36
|
"onReply-delete"?: ((item: CardReviewProps) => any) | undefined;
|
|
37
37
|
}>, {
|
|
38
38
|
item: CardReviewProps;
|
|
39
|
-
disabledMenu: boolean;
|
|
40
|
-
isProfile: boolean;
|
|
41
|
-
disabledLike: boolean;
|
|
42
|
-
allowReply: boolean;
|
|
43
|
-
replyAvatar: string;
|
|
44
39
|
place: {
|
|
45
40
|
id: string | number;
|
|
46
41
|
name?: string;
|
|
47
42
|
address?: string;
|
|
48
43
|
cover?: string;
|
|
49
44
|
};
|
|
45
|
+
disabledMenu: boolean;
|
|
46
|
+
isProfile: boolean;
|
|
47
|
+
disabledLike: boolean;
|
|
48
|
+
allowReply: boolean;
|
|
49
|
+
replyAvatar: string;
|
|
50
50
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
51
51
|
declare const _default: typeof __VLS_export;
|
|
52
52
|
export default _default;
|
|
@@ -15,9 +15,9 @@ type __VLS_Props = {
|
|
|
15
15
|
};
|
|
16
16
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
17
17
|
title: string;
|
|
18
|
-
state: "personal" | "office" | "business";
|
|
19
18
|
photos: MediaItem[];
|
|
20
19
|
videos: MediaItem[];
|
|
20
|
+
state: "personal" | "office" | "business";
|
|
21
21
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
22
22
|
declare const _default: typeof __VLS_export;
|
|
23
23
|
export default _default;
|
|
@@ -15,9 +15,9 @@ type __VLS_Props = {
|
|
|
15
15
|
};
|
|
16
16
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
17
17
|
title: string;
|
|
18
|
-
state: "personal" | "office" | "business";
|
|
19
18
|
photos: MediaItem[];
|
|
20
19
|
videos: MediaItem[];
|
|
20
|
+
state: "personal" | "office" | "business";
|
|
21
21
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
22
22
|
declare const _default: typeof __VLS_export;
|
|
23
23
|
export default _default;
|
|
@@ -30,9 +30,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
30
30
|
"onExplore-places"?: (() => any) | undefined;
|
|
31
31
|
"onRequire-auth"?: (() => any) | undefined;
|
|
32
32
|
}>, {
|
|
33
|
-
isMyProfile: boolean;
|
|
34
33
|
profileId: string;
|
|
35
34
|
defaultTab: "followers" | "following" | "favorites";
|
|
35
|
+
isMyProfile: boolean;
|
|
36
36
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
37
37
|
declare const _default: typeof __VLS_export;
|
|
38
38
|
export default _default;
|
|
@@ -30,9 +30,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
30
30
|
"onExplore-places"?: (() => any) | undefined;
|
|
31
31
|
"onRequire-auth"?: (() => any) | undefined;
|
|
32
32
|
}>, {
|
|
33
|
-
isMyProfile: boolean;
|
|
34
33
|
profileId: string;
|
|
35
34
|
defaultTab: "followers" | "following" | "favorites";
|
|
35
|
+
isMyProfile: boolean;
|
|
36
36
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
37
37
|
declare const _default: typeof __VLS_export;
|
|
38
38
|
export default _default;
|
|
@@ -48,11 +48,11 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
48
48
|
id: string;
|
|
49
49
|
name: string;
|
|
50
50
|
required: boolean;
|
|
51
|
-
options: AutocompleteOption[] | string[] | number[];
|
|
52
51
|
description: string;
|
|
53
52
|
labelKey: string;
|
|
54
53
|
placeholder: string;
|
|
55
54
|
limit: number;
|
|
55
|
+
options: AutocompleteOption[] | string[] | number[];
|
|
56
56
|
disabledErrorMessage: boolean;
|
|
57
57
|
disabledBorder: boolean;
|
|
58
58
|
showCounter: boolean;
|
|
@@ -48,11 +48,11 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
48
48
|
id: string;
|
|
49
49
|
name: string;
|
|
50
50
|
required: boolean;
|
|
51
|
-
options: AutocompleteOption[] | string[] | number[];
|
|
52
51
|
description: string;
|
|
53
52
|
labelKey: string;
|
|
54
53
|
placeholder: string;
|
|
55
54
|
limit: number;
|
|
55
|
+
options: AutocompleteOption[] | string[] | number[];
|
|
56
56
|
disabledErrorMessage: boolean;
|
|
57
57
|
disabledBorder: boolean;
|
|
58
58
|
showCounter: boolean;
|
|
@@ -35,8 +35,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
35
35
|
fullHeight: boolean;
|
|
36
36
|
fullWidth: boolean;
|
|
37
37
|
limit: number;
|
|
38
|
-
accept: string;
|
|
39
38
|
disabledErrorMessage: boolean;
|
|
39
|
+
accept: string;
|
|
40
40
|
labelIcon: string;
|
|
41
41
|
disabledDrop: boolean;
|
|
42
42
|
column: boolean;
|
|
@@ -35,8 +35,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
35
35
|
fullHeight: boolean;
|
|
36
36
|
fullWidth: boolean;
|
|
37
37
|
limit: number;
|
|
38
|
-
accept: string;
|
|
39
38
|
disabledErrorMessage: boolean;
|
|
39
|
+
accept: string;
|
|
40
40
|
labelIcon: string;
|
|
41
41
|
disabledDrop: boolean;
|
|
42
42
|
column: boolean;
|
|
@@ -11,9 +11,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
11
11
|
label: string;
|
|
12
12
|
name: string;
|
|
13
13
|
modelValue: LocalizedNameItem[];
|
|
14
|
-
options: InputSelectItem[];
|
|
15
14
|
placeholder: string;
|
|
16
15
|
limit: number;
|
|
16
|
+
options: InputSelectItem[];
|
|
17
17
|
showCounter: boolean;
|
|
18
18
|
addLabel: string;
|
|
19
19
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -11,9 +11,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
11
11
|
label: string;
|
|
12
12
|
name: string;
|
|
13
13
|
modelValue: LocalizedNameItem[];
|
|
14
|
-
options: InputSelectItem[];
|
|
15
14
|
placeholder: string;
|
|
16
15
|
limit: number;
|
|
16
|
+
options: InputSelectItem[];
|
|
17
17
|
showCounter: boolean;
|
|
18
18
|
addLabel: string;
|
|
19
19
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -25,8 +25,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
25
25
|
"onUpdate:modelValue"?: ((value: SelectedTag[]) => any) | undefined;
|
|
26
26
|
}>, {
|
|
27
27
|
name: string;
|
|
28
|
-
state: "user" | "admin";
|
|
29
28
|
placeholder: string;
|
|
29
|
+
state: "user" | "admin";
|
|
30
30
|
limit: number;
|
|
31
31
|
ignore: string[];
|
|
32
32
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -25,8 +25,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
25
25
|
"onUpdate:modelValue"?: ((value: SelectedTag[]) => any) | undefined;
|
|
26
26
|
}>, {
|
|
27
27
|
name: string;
|
|
28
|
-
state: "user" | "admin";
|
|
29
28
|
placeholder: string;
|
|
29
|
+
state: "user" | "admin";
|
|
30
30
|
limit: number;
|
|
31
31
|
ignore: string[];
|
|
32
32
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -19,8 +19,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
19
19
|
}>, {
|
|
20
20
|
name: string;
|
|
21
21
|
required: boolean;
|
|
22
|
-
options: import("../../../types/components/input/input-select.js").InputSelectItem[];
|
|
23
22
|
limit: number;
|
|
23
|
+
options: import("../../../types/components/input/input-select.js").InputSelectItem[];
|
|
24
24
|
showCounter: boolean;
|
|
25
25
|
selectClass: import("vue").HTMLAttributes["class"];
|
|
26
26
|
resetOnTypeChange: boolean;
|
|
@@ -19,8 +19,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
19
19
|
}>, {
|
|
20
20
|
name: string;
|
|
21
21
|
required: boolean;
|
|
22
|
-
options: import("../../../types/components/input/input-select.js").InputSelectItem[];
|
|
23
22
|
limit: number;
|
|
23
|
+
options: import("../../../types/components/input/input-select.js").InputSelectItem[];
|
|
24
24
|
showCounter: boolean;
|
|
25
25
|
selectClass: import("vue").HTMLAttributes["class"];
|
|
26
26
|
resetOnTypeChange: boolean;
|
|
@@ -23,8 +23,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
23
23
|
}>, {
|
|
24
24
|
title: string;
|
|
25
25
|
items: CarouselItem[];
|
|
26
|
-
startIndex: number;
|
|
27
26
|
uploaderLabel: string;
|
|
27
|
+
startIndex: number;
|
|
28
28
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
29
29
|
declare const _default: typeof __VLS_export;
|
|
30
30
|
export default _default;
|
|
@@ -23,8 +23,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
23
23
|
}>, {
|
|
24
24
|
title: string;
|
|
25
25
|
items: CarouselItem[];
|
|
26
|
-
startIndex: number;
|
|
27
26
|
uploaderLabel: string;
|
|
27
|
+
startIndex: number;
|
|
28
28
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
29
29
|
declare const _default: typeof __VLS_export;
|
|
30
30
|
export default _default;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<Modal class="w-[512px]" v-model="isOpen" :loading="
|
|
2
|
+
<Modal class="w-[512px]" v-model="isOpen" :loading="isSubmitting" @submit="onSubmit">
|
|
3
3
|
<template #header>
|
|
4
4
|
<div v-if="activeField === 'list'" class="font-title-medium-prominent">
|
|
5
5
|
แนะนำให้แก้ไข
|
|
@@ -396,79 +396,164 @@ const openLinkEditField = (channel) => {
|
|
|
396
396
|
const cancelEdit = () => {
|
|
397
397
|
activeField.value = "list";
|
|
398
398
|
};
|
|
399
|
-
const
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
399
|
+
const isSubmitting = ref(false);
|
|
400
|
+
const buildSuggestEditBody = () => {
|
|
401
|
+
switch (activeField.value) {
|
|
402
|
+
case "place_name":
|
|
403
|
+
return {
|
|
404
|
+
topic_key: "name",
|
|
405
|
+
edit_type: editType.value,
|
|
406
|
+
name: newName.value,
|
|
407
|
+
localized_names: localizedNames.value.filter((r) => r.editType === "new" && r.newName.trim()).map((r) => ({ language: r.language, name: r.newName }))
|
|
408
|
+
};
|
|
409
|
+
case "address":
|
|
410
|
+
return {
|
|
411
|
+
topic_key: "address",
|
|
412
|
+
edit_type: addressEditType.value,
|
|
413
|
+
address: addressValue.value,
|
|
414
|
+
latLng: addressLatLng.value ?? void 0
|
|
415
|
+
};
|
|
416
|
+
case "category":
|
|
417
|
+
return {
|
|
418
|
+
topic_key: "category",
|
|
419
|
+
edit_type: categoryEditType.value,
|
|
420
|
+
categories: categories.value
|
|
421
|
+
};
|
|
422
|
+
case "description":
|
|
423
|
+
return {
|
|
424
|
+
topic_key: "description",
|
|
425
|
+
edit_type: descriptionEditType.value,
|
|
426
|
+
description: descriptionValue.value
|
|
427
|
+
};
|
|
428
|
+
case "dateopening":
|
|
429
|
+
return {
|
|
430
|
+
topic_key: "opening_hours",
|
|
431
|
+
edit_type: dateOpeningEditType.value,
|
|
432
|
+
opening_hours: newOpeningHours.value,
|
|
433
|
+
special_days: newSpecialDays.value
|
|
434
|
+
};
|
|
435
|
+
case "phone":
|
|
436
|
+
return {
|
|
437
|
+
topic_key: "phone",
|
|
438
|
+
edit_type: "add",
|
|
439
|
+
value: phoneValue.value
|
|
440
|
+
};
|
|
441
|
+
case "phone_edit":
|
|
442
|
+
return {
|
|
443
|
+
topic_key: "phone",
|
|
444
|
+
edit_type: phoneEditType.value,
|
|
445
|
+
target_value: editingPhone.value,
|
|
446
|
+
value: editPhoneValue.value
|
|
447
|
+
};
|
|
448
|
+
case "link":
|
|
449
|
+
return {
|
|
450
|
+
topic_key: "contact_channels",
|
|
451
|
+
edit_type: "add",
|
|
452
|
+
contact_channels: newContactChannels.value
|
|
453
|
+
};
|
|
454
|
+
case "link_edit":
|
|
455
|
+
return {
|
|
456
|
+
topic_key: "contact_channels",
|
|
457
|
+
edit_type: linkEditType.value,
|
|
458
|
+
target_channel_id: editingChannel.value?.id,
|
|
459
|
+
target_value: editingChannel.value?.value,
|
|
460
|
+
value: editChannelValue.value
|
|
461
|
+
};
|
|
462
|
+
default:
|
|
463
|
+
return null;
|
|
443
464
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
465
|
+
};
|
|
466
|
+
const onSubmit = async () => {
|
|
467
|
+
const body = buildSuggestEditBody();
|
|
468
|
+
if (!body || isSubmitting.value) return;
|
|
469
|
+
isSubmitting.value = true;
|
|
470
|
+
try {
|
|
471
|
+
await api(`/suggest-places/${props.item.id}/suggest-edits`, {
|
|
472
|
+
method: "post",
|
|
473
|
+
body
|
|
450
474
|
});
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
475
|
+
if (activeField.value === "place_name") {
|
|
476
|
+
emit("submit-field", {
|
|
477
|
+
field: "place_name",
|
|
478
|
+
editType: editType.value,
|
|
479
|
+
value: newName.value,
|
|
480
|
+
localizedNames: localizedNames.value
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
if (activeField.value === "address") {
|
|
484
|
+
emit("submit-field", {
|
|
485
|
+
field: "address",
|
|
486
|
+
editType: addressEditType.value,
|
|
487
|
+
addressValue: addressValue.value,
|
|
488
|
+
latLng: addressLatLng.value
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
if (activeField.value === "category") {
|
|
492
|
+
emit("submit-field", {
|
|
493
|
+
field: "category",
|
|
494
|
+
editType: categoryEditType.value,
|
|
495
|
+
categories: categories.value
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
if (activeField.value === "description") {
|
|
499
|
+
emit("submit-field", {
|
|
500
|
+
field: "description",
|
|
501
|
+
editType: descriptionEditType.value,
|
|
502
|
+
value: descriptionValue.value
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
if (activeField.value === "dateopening") {
|
|
506
|
+
emit("submit-field", {
|
|
507
|
+
field: "dateopening",
|
|
508
|
+
editType: dateOpeningEditType.value,
|
|
509
|
+
openingHours: newOpeningHours.value,
|
|
510
|
+
specialDays: newSpecialDays.value
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
if (activeField.value === "phone") {
|
|
514
|
+
emit("submit-field", {
|
|
515
|
+
field: "phone",
|
|
516
|
+
value: phoneValue.value
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
if (activeField.value === "phone_edit") {
|
|
520
|
+
emit("submit-field", {
|
|
521
|
+
field: "phone_edit",
|
|
522
|
+
currentPhone: editingPhone.value,
|
|
523
|
+
editType: phoneEditType.value,
|
|
524
|
+
value: editPhoneValue.value
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
if (activeField.value === "link") {
|
|
528
|
+
emit("submit-field", {
|
|
529
|
+
field: "link",
|
|
530
|
+
channels: newContactChannels.value
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
if (activeField.value === "link_edit") {
|
|
534
|
+
emit("submit-field", {
|
|
535
|
+
field: "link_edit",
|
|
536
|
+
currentChannel: editingChannel.value,
|
|
537
|
+
editType: linkEditType.value,
|
|
538
|
+
value: editChannelValue.value
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
activeField.value = "list";
|
|
542
|
+
$alert.show({
|
|
543
|
+
type: "success",
|
|
544
|
+
title: "\u0E02\u0E2D\u0E1A\u0E04\u0E38\u0E13\u0E17\u0E35\u0E48\u0E41\u0E08\u0E49\u0E07\u0E43\u0E2B\u0E49\u0E40\u0E23\u0E32\u0E17\u0E23\u0E32\u0E1A !",
|
|
545
|
+
description: "\u0E40\u0E23\u0E32\u0E08\u0E30\u0E43\u0E0A\u0E49\u0E40\u0E27\u0E25\u0E32\u0E2A\u0E2D\u0E07\u0E2A\u0E32\u0E21\u0E27\u0E31\u0E19\u0E43\u0E19\u0E01\u0E32\u0E23\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E23\u0E32\u0E22\u0E07\u0E32\u0E19\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13"
|
|
456
546
|
});
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
value: editChannelValue.value
|
|
547
|
+
} catch (error) {
|
|
548
|
+
console.error(error);
|
|
549
|
+
$alert.show({
|
|
550
|
+
type: "error",
|
|
551
|
+
title: "\u0E40\u0E01\u0E34\u0E14\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14",
|
|
552
|
+
description: "\u0E01\u0E23\u0E38\u0E13\u0E32\u0E25\u0E2D\u0E07\u0E43\u0E2B\u0E21\u0E48\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07 !"
|
|
464
553
|
});
|
|
554
|
+
} finally {
|
|
555
|
+
isSubmitting.value = false;
|
|
465
556
|
}
|
|
466
|
-
activeField.value = "list";
|
|
467
|
-
$alert.show({
|
|
468
|
-
type: "success",
|
|
469
|
-
title: "\u0E02\u0E2D\u0E1A\u0E04\u0E38\u0E13\u0E17\u0E35\u0E48\u0E41\u0E08\u0E49\u0E07\u0E43\u0E2B\u0E49\u0E40\u0E23\u0E32\u0E17\u0E23\u0E32\u0E1A !",
|
|
470
|
-
description: "\u0E40\u0E23\u0E32\u0E08\u0E30\u0E43\u0E0A\u0E49\u0E40\u0E27\u0E25\u0E32\u0E2A\u0E2D\u0E07\u0E2A\u0E32\u0E21\u0E27\u0E31\u0E19\u0E43\u0E19\u0E01\u0E32\u0E23\u0E15\u0E23\u0E27\u0E08\u0E2A\u0E2D\u0E1A\u0E23\u0E32\u0E22\u0E07\u0E32\u0E19\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13"
|
|
471
|
-
});
|
|
472
557
|
};
|
|
473
558
|
const canSubmit = computed(() => {
|
|
474
559
|
switch (activeField.value) {
|
|
@@ -6,51 +6,11 @@
|
|
|
6
6
|
</div>
|
|
7
7
|
<div class="flex flex-col gap-[8px]">
|
|
8
8
|
<div class="font-body-large-prominent text-gray">วัน เวลาทำการเดิม</div>
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
ปิดชั่วคราว
|
|
15
|
-
</div>
|
|
16
|
-
<div
|
|
17
|
-
v-for="(hour, index) in businessHours"
|
|
18
|
-
:key="index"
|
|
19
|
-
class="flex items-start justify-between font-body-large"
|
|
20
|
-
>
|
|
21
|
-
<span>{{ hour.day }}</span>
|
|
22
|
-
<div class="flex flex-col items-end">
|
|
23
|
-
<span v-for="(line, li) in hour.time_lines" :key="li">{{
|
|
24
|
-
line
|
|
25
|
-
}}</span>
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
|
|
29
|
-
<template v-if="upcomingSpecialDays.length">
|
|
30
|
-
<div class="font-body-large-prominent text-warning">
|
|
31
|
-
วันทำการพิเศษ
|
|
32
|
-
</div>
|
|
33
|
-
<div
|
|
34
|
-
v-for="(special, index) in upcomingSpecialDays"
|
|
35
|
-
:key="index"
|
|
36
|
-
class="flex items-start justify-between text-warning font-body-large"
|
|
37
|
-
>
|
|
38
|
-
<span>{{ special.date_label }}</span>
|
|
39
|
-
<div class="flex flex-col items-end">
|
|
40
|
-
<span v-for="(line, li) in special.time_lines" :key="li">{{
|
|
41
|
-
line
|
|
42
|
-
}}</span>
|
|
43
|
-
</div>
|
|
44
|
-
</div>
|
|
45
|
-
</template>
|
|
46
|
-
</div>
|
|
47
|
-
<div
|
|
48
|
-
v-else-if="props.currentOpenStatus === 'temporarily_closed'"
|
|
49
|
-
class="font-body-large-prominent text-destructive"
|
|
50
|
-
>
|
|
51
|
-
ปิดชั่วคราว
|
|
52
|
-
</div>
|
|
53
|
-
<div v-else class="text-cloud">ไม่มีข้อมูลเวลาทำการ</div>
|
|
9
|
+
<CardOpeningHours
|
|
10
|
+
:items="props.currentOpeningHours"
|
|
11
|
+
:special-days="props.currentSpecialDays"
|
|
12
|
+
:open-status="props.currentOpenStatus"
|
|
13
|
+
/>
|
|
54
14
|
</div>
|
|
55
15
|
|
|
56
16
|
<InputSelect
|
|
@@ -92,39 +52,6 @@ const editTypeOptions = [
|
|
|
92
52
|
{ label: "\u0E40\u0E1B\u0E25\u0E35\u0E48\u0E22\u0E19\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E43\u0E2B\u0E21\u0E48", value: "new" },
|
|
93
53
|
{ label: "\u0E44\u0E21\u0E48\u0E17\u0E23\u0E32\u0E1A \u0E41\u0E15\u0E48\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E44\u0E21\u0E48\u0E16\u0E39\u0E01\u0E15\u0E49\u0E2D\u0E07", value: "incorrect" }
|
|
94
54
|
];
|
|
95
|
-
const DAY_NAMES = [
|
|
96
|
-
"\u0E27\u0E31\u0E19\u0E2D\u0E32\u0E17\u0E34\u0E15\u0E22\u0E4C",
|
|
97
|
-
"\u0E27\u0E31\u0E19\u0E08\u0E31\u0E19\u0E17\u0E23\u0E4C",
|
|
98
|
-
"\u0E27\u0E31\u0E19\u0E2D\u0E31\u0E07\u0E04\u0E32\u0E23",
|
|
99
|
-
"\u0E27\u0E31\u0E19\u0E1E\u0E38\u0E18",
|
|
100
|
-
"\u0E27\u0E31\u0E19\u0E1E\u0E24\u0E2B\u0E31\u0E2A\u0E1A\u0E14\u0E35",
|
|
101
|
-
"\u0E27\u0E31\u0E19\u0E28\u0E38\u0E01\u0E23\u0E4C",
|
|
102
|
-
"\u0E27\u0E31\u0E19\u0E40\u0E2A\u0E32\u0E23\u0E4C"
|
|
103
|
-
];
|
|
104
|
-
const toArray = (value) => Array.isArray(value) ? value : [];
|
|
105
|
-
const getTimeLines = (isOpen, timeSlots, isAllDay) => {
|
|
106
|
-
if (!isOpen) return ["\u0E2B\u0E22\u0E38\u0E14\u0E17\u0E33\u0E01\u0E32\u0E23"];
|
|
107
|
-
const slots = toArray(timeSlots);
|
|
108
|
-
if (isAllDay || slots.length === 0) return ["\u0E40\u0E1B\u0E34\u0E14\u0E15\u0E25\u0E2D\u0E14 24 \u0E0A\u0E21."];
|
|
109
|
-
return slots.map((t) => `${t.start} - ${t.end} \u0E19.`);
|
|
110
|
-
};
|
|
111
|
-
const businessHours = computed(
|
|
112
|
-
() => toArray(props.currentOpeningHours).filter((h) => !!h).map((h) => ({
|
|
113
|
-
day: DAY_NAMES[h.day] ?? "",
|
|
114
|
-
time_lines: getTimeLines(h.isOpen, h.timeSlots, h.isAllDay)
|
|
115
|
-
}))
|
|
116
|
-
);
|
|
117
|
-
const sortedSpecialDays = computed(() => {
|
|
118
|
-
const today = dayjs().startOf("day");
|
|
119
|
-
const maxDate = today.add(30, "day").endOf("day");
|
|
120
|
-
return toArray(props.currentSpecialDays).filter((s) => !!s?.date).map((s) => ({ ...s, date: dayjs(s.date) })).filter((s) => s.date.isValid()).filter((s) => !s.date.isBefore(today) && !s.date.isAfter(maxDate)).sort((a, b) => a.date.valueOf() - b.date.valueOf());
|
|
121
|
-
});
|
|
122
|
-
const upcomingSpecialDays = computed(
|
|
123
|
-
() => sortedSpecialDays.value.map((s) => ({
|
|
124
|
-
date_label: s.date.locale("th").format("D MMMM BBBB"),
|
|
125
|
-
time_lines: getTimeLines(s.isOpen, s.timeSlots)
|
|
126
|
-
}))
|
|
127
|
-
);
|
|
128
55
|
const isNewOpeningHoursCompleted = computed(
|
|
129
56
|
() => Array.isArray(newOpeningHours.value) && newOpeningHours.value.some((s) => s.isOpen)
|
|
130
57
|
);
|
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
import type { OpeningHour, SpecialDay } from "#pukaad-ui/runtime/components/card/card-opening-hours.vue";
|
|
1
2
|
export interface TimelineItem {
|
|
2
3
|
id?: string | number;
|
|
3
4
|
avatar?: string;
|
|
4
5
|
name?: string;
|
|
5
6
|
time?: string | Date;
|
|
6
7
|
description?: string;
|
|
8
|
+
value?: string;
|
|
9
|
+
suggested_value?: string;
|
|
10
|
+
hours?: OpeningHour[];
|
|
11
|
+
opening_hours?: OpeningHour[];
|
|
12
|
+
suggested_hours?: OpeningHour[];
|
|
13
|
+
special_days?: SpecialDay[];
|
|
14
|
+
suggested_special_days?: SpecialDay[];
|
|
15
|
+
[key: string]: any;
|
|
7
16
|
}
|
|
8
17
|
type __VLS_Props = {
|
|
9
18
|
items: TimelineItem[];
|
|
@@ -11,9 +20,14 @@ type __VLS_Props = {
|
|
|
11
20
|
declare var __VLS_1: {
|
|
12
21
|
item: TimelineItem;
|
|
13
22
|
index: number;
|
|
23
|
+
}, __VLS_8: {
|
|
24
|
+
item: TimelineItem;
|
|
25
|
+
index: number;
|
|
14
26
|
};
|
|
15
27
|
type __VLS_Slots = {} & {
|
|
16
28
|
content?: (props: typeof __VLS_1) => any;
|
|
29
|
+
} & {
|
|
30
|
+
description?: (props: typeof __VLS_8) => any;
|
|
17
31
|
};
|
|
18
32
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
33
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="flex flex-col">
|
|
2
|
+
<div class="flex flex-col w-full">
|
|
3
3
|
<div
|
|
4
4
|
v-for="(item, index) in props.items"
|
|
5
5
|
:key="item.id ?? index"
|
|
6
|
-
class="flex gap-[8px]"
|
|
6
|
+
class="flex gap-[8px] w-full"
|
|
7
7
|
>
|
|
8
8
|
<!-- dot + connecting line (โครงของ component เอง) -->
|
|
9
9
|
<div class="flex flex-col items-center w-[8px]">
|
|
@@ -15,22 +15,40 @@
|
|
|
15
15
|
|
|
16
16
|
<!-- เนื้อหา — ปล่อยให้ผู้ใช้ครอบเองผ่าน slot ได้ ถ้าไม่ส่งมาใช้ default นี้ -->
|
|
17
17
|
<div
|
|
18
|
-
class="flex flex-col gap-[8px]"
|
|
18
|
+
class="flex flex-col gap-[8px] flex-1 min-w-0"
|
|
19
19
|
:class="index < props.items.length - 1 ? 'pb-[16px]' : ''"
|
|
20
20
|
>
|
|
21
21
|
<slot name="content" :item="item" :index="index">
|
|
22
|
-
<div class="flex gap-[8px]">
|
|
22
|
+
<div class="flex gap-[8px] w-full">
|
|
23
23
|
<Avatar :src="item.avatar" :alt="item.name" :size="30" />
|
|
24
|
-
<div class="flex flex-col gap-[8px]">
|
|
24
|
+
<div class="flex flex-col gap-[8px] flex-1 min-w-0">
|
|
25
25
|
<div class="flex flex-col gap-[4px]">
|
|
26
26
|
<span class="font-body-large text-gray">{{ item.name }}</span>
|
|
27
|
-
<span
|
|
28
|
-
|
|
27
|
+
<span
|
|
28
|
+
v-if="item.time"
|
|
29
|
+
class="font-body-small text-gray"
|
|
29
30
|
>
|
|
31
|
+
{{ convertDateTime(item.time) }} น.
|
|
32
|
+
</span>
|
|
30
33
|
</div>
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
<slot name="description" :item="item" :index="index">
|
|
35
|
+
<CardOpeningHours
|
|
36
|
+
v-if="
|
|
37
|
+
item.opening_hours || item.suggested_hours || item.hours
|
|
38
|
+
"
|
|
39
|
+
:items="
|
|
40
|
+
item.opening_hours || item.suggested_hours || item.hours
|
|
41
|
+
"
|
|
42
|
+
:special-days="
|
|
43
|
+
item.special_days || item.suggested_special_days
|
|
44
|
+
"
|
|
45
|
+
:open-status="item.open_status"
|
|
46
|
+
class="text-gray w-full"
|
|
47
|
+
/>
|
|
48
|
+
<p v-else class="font-body-large text-gray">
|
|
49
|
+
{{ item.description }}
|
|
50
|
+
</p>
|
|
51
|
+
</slot>
|
|
34
52
|
</div>
|
|
35
53
|
</div>
|
|
36
54
|
</slot>
|
|
@@ -41,6 +59,7 @@
|
|
|
41
59
|
|
|
42
60
|
<script setup>
|
|
43
61
|
import { useConvert } from "#pukaad-ui/runtime/composables/useConvert";
|
|
62
|
+
import CardOpeningHours from "#pukaad-ui/runtime/components/card/card-opening-hours.vue";
|
|
44
63
|
const props = defineProps({
|
|
45
64
|
items: { type: Array, required: true }
|
|
46
65
|
});
|
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
import type { OpeningHour, SpecialDay } from "#pukaad-ui/runtime/components/card/card-opening-hours.vue";
|
|
1
2
|
export interface TimelineItem {
|
|
2
3
|
id?: string | number;
|
|
3
4
|
avatar?: string;
|
|
4
5
|
name?: string;
|
|
5
6
|
time?: string | Date;
|
|
6
7
|
description?: string;
|
|
8
|
+
value?: string;
|
|
9
|
+
suggested_value?: string;
|
|
10
|
+
hours?: OpeningHour[];
|
|
11
|
+
opening_hours?: OpeningHour[];
|
|
12
|
+
suggested_hours?: OpeningHour[];
|
|
13
|
+
special_days?: SpecialDay[];
|
|
14
|
+
suggested_special_days?: SpecialDay[];
|
|
15
|
+
[key: string]: any;
|
|
7
16
|
}
|
|
8
17
|
type __VLS_Props = {
|
|
9
18
|
items: TimelineItem[];
|
|
@@ -11,9 +20,14 @@ type __VLS_Props = {
|
|
|
11
20
|
declare var __VLS_1: {
|
|
12
21
|
item: TimelineItem;
|
|
13
22
|
index: number;
|
|
23
|
+
}, __VLS_8: {
|
|
24
|
+
item: TimelineItem;
|
|
25
|
+
index: number;
|
|
14
26
|
};
|
|
15
27
|
type __VLS_Slots = {} & {
|
|
16
28
|
content?: (props: typeof __VLS_1) => any;
|
|
29
|
+
} & {
|
|
30
|
+
description?: (props: typeof __VLS_8) => any;
|
|
17
31
|
};
|
|
18
32
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
33
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface TimeSlot {
|
|
2
|
+
start: string;
|
|
3
|
+
end: string;
|
|
4
|
+
}
|
|
5
|
+
export interface OpeningHour {
|
|
6
|
+
day: number;
|
|
7
|
+
isOpen: boolean;
|
|
8
|
+
isAllDay?: boolean;
|
|
9
|
+
timeSlots?: TimeSlot[];
|
|
10
|
+
}
|
|
11
|
+
export interface SpecialDay {
|
|
12
|
+
date: string | Date;
|
|
13
|
+
isOpen: boolean;
|
|
14
|
+
timeSlots?: TimeSlot[];
|
|
15
|
+
}
|
|
16
|
+
export declare const DAY_NAMES: string[];
|
|
17
|
+
export declare const getTimeLines: (isOpen: boolean, timeSlots?: TimeSlot[], isAllDay?: boolean) => string[];
|
|
18
|
+
export declare const toDayLines: (hours?: OpeningHour[]) => {
|
|
19
|
+
day: string;
|
|
20
|
+
time_lines: string[];
|
|
21
|
+
}[];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const DAY_NAMES = [
|
|
2
|
+
"\u0E27\u0E31\u0E19\u0E2D\u0E32\u0E17\u0E34\u0E15\u0E22\u0E4C",
|
|
3
|
+
"\u0E27\u0E31\u0E19\u0E08\u0E31\u0E19\u0E17\u0E23\u0E4C",
|
|
4
|
+
"\u0E27\u0E31\u0E19\u0E2D\u0E31\u0E07\u0E04\u0E32\u0E23",
|
|
5
|
+
"\u0E27\u0E31\u0E19\u0E1E\u0E38\u0E18",
|
|
6
|
+
"\u0E27\u0E31\u0E19\u0E1E\u0E24\u0E2B\u0E31\u0E2A\u0E1A\u0E14\u0E35",
|
|
7
|
+
"\u0E27\u0E31\u0E19\u0E28\u0E38\u0E01\u0E23\u0E4C",
|
|
8
|
+
"\u0E27\u0E31\u0E19\u0E40\u0E2A\u0E32\u0E23\u0E4C"
|
|
9
|
+
];
|
|
10
|
+
const toArray = (value) => Array.isArray(value) ? value : [];
|
|
11
|
+
export const getTimeLines = (isOpen, timeSlots, isAllDay) => {
|
|
12
|
+
if (!isOpen) return ["\u0E2B\u0E22\u0E38\u0E14\u0E17\u0E33\u0E01\u0E32\u0E23"];
|
|
13
|
+
const slots = toArray(timeSlots);
|
|
14
|
+
if (isAllDay || slots.length === 0) return ["\u0E40\u0E1B\u0E34\u0E14\u0E15\u0E25\u0E2D\u0E14 24 \u0E0A\u0E21."];
|
|
15
|
+
return slots.map((t) => `${t.start} - ${t.end} \u0E19.`);
|
|
16
|
+
};
|
|
17
|
+
export const toDayLines = (hours) => toArray(hours).filter((h) => !!h).map((h) => ({
|
|
18
|
+
day: DAY_NAMES[h.day] ?? "",
|
|
19
|
+
time_lines: getTimeLines(h.isOpen, h.timeSlots, h.isAllDay)
|
|
20
|
+
}));
|