@finema/finework-layer 2.0.28 → 2.0.29

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/CHANGELOG.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.29](https://gitlab.finema.co/finema/finework/finework-frontend-layer/compare/2.0.28...2.0.29) (2026-08-18)
4
+
3
5
  ## [2.0.28](https://gitlab.finema.co/finema/finework/finework-frontend-layer/compare/2.0.27...2.0.28) (2026-08-18)
4
6
 
5
7
  ## [2.0.27](https://gitlab.finema.co/finema/finework/finework-frontend-layer/compare/2.0.26...2.0.27) (2026-08-16)
package/app/app.vue CHANGED
@@ -6,6 +6,6 @@
6
6
  }"
7
7
  >
8
8
  <NuxtPage />
9
- <!-- <IssueLog /> -->
9
+ <FeedbackTicket />
10
10
  </App>
11
11
  </template>
@@ -23,13 +23,13 @@
23
23
  แจ้งปัญหา / ขอ Feature
24
24
  </h2>
25
25
  <p class="text-xs text-gray-500">
26
- Issue Log
26
+ Feedback Ticket
27
27
  </p>
28
28
  </div>
29
29
  </div>
30
30
  <div class="flex items-center gap-1">
31
31
  <NuxtLink
32
- :to="routes.issueLog.issues.to"
32
+ :to="routes.feedbackTicket.tickets.to"
33
33
  class="flex size-8 cursor-pointer items-center justify-center rounded-lg text-gray-400 transition hover:bg-gray-100 hover:text-gray-600"
34
34
  title="ดูรายการทั้งหมด"
35
35
  @click="emit('update', false)"
@@ -87,8 +87,9 @@
87
87
 
88
88
  <script lang="ts" setup>
89
89
  import { UserModuleOptions } from '#layer/app/composables/useAuth'
90
- import { IssueLogTypeOptions } from '#layer/app/constants/issue-log/type'
91
- import { useIssueLogAddLoader } from '#layer/app/loaders/issue-log/issue-log'
90
+ import { FeedbackTicketCategoryOptions } from '#layer/app/constants/feedback-ticket/category'
91
+ import { FeedbackTicketPriority, FeedbackTicketPriorityOptions } from '#layer/app/constants/feedback-ticket/priority'
92
+ import { useFeedbackTicketAddLoader } from '#layer/app/loaders/feedback/ticket'
92
93
 
