pukaad-ui-lib 1.419.0 → 1.421.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pukaad-ui-lib",
3
3
  "configKey": "pukaadUI",
4
- "version": "1.419.0",
4
+ "version": "1.421.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
@@ -108,6 +108,29 @@ const actions = computed(() => {
108
108
  }
109
109
  return result;
110
110
  }
111
+ if (props.state === "expired") {
112
+ return [
113
+ ...props.hidePreview ? [] : [{ name: "preview", icon: "lucide:tv-minimal-play" }],
114
+ { name: "renew", icon: "lucide:history" },
115
+ {
116
+ name: "delete",
117
+ icon: "lucide:trash-2",
118
+ variant: "default",
119
+ color: "destructive"
120
+ }
121
+ ];
122
+ }
123
+ if (props.state === "trash") {
124
+ return [
125
+ { name: "recover", icon: "lucide:rotate-ccw" },
126
+ {
127
+ name: "delete",
128
+ icon: "lucide:trash-2",
129
+ variant: "default",
130
+ color: "destructive"
131
+ }
132
+ ];
133
+ }
111
134
  if (props.state === "draft") {
112
135
  return [
113
136
  {
@@ -1,10 +1,11 @@
1
1
  import type { SelectPlaceItem } from "../input/input-select-place.vue.js";
2
2
  import type { MentionItem } from "../input/input-mention.vue.js";
3
- interface IFileItem {
3
+ export interface IFileItem {
4
4
  file?: File;
5
5
  url: string;
6
6
  description?: string;
7
7
  duration?: string;
8
+ mediaType?: "image" | "video";
8
9
  }
9
10
  interface SelectedTag {
10
11
  id: string;
@@ -24,6 +25,7 @@ export interface DrawerPostContentItem {
24
25
  }
25
26
  export interface DrawerPostContentProps {
26
27
  item?: DrawerPostContentItem;
28
+ state?: "personal" | "business";
27
29
  }
28
30
  type __VLS_Props = DrawerPostContentProps;
29
31
  declare const modelValue: import("vue").ModelRef<boolean | undefined, string, boolean | undefined, boolean | undefined>;
@@ -41,6 +43,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
41
43
  onSaveDraft?: ((data: unknown) => any) | undefined;
42
44
  }>, {
43
45
  item: DrawerPostContentItem;
46
+ state: "personal" | "business";
44
47
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
45
48
  declare const _default: typeof __VLS_export;
46
49
  export default _default;
@@ -171,7 +171,8 @@ const props = defineProps({
171
171
  tags: [],
172
172
  mentions: [],
173
173
  places: []
174
- }) }
174
+ }) },
175
+ state: { type: String, required: false, default: "personal" }
175
176
  });
176
177
  const modelValue = defineModel({ type: Boolean });
177
178
  const currentId = ref(void 0);
@@ -197,6 +198,7 @@ const hasCoverFile = computed(() => coverFiles.value.length > 0);
197
198
  const coverFileType = computed(() => {
198
199
  const first = coverFiles.value[0];
199
200
  if (!first) return null;
201
+ if (first.mediaType) return first.mediaType;
200
202
  return first.file?.type?.startsWith("video") ? "video" : "image";
201
203
  });
