@neutron.co.id/operasional-interfaces 1.17.10-beta.1 → 1.17.11

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 (21) hide show
  1. package/build/@office/models/personalia/attendance/AttendanceDelegate.vue +102 -13
  2. package/build/@office/models/personalia/attendance/AttendanceManager.vue +133 -14
  3. package/build/@office/models/personalia/attendance/AttendanceSingle/AttendanceSingle.vue +3 -1
  4. package/build/@office/models/personalia/attendance/AttendanceStaff.vue +171 -44
  5. package/build/@office/models/personalia/attendance/AttendanceSupervisor.vue +151 -35
  6. package/build/@office/models/personalia/leaveConflict/LeaveConflictCollection/LeaveConflictCollection.vue +12 -7
  7. package/build/@office/models/personalia/leaveConflict/LeaveConflictSingle/LeaveConflictSingle.vue +10 -32
  8. package/build/@office/models/personalia/leaveQuota/LeaveQuotaSingle/LeaveQuotaSingle.vue +60 -44
  9. package/build/@office/models/personalia/leaveStaff/LeaveStaffSingle/LeaveStaffSingle.vue +10 -31
  10. package/build/@office/models/personalia/shift/ShiftAdministrator.vue +1 -33
  11. package/build/@office/models/personalia/shift/ShiftSupervisor.vue +0 -1
  12. package/build/@office/models/personalia/shiftStaff/ShiftStaffCollectionBranch.vue +1 -1
  13. package/build/@office/models/personalia/shiftStaff/ShiftStaffCollectionStaff.vue +2 -1
  14. package/build/@office/models/personalia/shiftStaff/ShiftStaffWrapper/ShiftStaffDisplay.vue +4 -2
  15. package/build/@office/models/personalia/shiftStaff/ShiftStaffWrapper/ShiftStaffWrapper.vue +9 -13
  16. package/build/mock/index.cjs +1536 -1132
  17. package/build/mock/index.mjs +1536 -1132
  18. package/build/mock/style.css +16 -16
  19. package/build/module.json +1 -1
  20. package/build/nuxt.json +1 -1
  21. package/package.json +6 -6
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { GraphUtil, NeonSingle, useSingle } from '@neon.id/context'
2
+ import { GraphUtil, NeonSingle, useSingle, useAppStore } from '@neon.id/context'
3
3
  import { NeonCheck, NeonField, NeonForm } from '@neon.id/form'
