pukaad-ui-lib 1.234.0 → 1.235.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-user-blog.d.vue.ts +2 -2
- package/dist/runtime/components/card/card-user-blog.vue +51 -7
- package/dist/runtime/components/card/card-user-blog.vue.d.ts +2 -2
- package/dist/runtime/components/drawer/drawer-post-blog.vue +54 -31
- package/dist/runtime/components/input/input-tag.vue +2 -2
- package/dist/runtime/components/picker/picker-option-menu/picker-option-menu-user.d.vue.ts +2 -2
- package/dist/runtime/components/picker/picker-option-menu/picker-option-menu-user.vue.d.ts +2 -2
- package/package.json +1 -1
- /package/dist/runtime/assets/svg/socials/{WhatsApp.svg → Whatsapp.svg} +0 -0
package/dist/module.json
CHANGED
|
@@ -24,9 +24,9 @@ type __VLS_Props = {
|
|
|
24
24
|
isMyProfile?: boolean;
|
|
25
25
|
};
|
|
26
26
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
27
|
-
"blog-
|
|
27
|
+
"blog-updated": () => any;
|
|
28
28
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
29
|
-
"onBlog-
|
|
29
|
+
"onBlog-updated"?: (() => any) | undefined;
|
|
30
30
|
}>, {
|
|
31
31
|
isMyProfile: boolean;
|
|
32
32
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -74,20 +74,34 @@
|
|
|
74
74
|
state="blog"
|
|
75
75
|
/>
|
|
76
76
|
</div>
|
|
77
|
+
|
|
78
|
+
<!-- Edit Blog Drawer -->
|
|
79
|
+
<DrawerPostBlog
|
|
80
|
+
v-if="editBlogItem"
|
|
81
|
+
v-model="isEditDrawerOpen"
|
|
82
|
+
:item="editBlogItem"
|
|
83
|
+
@success="onEditSuccess"
|
|
84
|
+
/>
|
|
77
85
|
</template>
|
|
78
86
|
|
|
79
87
|
<script setup>
|
|
80
88
|
import { useRouter } from "vue-router";
|
|
81
89
|
import { ref, watch } from "vue";
|
|
90
|
+
import { useNuxtApp } from "nuxt/app";
|
|
82
91
|
import { useConvert } from "@/runtime/composables/useConvert";
|
|
92
|
+
import { useApi } from "../../composables/useApi";
|
|
83
93
|
const { convertNumber, convertDateTorelativeText } = useConvert();
|
|
94
|
+
const { $toast } = useNuxtApp();
|
|
95
|
+
const api = useApi();
|
|
84
96
|
const props = defineProps({
|
|
85
97
|
item: { type: Object, required: true },
|
|
86
98
|
isMyProfile: { type: Boolean, required: false, default: false }
|
|
87
99
|
});
|
|
88
100
|
const router = useRouter();
|
|
89
|
-
const emit = defineEmits(["blog-
|
|
101
|
+
const emit = defineEmits(["blog-updated"]);
|
|
90
102
|
const isPinned = ref(props.item.ispinned);
|
|
103
|
+
const isEditDrawerOpen = ref(false);
|
|
104
|
+
const editBlogItem = ref(null);
|
|
91
105
|
watch(
|
|
92
106
|
() => props.item.ispinned,
|
|
93
107
|
(val) => {
|
|
@@ -97,16 +111,46 @@ watch(
|
|
|
97
111
|
const onProfileClick = () => {
|
|
98
112
|
router.push(`/@${props.item.user.path_name}`);
|
|
99
113
|
};
|
|
100
|
-
const onBlogPin = () => {
|
|
101
|
-
|
|
114
|
+
const onBlogPin = async () => {
|
|
115
|
+
try {
|
|
116
|
+
await api(`/blogs/${props.item.id}/pin`, { method: "POST" });
|
|
117
|
+
isPinned.value = true;
|
|
118
|
+
$toast.success("\u0E1B\u0E31\u0E01\u0E2B\u0E21\u0E38\u0E14\u0E1A\u0E17\u0E04\u0E27\u0E32\u0E21\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08");
|
|
119
|
+
} catch (e) {
|
|
120
|
+
$toast.error(e?.data?.message?.description || "\u0E44\u0E21\u0E48\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E1B\u0E31\u0E01\u0E2B\u0E21\u0E38\u0E14\u0E44\u0E14\u0E49");
|
|
121
|
+
}
|
|
102
122
|
};
|
|
103
|
-
const onBlogUnpin = () => {
|
|
104
|
-
|
|
123
|
+
const onBlogUnpin = async () => {
|
|
124
|
+
try {
|
|
125
|
+
await api(`/blogs/${props.item.id}/pin`, { method: "DELETE" });
|
|
126
|
+
isPinned.value = false;
|
|
127
|
+
$toast.success("\u0E40\u0E2D\u0E32\u0E2B\u0E21\u0E38\u0E14\u0E2D\u0E2D\u0E01\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08");
|
|
128
|
+
} catch (e) {
|
|
129
|
+
$toast.error(e?.data?.message?.description || "\u0E44\u0E21\u0E48\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E40\u0E2D\u0E32\u0E2B\u0E21\u0E38\u0E14\u0E2D\u0E2D\u0E01\u0E44\u0E14\u0E49");
|
|
130
|
+
}
|
|
105
131
|
};
|
|
106
132
|
const onBlogClick = () => {
|
|
107
133
|
router.push(`/blog/${props.item.id}`);
|
|
108
134
|
};
|
|
109
|
-
const onBlogEdit = () => {
|
|
110
|
-
|
|
135
|
+
const onBlogEdit = async () => {
|
|
136
|
+
try {
|
|
137
|
+
const res = await api(`/blogs/${props.item.id}`, { method: "GET" });
|
|
138
|
+
const blog = res.data;
|
|
139
|
+
const content = blog.content?.ops ?? (Array.isArray(blog.content) ? blog.content : []);
|
|
140
|
+
editBlogItem.value = {
|
|
141
|
+
id: blog.id,
|
|
142
|
+
title: blog.title,
|
|
143
|
+
content,
|
|
144
|
+
tags: blog.tags ?? [],
|
|
145
|
+
disableComment: false,
|
|
146
|
+
coverImage: blog.cover_image_url ? [{ url: blog.cover_image_url }] : []
|
|
147
|
+
};
|
|
148
|
+
isEditDrawerOpen.value = true;
|
|
149
|
+
} catch (e) {
|
|
150
|
+
$toast.error(e?.data?.message?.description || "\u0E44\u0E21\u0E48\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E42\u0E2B\u0E25\u0E14\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E1A\u0E17\u0E04\u0E27\u0E32\u0E21\u0E44\u0E14\u0E49");
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
const onEditSuccess = () => {
|
|
154
|
+
emit("blog-updated");
|
|
111
155
|
};
|
|
112
156
|
</script>
|
|
@@ -24,9 +24,9 @@ type __VLS_Props = {
|
|
|
24
24
|
isMyProfile?: boolean;
|
|
25
25
|
};
|
|
26
26
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
27
|
-
"blog-
|
|
27
|
+
"blog-updated": () => any;
|
|
28
28
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
29
|
-
"onBlog-
|
|
29
|
+
"onBlog-updated"?: (() => any) | undefined;
|
|
30
30
|
}>, {
|
|
31
31
|
isMyProfile: boolean;
|
|
32
32
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -1,13 +1,37 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<Drawer
|
|
3
|
-
|
|
2
|
+
<Drawer
|
|
3
|
+
class="w-[748px]"
|
|
4
|
+
:title="drawerTitle"
|
|
5
|
+
@close="onClose"
|
|
6
|
+
disabled-auto-close
|
|
7
|
+
@submit="onSubmit"
|
|
8
|
+
v-model="isOpen"
|
|
9
|
+
>
|
|
4
10
|
<div class="flex flex-col gap-[16px]">
|
|
5
|
-
<InputTextField
|
|
6
|
-
|
|
11
|
+
<InputTextField
|
|
12
|
+
name="title"
|
|
13
|
+
label="หัวข้อ"
|
|
14
|
+
placeholder="ตั้งชื่อบทความให้น่าสนใจ"
|
|
15
|
+
showCounter
|
|
16
|
+
:limit="180"
|
|
17
|
+
v-model="form.title"
|
|
18
|
+
disabled-border
|
|
19
|
+
required
|
|
20
|
+
/>
|
|
7
21
|
|
|
8
|
-
<InputContent
|
|
22
|
+
<InputContent
|
|
23
|
+
placeholder="อยากเล่าอะไร"
|
|
24
|
+
:height="288"
|
|
25
|
+
v-model="form.content"
|
|
26
|
+
/>
|
|
9
27
|
|
|
10
|
-
<InputTag
|
|
28
|
+
<InputTag
|
|
29
|
+
v-model="form.tags"
|
|
30
|
+
name="tags"
|
|
31
|
+
label="แท็ก"
|
|
32
|
+
placeholder="เพิ่มแท็ก"
|
|
33
|
+
:limit="5"
|
|
34
|
+
/>
|
|
11
35
|
|
|
12
36
|
<!-- <InputCheckbox
|
|
13
37
|
name="disableComment"
|
|
@@ -17,8 +41,12 @@
|
|
|
17
41
|
|
|
18
42
|
<div class="flex flex-col gap-[8px]">
|
|
19
43
|
<div class="text-gray font-body-large">ภาพหน้าปก</div>
|
|
20
|
-
<InputFile
|
|
21
|
-
|
|
44
|
+
<InputFile
|
|
45
|
+
:limit="1"
|
|
46
|
+
name="coverImage"
|
|
47
|
+
accept="image/jpeg,image/png,image/webp,image/bmp,image/gif"
|
|
48
|
+
v-model="form.coverImage"
|
|
49
|
+
/>
|
|
22
50
|
<div class="flex flex-col text-gray font-body-small">
|
|
23
51
|
<div>รองรับไฟล์ *.jpg *.jpeg *.png *.webp *.bmp *.gif</div>
|
|
24
52
|
<div>ขนาดไม่เกิน 30 mb</div>
|
|
@@ -30,7 +58,11 @@
|
|
|
30
58
|
<div class="flex justify-end gap-[16px] items-center">
|
|
31
59
|
<Button variant="outline" @click="onClose">ยกเลิก</Button>
|
|
32
60
|
<Button @click="onSaveDraft"> บันทึกแบบร่าง </Button>
|
|
33
|
-
<Button
|
|
61
|
+
<Button
|
|
62
|
+
type="submit"
|
|
63
|
+
color="primary"
|
|
64
|
+
:disabled="!meta.valid || isLoading"
|
|
65
|
+
>
|
|
34
66
|
<span v-if="isLoading">กำลังบันทึก...</span>
|
|
35
67
|
<span v-else>เผยแพร่</span>
|
|
36
68
|
</Button>
|
|
@@ -99,10 +131,6 @@ const uploadImage = async (file) => {
|
|
|
99
131
|
method: "POST",
|
|
100
132
|
headers: {
|
|
101
133
|
"Content-Type": "application/json"
|
|
102
|
-
// Note: We might need Auth token here if the endpoint requires it,
|
|
103
|
-
// but user instruction said "ห้าม ส่ง Authorization Header ไปยัง S3"
|
|
104
|
-
// It didn't say forbid Auth to /storage/presigned-urls.
|
|
105
|
-
// Let's try adding token manually if useApi was doing it.
|
|
106
134
|
},
|
|
107
135
|
body: JSON.stringify({
|
|
108
136
|
file_name: [file.name],
|
|
@@ -119,8 +147,8 @@ const uploadImage = async (file) => {
|
|
|
119
147
|
}
|
|
120
148
|
}
|
|
121
149
|
});
|
|
122
|
-
if (
|
|
123
|
-
throw new Error(
|
|
150
|
+
if (!res.data?.items?.[0]) {
|
|
151
|
+
throw new Error("\u0E44\u0E21\u0E48\u0E2A\u0E32\u0E21\u0E32\u0E23\u0E16\u0E2A\u0E23\u0E49\u0E32\u0E07 upload URL \u0E44\u0E14\u0E49");
|
|
124
152
|
}
|
|
125
153
|
const item = res.data.items[0];
|
|
126
154
|
console.log("Uploading to S3:", item.upload_url);
|
|
@@ -155,24 +183,19 @@ const onSubmit = async () => {
|
|
|
155
183
|
tags: form.value.tags.map((t) => t.name || t),
|
|
156
184
|
cover_image_url: coverImageUrl
|
|
157
185
|
};
|
|
158
|
-
const res = await api(
|
|
159
|
-
isEditMode.value ?
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
186
|
+
const res = await api(isEditMode.value ? `/blogs/${form.value.id}` : "/profiles/me/blog", {
|
|
187
|
+
method: isEditMode.value ? "PUT" : "POST",
|
|
188
|
+
body: payload
|
|
189
|
+
});
|
|
190
|
+
$toast.success(
|
|
191
|
+
isEditMode.value ? "\u0E2D\u0E31\u0E1B\u0E40\u0E14\u0E15\u0E1A\u0E17\u0E04\u0E27\u0E32\u0E21\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08" : "\u0E2A\u0E23\u0E49\u0E32\u0E07\u0E1A\u0E17\u0E04\u0E27\u0E32\u0E21\u0E2A\u0E33\u0E40\u0E23\u0E47\u0E08"
|
|
164
192
|
);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
emit("submit", form.value);
|
|
169
|
-
emit("success", res.data);
|
|
170
|
-
isOpen.value = false;
|
|
171
|
-
} else {
|
|
172
|
-
throw new Error(res.message || "\u0E40\u0E01\u0E34\u0E14\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14");
|
|
173
|
-
}
|
|
193
|
+
emit("submit", form.value);
|
|
194
|
+
emit("success", res.data);
|
|
195
|
+
isOpen.value = false;
|
|
174
196
|
} catch (error) {
|
|
175
|
-
|
|
197
|
+
const msg = error?.data?.message?.description || error?.message || "\u0E40\u0E01\u0E34\u0E14\u0E02\u0E49\u0E2D\u0E1C\u0E34\u0E14\u0E1E\u0E25\u0E32\u0E14\u0E43\u0E19\u0E01\u0E32\u0E23\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01\u0E1A\u0E17\u0E04\u0E27\u0E32\u0E21";
|
|
198
|
+
$toast.error(msg);
|
|
176
199
|
console.error("Submit error:", error);
|
|
177
200
|
} finally {
|
|
178
201
|
isLoading.value = false;
|
|
@@ -207,11 +207,11 @@ const fetchTags = async (type) => {
|
|
|
207
207
|
const res = await api(
|
|
208
208
|
`/tags/${type}?page=${state.page}&page_size=${PAGE_SIZE}`
|
|
209
209
|
);
|
|
210
|
-
if (
|
|
210
|
+
if (res.data && Array.isArray(res.data)) {
|
|
211
211
|
const newTags = res.data.map(mapTag);
|
|
212
212
|
state.data = [...state.data, ...newTags];
|
|
213
213
|
state.page++;
|
|
214
|
-
state.hasMore = state.page <= res.meta
|
|
214
|
+
state.hasMore = state.page <= (res.meta?.total_page ?? 1);
|
|
215
215
|
} else {
|
|
216
216
|
state.hasMore = false;
|
|
217
217
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { PickerOptionMenuUserProps } from "@/types/components/picker/picker-option-menu/picker-option-menu-user";
|
|
2
2
|
declare const __VLS_export: import("vue").DefineComponent<PickerOptionMenuUserProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
3
|
-
"blog-edit": () => any;
|
|
4
3
|
"report-announce": () => any;
|
|
5
4
|
"blog-unpin": () => any;
|
|
6
5
|
"blog-pin": () => any;
|
|
6
|
+
"blog-edit": () => any;
|
|
7
7
|
"profile-name-updated": (name: string) => any;
|
|
8
8
|
"profile-edit": () => any;
|
|
9
9
|
"profile-share": () => any;
|
|
@@ -19,10 +19,10 @@ declare const __VLS_export: import("vue").DefineComponent<PickerOptionMenuUserPr
|
|
|
19
19
|
"review-delete": () => any;
|
|
20
20
|
archive: () => any;
|
|
21
21
|
}, string, import("vue").PublicProps, Readonly<PickerOptionMenuUserProps> & Readonly<{
|
|
22
|
-
"onBlog-edit"?: (() => any) | undefined;
|
|
23
22
|
"onReport-announce"?: (() => any) | undefined;
|
|
24
23
|
"onBlog-unpin"?: (() => any) | undefined;
|
|
25
24
|
"onBlog-pin"?: (() => any) | undefined;
|
|
25
|
+
"onBlog-edit"?: (() => any) | undefined;
|
|
26
26
|
"onProfile-name-updated"?: ((name: string) => any) | undefined;
|
|
27
27
|
"onProfile-edit"?: (() => any) | undefined;
|
|
28
28
|
"onProfile-share"?: (() => any) | undefined;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { PickerOptionMenuUserProps } from "@/types/components/picker/picker-option-menu/picker-option-menu-user";
|
|
2
2
|
declare const __VLS_export: import("vue").DefineComponent<PickerOptionMenuUserProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
3
|
-
"blog-edit": () => any;
|
|
4
3
|
"report-announce": () => any;
|
|
5
4
|
"blog-unpin": () => any;
|
|
6
5
|
"blog-pin": () => any;
|
|
6
|
+
"blog-edit": () => any;
|
|
7
7
|
"profile-name-updated": (name: string) => any;
|
|
8
8
|
"profile-edit": () => any;
|
|
9
9
|
"profile-share": () => any;
|
|
@@ -19,10 +19,10 @@ declare const __VLS_export: import("vue").DefineComponent<PickerOptionMenuUserPr
|
|
|
19
19
|
"review-delete": () => any;
|
|
20
20
|
archive: () => any;
|
|
21
21
|
}, string, import("vue").PublicProps, Readonly<PickerOptionMenuUserProps> & Readonly<{
|
|
22
|
-
"onBlog-edit"?: (() => any) | undefined;
|
|
23
22
|
"onReport-announce"?: (() => any) | undefined;
|
|
24
23
|
"onBlog-unpin"?: (() => any) | undefined;
|
|
25
24
|
"onBlog-pin"?: (() => any) | undefined;
|
|
25
|
+
"onBlog-edit"?: (() => any) | undefined;
|
|
26
26
|
"onProfile-name-updated"?: ((name: string) => any) | undefined;
|
|
27
27
|
"onProfile-edit"?: (() => any) | undefined;
|
|
28
28
|
"onProfile-share"?: (() => any) | undefined;
|
package/package.json
CHANGED
|
File without changes
|