202
204
  const coverAccept = computed(() => {
@@ -319,6 +321,10 @@ const onClose = async () => {
319
321
  modelValue.value = false;
320
322
  };
321
323
  const onSaveDraft = async () => {
324
+ if (props.state === "business") {
325
+ await submitContent("DRAFT");
326
+ return;
327
+ }
322
328
  if (isSubmitting.value) return;
323
329
  isSubmitting.value = true;
324
330
  try {
@@ -331,13 +337,15 @@ const onSaveDraft = async () => {
331
337
  file: f.file,
332
338
  url: f.url,
333
339
  description: f.description,
334
- duration: f.duration
340
+ duration: f.duration,
341
+ mediaType: f.mediaType
335
342
  })),
336
343
  posterFiles: posterFiles.value.map((f) => ({
337
344
  file: f.file,
338
345
  url: f.url,
339
346
  description: f.description,
340
- duration: f.duration
347
+ duration: f.duration,
348
+ mediaType: f.mediaType
341
349
  })),
342
350
  description: description.value,
343
351
  tags: JSON.parse(JSON.stringify(selectedTags.value)),
@@ -373,6 +381,10 @@ const parseDurationToSeconds = (duration) => {
373
381
  if (Number.isNaN(m) || Number.isNaN(s)) return 0;
374
382
  return m * 60 + s;
375
383
  };
384
+ const endpointMap = {
385
+ personal: "/personal/contents",
386
+ business: "/business/contents"
387
+ };
376
388
  const submitContent = async (status) => {
377
389
  if (isSubmitting.value) return;
378
390
  if (!hasCoverText.value && !hasCoverFile.value) {
@@ -414,7 +426,8 @@ const submitContent = async (status) => {
414
426
  place_ids: selectedPlaces.value.map((p) => p.id),
415
427
  status
416
428
  };
417
- const endpoint = isEditMode.value ? `/personal/contents/${currentId.value}` : "/personal/contents";
429
+ const baseEndpoint = endpointMap[props.state];
430
+ const endpoint = isEditMode.value ? `${baseEndpoint}/${currentId.value}` : baseEndpoint;
418
431
  const method = isEditMode.value ? "PATCH" : "POST";
419
432
  const res = await api(
420
433
  endpoint,
@@ -426,7 +439,8 @@ const submitContent = async (status) => {
426
439
  if (currentId.value?.startsWith("draft_")) {
427
440
  await deleteDraft(currentId.value);
428
441
  }
429
- emit("success", res.data);
442
+ if (status === "DRAFT") emit("saveDraft", res.data);
443
+ else emit("success", res.data);
430
444
  modelValue.value = false;
431
445
  } catch (e) {
432
446
  const apiErr = e;
@@ -1,10 +1,11 @@
1
1
  import type { SelectPlaceItem } from "../input/input-select-place.vue.js";
2
2
  import type { MentionItem } from "../input/input-mention.vue.js";
3
- interface IFileItem {
3
+ export interface IFileItem {
4
4
  file?: File;
5
5
  url: string;
6
6
  description?: string;
7
7
  duration?: string;
8
+ mediaType?: "image" | "video";
8
9
  }
9
10
  interface SelectedTag {
10
11
  id: string;
@@ -24,6 +25,7 @@ export interface DrawerPostContentItem {
24
25
  }
25
26
  export interface DrawerPostContentProps {
26
27
  item?: DrawerPostContentItem;
28
+ state?: "personal" | "business";
27
29
  }
28
30
  type __VLS_Props = DrawerPostContentProps;
29
31
  declare const modelValue: import("vue").ModelRef<boolean | undefined, string, boolean | undefined, boolean | undefined>;
@@ -41,6 +43,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
41
43
  onSaveDraft?: ((data: unknown) => any) | undefined;
42
44
  }>, {
43
45
  item: DrawerPostContentItem;
46
+ state: "personal" | "business";
44
47
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
45
48
  declare const _default: typeof __VLS_export;
46
49
  export default _default;
@@ -64,11 +64,11 @@ declare const __VLS_export: import("vue").DefineComponent<ImageCropperProps, {
64
64
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ImageCropperProps> & Readonly<{}>, {
65
65
  src: string;
66
66
  center: boolean;
67
+ crossorigin: "" | "anonymous" | "use-credentials";
67
68
  responsive: boolean;
68
69
  restore: boolean;
69
70
  checkCrossOrigin: boolean;
70
71
  checkOrientation: boolean;
71
- crossorigin: "" | "anonymous" | "use-credentials";
72
72
  modal: boolean;
73
73
  guides: boolean;
74
74
  highlight: boolean;
@@ -64,11 +64,11 @@ declare const __VLS_export: import("vue").DefineComponent<ImageCropperProps, {
64
64
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ImageCropperProps> & Readonly<{}>, {
65
65
  src: string;
66
66
  center: boolean;
67
+ crossorigin: "" | "anonymous" | "use-credentials";
67
68
  responsive: boolean;
68
69
  restore: boolean;
69
70
  checkCrossOrigin: boolean;
70
71
  checkOrientation: boolean;
71
- crossorigin: "" | "anonymous" | "use-credentials";
72
72
  modal: boolean;
73
73
  guides: boolean;
74
74
  highlight: boolean;
@@ -0,0 +1,52 @@
1
+ import type { InputTagModalOption, InputTagModalProps } from "../../../types/components/input/input-tag-modal.js";
2
+ interface InputTextFieldExpose {
3
+ setErrors?: (errors: string[]) => void;
4
+ validate?: () => Promise<unknown>;
5
+ }
6
+ type __VLS_Props = InputTagModalProps;
7
+ type __VLS_ModelProps = {
8
+ modelValue?: string | number | null;
9
+ };
10
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
11
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
12
+ setErrors: (errors: string[]) => void;
13
+ validate: () => Promise<unknown>;
14
+ reload: () => Promise<void>;
15
+ fieldRef: import("vue").Ref<{
16
+ setErrors?: ((errors: string[]) => void) | undefined;
17
+ validate?: (() => Promise<unknown>) | undefined;
18
+ } | null, InputTextFieldExpose | {
19
+ setErrors?: ((errors: string[]) => void) | undefined;
20
+ validate?: (() => Promise<unknown>) | undefined;
21
+ } | null>;
22
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
23
+ "update:modelValue": (value: string | number | null) => any;
24
+ } & {
25
+ select: (option: InputTagModalOption) => any;
26
+ clear: () => any;
27
+ open: () => any;
28
+ "fetch-error": (error: unknown) => any;
29
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
30
+ onSelect?: ((option: InputTagModalOption) => any) | undefined;
31
+ onClear?: (() => any) | undefined;
32
+ "onUpdate:modelValue"?: ((value: string | number | null) => any) | undefined;
33
+ onOpen?: (() => any) | undefined;
34
+ "onFetch-error"?: ((error: unknown) => any) | undefined;
35
+ }>, {
36
+ title: string;
37
+ loading: boolean;
38
+ disabled: boolean;
39
+ pageSize: number;
40
+ id: string;
41
+ name: string;
42
+ required: boolean;
43
+ options: InputTagModalOption[];
44
+ labelKey: string;
45
+ placeholder: string;
46
+ disabledErrorMessage: boolean;
47
+ valueKey: string;
48
+ searchPlaceholder: string;
49
+ clearable: boolean;
50
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
51
+ declare const _default: typeof __VLS_export;
52
+ export default _default;
@@ -0,0 +1,307 @@
1
+ <template>
2
+ <div :class="cn('w-full', props.class)">
3
+ <InputTextField
4
+ ref="fieldRef"
5
+ v-model="displayValue"
6
+ :id="props.id"
7
+ :name="props.name"
8
+ :label="props.label"
9
+ :placeholder="props.placeholder"
10
+ :description="props.description"
11
+ :rules="props.rules"
12
+ :required="props.required"
13
+ :disabled="props.disabled"
14
+ :disabled-error-message="props.disabledErrorMessage"
15
+ :icon-append="appendIcon"
16
+ class="cursor-pointer"
17
+ readonly
18
+ @click="onOpenModal"
19
+ @click-icon-append="onAppendClick"
20
+ />
21
+
22
+ <Modal v-model="isOpenModal" :title="props.title">
23
+ <template #title>
24
+ <span class="font-title-medium-prominent text-black">
25
+ {{ props.title }}
26
+ </span>
27
+ </template>
28
+
29
+ <div class="flex w-full flex-col gap-[16px]">
30
+ <InputSearch
31
+ v-model="searchKeyword"
32
+ name="tag-modal-search"
33
+ :placeholder="props.searchPlaceholder"
34
+ icon="lucide:search"
35
+ icon-position="right"
36
+ disabled-error-message
37
+ />
38
+
39
+ <div
40
+ v-if="isInitialLoading"
41
+ class="flex h-[392px] items-center justify-center"
42
+ >
43
+ <Icon
44
+ name="lucide:loader-circle"
45
+ :size="24"
46
+ class="animate-spin text-primary"
47
+ />
48
+ </div>
49
+
50
+ <div
51
+ v-else-if="filteredOptions.length > 0"
52
+ class="flex max-h-[592px] flex-wrap content-start gap-[8px] overflow-y-auto pr-[4px]"
53
+ @scroll.passive="onListScroll"
54
+ >
55
+ <Chip
56
+ v-for="option in filteredOptions"
57
+ :key="optionKey(option)"
58
+ :color="isSelected(option) ? 'primary' : 'bright'"
59
+ class="cursor-pointer transition-colors"
60
+ @click="onSelectOption(option)"
61
+ >
62
+ {{ option.label }}
63
+ </Chip>
64
+
65
+ <div
66
+ v-if="isLoadingMore"
67
+ class="flex w-full items-center justify-center py-[8px]"
68
+ >
69
+ <Icon
70
+ name="lucide:loader-circle"
71
+ :size="20"
72
+ class="animate-spin text-primary"
73
+ />
74
+ </div>
75
+ </div>
76
+
77
+ <div
78
+ v-else
79
+ class="flex h-[392px] flex-col items-center justify-center gap-[8px]"
80
+ >
81
+ <Icon name="pukaad:page-not-found" class="h-[100px] w-[121px]" />
82
+ <div class="font-body-large text-gray">ไม่พบข้อมูล</div>
83
+ </div>
84
+ </div>
85
+ </Modal>
86
+ </div>
87
+ </template>
88
+
89
+ <script setup>
90
+ import { computed, nextTick, reactive, ref, watch } from "vue";
91
+ import { useDebounceFn } from "@vueuse/core";
92
+ import { cn } from "#pukaad-ui/runtime/plugins/shadcn";
93
+ defineOptions({ inheritAttrs: false });
94
+ const props = defineProps({
95
+ class: { type: null, required: false },
96
+ id: { type: String, required: false, default: "input-tag-modal" },
97
+ name: { type: String, required: false, default: "input-tag-modal" },
98
+ label: { type: String, required: false },
99
+ placeholder: { type: String, required: false, default: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E41\u0E17\u0E47\u0E01" },
100
+ searchPlaceholder: { type: String, required: false, default: "\u0E04\u0E49\u0E19\u0E2B\u0E32\u0E41\u0E17\u0E47\u0E01" },
101
+ title: { type: String, required: false, default: "\u0E41\u0E17\u0E47\u0E01\u0E17\u0E35\u0E48\u0E40\u0E01\u0E35\u0E48\u0E22\u0E27\u0E02\u0E49\u0E2D\u0E07" },
102
+ description: { type: String, required: false },
103
+ rules: { type: [Object, String, Function], required: false },
104
+ options: { type: Array, required: false, default: () => [] },
105
+ fetchFn: { type: Function, required: false },
106
+ valueKey: { type: String, required: false, default: "value" },
107
+ labelKey: { type: String, required: false, default: "label" },
108
+ pageSize: { type: Number, required: false, default: 30 },
109
+ required: { type: Boolean, required: false, default: false },
110
+ disabled: { type: Boolean, required: false, default: false },
111
+ disabledErrorMessage: { type: Boolean, required: false, default: false },
112
+ clearable: { type: Boolean, required: false, default: true },
113
+ loading: { type: Boolean, required: false, default: false }
114
+ });
115
+ const emit = defineEmits(["open", "select", "clear", "fetch-error"]);
116
+ const modelValue = defineModel({ type: [String, Number, null], ...{ default: null } });
117
+ const fieldRef = ref(null);
118
+ const isOpenModal = ref(false);
119
+ const searchKeyword = ref("");
120
+ const selectedOptionCache = ref(null);
121
+ const suppressSearchWatch = ref(false);
122
+ const remoteState = reactive({
123
+ data: [],
124
+ page: 1,
125
+ hasMore: true,
126
+ loading: false,
127
+ lastSearch: "",
128
+ generation: 0
129
+ });
130
+ const hasValue = computed(
131
+ () => modelValue.value !== null && modelValue.value !== void 0 && modelValue.value !== ""
132
+ );
133
+ const optionKey = (option) => `${typeof option.value}:${String(option.value)}`;
134
+ const mergeOptions = (current, incoming) => {
135
+ const map = new Map(current.map((option) => [optionKey(option), option]));
136
+ incoming.forEach((option) => map.set(optionKey(option), option));
137
+ return Array.from(map.values());
138
+ };
139
+ const mapRemoteOption = (item) => {
140
+ if (typeof item !== "object" || item === null) return null;
141
+ const record = item;
142
+ const rawValue = record[props.valueKey];
143
+ const rawLabel = record[props.labelKey];
144
+ if (rawValue === void 0 || rawValue === null || rawLabel === void 0) {
145
+ return null;
146
+ }
147
+ return {
148
+ value: typeof rawValue === "number" ? rawValue : String(rawValue),
149
+ label: String(rawLabel)
150
+ };
151
+ };
152
+ const resolvedOptions = computed(
153
+ () => props.fetchFn ? remoteState.data : props.options
154
+ );
155
+ const filteredOptions = computed(() => {
156
+ if (props.fetchFn) return resolvedOptions.value;
157
+ const query = searchKeyword.value.trim().toLocaleLowerCase("th");
158
+ if (!query) return resolvedOptions.value;
159
+ return resolvedOptions.value.filter(
160
+ (option) => option.label.toLocaleLowerCase("th").includes(query)
161
+ );
162
+ });
163
+ const knownOptions = computed(
164
+ () => mergeOptions(props.options, remoteState.data)
165
+ );
166
+ watch(
167
+ [modelValue, knownOptions],
168
+ ([value, options]) => {
169
+ if (value === null || value === void 0 || value === "") {
170
+ selectedOptionCache.value = null;
171
+ return;
172
+ }
173
+ const found = options.find((option) => option.value === value);
174
+ if (found) {
175
+ selectedOptionCache.value = found;
176
+ return;
177
+ }
178
+ if (selectedOptionCache.value?.value !== value) {
179
+ selectedOptionCache.value = null;
180
+ }
181
+ },
182
+ { immediate: true, deep: true }
183
+ );
184
+ const displayValue = computed({
185
+ get: () => selectedOptionCache.value?.label ?? "",
186
+ set: () => void 0
187
+ });
188
+ const appendIcon = computed(
189
+ () => hasValue.value && props.clearable ? "lucide:x" : "lucide:chevron-down"
190
+ );
191
+ const isInitialLoading = computed(
192
+ () => (props.loading || remoteState.loading) && filteredOptions.value.length === 0
193
+ );
194
+ const isLoadingMore = computed(
195
+ () => !!props.fetchFn && remoteState.loading && remoteState.data.length > 0
196
+ );
197
+ const fetchRemote = async (reset = false, search = searchKeyword.value.trim()) => {
198
+ if (!props.fetchFn) return;
199
+ if (!reset && (remoteState.loading || !remoteState.hasMore)) return;
200
+ let generation = remoteState.generation;
201
+ if (reset) {
202
+ generation = remoteState.generation + 1;
203
+ remoteState.generation = generation;
204
+ remoteState.page = 1;
205
+ remoteState.data = [];
206
+ remoteState.hasMore = true;
207
+ remoteState.loading = false;
208
+ remoteState.lastSearch = search;
209
+ }
210
+ if (remoteState.loading) return;
211
+ const page = remoteState.page;
212
+ remoteState.loading = true;
213
+ try {
214
+ const response = await props.fetchFn(
215
+ page,
216
+ props.pageSize,
217
+ search || void 0
218
+ );
219
+ if (generation !== remoteState.generation) return;
220
+ const mapped = (response.data ?? []).map(mapRemoteOption).filter((option) => option !== null);
221
+ remoteState.data = reset ? mergeOptions([], mapped) : mergeOptions(remoteState.data, mapped);
222
+ const totalPages = Number(response.meta?.total_pages ?? 1);
223
+ remoteState.page = page + 1;
224
+ remoteState.hasMore = page < totalPages;
225
+ } catch (error) {
226
+ if (generation === remoteState.generation) {
227
+ remoteState.hasMore = false;
228
+ emit("fetch-error", error);
229
+ console.error("InputTagModal: Failed to fetch options:", error);
230
+ }
231
+ } finally {
232
+ if (generation === remoteState.generation) {
233
+ remoteState.loading = false;
234
+ }
235
+ }
236
+ };
237
+ const debouncedRemoteSearch = useDebounceFn(() => {
238
+ void fetchRemote(true);
239
+ }, 300);
240
+ watch(searchKeyword, () => {
241
+ if (!props.fetchFn || !isOpenModal.value || suppressSearchWatch.value) return;
242
+ debouncedRemoteSearch();
243
+ });
244
+ watch(
245
+ () => props.fetchFn,
246
+ () => {
247
+ remoteState.generation += 1;
248
+ remoteState.data = [];
249
+ remoteState.page = 1;
250
+ remoteState.hasMore = true;
251
+ remoteState.loading = false;
252
+ remoteState.lastSearch = "";
253
+ }
254
+ );
255
+ const onOpenModal = async () => {
256
+ if (props.disabled) return;
257
+ suppressSearchWatch.value = true;
258
+ searchKeyword.value = "";
259
+ isOpenModal.value = true;
260
+ emit("open");
261
+ await nextTick();
262
+ suppressSearchWatch.value = false;
263
+ if (props.fetchFn && (remoteState.data.length === 0 || remoteState.lastSearch !== "")) {
264
+ await fetchRemote(true, "");
265
+ }
266
+ };
267
+ const onAppendClick = () => {
268
+ if (props.disabled) return;
269
+ if (hasValue.value && props.clearable) {
270
+ modelValue.value = null;
271
+ selectedOptionCache.value = null;
272
+ emit("clear");
273
+ return;
274
+ }
275
+ void onOpenModal();
276
+ };
277
+ const onSelectOption = (option) => {
278
+ modelValue.value = option.value;
279
+ selectedOptionCache.value = option;
280
+ emit("select", option);
281
+ isOpenModal.value = false;
282
+ };
283
+ const isSelected = (option) => option.value === modelValue.value;
284
+ const onListScroll = (event) => {
285
+ if (!props.fetchFn || remoteState.loading || !remoteState.hasMore) return;
286
+ const target = event.currentTarget;
287
+ if (!target) return;
288
+ const distanceFromBottom = target.scrollHeight - target.scrollTop - target.clientHeight;
289
+ if (distanceFromBottom < 48) {
290
+ void fetchRemote();
291
+ }
292
+ };
293
+ const reload = async () => {
294
+ if (!props.fetchFn) return;
295
+ await fetchRemote(true);
296
+ };
297
+ const setErrors = (errors) => {
298
+ fieldRef.value?.setErrors?.(errors);
299
+ };
300
+ const validate = async () => await fieldRef.value?.validate?.();
301
+ defineExpose({
302
+ setErrors,
303
+ validate,
304
+ reload,
305
+ fieldRef
306
+ });
307
+ </script>
@@ -0,0 +1,52 @@
1
+ import type { InputTagModalOption, InputTagModalProps } from "../../../types/components/input/input-tag-modal.js";
2
+ interface InputTextFieldExpose {
3
+ setErrors?: (errors: string[]) => void;
4
+ validate?: () => Promise<unknown>;
5
+ }
6
+ type __VLS_Props = InputTagModalProps;
7
+ type __VLS_ModelProps = {
8
+ modelValue?: string | number | null;
9
+ };
10
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
11
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
12
+ setErrors: (errors: string[]) => void;
13
+ validate: () => Promise<unknown>;
14
+ reload: () => Promise<void>;
15
+ fieldRef: import("vue").Ref<{
16
+ setErrors?: ((errors: string[]) => void) | undefined;
17
+ validate?: (() => Promise<unknown>) | undefined;
18
+ } | null, InputTextFieldExpose | {
19
+ setErrors?: ((errors: string[]) => void) | undefined;
20
+ validate?: (() => Promise<unknown>) | undefined;
21
+ } | null>;
22
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
23
+ "update:modelValue": (value: string | number | null) => any;
24
+ } & {
25
+ select: (option: InputTagModalOption) => any;
26
+ clear: () => any;
27
+ open: () => any;
28
+ "fetch-error": (error: unknown) => any;
29
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
30
+ onSelect?: ((option: InputTagModalOption) => any) | undefined;
31
+ onClear?: (() => any) | undefined;
32
+ "onUpdate:modelValue"?: ((value: string | number | null) => any) | undefined;
33
+ onOpen?: (() => any) | undefined;
34
+ "onFetch-error"?: ((error: unknown) => any) | undefined;
35
+ }>, {
36
+ title: string;
37
+ loading: boolean;
38
+ disabled: boolean;
39
+ pageSize: number;
40
+ id: string;
41
+ name: string;
42
+ required: boolean;
43
+ options: InputTagModalOption[];
44
+ labelKey: string;
45
+ placeholder: string;
46
+ disabledErrorMessage: boolean;
47
+ valueKey: string;
48
+ searchPlaceholder: string;
49
+ clearable: boolean;
50
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
51
+ declare const _default: typeof __VLS_export;
52
+ export default _default;
@@ -59,8 +59,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
59
59
  id: string;
60
60
  name: string;
61
61
  required: boolean;
62
- readonly: boolean;
63
62
  limit: number;
63
+ readonly: boolean;
64
64
  disabledErrorMessage: boolean;
65
65
  disabledBorder: boolean;
66
66
  showCounter: boolean;
@@ -59,8 +59,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
59
59
  id: string;
60
60
  name: string;
61
61
  required: boolean;
62
- readonly: boolean;
63
62
  limit: number;
63
+ readonly: boolean;
64
64
  disabledErrorMessage: boolean;
65
65
  disabledBorder: boolean;
66
66
  showCounter: boolean;
@@ -47,8 +47,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
47
47
  fullHeight: boolean;
48
48
  fullWidth: boolean;
49
49
  rows: number;
50
- readonly: boolean;
51
50
  limit: number;
51
+ readonly: boolean;
52
52
  disabledErrorMessage: boolean;
53
53
  disabledBorder: boolean;
54
54
  showCounter: boolean;
@@ -47,8 +47,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
47
47
  fullHeight: boolean;
48
48
  fullWidth: boolean;
49
49
  rows: number;
50
- readonly: boolean;
51
50
  limit: number;
51
+ readonly: boolean;
52
52
  disabledErrorMessage: boolean;
53
53
  disabledBorder: boolean;
54
54
  showCounter: boolean;
@@ -25,7 +25,7 @@
25
25
 
26
26
  <script setup>
27
27
  import { computed, ref } from "vue";
28
- const emit = defineEmits(["profile-edit", "profile-share", "profile-follower-delete", "profile-block", "blog-pin", "blog-unpin", "blog-edit", "blog-delete", "report-blog", "report-place", "report-profile", "report-content", "delete-content", "content-delete", "delete", "report", "report-review", "place-close-duplicate", "review-edit", "review-delete", "review-reply", "reply-edit", "reply-delete", "archive", "profile-name-updated", "report-submit"]);
28
+ const emit = defineEmits(["profile-edit", "profile-share", "profile-follower-delete", "profile-block", "blog-pin", "blog-unpin", "blog-edit", "blog-delete", "report-blog", "report-place", "report-profile", "report-content", "report-spotlight", "report-tag", "report-label", "delete-content", "content-delete", "delete", "report", "report-review", "place-close-duplicate", "review-edit", "review-delete", "review-reply", "reply-edit", "reply-delete", "archive", "profile-name-updated", "report-submit"]);
29
29
  const props = defineProps({
30
30
  state: { type: String, required: false },
31
31
  profileDetail: { type: Object, required: false },
@@ -173,6 +173,39 @@ const menu = [
173
173
  emit("report");
174
174
  }
175
175
  },
176
+ {
177
+ label: "\u0E23\u0E32\u0E22\u0E07\u0E32\u0E19\u0E2B\u0E31\u0E27\u0E02\u0E49\u0E2D\u0E41\u0E19\u0E30\u0E19\u0E33\u0E19\u0E35\u0E49",
178
+ name: "report-spotlight",
179
+ icon: "lucide:flag",
180
+ action: () => {
181
+ reportState.value = "spotlight";
182
+ isOpenModalReport.value = true;
183
+ emit("report-spotlight");
184
+ emit("report");
185
+ }
186
+ },
187
+ {
188
+ label: "\u0E23\u0E32\u0E22\u0E07\u0E32\u0E19\u0E41\u0E17\u0E47\u0E01\u0E19\u0E35\u0E49",
189
+ name: "report-tag",
190
+ icon: "lucide:flag",
191
+ action: () => {
192
+ reportState.value = "tag";
193
+ isOpenModalReport.value = true;
194
+ emit("report-tag");
195
+ emit("report");
196
+ }
197
+ },
198
+ {
199
+ label: "\u0E23\u0E32\u0E22\u0E07\u0E32\u0E19\u0E2B\u0E21\u0E27\u0E14\u0E2B\u0E21\u0E39\u0E48\u0E19\u0E35\u0E49",
200
+ name: "report-label",
201
+ icon: "lucide:flag",
202
+ action: () => {
203
+ reportState.value = "label";
204
+ isOpenModalReport.value = true;
205
+ emit("report-label");
206
+ emit("report");
207
+ }
208
+ },
176
209
  {
177
210
  label: "\u0E25\u0E1A\u0E40\u0E19\u0E37\u0E49\u0E2D\u0E2B\u0E32\u0E19\u0E35\u0E49",
178
211
  name: "delete-content",
@@ -302,6 +335,21 @@ const items = computed(() => {
302
335
  (item) => ["report-content"].includes(item.name)
303
336
  );
304
337
  }
338
+ if (props.state === "spotlight") {
339
+ return menu.filter(
340
+ (item) => ["report-spotlight"].includes(item.name)
341
+ );
342
+ }
343
+ if (props.state === "tag") {
344
+ return menu.filter(
345
+ (item) => ["report-tag"].includes(item.name)
346
+ );
347
+ }
348
+ if (props.state === "label") {
349
+ return menu.filter(
350
+ (item) => ["report-label"].includes(item.name)
351
+ );
352
+ }
305
353
  if (props.state === "delete-content") {
306
354
  return menu.filter(
307
355
  (item) => ["delete-content", "content-delete"].includes(item.name)
@@ -3,6 +3,7 @@ export const useApi = () => {
3
3
  const config = useRuntimeConfig();
4
4
  const baseURL = config.public.BASE_URL_API;
5
5
  const provinceIdState = useState("pukaad:province-id", () => null);
6
+ const businessProfileId = useCookie("PUKAAD_BUSINESS_PROFILE_ID");
6
7
  const configProvinceId = config.public.APP_PROVINCE_ID;
7
8
  const { APP_TYPE } = config.public;
8
9
  const secId = useCookie(
@@ -22,6 +23,9 @@ export const useApi = () => {
22
23
  if (pid) {
23
24
  headers.set("X-Province-ID", String(pid));
24
25
  }
26
+ if (businessProfileId.value) {
27
+ headers.set("X-Business-Profile-ID", businessProfileId.value);
28
+ }
25
29
  options.headers = headers;
26
30
  },
27
31
  onResponseError({ response }) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pukaad-ui-lib",
3
- "version": "1.419.0",
3
+ "version": "1.421.0",
4
4
  "description": "pukaad-ui for MeMSG",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,3 +0,0 @@
1
- declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
- declare const _default: typeof __VLS_export;
3
- export default _default;
@@ -1,57 +0,0 @@
1
- <template>
2
- <!-- <InputTextField
3
- :name="props.name"
4
- :label="props.label"
5
- :placeholder="props.placeholder"
6
- :full-width="props.fullWidth"
7
- :width="props.width"
8
- :height="props.height"
9
- :required="props.required"
10
- :disabled="props.disabled"
11
- :readonly="props.readonly"
12
- :append-icon="props.appendIcon"
13
- @click="isOpenModal = true"
14
- @clickAppendIcon="isOpenModal = true"
15
- @reset="isOpenModal = true"
16
- reset
17
- v-model="selectedTag"
18
- />
19
- <Modal
20
- v-model="isOpenModal"
21
- title="แท็กที่เกี่ยวข้อง"
22
- :gap="16"
23
- :width="604"
24
- :height="670"
25
- >
26
- <div class="space-y-[16px]">
27
- <InputSearch v-model="search" placeholder="ค้นหาแท็ก" full-width />
28
- <Divider :height="0" />
29
- <div
30
- v-if="filteredTags.length > 0"
31
- class="flex flex-wrap gap-[8px] h-[526px] overflow-y-auto"
32
- >
33
- <Chip
34
- v-for="tag in filteredTags"
35
- :key="tag"
36
- size="small"
37
- :color="selectedTag === tag ? 'primary' : 'default'"
38
- class="cursor-pointer"
39
- @click="onSelectTag(tag)"
40
- >
41
- {{ tag }}
42
- </Chip>
43
- </div>
44
- <div
45
- v-else
46
- class="flex flex-col gap-[8px] items-center justify-center h-[526px]"
47
- >
48
- <Icon name="pukaad:page-not-found" size="100" />
49
- <div class="text-gray font-body-large">ไม่พบข้อมูล</div>
50
- </div>
51
- </div>
52
- </Modal> -->
53
- </template>
54
-
55
- <script setup>
56
-
57
- </script>
@@ -1,3 +0,0 @@
1
- declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
- declare const _default: typeof __VLS_export;
3
- export default _default;