4
4
  import {
5
5
  NeonAlert,
@@ -21,6 +21,7 @@ import { DateUtil } from '../../../common/utils/util.date'
21
21
  import { NeonTime, useOperasional } from '../../../common'
22
22
  import { AttendanceNoteTab } from './sections'
23
23
  import { useClientHandle } from '@urql/vue'
24
+ import { ofetch } from 'ofetch'
24
25
 
25
26
  const {
26
27
  fields,
@@ -164,7 +165,7 @@ async function generateAttendance() {
164
165
  // Attendance input.
165
166
  status: values.value.status,
166
167
  submitStaffId: values.value.submitStaffId,
167
- type: values.value.type,
168
+ typeId: values.value.type?.id,
168
169
  decideStaffId: values.value.decideStaffId,
169
170
  delegateStaffIds: values.value.delegateStaffIds,
170
171
  monitoringStaffIds: values.value.monitoringStaffIds,
@@ -172,6 +173,7 @@ async function generateAttendance() {
172
173
  submittedAt: values.value.submittedAt,
173
174
  startedAt: values.value.startedAt,
174
175
  endedAt: values.value.endedAt,
176
+ leaveQuota: quotaTaken.value,
175
177
  },
176
178
  })
177
179
  .toPromise()
@@ -185,6 +187,86 @@ async function generate() {
185
187
  await getNotified()
186
188
  await syncOne()
187
189
  }
190
+
191
+ const appStore = useAppStore()
192
+ const officeAppUrl = computed(() => {
193
+ if (appStore.appEnv === 'dev')
194
+ return 'https://dev.api.office.operasional.neutron.neon.id'
195
+
196
+ if (appStore.appEnv === 'prod')
197
+ return 'https://api.office.operasional.neutron.neon.id'
198
+
199
+ return 'http://127.0.0.1:7020'
200
+ })
201
+
202
+ const type = ref('')
203
+ const showLeaveQuota = ref(true)
204
+ // const authStore = useAuthStore()
205
+ // const createdBy = authStore.userId
206
+ const quota = ref(0)
207
+ const maxDuration = ref(0)
208
+ const quotaTaken = ref(0)
209
+
210
+ function checkDurationLeave() {
211
+ console.log('cek', values.value)
212
+ if (!values.value.startedAt || !values.value.endedAt) {
213
+ return true
214
+ }
215
+
216
+ const startedAt = new Date(values.value.startedAt)
217
+ const endedAt = new Date(values.value.endedAt)
218
+
219
+ const durationMilliseconds = endedAt.getTime() - startedAt.getTime()
220
+
221
+ const days = Math.floor(durationMilliseconds / (1000 * 60 * 60 * 24))
222
+ quotaTaken.value = days
223
+ console.log('days', days, maxDuration.value)
224
+
225
+ if (days > maxDuration.value) return false
226
+
227
+ return true
228
+ }
229
+
230
+ watch(
231
+ () => values.value,
232
+ async (newType) => {
233
+ console.log('new', newType)
234
+ console.log('new val', values.value)
235
+ console.log('type', values.value.type)
236
+ const response = await ofetch(`${officeAppUrl.value}/getAttendanceType`, {
237
+ method: 'POST',
238
+ headers: {
239
+ 'X-Neon-Key': 'CH7JLKT6MW',
240
+ },
241
+ body: {
242
+ id: values.value.attendanceTypeId,
243
+ },
244
+ })
245
+ console.log(response)
246
+ type.value = response.data[0].code
247
+ showLeaveQuota.value = response.data[0].showLeaveQuota
248
+ quota.value = response.data[0].leaveQuota
249
+ maxDuration.value = response.data[0].maxDurationDays
250
+ },
251
+ )
252
+
253
+ const isLeaveStaff = ref(false)
254
+
255
+ const showDurationAlert = ref(false)
256
+ async function saveData() {
257
+ const result = await checkDurationLeave()
258
+
259
+ console.log('dur', result)
260
+
261
+ if (result == true && isLeaveStaff.value == true) {
262
+ showDurationAlert.value = false
263
+ console.log('save')
264
+ await saveOne()
265
+ } else {
266
+ showDurationAlert.value = true
267
+ console.log('error')
268
+ }
269
+ }
188
270
  </script>
189
271
 
190
272
  <template>
@@ -198,14 +280,21 @@ async function generate() {
198
280
  :is-changed="isChanged"
199
281
  use-unsaved
200
282
  @cancel="discardChanges"
201
- @submit="saveOne"
283
+ @submit="saveData"
202
284
  >
285
+ <NeonAlert
286
+ v-if="showDurationAlert == true"
287
+ icon="circle-info"
288
+ label="Durasi Melebihi Batas!."
289
+ description="Durasi cuti yang diajukan melebihi batas maksimum yang telah ditentukan. Mohon sesuaikan kembali permohonan cuti sesuai dengan ketentuan yang berlaku"
290
+ color="#F7CF6D"
291
+ />
203
292
  <OfficeRelation
204
293
  v-if="
205
- values.type?.code == 'leave' ||
294
+ values.type?.code == 'cuti' ||
206
295
  values.type?.code == 'dayOff' ||
207
296
  values.type?.code == 'sick' ||
208
- values.type?.code == 'permission'
297
+ values.type?.code == 'izin'
209
298
  "
210
299
  v-model="values"
211
300
  :field="fields.delegateStaffs"
@@ -251,10 +340,10 @@ async function generate() {
251
340
  />
252
341
  <!-- <OfficeRelation
253
342
  v-if="
254
- values.type?.code == 'leave' ||
255
- values.type?.code == 'sick' ||
256
- values.type?.code == 'dayOff' ||
257
- values.type?.code == 'permission'
343
+ values.type == 'leave' ||
344
+ values.type == 'sick' ||
345
+ values.type == 'dayOff' ||
346
+ values.type == 'permission'
258
347
  "
259
348
  v-model="values"
260
349
  :field="fields.monitoringStaffs"
@@ -264,10 +353,10 @@ async function generate() {
264
353
  /> -->
265
354
  <NeonField
266
355
  v-if="
267
- values.type?.code == 'leave' ||
268
- values.type?.code == 'dayOff' ||
269
- values.type?.code == 'sick' ||
270
- values.type?.code == 'permission'
356
+ type == 'cuti' ||
357
+ type == 'dayOff' ||
358
+ type == 'sick' ||
359
+ type == 'izin'
271
360
  "
272
361
  v-model="values.delegateNotes"
273
362
  v-bind="fields.delegateNotes"
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { NeonSingle, useSingle } from '@neon.id/context'
2
+ import { NeonSingle, useSingle, useAppStore } from '@neon.id/context'
3
3
  import { NeonField, NeonForm } from '@neon.id/form'
4
4
  import { NeonButton, NeonDivider } from '@neon.id/interfaces'
5
5
  import { OfficeRelation, OfficeTab, OfficeTabs } from '@neon.id/office'
@@ -11,6 +11,7 @@ import type {
11
11
  } from '@neutron.co.id/personalia-models'
12
12
  import { DateUtil } from '../../..//common/utils/util.date'
13
13
  import { useOperasional, NeonTime } from '../../../common'
14
+ import { ofetch } from 'ofetch'
14
15
 
15
16
  const {
16
17
  fields,
@@ -108,6 +109,108 @@ const rejectedAbsensi = async () => {
108
109
  await executeOne('rejectedAttendance', { attendanceId: id.value })
109
110
  await syncOne()
110
111
  }
112
+
113
+ const appStore = useAppStore()
114
+ const officeAppUrl = computed(() => {
115
+ if (appStore.appEnv === 'dev')
116
+ return 'https://dev.api.office.operasional.neutron.neon.id'
117
+
118
+ if (appStore.appEnv === 'prod')
119
+ return 'https://api.office.operasional.neutron.neon.id'
120
+
121
+ return 'http://127.0.0.1:7020'
122
+ })
123
+
124
+ const type = ref('')
125
+ const showLeaveQuota = ref(true)
126
+ const quota = ref(0)
127
+ const maxDuration = ref(0)
128
+ const quotaTaken = ref(0)
129
+
130
+ function checkDurationLeave() {
131
+ if (!values.value.startedAt || !values.value.endedAt) {
132
+ return true
133
+ }
134
+
135
+ const startedAt = new Date(values.value.startedAt)
136
+ const endedAt = new Date(values.value.endedAt)
137
+
138
+ const durationMilliseconds = endedAt.getTime() - startedAt.getTime()
139
+
140
+ const days = Math.floor(durationMilliseconds / (1000 * 60 * 60 * 24)) + 1
141
+ quotaTaken.value = days
142
+
143
+ if (days > maxDuration.value) return false
144
+
145
+ return true
146
+ }
147
+
148
+ watch(
149
+ () => values.value,
150
+ async (newType) => {
151
+ checkDurationLeave()
152
+ const response = await ofetch(`${officeAppUrl.value}/getAttendanceType`, {
153
+ method: 'POST',
154
+ headers: {
155
+ 'X-Neon-Key': 'CH7JLKT6MW',
156
+ },
157
+ body: {
158
+ id: values.value.attendanceTypeId,
159
+ },
160
+ })
161
+ type.value = response.data[0].code
162
+ showLeaveQuota.value = response.data[0].showLeaveQuota
163
+ quota.value = response.data[0].leaveQuota
164
+ maxDuration.value = response.data[0].maxDurationDays
165
+ },
166
+ )
167
+
168
+ const isLeaveStaff = ref(false)
169
+
170
+ watch(
171
+ () => [values.value.startedAt, values.value.endedAt],
172
+ async (newType) => {
173
+ if (values.value.startedAt && values.value.endedAt) {
174
+ const leaveStaff = await ofetch(`${officeAppUrl.value}/getLeaveQuota`, {
175
+ method: 'POST',
176
+ headers: {
177
+ 'X-Neon-Key': 'CH7JLKT6MW',
178
+ },
179
+ body: {
180
+ id: values.value.attendanceTypeId,
181
+ staffId: initialValues.value.submitStaffId,
182
+ startedAt: values.value.startedAt,
183
+ endedAt: values.value.endedAt,
184
+ },
185
+ })
186
+
187
+ if (leaveStaff.code === 200 && leaveStaff.data.quota > 0) {
188
+ isLeaveStaff.value = true
189
+ quota.value = leaveStaff.data.quota
190
+ maxDuration.value = leaveStaff.data.quota
191
+ } else {
192
+ isLeaveStaff.value = false
193
+ }
194
+ }
195
+ },
196
+ )
197
+
198
+ const showDurationAlert = ref(false)
199
+ async function saveData() {
200
+ const result = await checkDurationLeave()
201
+
202
+ if (
203
+ (result === true && isLeaveStaff.value === true) ||
204
+ (type.value !== 'cuti' && type.value !== 'izin' && type.value !== 'sakit')
205
+ ) {
206
+ showDurationAlert.value = false
207
+ console.log('save')
208
+ await saveOne()
209
+ } else {
210
+ showDurationAlert.value = true
211
+ console.log('error')
212
+ }
213
+ }
111
214
  </script>
112
215
 
113
216
  <template>
@@ -121,8 +224,22 @@ const rejectedAbsensi = async () => {
121
224
  :is-changed="isChanged"
122
225
  use-unsaved
123
226
  @cancel="discardChanges"
124
- @submit="saveOne"
227
+ @submit="saveData"
125
228
  >
229
+ <NeonStat
230
+ v-if="showLeaveQuota"
231
+ class="w-36 mb-2"
232
+ label="Cuti Pribadi"
233
+ icon="person-to-door"
234
+ >{{ quota }} hari</NeonStat
235
+ >
236
+ <NeonAlert
237
+ v-if="showDurationAlert == true"
238
+ icon="circle-info"
239
+ label="Durasi Melebihi Batas!."
240
+ description="Durasi cuti yang diajukan melebihi batas maksimum yang telah ditentukan. Mohon sesuaikan kembali permohonan cuti sesuai dengan ketentuan yang berlaku"
241
+ color="#F7CF6D"
242
+ />
126
243
  <div class="flex flex-wrap">
127
244
  <div class="mt-2">
128
245
  <NeonField>
@@ -197,13 +314,14 @@ const rejectedAbsensi = async () => {
197
314
  />
198
315
 
199
316
  <OfficeRelation
200
- v-if="values.type?.code === 'leave'"
317
+ v-if="type === 'cuti'"
201
318
  v-model="values"
202
319
  :field="fields.delegateStaffs"
203
320
  :is-disabled="
204
321
  values.status == 'approved' || values.status == 'rejected'
205
322
  "
206
323
  />
324
+ <NeonField v-model="values.image" v-bind="fields.image" />
207
325
 
208
326
  <NeonField
209
327
  v-if="isNew || isReady"
@@ -211,14 +329,18 @@ const rejectedAbsensi = async () => {
211
329
  v-bind="fields.notes"
212
330
  />
213
331
 
214
- <NeonDivider v-if="values.type" is-dashed label="Keterangan" />
332
+ <NeonDivider
333
+ v-if="values.attendanceTypeId"
334
+ is-dashed
335
+ label="Keterangan"
336
+ />
215
337
 
216
338
  <NeonField
217
339
  v-if="
218
- values.type?.code === 'dayOff' ||
219
- values.type?.code === 'sick' ||
220
- values.type?.code === 'permission' ||
221
- values.type?.code === 'leave'
340
+ type == 'cuti' ||
341
+ type == 'dayOff' ||
342
+ type == 'sick' ||
343
+ type == 'izin'
222
344
  "
223
345
  v-model="values.submittedAt"
224
346
  v-bind="fields.submittedAt"
@@ -227,7 +349,7 @@ const rejectedAbsensi = async () => {
227
349
 
228
350
  <!-- EARLY GO HOME -->
229
351
  <div
230
- v-if="values.type?.code == 'homeEarly'"
352
+ v-if="type == 'pulangLebihAwal'"
231
353
  class="grid gap-2 sm:grid-cols-2"
232
354
  >
233
355
  <NeonField
@@ -275,7 +397,7 @@ const rejectedAbsensi = async () => {
275
397
 
276
398
  <!-- COME TOO LATE -->
277
399
  <div
278
- v-if="values.type?.code == 'comeLate'"
400
+ v-if="type == 'datangTerlambat'"
279
401
  class="grid gap-2 sm:grid-cols-2"
280
402
  >
281
403
  <NeonField
@@ -322,10 +444,7 @@ const rejectedAbsensi = async () => {
322
444
  </div>
323
445
 
324
446
  <!-- TIMEOUT -->
325
- <div
326
- v-if="values.type?.code == 'timeout'"
327
- class="grid gap-2 sm:grid-cols-2"
328
- >
447
+ <div v-if="type == 'timeout'" class="grid gap-2 sm:grid-cols-2">
329
448
  <NeonField
330
449
  v-model="values.startedAt"
331
450
  v-bind="{
@@ -30,6 +30,8 @@ const diff = computed(() => {
30
30
  return DateUtil.day(values.value.endedAt).diff(values.value.startedAt)
31
31
  })
32
32
 
33
+ console.log('single', values.value)
34
+
33
35
  const duration = computed(() => {
34
36
  if (isNaN(diff.value)) return '-'
35
37
  const duration = DateUtil.day.duration(diff.value)
@@ -91,7 +93,7 @@ function onStartedAtUpdate(date: any) {
91
93
  @update:model-value="onStartedAtUpdate"
92
94
  />
93
95
 
94
- <OfficeRelation v-model="values" :field="fields.type" />
96
+ <OfficeRelation v-model="values.type" :field="fields.type" />
95
97
 
96
98
  <OfficeRelation v-model="values" :field="fields.decideStaff" />
97
99