93
94
  const emit = defineEmits<{
94
95
  (e: 'update', value: boolean): void
@@ -99,7 +100,7 @@ defineProps<{
99
100
  isOpen: boolean
100
101
  }>()
101
102
 
102
- const addLoader = useIssueLogAddLoader()
103
+ const addLoader = useFeedbackTicketAddLoader()
103
104
  const noti = useNotification()
104
105
 
105
106
  const form = useForm({
@@ -107,15 +108,20 @@ const form = useForm({
107
108
  v.object({
108
109
  title: v.pipe(v.string(), v.minLength(1, 'กรุณาระบุหัวข้อ')),
109
110
  description: v.pipe(v.string(), v.minLength(1, 'กรุณาระบุรายละเอียด')),
110
- type: v.pipe(v.string(), v.minLength(1, 'กรุณาเลือกประเภท')),
111
+ category: v.pipe(v.string(), v.minLength(1, 'กรุณาเลือกประเภท')),
112
+ priority: v.optional(v.string(), FeedbackTicketPriority.LOW),
111
113
  app: v.nullish(v.string()),
112
- file: v.nullish(v.object({
113
- url: v.string(),
114
- name: v.string(),
115
- path: v.string(),
116
- size: v.number(),
117
- id: v.string(),
118
- })),
114
+ files: v.nullish(
115
+ v.array(
116
+ v.object({
117
+ url: v.string(),
118
+ name: v.string(),
119
+ path: v.string(),
120
+ size: v.number(),
121
+ id: v.string(),
122
+ }),
123
+ ),
124
+ ),
119
125
  }),
120
126
  ),
121
127
  })
@@ -146,18 +152,27 @@ const formFields = createFormFields(() => [
146
152
  },
147
153
  {
148
154
  type: INPUT_TYPES.SELECT,
149
- class: 'col-span-2',
150
155
  props: {
151
156
  form,
152
- name: 'type',
157
+ name: 'category',
153
158
  label: 'ประเภท',
154
159
  placeholder: 'เลือกประเภท',
155
- options: IssueLogTypeOptions,
160
+ options: FeedbackTicketCategoryOptions,
156
161
  required: true,
157
162
  },
158
163
  },
159
164
  {
160
- type: INPUT_TYPES.TEXTAREA,
165
+ type: INPUT_TYPES.SELECT,
166
+ props: {
167
+ form,
168
+ name: 'priority',
169
+ label: 'ความสำคัญ',
170
+ placeholder: 'เลือกความสำคัญ',
171
+ options: FeedbackTicketPriorityOptions,
172
+ },
173
+ },
174
+ {
175
+ type: INPUT_TYPES.WYSIWYG,
161
176
  class: 'col-span-2',
162
177
  props: {
163
178
  form,
@@ -169,11 +184,11 @@ const formFields = createFormFields(() => [
169
184
  },
170
185
  },
171
186
  {
172
- type: INPUT_TYPES.UPLOAD_DROPZONE_AUTO,
187
+ type: INPUT_TYPES.UPLOAD_DROPZONE_AUTO_MULTIPLE,
173
188
  class: 'col-span-2',
174
189
  props: {
175
190
  form,
176
- name: 'file_id',
191
+ name: 'files',
177
192
  label: 'แนบรูปภาพ (ถ้ามี)',
178
193
  placeholder: 'PNG, JPG, GIF, WEBP (สูงสุด 5MB)',
179
194
  requestOptions: useRequestOptions().file(FileAppType.COMMON),
@@ -185,10 +200,7 @@ const formFields = createFormFields(() => [
185
200
 
186
201
  const onSubmit = form.handleSubmit((values) => {
187
202
  addLoader.run({
188
- data: {
189
- ...values,
190
- file_id: values.file?.id,
191
- },
203
+ data: values,
192
204
  })
193
205
  })
194
206
 
@@ -12,7 +12,7 @@
12
12
  </button>
13
13
  </div>
14
14
 
15
- <IssueLogFormIssue
15
+ <FeedbackTicketForm
16
16
  :is-open="isOpen"
17
17
  @update="(v) => isOpen = v"
18
18
  @success="isOpen = false"
@@ -0,0 +1,16 @@
1
+ export enum FeedbackTicketCategory {
2
+ BUG = 'BUG',
3
+ FEATURE_REQUEST = 'FEATURE_REQUEST',
4
+ IMPROVEMENT = 'IMPROVEMENT',
5
+ }
6
+
7
+ export const FeedbackTicketCategoryLabel: Record<FeedbackTicketCategory, string> = {
8
+ [FeedbackTicketCategory.BUG]: 'Report Bug',
9
+ [FeedbackTicketCategory.FEATURE_REQUEST]: 'Request Feature',
10
+ [FeedbackTicketCategory.IMPROVEMENT]: 'Improve',
11
+ }
12
+
13
+ export const FeedbackTicketCategoryOptions = Object.entries(FeedbackTicketCategoryLabel).map(([value, label]) => ({
14
+ value,
15
+ label,
16
+ }))
@@ -0,0 +1,18 @@
1
+ export enum FeedbackTicketPriority {
2
+ CRITICAL = 'CRITICAL',
3
+ HIGH = 'HIGH',
4
+ MEDIUM = 'MEDIUM',
5
+ LOW = 'LOW',
6
+ }
7
+
8
+ export const FeedbackTicketPriorityLabel: Record<FeedbackTicketPriority, string> = {
9
+ [FeedbackTicketPriority.CRITICAL]: 'Critical',
10
+ [FeedbackTicketPriority.HIGH]: 'High',
11
+ [FeedbackTicketPriority.MEDIUM]: 'Medium',
12
+ [FeedbackTicketPriority.LOW]: 'Low',
13
+ }
14
+
15
+ export const FeedbackTicketPriorityOptions = Object.entries(FeedbackTicketPriorityLabel).map(([value, label]) => ({
16
+ value,
17
+ label,
18
+ }))
@@ -244,10 +244,10 @@ export const routes = {
244
244
  permissions: ['setting:USER', 'setting:ADMIN', 'setting:SUPER'],
245
245
  },
246
246
  },
247
- issueLog: {
248
- issues: {
249
- label: 'Issue Log',
250
- to: '/issue-logs',
247
+ feedbackTicket: {
248
+ tickets: {
249
+ label: 'Feedback Tickets',
250
+ to: '/feedback/tickets',
251
251
  icon: 'ph:bug-beetle',
252
252
  },
253
253
  },
@@ -1,28 +1,28 @@
1
- export const useIssueLogPageLoader = () => {
1
+ export const useFeedbackTicketPageLoader = () => {
2
2
  const options = useRequestOptions()
3
3
 
4
4
  return usePageLoader({
5
- baseURL: `/issue-logs`,
5
+ baseURL: `/feedback/tickets`,
6
6
  getBaseRequestOptions: options.auth,
7
7
  })
8
8
  }
9
9
 
10
- export const useIssueLogAddLoader = () => {
10
+ export const useFeedbackTicketAddLoader = () => {
11
11
  const options = useRequestOptions()
12
12
 
13
13
  return useObjectLoader({
14
14
  method: 'POST',
15
- url: `/issue-logs`,
15
+ url: `/feedback/tickets`,
16
16
  getRequestOptions: options.auth,
17
17
  })
18
18
  }
19
19
 
20
- export const useIssueLogDeleteLoader = (id: string) => {
20
+ export const useFeedbackTicketDeleteLoader = (id: string) => {
21
21
  const options = useRequestOptions()
22
22
 
23
23
  return useObjectLoader({
24
24
  method: 'DELETE',
25
- url: `/issue-logs/${id}`,
25
+ url: `/feedback/tickets/${id}`,
26
26
  getRequestOptions: options.auth,
27
27
  })
28
28
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@finema/finework-layer",
3
3
  "type": "module",
4
- "version": "2.0.28",
4
+ "version": "2.0.29",
5
5
  "main": "./nuxt.config.ts",
6
6
  "scripts": {
7
7
  "dev": "nuxi dev .playground -o",
@@ -1,16 +0,0 @@
1
- <template>
2
- <Badge
3
- variant="outline"
4
- :leading-icon="IssueLogPriorityIcon[props.value]"
5
- :color="IssueLogPriorityColor[props.value]"
6
- :label="IssueLogPriorityLabel[props.value]"
7
- />
8
- </template>
9
-
10
- <script lang="ts" setup>
11
- import { IssueLogPriorityColor, IssueLogPriorityIcon, IssueLogPriorityLabel, type IssueLogPriority } from '#layer/app/constants/issue-log/priority'
12
-
13
- const props = defineProps<{
14
- value: IssueLogPriority
15
- }>()
16
- </script>
@@ -1,16 +0,0 @@
1
- <template>
2
- <Badge
3
- variant="outline"
4
- leading-icon="ci:dot-04-l"
5
- :color="IssueLogStatusColor[props.value]"
6
- :label="IssueLogStatusLabel[props.value]"
7
- />
8
- </template>
9
-
10
- <script lang="ts" setup>
11
- import { IssueLogStatusColor, IssueLogStatusLabel, type IssueLogStatus } from '#layer/app/constants/issue-log/status'
12
-
13
- const props = defineProps<{
14
- value: IssueLogStatus
15
- }>()
16
- </script>
@@ -1,16 +0,0 @@
1
- <template>
2
- <Badge
3
- variant="outline"
4
- :leading-icon="IssueLogTypeIcon[props.value]"
5
- :color="IssueLogTypeColor[props.value]"
6
- :label="IssueLogTypeLabel[props.value]"
7
- />
8
- </template>
9
-
10
- <script lang="ts" setup>
11
- import { IssueLogTypeColor, IssueLogTypeIcon, IssueLogTypeLabel, type IssueLogType } from '#layer/app/constants/issue-log/type'
12
-
13
- const props = defineProps<{
14
- value: IssueLogType
15
- }>()
16
- </script>
@@ -1,35 +0,0 @@
1
- export enum IssueLogPriority {
2
- CRITICAL = 'CRITICAL',
3
- HIGH = 'HIGH',
4
- MEDIUM = 'MEDIUM',
5
- LOW = 'LOW',
6
- }
7
-
8
- export const IssueLogPriorityLabel: Record<IssueLogPriority, string> = {
9
- [IssueLogPriority.CRITICAL]: 'Critical',
10
- [IssueLogPriority.HIGH]: 'High',
11
- [IssueLogPriority.MEDIUM]: 'Medium',
12
- [IssueLogPriority.LOW]: 'Low',
13
- }
14
-
15
- export const IssueLogPriorityColor: Record<IssueLogPriority, 'info' | 'neutral' | 'success' | 'warning' | 'error'> = {
16
- [IssueLogPriority.CRITICAL]: 'error',
17
- [IssueLogPriority.HIGH]: 'warning',
18
- [IssueLogPriority.MEDIUM]: 'info',
19
- [IssueLogPriority.LOW]: 'neutral',
20
- }
21
-
22
- export const IssueLogPriorityIcon: Record<IssueLogPriority, string> = {
23
- [IssueLogPriority.CRITICAL]: 'ph:warning-circle-fill',
24
- [IssueLogPriority.HIGH]: 'ph:arrow-up',
25
- [IssueLogPriority.MEDIUM]: 'ph:minus',
26
- [IssueLogPriority.LOW]: 'ph:arrow-down',
27
- }
28
-
29
- export const IssueLogPriorityOptions = Object.entries(IssueLogPriorityLabel).map(([value, label]) => ({
30
- value,
31
- label,
32
- chip: {
33
- color: IssueLogPriorityColor[value as IssueLogPriority],
34
- },
35
- }))
@@ -1,7 +0,0 @@
1
- export const issueLogRoutes = {
2
- issues: {
3
- label: 'Issue Log',
4
- to: '/issue-logs',
5
- icon: 'ph:bug-beetle',
6
- },
7
- } as const
@@ -1,31 +0,0 @@
1
- export enum IssueLogStatus {
2
- OPEN = 'OPEN',
3
- IN_PROGRESS = 'IN_PROGRESS',
4
- RESOLVED = 'RESOLVED',
5
- CLOSED = 'CLOSED',
6
- DUPLICATE = 'DUPLICATE',
7
- }
8
-
9
- export const IssueLogStatusLabel: Record<IssueLogStatus, string> = {
10
- [IssueLogStatus.OPEN]: 'เปิด',
11
- [IssueLogStatus.IN_PROGRESS]: 'กำลังดำเนินการ',
12
- [IssueLogStatus.RESOLVED]: 'แก้ไขแล้ว',
13
- [IssueLogStatus.CLOSED]: 'ปิด',
14
- [IssueLogStatus.DUPLICATE]: 'ซ้ำกับที่แจ้งแล้ว',
15
- }
16
-
17
- export const IssueLogStatusColor: Record<IssueLogStatus, 'info' | 'neutral' | 'success' | 'warning' | 'error'> = {
18
- [IssueLogStatus.OPEN]: 'info',
19
- [IssueLogStatus.IN_PROGRESS]: 'warning',
20
- [IssueLogStatus.RESOLVED]: 'success',
21
- [IssueLogStatus.CLOSED]: 'error',
22
- [IssueLogStatus.DUPLICATE]: 'error',
23
- }
24
-
25
- export const IssueLogStatusOptions = Object.entries(IssueLogStatusLabel).map(([value, label]) => ({
26
- value,
27
- label,
28
- chip: {
29
- color: IssueLogStatusColor[value as IssueLogStatus],
30
- },
31
- }))
@@ -1,80 +0,0 @@
1
- export enum IssueLogType {
2
- BUG = 'BUG',
3
- FEATURE_REQUEST = 'FEATURE_REQUEST',
4
- IMPROVEMENT = 'IMPROVEMENT',
5
- }
6
-
7
- export const IssueLogTypeLabel: Record<IssueLogType, string> = {
8
- [IssueLogType.BUG]: 'Report Bug',
9
- [IssueLogType.FEATURE_REQUEST]: 'Request Feature',
10
- [IssueLogType.IMPROVEMENT]: 'Improve',
11
- }
12
-
13
- export const IssueLogTypeColor: Record<IssueLogType, 'info' | 'neutral' | 'success' | 'warning' | 'error'> = {
14
- [IssueLogType.BUG]: 'error',
15
- [IssueLogType.FEATURE_REQUEST]: 'info',
16
- [IssueLogType.IMPROVEMENT]: 'warning',
17
- }
18
-
19
- export const IssueLogTypeIcon: Record<IssueLogType, string> = {
20
- [IssueLogType.BUG]: 'ph:bug',
21
- [IssueLogType.FEATURE_REQUEST]: 'ph:sparkle',
22
- [IssueLogType.IMPROVEMENT]: 'ph:wrench',
23
- }
24
-
25
- export const IssueLogTypeOptions = Object.entries(IssueLogTypeLabel).map(([value, label]) => ({
26
- value,
27
- label,
28
- chip: {
29
- color: IssueLogTypeColor[value as IssueLogType],
30
- },
31
- }))
32
-
33
- const UserModuleLabel = {
34
- [UserModule.CHECKIN]: 'Clock-In',
35
- [UserModule.TIMESHEET]: 'Timesheet',
36
- [UserModule.TODO]: 'Todo',
37
- [UserModule.PMO]: 'PMO',
38
- [UserModule.REQUEST]: 'Request',
39
- [UserModule.SETTING]: 'Setting',
40
- [UserModule.QUOTATION]: 'Quotation',
41
- [UserModule.COSTSHEET]: 'Cost Sheet',
42
- [UserModule.NEWSLETTER]: 'Newsletter',
43
- [UserModule.CONTRACT]: 'Contract',
44
- [UserModule.EVALUATION]: 'Evaluation',
45
- [UserModule.EMPLOYEE]: 'Employee',
46
- [UserModule.ASSET]: 'Asset',
47
- [UserModule.RECRUIT]: 'Recruit',
48
- [UserModule.LG]: 'งบค้ำประกัน',
49
- [UserModule.EFACTORING]: 'E-Factoring',
50
- [UserModule.RESOURCE]: 'Resource',
51
- }
52
-
53
- const UserModuleLogo = {
54
- [UserModule.CHECKIN]: '/admin/clock-in-logo.png',
55
- [UserModule.TIMESHEET]: '/admin/timesheet-logo.png',
56
- [UserModule.TODO]: '/admin/todo.png',
57
- [UserModule.PMO]: '/admin/pmo-logo.png',
58
- [UserModule.REQUEST]: '/admin/request.png',
59
- [UserModule.SETTING]: '/admin/report.svg',
60
- [UserModule.QUOTATION]: '/admin/quotation.png',
61
- [UserModule.COSTSHEET]: '/admin/cost-sheet.png',
62
- [UserModule.NEWSLETTER]: '/admin/newsletter.png',
63
- [UserModule.CONTRACT]: '/admin/contract.png',
64
- [UserModule.EVALUATION]: '/admin/evaluation.png',
65
- [UserModule.EMPLOYEE]: '/admin/employee.png',
66
- [UserModule.ASSET]: '/admin/assets.png',
67
- [UserModule.RECRUIT]: '/admin/recruit.png',
68
- [UserModule.LG]: '/admin/guarantee.png',
69
- [UserModule.EFACTORING]: '/admin/efactoring.png',
70
- [UserModule.RESOURCE]: '/admin/resource.svg',
71
- }
72
-
73
- export const UserModuleOptions = Object.entries(UserModuleLabel).map(([value, label]) => ({
74
- value,
75
- label,
76
- avatar: {
77
- src: UserModuleLogo[value as keyof typeof UserModuleLogo],
78
- alt: label,
79
- },
80
- }))