pukaad-ui-lib 1.360.0 → 1.362.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.360.0",
4
+ "version": "1.362.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
@@ -1,4 +1,5 @@
1
1
  export interface CarouselItem {
2
+ id?: string | number;
2
3
  url: string;
3
4
  description?: string;
4
5
  }
@@ -1,4 +1,5 @@
1
1
  export interface CarouselItem {
2
+ id?: string | number;
2
3
  url: string;
3
4
  description?: string;
4
5
  }
@@ -1,4 +1,6 @@
1
+ import { type HTMLAttributes } from "vue";
1
2
  export interface MediaItem {
3
+ id?: string | number;
2
4
  url: string;
3
5
  description?: string;
4
6
  }
@@ -8,6 +10,8 @@ type __VLS_Props = {
8
10
  variant?: "featured" | "album";
9
11
  state?: "personal" | "office" | "business";
10
12
  title?: string;
13
+ placeId?: string | number;
14
+ class?: HTMLAttributes["class"];
11
15
  };
12
16
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
13
17
  title: string;
@@ -2,7 +2,7 @@
2
2
  <!-- Personal state → Featured layout — 1 รูป: w-full -->
3
3
  <div
4
4
  v-if="layoutMode === 'featured' && photos.length === 1"
5
- class="h-[360px]"
5
+ :class="cn('h-[360px]', props.class)"
6
6
  >
7
7
  <div
8
8
  class="w-full h-full rounded-[8px] overflow-hidden cursor-pointer"
@@ -20,7 +20,7 @@
20
20
  <!-- Personal state → Featured layout — 2 รูป: แบ่งครึ่ง w-full -->
21
21
  <div
22
22
  v-else-if="layoutMode === 'featured' && photos.length === 2"
23
- class="flex gap-[8px] h-[360px]"
23
+ :class="cn('flex gap-[8px] h-[360px]', props.class)"
24
24
  >
25
25
  <div
26
26
  class="flex-1 rounded-[8px] overflow-hidden cursor-pointer"
@@ -47,7 +47,10 @@
47
47
  </div>
48
48
 
49
49
  <!-- Personal state → Featured layout — 3+ รูป: layout เดิม -->
50
- <div v-else-if="layoutMode === 'featured'" class="flex gap-[8px] h-[360px]">
50
+ <div
51
+ v-else-if="layoutMode === 'featured'"
52
+ :class="cn('flex gap-[8px] h-[360px]', props.class)"
53
+ >
51
54
  <div
52
55
  v-if="photos[0]"
53
56
  class="w-[620px] shrink-0 rounded-[8px] overflow-hidden cursor-pointer"
@@ -140,7 +143,10 @@
140
143
  </div>
141
144
 
142
145
  <!-- Office / Business state → Album layout -->
143
- <div v-else-if="layoutMode === 'album'" class="grid grid-cols-5 gap-[10px]">
146
+ <div
147
+ v-else-if="layoutMode === 'album'"
148
+ :class="cn('grid grid-cols-5 gap-[10px]', props.class)"
149
+ >
144
150
  <!-- Row 1: photos[0..3] -->
145
151
  <div
146
152
  v-for="(photo, i) in galleryRow1"
@@ -222,19 +228,24 @@
222
228
  :title="props.title"
223
229
  :start-index="mediaStartIndex"
224
230
  :uploader-label="uploaderLabel"
231
+ :place-id="props.placeId"
225
232
  />
226
233
  </template>
227
234
 
228
235
  <script setup>
229
236
  import { computed, ref } from "vue";
230
237
  import { useConvert } from "../../composables/useConvert";
238
+ import { cn } from "../../plugins/shadcn";
239
+ defineOptions({ inheritAttrs: false });
231
240
  const { convertNumber } = useConvert();
232
241
  const props = defineProps({
233
242
  photos: { type: Array, required: false, default: () => [] },
234
243
  videos: { type: Array, required: false, default: () => [] },
235
244
  variant: { type: String, required: false },
236
245
  state: { type: String, required: false, default: "personal" },
237
- title: { type: String, required: false, default: "" }
246
+ title: { type: String, required: false, default: "" },
247
+ placeId: { type: [String, Number], required: false },
248
+ class: { type: null, required: false }
238
249
  });
