@neutron.co.id/operasional-interfaces 1.17.30 → 1.17.32

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.
Files changed (30) hide show
  1. package/build/@office/config.mjs +3 -0
  2. package/build/@office/models/personalia/submission/SubmissionAction/SubmissionAction.vue +313 -0
  3. package/build/@office/models/personalia/submission/SubmissionAction/SubmissionActionDecision.vue +189 -0
  4. package/build/@office/models/personalia/submission/SubmissionAction/index.d.ts +2 -0
  5. package/build/@office/models/personalia/submission/SubmissionAction/index.mjs +2 -0
  6. package/build/@office/models/personalia/submission/SubmissionAudit.vue +76 -35
  7. package/build/@office/models/personalia/submission/SubmissionFollowUp.vue +4 -1
  8. package/build/@office/models/personalia/submission/SubmissionForDecision.vue +4 -1
  9. package/build/@office/models/personalia/submission/SubmissionNoteModal/SubmissionNoteModal.vue +94 -0
  10. package/build/@office/models/personalia/submission/SubmissionNoteModal/SubmissionNoteViewModal.vue +149 -0
  11. package/build/@office/models/personalia/submission/SubmissionNoteModal/index.d.ts +1 -0
  12. package/build/@office/models/personalia/submission/SubmissionNoteModal/index.mjs +1 -0
  13. package/build/@office/models/personalia/submission/SubmissionStaff.vue +14 -0
  14. package/build/@office/models/personalia/submission/SubmissionSupervisor.vue +4 -1
  15. package/build/@office/models/personalia/submission/index.d.ts +2 -0
  16. package/build/@office/models/personalia/submission/index.mjs +2 -0
  17. package/build/@package/@office/models/personalia/submission/SubmissionAction/SubmissionAction.vue.d.ts +2 -0
  18. package/build/@package/@office/models/personalia/submission/SubmissionAction/SubmissionActionDecision.vue.d.ts +2 -0
  19. package/build/@package/@office/models/personalia/submission/SubmissionAction/index.d.ts +2 -0
  20. package/build/@package/@office/models/personalia/submission/SubmissionNoteModal/SubmissionNoteModal.vue.d.ts +56 -0
  21. package/build/@package/@office/models/personalia/submission/SubmissionNoteModal/SubmissionNoteViewModal.vue.d.ts +46 -0
  22. package/build/@package/@office/models/personalia/submission/SubmissionNoteModal/index.d.ts +1 -0
  23. package/build/@package/@office/models/personalia/submission/index.d.ts +2 -0
  24. package/build/mock/index.cjs +1114 -471
  25. package/build/mock/index.mjs +1116 -473
  26. package/build/mock/style.css +232 -14
  27. package/build/module.json +1 -1
  28. package/build/nuxt.json +1 -1
  29. package/build/nuxt.mjs +3 -0
  30. package/package.json +5 -5