239
250
  const layoutMode = computed(() => {
240
251
  if (props.variant) return props.variant;
@@ -1,4 +1,6 @@
1
+ import { type HTMLAttributes } from "vue";
1
2
  export interface MediaItem {
3
+ id?: string | number;
2
4
  url: string;
3
5
  description?: string;
4
6
  }
@@ -8,6 +10,8 @@ type __VLS_Props = {
8
10
  variant?: "featured" | "album";
9
11
  state?: "personal" | "office" | "business";
10
12
  title?: string;
13
+ placeId?: string | number;
14
+ class?: HTMLAttributes["class"];
11
15
  };
12
16
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
13
17
  title: string;
@@ -48,10 +48,10 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
48
48
  id: string;
49
49
  name: string;
50
50
  required: boolean;
51
- labelKey: string;
52
- placeholder: string;
53
51
  options: AutocompleteOption[] | string[] | number[];
54
52
  description: string;
53
+ labelKey: string;
54
+ placeholder: string;
55
55
  limit: number;
56
56
  disabledErrorMessage: boolean;
57
57
  disabledBorder: boolean;
@@ -48,10 +48,10 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
48
48
  id: string;
49
49
  name: string;
50
50
  required: boolean;
51
- labelKey: string;
52
- placeholder: string;
53
51
  options: AutocompleteOption[] | string[] | number[];
54
52
  description: string;
53
+ labelKey: string;
54
+ placeholder: string;
55
55
  limit: number;
56
56
  disabledErrorMessage: boolean;
57
57
  disabledBorder: boolean;
@@ -11,8 +11,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
11
11
  label: string;
12
12
  name: string;
13
13
  modelValue: LocalizedNameItem[];
14
- placeholder: string;
15
14
  options: InputSelectItem[];
15
+ placeholder: string;
16
16
  limit: number;
17
17
  showCounter: boolean;
18
18
  addLabel: string;
@@ -11,8 +11,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
11
11
  label: string;
12
12
  name: string;
13
13
  modelValue: LocalizedNameItem[];
14
- placeholder: string;
15
14
  options: InputSelectItem[];
15
+ placeholder: string;
16
16
  limit: number;
17
17
  showCounter: boolean;
18
18
  addLabel: string;
@@ -19,9 +19,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
19
19
  id: string;
20
20
  name: string;
21
21
  required: boolean;
22
+ description: string;
22
23
  labelKey: string;
23
24
  placeholder: string;
24
- description: string;
25
25
  limit: number;
26
26
  disabledErrorMessage: boolean;
27
27
  disabledBorder: boolean;
@@ -19,9 +19,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
19
19
  id: string;
20
20
  name: string;
21
21
  required: boolean;
22
+ description: string;
22
23
  labelKey: string;
23
24
  placeholder: string;
24
- description: string;
25
25
  limit: number;
26
26
  disabledErrorMessage: boolean;
27
27
  disabledBorder: boolean;
@@ -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
- placeholder: string;
29
28
  state: "user" | "admin";
29
+ placeholder: string;
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
- placeholder: string;
29
28
  state: "user" | "admin";
29
+ placeholder: string;
30
30
  limit: number;
31
31
  ignore: string[];
32
32
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -8,6 +8,8 @@ export interface ModalMediaViewProps {
8
8
  review?: CardReviewProps;
9
9
  /** ป้ายชื่อผู้ดูแลสื่อนี้ ที่แสดงใน overlay (โหมดไม่ใช่ review) — office = "ผู้ดูแลระบบ", business = "ฝ่ายจัดการ" */
10
10
  uploaderLabel?: string;
11
+ /** placeId ของสถานที่เจ้าของสื่อนี้ — ใช้ยิง POST /suggest-places/:id/reports ตอนกดรายงาน */
12
+ placeId?: string | number;
11
13
  }
12
14
  type __VLS_Props = ModalMediaViewProps;
13
15
  type __VLS_ModelProps = {
@@ -174,22 +174,44 @@
174
174
 
175
175
  <script setup>
176
176
  import { ref, computed } from "vue";
177
+ import { useNuxtApp } from "nuxt/app";
177
178
  import { useConvert } from "../../composables/useConvert";
179
+ import { useApi } from "../../composables/useApi";
178
180
  const { convertNumber, convertDateTorelativeText } = useConvert();
181
+ const api = useApi();
182
+ const { $toast } = useNuxtApp();
179
183
  const props = defineProps({
180
184
  items: { type: Array, required: false, default: () => [] },
181
185
  title: { type: String, required: false, default: "" },
182
186
  startIndex: { type: Number, required: false, default: 0 },
183
187
  review: { type: Object, required: false },
184
- uploaderLabel: { type: String, required: false, default: "\u0E1C\u0E39\u0E49\u0E14\u0E39\u0E41\u0E25\u0E23\u0E30\u0E1A\u0E1A" }
188
+ uploaderLabel: { type: String, required: false, default: "\u0E1C\u0E39\u0E49\u0E14\u0E39\u0E41\u0E25\u0E23\u0E30\u0E1A\u0E1A" },
189
+ placeId: { type: [String, Number], required: false }
185
190
  });
186
191
  const isOpen = defineModel({ type: Boolean, ...{ default: false } });
187
192
  const showMoreDescription = ref(false);
188
193
  const currentIndex = ref(props.startIndex ?? 0);
189
194
  const isOpenModalReport = ref(false);
190
195
  const currentItem = computed(() => props.items[currentIndex.value] ?? null);
191
- const onReportSubmit = (payload) => {
192
- console.log("report payload:", payload);
196
+ const onReportSubmit = async (payload) => {
197
+ if (!props.placeId || !currentItem.value?.id) {
198
+ isOpenModalReport.value = false;
199
+ return;
200
+ }
201
+ try {
202
+ await api(`/suggest-places/${props.placeId}/reports`, {
203
+ method: "post",
204
+ body: {
205
+ media_id: String(currentItem.value.id),
206
+ reason_code: payload.value,
207
+ description: payload.description
208
+ }
209
+ });
210
+ $toast?.success("\u0E2A\u0E48\u0E07\u0E23\u0E32\u0E22\u0E07\u0E32\u0E19\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08 !");
211
+ } catch (error) {
212
+ console.error(error);
213
+ $toast?.error("\u0E40\u0E01\u0E34\u0E14\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14 \u0E01\u0E23\u0E38\u0E13\u0E32\u0E25\u0E2D\u0E07\u0E43\u0E2B\u0E21\u0E48\u0E2D\u0E35\u0E01\u0E04\u0E23\u0E31\u0E49\u0E07 !");
214
+ }
193
215
  isOpenModalReport.value = false;
194
216
  };
195
217
  </script>
@@ -8,6 +8,8 @@ export interface ModalMediaViewProps {
8
8
  review?: CardReviewProps;
9
9
  /** ป้ายชื่อผู้ดูแลสื่อนี้ ที่แสดงใน overlay (โหมดไม่ใช่ review) — office = "ผู้ดูแลระบบ", business = "ฝ่ายจัดการ" */
10
10
  uploaderLabel?: string;
11
+ /** placeId ของสถานที่เจ้าของสื่อนี้ — ใช้ยิง POST /suggest-places/:id/reports ตอนกดรายงาน */
12
+ placeId?: string | number;
11
13
  }
12
14
  type __VLS_Props = ModalMediaViewProps;
13
15
  type __VLS_ModelProps = {
@@ -11,7 +11,7 @@
11
11
  <div
12
12
  v-for="(item, i) in items"
13
13
  :key="i"
14
- class="flex flex-col border-bright px-[8px] py-[6px] border-b"
14
+ class="flex flex-col border-bright px-[8px] py-[6px] border-b last:border-b-0"
15
15
  >
16
16
  <InputRadio
17
17
  name="report_value"
@@ -58,7 +58,7 @@ const props = defineProps({
58
58
  });
59
59
  const placeEditOptions = [
60
60
  { label: "\u0E1B\u0E34\u0E14\u0E2B\u0E23\u0E37\u0E2D\u0E2B\u0E22\u0E38\u0E14\u0E01\u0E34\u0E08\u0E01\u0E32\u0E23\u0E41\u0E25\u0E49\u0E27", value: "closed" },
61
- { label: "\u0E44\u0E21\u0E48\u0E2D\u0E22\u0E39\u0E48\u0E17\u0E35\u0E48\u0E19\u0E35\u0E48", value: "not_exist" },
61
+ { label: "\u0E44\u0E21\u0E48\u0E21\u0E35\u0E2D\u0E22\u0E39\u0E48\u0E17\u0E35\u0E48\u0E19\u0E35\u0E48", value: "not_exist" },
62
62
  { label: "\u0E0B\u0E49\u0E33\u0E01\u0E31\u0E1A\u0E2A\u0E16\u0E32\u0E19\u0E17\u0E35\u0E48\u0E2D\u0E37\u0E48\u0E19", value: "duplicate" },
63
63
  { label: "\u0E22\u0E49\u0E32\u0E22\u0E44\u0E1B\u0E22\u0E31\u0E07\u0E15\u0E33\u0E41\u0E2B\u0E19\u0E48\u0E07\u0E17\u0E35\u0E48\u0E15\u0E31\u0E49\u0E07\u0E43\u0E2B\u0E21\u0E48\u0E41\u0E25\u0E49\u0E27", value: "relocated" },
64
64
  { label: "\u0E2D\u0E37\u0E48\u0E19\u0E46", value: "other" }
@@ -67,7 +67,10 @@ const mediaOptions = [
67
67
  { label: "\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E2B\u0E23\u0E37\u0E2D\u0E27\u0E34\u0E14\u0E35\u0E42\u0E2D\u0E44\u0E21\u0E48\u0E40\u0E2B\u0E21\u0E32\u0E30\u0E2A\u0E21", value: "inappropriate" },
68
68
  { label: "\u0E02\u0E49\u0E2D\u0E01\u0E31\u0E07\u0E27\u0E25\u0E40\u0E01\u0E35\u0E48\u0E22\u0E27\u0E01\u0E31\u0E1A\u0E04\u0E27\u0E32\u0E21\u0E40\u0E1B\u0E47\u0E19\u0E2A\u0E48\u0E27\u0E19\u0E15\u0E31\u0E27", value: "privacy" },
69
69
  { label: "\u0E04\u0E38\u0E13\u0E20\u0E32\u0E1E\u0E15\u0E48\u0E33", value: "low_quality" },
70
- { label: "\u0E40\u0E19\u0E37\u0E49\u0E2D\u0E2B\u0E32\u0E17\u0E35\u0E48\u0E21\u0E38\u0E48\u0E07\u0E23\u0E49\u0E32\u0E22 \u0E40\u0E1B\u0E47\u0E19\u0E2D\u0E31\u0E19\u0E15\u0E23\u0E32\u0E22 \u0E2B\u0E23\u0E37\u0E2D\u0E21\u0E35\u0E04\u0E27\u0E32\u0E21\u0E23\u0E38\u0E19\u0E41\u0E23\u0E07", value: "harmful" },
70
+ {
71
+ label: "\u0E40\u0E19\u0E37\u0E49\u0E2D\u0E2B\u0E32\u0E17\u0E35\u0E48\u0E21\u0E38\u0E48\u0E07\u0E23\u0E49\u0E32\u0E22 \u0E40\u0E1B\u0E47\u0E19\u0E2D\u0E31\u0E19\u0E15\u0E23\u0E32\u0E22 \u0E2B\u0E23\u0E37\u0E2D\u0E21\u0E35\u0E04\u0E27\u0E32\u0E21\u0E23\u0E38\u0E19\u0E41\u0E23\u0E07",
72
+ value: "harmful"
73
+ },
71
74
  { label: "\u0E44\u0E21\u0E48\u0E43\u0E0A\u0E48\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E\u0E2B\u0E23\u0E37\u0E2D\u0E27\u0E34\u0E14\u0E35\u0E42\u0E2D\u0E02\u0E2D\u0E07\u0E2A\u0E16\u0E32\u0E19\u0E17\u0E35\u0E48\u0E19\u0E35\u0E49", value: "wrong_place" },
72
75
  { label: "\u0E2D\u0E37\u0E48\u0E19\u0E46", value: "other" }
73
76
  ];
@@ -44,7 +44,7 @@ const isOpenModalReport = ref(false);
44
44
  const isOpenModalProfileEdit = ref(false);
45
45
  const reportState = ref("place-edit");
46
46
  const onReportSubmit = (payload) => {
47
- console.log(payload);
47
+ emit("report-submit", payload);
48
48
  isOpenModalReport.value = false;
49
49
  };
50
50
  const menu = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pukaad-ui-lib",
3
- "version": "1.360.0",
3
+ "version": "1.362.0",
4
4
  "description": "pukaad-ui for MeMSG",
5
5
  "repository": {
6
6
  "type": "git",