@@ -100,6 +100,9 @@ export const config = OfficeInterfaces.define({
100
100
  "SubmissionSupervisor",
101
101
  "SubmissionWaitingDecision",
102
102
  "SubmissionForDecision",
103
+ "SubmissionAction",
104
+ "SubmissionActionDecision",
105
+ "SubmissionNoteModal",
103
106
  // Submission Type
104
107
  "SubmissionTypeCollection",
105
108
  "SubmissionTypeSingle",
@@ -0,0 +1,313 @@
1
+ <script setup lang="ts">
2
+ import { useSingle } from '@neon.id/context'
3
+ import {
4
+ NeonButton,
5
+ NeonLabel,
6
+ NeonModal,
7
+ NeonModalDialog,
8
+ useToastStore,
9
+ } from '@neon.id/interfaces'
10
+ import type {
11
+ TPersonaliaSubmissionModel,
12
+ Schema,
13
+ } from '@neutron.co.id/personalia-models'
14
+ import { computed, onMounted, ref, watch } from 'vue'
15
+ import { ofetch } from 'ofetch'
16
+ import SubmissionNoteModal from '../SubmissionNoteModal/SubmissionNoteModal.vue'
17
+ import SubmissionNoteViewModal from '../SubmissionNoteModal/SubmissionNoteViewModal.vue'
18
+ import { apiUrl, useOperasional } from '../../../../common'
19
+
20
+ defineOptions({ name: 'SubmissionAction' })
21
+
22
+ const { isNew, values, id, isLoading } = useSingle<
23
+ Schema.Submission,
24
+ TPersonaliaSubmissionModel
25
+ >()
26
+
27
+ const toast = useToastStore()
28
+
29
+ const staff = useOperasional()
30
+ const isDirector = computed(() => {
31
+ const staffRoles = staff.staff.value?.user?.roles?.map((item) => item.handle)
32
+ if (
33
+ staffRoles?.includes('neu:pengambilKeputusan') ||
34
+ staffRoles?.includes('neu:pimpinan')
35
+ ) {
36
+ return true
37
+ }
38
+
39
+ return false
40
+ })
41
+
42
+ const actions = {
43
+ prepared: {
44
+ iconLeft: 'pen-line',
45
+ label: 'Disiapkan',
46
+ color: 'base',
47
+ },
48
+ raised: {
49
+ iconLeft: 'arrow-up-from-line',
50
+ label: 'Dinaikkan',
51
+ color: 'dark',
52
+ },
53
+ waitForAudit: {
54
+ label: 'Menunggu Pengawas Lain',
55
+ color: '#57452fff',
56
+ iconLeft: 'hourglass',
57
+ },
58
+ processed: {
59
+ iconLeft: 'spinner',
60
+ label: 'Diproses',
61
+ color: 'warning',
62
+ },
63
+ delay: {
64
+ iconLeft: 'circle-stop',
65
+ label: 'Ditunda',
66
+ color: 'danger',
67
+ },
68
+ approved: {
69
+ iconLeft: 'list-check',
70
+ label: 'Disetujui',
71
+ color: 'success',
72
+ },
73
+ monitored: {
74
+ iconLeft: 'binoculars',
75
+ label: 'Dipantau',
76
+ color: 'info',
77
+ },
78
+ discontinued: {
79
+ iconLeft: 'ban',
80
+ label: 'Dihentikan',
81
+ color: 'danger',
82
+ },
83
+ resolved: {
84
+ iconLeft: 'file-check',
85
+ label: 'Diselesaikan',
86
+ color: 'success',
87
+ },
88
+ } as Record<string, any>
89
+
90
+ const status = computed(() => actions[values.value?.status || ''])
91
+
92
+ const isModalOpen = ref(false)
93
+ const isGetLoading = ref(false)
94
+ const isViewModalOpen = ref(false)
95
+
96
+ const officeAppUrl = computed(() => {
97
+ const url = apiUrl()
98
+ return url.action
99
+ })
100
+
101
+ interface SubmissionNoteOwner {
102
+ id: string
103
+ name: string
104
+ }
105
+
106
+ interface SubmissionNote {
107
+ id: string
108
+ note: string
109
+ owner: SubmissionNoteOwner
110
+ }
111
+
112
+ const submissionNote = ref('')
113
+ const submissionNotes = ref<SubmissionNote[]>([])
114
+ const isSaving = ref(false)
115
+
116
+ async function getSubmissionNote() {
117
+ if (!values.value?.id) return
118
+ isGetLoading.value = true
119
+ const result = await ofetch(`${officeAppUrl.value}/getSubmissionNotes`, {
120
+ method: 'POST',
121
+ headers: {
122
+ 'X-Neon-Key': 'YE96OWDFNY',
123
+ },
124
+ body: {
125
+ submissionId: values.value?.id,
126
+ ownerId: staff.staff.value?.id,
127
+ },
128
+ })
129
+ submissionNote.value = result?.data?.[0]?.note ?? ''
130
+ isGetLoading.value = false
131
+ }
132
+
133
+ async function getSubmissionNotes() {
134
+ if (!values.value?.id) return
135
+ isGetLoading.value = true
136
+ const result = await ofetch(`${officeAppUrl.value}/getSubmissionNotes`, {
137
+ method: 'POST',
138
+ headers: {
139
+ 'X-Neon-Key': 'YE96OWDFNY',
140
+ },
141
+ body: {
142
+ submissionId: values.value?.id,
143
+ },
144
+ })
145
+ submissionNotes.value = result?.data ?? []
146
+ isGetLoading.value = false
147
+ }
148
+
149
+ async function createNote(note: string) {
150
+ if (!note || !values.value?.id) {
151
+ console.warn('note or submissionId is empty')
152
+ return
153
+ }
154
+
155
+ isSaving.value = true
156
+
157
+ try {
158
+ const result = await ofetch(`${officeAppUrl.value}/createSubmissionNote`, {
159
+ method: 'POST',
160
+ headers: {
161
+ 'X-Neon-Key': 'YE96OWDFNY',
162
+ },
163
+ body: {
164
+ submissionId: values.value.id,
165
+ ownerId: staff.staff.value?.id,
166
+ note,
167
+ },
168
+ })
169
+
170
+ if (result.state === 'createSubmissionNoteSuccess') {
171
+ toast.push({
172
+ id: 'create:note',
173
+ content: 'Successfully created note.',
174
+ color: 'success',
175
+ duration: 5000,
176
+ })
177
+ }
178
+
179
+ submissionNote.value = note
180
+ } catch (err: any) {
181
+ const errorMessage = err?.data?.message
182
+ toast.push({
183
+ id: 'create:note',
184
+ content: errorMessage || 'Failed to create note.',
185
+ color: 'danger',
186
+ duration: 5000,
187
+ })
188
+ } finally {
189
+ isSaving.value = false
190
+ isModalOpen.value = false
191
+ }
192
+ }
193
+
194
+ watch(isModalOpen, async (newValue) => {
195
+ if (newValue) {
196
+ await getSubmissionNote()
197
+ }
198
+ })
199
+
200
+ watch(isViewModalOpen, async (newValue) => {
201
+ if (newValue) {
202
+ await getSubmissionNotes()
203
+ }
204
+ })
205
+
206
+ const hasFetched = ref(false)
207
+
208
+ watch(
209
+ [isLoading, id],
210
+ async ([loading, idVal]) => {
211
+ if (!loading && idVal != null && !hasFetched.value) {
212
+ hasFetched.value = true
213
+ await getSubmissionNote()
214
+ }
215
+ },
216
+ { immediate: true },
217
+ )
218
+ </script>
219
+
220
+ <template>
221
+ <div class="submission-single-actions">
222
+ <NeonLabel
223
+ :text="status?.label"
224
+ :color="status?.color"
225
+ :icon="status?.iconLeft"
226
+ :is-loading="isGetLoading && isLoading"
227
+ is-rounded
228
+ />
229
+
230
+ <div class="uji-problem-import">
231
+ <NeonButton
232
+ v-if="!isDirector"
233
+ :label="
234
+ submissionNote !== ''
235
+ ? 'Lihat atau Edit Catatan Pengawas'
236
+ : 'Tambah Catatan Pengawas'
237
+ "
238
+ size="xs"
239
+ display="fill"
240
+ color="danger"
241
+ is-rounded
242
+ is-squared-mobile
243
+ :is-loading="isGetLoading"
244
+ @click="isModalOpen = true"
245
+ />
246
+ <NeonButton
247
+ v-if="isDirector"
248
+ label="Lihat Catatan dari Pengawas"
249
+ size="xs"
250
+ display="outline"
251
+ is-rounded
252
+ is-squared-mobile
253
+ :is-loading="isGetLoading"
254
+ @click="isViewModalOpen = true"
255
+ />
256
+ </div>
257
+
258
+ <SubmissionNoteModal
259
+ :is-active="isModalOpen"
260
+ :submission-id="values?.id || ''"
261
+ :note="submissionNote"
262
+ :is-saving="isSaving"
263
+ :is-disabled="
264
+ values.status === 'processed' ||
265
+ values.status === 'waitForAudit' ||
266
+ values.status === 'approved' ||
267
+ values.status === 'delay' ||
268
+ values.status === 'monitored' ||
269
+ values.status === 'discontinued' ||
270
+ values.status === 'resolved' ||
271
+ isLoading ||
272
+ isGetLoading
273
+ "
274
+ @save="createNote"
275
+ @close="isModalOpen = false"
276
+ />
277
+ <SubmissionNoteViewModal
278
+ :is-active="isViewModalOpen"
279
+ :submission-id="values?.id || ''"
280
+ :notes="submissionNotes"
281
+ @close="isViewModalOpen = false"
282
+ />
283
+ </div>
284
+ </template>
285
+
286
+ <style scoped>
287
+ .submission-single-actions {
288
+ @apply flex flex-row items-center space-x-1 mr-1;
289
+
290
+ .publication {
291
+ @apply flex items-center;
292
+ @apply rounded-xl;
293
+
294
+ .neon-label {
295
+ @apply pointer-events-none rounded-none;
296
+ }
297
+
298
+ .neon-label:first-child {
299
+ @apply rounded-l-xl;
300
+ }
301
+
302
+ .neon-label:last-child {
303
+ @apply rounded-r-xl;
304
+ }
305
+ }
306
+ }
307
+ </style>
308
+
309
+ <style>
310
+ .neon-modal-problem-importer {
311
+ @apply p-4;
312
+ }
313
+ </style>
@@ -0,0 +1,189 @@
1
+ <script setup lang="ts">
2
+ import { useSingle } from '@neon.id/context'
3
+ import { NeonButton } from '@neon.id/interfaces'
4
+ import type {
5
+ TPersonaliaSubmissionModel,
6
+ Schema,
7
+ } from '@neutron.co.id/personalia-models'
8
+ import { computed, onMounted, ref, watch } from 'vue'
9
+ import { ofetch } from 'ofetch'
10
+ import SubmissionNoteViewModal from '../SubmissionNoteModal/SubmissionNoteViewModal.vue'
11
+ import { apiUrl, useOperasional } from '../../../../common'
12
+ import { useRoute } from 'vue-router'
13
+
14
+ defineOptions({ name: 'SubmissionActionDecision' })
15
+
16
+ const { isNew, id, values, isChanged, isLoading, executeOne, syncOne } =
17
+ useSingle<Schema.Submission, TPersonaliaSubmissionModel>()
18
+ const { staff } = useOperasional()
19
+ const route = useRoute()
20
+
21
+ interface SubmissionNoteOwner {
22
+ id: string
23
+ name: string
24
+ }
25
+
26
+ interface SubmissionNote {
27
+ id: string
28
+ note: string
29
+ owner: SubmissionNoteOwner
30
+ }
31
+
32
+ const submissionNotes = ref<SubmissionNote[]>([])
33
+
34
+ const isDelayDisabled = computed(() => {
35
+ return (
36
+ isNew.value ||
37
+ isChanged.value ||
38
+ values.value.status === 'prepared' ||
39
+ values.value.status === 'raised' ||
40
+ (values.value.delayStaffIds?.includes(staff.value?.id || '') ?? false)
41
+ )
42
+ })
43
+
44
+ const isApproveDisabled = computed(() => {
45
+ return (
46
+ isNew.value ||
47
+ isChanged.value ||
48
+ values.value.status === 'prepared' ||
49
+ values.value.status === 'raised' ||
50
+ (values.value.agreedStaffIds?.includes(staff.value?.id || '') ?? false)
51
+ )
52
+ })
53
+
54
+ const isViewModalOpen = ref(false)
55
+
56
+ const officeAppUrl = computed(() => {
57
+ const url = apiUrl()
58
+ return url.action
59
+ })
60
+
61
+ async function getSubmissionNotes() {
62
+ if (!values.value?.id && !id) return
63
+ const result = await ofetch(`${officeAppUrl.value}/getSubmissionNotes`, {
64
+ method: 'POST',
65
+ headers: {
66
+ 'X-Neon-Key': 'YE96OWDFNY',
67
+ },
68
+ body: {
69
+ submissionId: values.value?.id || id,
70
+ },
71
+ })
72
+ submissionNotes.value = result?.data ?? []
73
+ }
74
+
75
+ watch(isViewModalOpen, async (newValue) => {
76
+ if (newValue) {
77
+ await getSubmissionNotes()
78
+ }
79
+ })
80
+
81
+ const goBack = () => {
82
+ window.location.reload()
83
+ }
84
+
85
+ const syncDelay = async () => {
86
+ await executeOne('delaySubmission', {
87
+ submissionId: id.value,
88
+ staffId: staff.value?.id,
89
+ })
90
+ await syncOne()
91
+ goBack()
92
+ }
93
+
94
+ const syncApproved = async () => {
95
+ await executeOne('approvedSubmission', {
96
+ submissionId: id.value,
97
+ staffId: staff.value?.id,
98
+ })
99
+ await syncOne()
100
+ goBack()
101
+ }
102
+
103
+ const hasFetched = ref(false)
104
+
105
+ watch(
106
+ [isLoading, id],
107
+ async ([loading, idVal]) => {
108
+ if (!loading && idVal != null && !hasFetched.value) {
109
+ hasFetched.value = true
110
+ await getSubmissionNotes()
111
+ }
112
+ },
113
+ { immediate: true },
114
+ )
115
+ </script>
116
+
117
+ <template>
118
+ <div class="submission-single-actions">
119
+ <NeonButton
120
+ label="Disetujui"
121
+ size="xs"
122
+ display="outline"
123
+ color="success"
124
+ icon-left="list-check"
125
+ is-rounded
126
+ :is-loading="isLoading"
127
+ :is-disabled="isApproveDisabled"
128
+ @click="syncApproved"
129
+ />
130
+ <NeonButton
131
+ label="Ditunda"
132
+ size="xs"
133
+ display="outline"
134
+ color="danger"
135
+ icon-left="circle-stop"
136
+ is-rounded
137
+ :is-loading="isLoading"
138
+ :is-disabled="isDelayDisabled"
139
+ @click="syncDelay"
140
+ />
141
+ <NeonButton
142
+ label="Lihat Catatan dari Pengawas"
143
+ size="xs"
144
+ display="outline"
145
+ color="danger"
146
+ is-rounded
147
+ is-squared-mobile
148
+ :is-disabled="submissionNotes.length === 0"
149
+ :is-loading="isLoading"
150
+ @click="isViewModalOpen = true"
151
+ />
152
+
153
+ <SubmissionNoteViewModal
154
+ :is-active="isViewModalOpen"
155
+ :submission-id="values?.id || ''"
156
+ :notes="submissionNotes"
157
+ @close="isViewModalOpen = false"
158
+ />
159
+ </div>
160
+ </template>
161
+
162
+ <style scoped>
163
+ .submission-single-actions {
164
+ @apply flex flex-row items-center space-x-1 mr-1;
165
+
166
+ .publication {
167
+ @apply flex items-center;
168
+ @apply rounded-xl;
169
+
170
+ .neon-label {
171
+ @apply pointer-events-none rounded-none;
172
+ }
173
+
174
+ .neon-label:first-child {
175
+ @apply rounded-l-xl;
176
+ }
177
+
178
+ .neon-label:last-child {
179
+ @apply rounded-r-xl;
180
+ }
181
+ }
182
+ }
183
+ </style>
184
+
185
+ <style>
186
+ .neon-modal-problem-importer {
187
+ @apply p-4;
188
+ }
189
+ </style>
@@ -0,0 +1,2 @@
1
+ export { default as SubmissionAction } from './SubmissionAction.vue';
2
+ export { default as SubmissionActionDecision } from './SubmissionActionDecision.vue';
@@ -0,0 +1,2 @@
1
+ export { default as SubmissionAction } from "./SubmissionAction.vue";
2
+ export { default as SubmissionActionDecision } from "./SubmissionActionDecision.vue";