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

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/common/providers/api/apiUrl.d.ts +3 -0
  2. package/build/@office/common/providers/api/apiUrl.mjs +43 -0
  3. package/build/@office/common/providers/api/index.d.ts +1 -0
  4. package/build/@office/common/providers/api/index.mjs +1 -0
  5. package/build/@office/common/providers/index.d.ts +1 -0
  6. package/build/@office/common/providers/index.mjs +1 -0
  7. package/build/@office/models/personalia/attendance/AttendanceDelegate.vue +99 -14
  8. package/build/@office/models/personalia/attendance/AttendanceManager.vue +129 -15
  9. package/build/@office/models/personalia/attendance/AttendanceSingle/AttendanceSingle.vue +3 -1
  10. package/build/@office/models/personalia/attendance/AttendanceStaff.vue +184 -45
  11. package/build/@office/models/personalia/attendance/AttendanceSupervisor.vue +163 -36
  12. package/build/@office/models/personalia/leaveConflict/LeaveConflictCollection/LeaveConflictCollection.vue +1 -1
  13. package/build/@office/models/personalia/leaveConflict/LeaveConflictSingle/LeaveConflictSingle.vue +2 -2
  14. package/build/@office/models/personalia/leaveQuota/LeaveQuotaSingle/LeaveQuotaSingle.vue +27 -3
  15. package/build/@office/models/personalia/leaveStaff/LeaveStaffSingle/LeaveStaffSingle.vue +2 -2
  16. package/build/@office/models/personalia/shift/ShiftAdministrator.vue +1 -33
  17. package/build/@office/models/personalia/shift/ShiftSupervisor.vue +0 -1
  18. package/build/@office/models/personalia/shiftStaff/ShiftStaffCollectionBranch.vue +1 -1
  19. package/build/@office/models/personalia/shiftStaff/ShiftStaffCollectionStaff.vue +2 -1
  20. package/build/@office/models/personalia/shiftStaff/ShiftStaffWrapper/ShiftStaffDisplay.vue +4 -2
  21. package/build/@office/models/personalia/shiftStaff/ShiftStaffWrapper/ShiftStaffWrapper.vue +9 -13
  22. package/build/@package/@office/common/providers/api/apiUrl.d.ts +3 -0
  23. package/build/@package/@office/common/providers/api/index.d.ts +1 -0
  24. package/build/@package/@office/common/providers/index.d.ts +1 -0
  25. package/build/mock/index.cjs +1484 -1043
  26. package/build/mock/index.mjs +1484 -1043
  27. package/build/mock/style.css +16 -16
  28. package/build/module.json +1 -1
  29. package/build/nuxt.json +1 -1
  30. package/package.json +5 -5
@@ -0,0 +1,3 @@
1
+ export declare function apiUrl(): {
2
+ action: string;
3
+ };
@@ -0,0 +1,43 @@
1
+ export function apiUrl() {
2
+ const url = `${window.location.protocol}//${window.location.host}`;
3
+ const cleanUrl = url.replace(/^https?:\/\//, "");
4
+ const parts = cleanUrl.split(".");
5
+ if (parts.length < 3) {
6
+ return {
7
+ action: "http://localhost:7021"
8
+ };
9
+ }
10
+ const subDomainWithDev = parts[1];
11
+ const subDomain = parts[0];
12
+ let action;
13
+ if (subDomain === "dev") {
14
+ action = switchUrl(subDomainWithDev, true);
15
+ } else {
16
+ action = switchUrl(subDomain, false);
17
+ }
18
+ return { action };
19
+ }
20
+ function switchUrl(subdomain, isDev) {
21
+ let action;
22
+ switch (subdomain) {
23
+ case "aplikasi":
24
+ action = "api.office.neutron.neon.id";
25
+ break;
26
+ case "office":
27
+ action = "api.office.ion.neutron.neon.id";
28
+ break;
29
+ case "holding":
30
+ action = "api.office.holding.neutron.neon.id";
31
+ break;
32
+ case "operasional":
33
+ action = "api.office.operasional.neutron.neon.id";
34
+ break;
35
+ default:
36
+ action = "127.0.0.1:7020";
37
+ }
38
+ if (isDev) {
39
+ return `https://dev.${action}`;
40
+ } else {
41
+ return `https://${action}`;
42
+ }
43
+ }
@@ -0,0 +1 @@
1
+ export * from './apiUrl';
@@ -0,0 +1 @@
1
+ export * from "./apiUrl.mjs";
@@ -2,3 +2,4 @@ export * from './operasional';
2
2
  export * from './import';
3
3
  export * from './office';
4
4
  export * from './period';
5
+ export * from './api';
@@ -2,3 +2,4 @@ export * from "./operasional/index.mjs";
2
2
  export * from "./import/index.mjs";
3
3
  export * from "./office/index.mjs";
4
4
  export * from "./period/index.mjs";
5
+ export * from "./api/index.mjs";
@@ -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,
@@ -18,9 +18,10 @@ import {
18
18
  type Schema,
19
19
  } from '@neutron.co.id/personalia-models'
20
20
  import { DateUtil } from '../../../common/utils/util.date'
21
- import { NeonTime, useOperasional } from '../../../common'
21
+ import { NeonTime, useOperasional, apiUrl } 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,82 @@ async function generate() {
185
187
  await getNotified()
186
188
  await syncOne()
187
189
  }
190
+
191
+ const appStore = useAppStore()
192
+ const officeAppUrl = computed(() => {
193
+ const url = apiUrl()
194
+
195
+ return url.action
196
+ })
197
+
198
+ const type = ref('')
199
+ const showLeaveQuota = ref(true)
200
+ // const authStore = useAuthStore()
201
+ // const createdBy = authStore.userId
202
+ const quota = ref(0)
203
+ const maxDuration = ref(0)
204
+ const quotaTaken = ref(0)
205
+
206
+ function checkDurationLeave() {
207
+ console.log('cek', values.value)
208
+ if (!values.value.startedAt || !values.value.endedAt) {
209
+ return true
210
+ }
211
+
212
+ const startedAt = new Date(values.value.startedAt)
213
+ const endedAt = new Date(values.value.endedAt)
214
+
215
+ const durationMilliseconds = endedAt.getTime() - startedAt.getTime()
216
+
217
+ const days = Math.floor(durationMilliseconds / (1000 * 60 * 60 * 24))
218
+ quotaTaken.value = days
219
+ console.log('days', days, maxDuration.value)
220
+
221
+ if (days > maxDuration.value) return false
222
+
223
+ return true
224
+ }
225
+
226
+ watch(
227
+ () => values.value,
228
+ async (newType) => {
229
+ // console.log('new', newType)
230
+ // console.log('new val', values.value)
231
+ // console.log('type', values.value.type)
232
+ const response = await ofetch(`${officeAppUrl.value}/getAttendanceType`, {
233
+ method: 'POST',
234
+ headers: {
235
+ 'X-Neon-Key': 'CH7JLKT6MW',
236
+ },
237
+ body: {
238
+ id: values.value.attendanceTypeId,
239
+ },
240
+ })
241
+ // console.log(response)
242
+ type.value = response.data[0].code
243
+ showLeaveQuota.value = response.data[0].showLeaveQuota
244
+ quota.value = response.data[0].leaveQuota
245
+ maxDuration.value = response.data[0].maxDurationDays
246
+ },
247
+ )
248
+
249
+ const isLeaveStaff = ref(false)
250
+
251
+ const showDurationAlert = ref(false)
252
+ async function saveData() {
253
+ const result = await checkDurationLeave()
254
+
255
+ console.log('dur', result)
256
+
257
+ if (result == true && isLeaveStaff.value == true) {
258
+ showDurationAlert.value = false
259
+ console.log('save')
260
+ await saveOne()
261
+ } else {
262
+ showDurationAlert.value = true
263
+ console.log('error')
264
+ }
265
+ }
188
266
  </script>
189
267
 
190
268
  <template>
@@ -198,14 +276,21 @@ async function generate() {
198
276
  :is-changed="isChanged"
199
277
  use-unsaved
200
278
  @cancel="discardChanges"
201
- @submit="saveOne"
279
+ @submit="saveData"
202
280
  >
281
+ <NeonAlert
282
+ v-if="showDurationAlert == true"
283
+ icon="circle-info"
284
+ label="Durasi Melebihi Batas!."
285
+ description="Durasi cuti yang diajukan melebihi batas maksimum yang telah ditentukan. Mohon sesuaikan kembali permohonan cuti sesuai dengan ketentuan yang berlaku"
286
+ color="#F7CF6D"
287
+ />
203
288
  <OfficeRelation
204
289
  v-if="
205
- values.type?.code == 'leave' ||
290
+ values.type?.code == 'cuti' ||
206
291
  values.type?.code == 'dayOff' ||
207
292
  values.type?.code == 'sick' ||
208
- values.type?.code == 'permission'
293
+ values.type?.code == 'izin'
209
294
  "
210
295
  v-model="values"
211
296
  :field="fields.delegateStaffs"
@@ -251,10 +336,10 @@ async function generate() {
251
336
  />
252
337
  <!-- <OfficeRelation
253
338
  v-if="
254
- values.type?.code == 'leave' ||
255
- values.type?.code == 'sick' ||
256
- values.type?.code == 'dayOff' ||
257
- values.type?.code == 'permission'
339
+ values.type == 'leave' ||
340
+ values.type == 'sick' ||
341
+ values.type == 'dayOff' ||
342
+ values.type == 'permission'
258
343
  "
259
344
  v-model="values"
260
345
  :field="fields.monitoringStaffs"
@@ -264,10 +349,10 @@ async function generate() {
264
349
  /> -->
265
350
  <NeonField
266
351
  v-if="
267
- values.type?.code == 'leave' ||
268
- values.type?.code == 'dayOff' ||
269
- values.type?.code == 'sick' ||
270
- values.type?.code == 'permission'
352
+ type == 'cuti' ||
353
+ type == 'dayOff' ||
354
+ type == 'sakit' ||
355
+ type == 'izin'
271
356
  "
272
357
  v-model="values.delegateNotes"
273
358
  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'
@@ -10,7 +10,8 @@ import type {
10
10
  Schema,
11
11
  } from '@neutron.co.id/personalia-models'
12
12
  import { DateUtil } from '../../..//common/utils/util.date'
13
- import { useOperasional, NeonTime } from '../../../common'
13
+ import { useOperasional, NeonTime, apiUrl } from '../../../common'
14
+ import { ofetch } from 'ofetch'
14
15
 
15
16
  const {
16
17
  fields,
@@ -108,6 +109,103 @@ 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
+ const url = apiUrl()
116
+ return url.action
117
+ })
118
+
119
+ const type = ref('')
120
+ const showLeaveQuota = ref(true)
121
+ const quota = ref(0)
122
+ const maxDuration = ref(0)
123
+ const quotaTaken = ref(0)
124
+
125
+ function checkDurationLeave() {
126
+ if (!values.value.startedAt || !values.value.endedAt) {
127
+ return true
128
+ }
129
+
130
+ const startedAt = new Date(values.value.startedAt)
131
+ const endedAt = new Date(values.value.endedAt)
132
+
133
+ const durationMilliseconds = endedAt.getTime() - startedAt.getTime()
134
+
135
+ const days = Math.floor(durationMilliseconds / (1000 * 60 * 60 * 24)) + 1
136
+ quotaTaken.value = days
137
+
138
+ if (days > maxDuration.value) return false
139
+
140
+ return true
141
+ }
142
+
143
+ watch(
144
+ () => values.value,
145
+ async (newType) => {
146
+ checkDurationLeave()
147
+ const response = await ofetch(`${officeAppUrl.value}/getAttendanceType`, {
148
+ method: 'POST',
149
+ headers: {
150
+ 'X-Neon-Key': 'CH7JLKT6MW',
151
+ },
152
+ body: {
153
+ id: values.value.attendanceTypeId,
154
+ },
155
+ })
156
+ type.value = response.data[0].code
157
+ showLeaveQuota.value = response.data[0].showLeaveQuota
158
+ quota.value = response.data[0].leaveQuota
159
+ maxDuration.value = response.data[0].maxDurationDays
160
+ },
161
+ )
162
+
163
+ const isLeaveStaff = ref(false)
164
+
165
+ watch(
166
+ () => [values.value.startedAt, values.value.endedAt],
167
+ async (newType) => {
168
+ if (values.value.startedAt && values.value.endedAt) {
169
+ const leaveStaff = await ofetch(`${officeAppUrl.value}/getLeaveQuota`, {
170
+ method: 'POST',
171
+ headers: {
172
+ 'X-Neon-Key': 'CH7JLKT6MW',
173
+ },
174
+ body: {
175
+ id: values.value.attendanceTypeId,
176
+ staffId: initialValues.value.submitStaffId,
177
+ startedAt: values.value.startedAt,
178
+ endedAt: values.value.endedAt,
179
+ },
180
+ })
181
+
182
+ if (leaveStaff.code === 200 && leaveStaff.data.quota > 0) {
183
+ isLeaveStaff.value = true
184
+ quota.value = leaveStaff.data.quota
185
+ maxDuration.value = leaveStaff.data.quota
186
+ } else {
187
+ isLeaveStaff.value = false
188
+ }
189
+ }
190
+ },
191
+ )
192
+
193
+ const showDurationAlert = ref(false)
194
+ async function saveData() {
195
+ const result = await checkDurationLeave()
196
+
197
+ if (
198
+ (result === true && isLeaveStaff.value === true) ||
199
+ (type.value !== 'cuti' && type.value !== 'izin' && type.value !== 'sakit')
200
+ ) {
201
+ showDurationAlert.value = false
202
+ console.log('save')
203
+ await saveOne()
204
+ } else {
205
+ showDurationAlert.value = true
206
+ console.log('error')
207
+ }
208
+ }
111
209
  </script>
112
210
 
113
211
  <template>
@@ -121,8 +219,22 @@ const rejectedAbsensi = async () => {
121
219
  :is-changed="isChanged"
122
220
  use-unsaved
123
221
  @cancel="discardChanges"
124
- @submit="saveOne"
222
+ @submit="saveData"
125
223
  >
224
+ <NeonStat
225
+ v-if="showLeaveQuota"
226
+ class="w-36 mb-2"
227
+ label="Cuti Pribadi"
228
+ icon="person-to-door"
229
+ >{{ quota }} hari</NeonStat
230
+ >
231
+ <NeonAlert
232
+ v-if="showDurationAlert == true"
233
+ icon="circle-info"
234
+ label="Durasi Melebihi Batas!."
235
+ description="Durasi cuti yang diajukan melebihi batas maksimum yang telah ditentukan. Mohon sesuaikan kembali permohonan cuti sesuai dengan ketentuan yang berlaku"
236
+ color="#F7CF6D"
237
+ />
126
238
  <div class="flex flex-wrap">
127
239
  <div class="mt-2">
128
240
  <NeonField>
@@ -197,13 +309,14 @@ const rejectedAbsensi = async () => {
197
309
  />
198
310
 
199
311
  <OfficeRelation
200
- v-if="values.type?.code === 'leave'"
312
+ v-if="type === 'cuti'"
201
313
  v-model="values"
202
314
  :field="fields.delegateStaffs"
203
315
  :is-disabled="
204
316
  values.status == 'approved' || values.status == 'rejected'
205
317
  "
206
318
  />
319
+ <NeonField v-model="values.image" v-bind="fields.image" />
207
320
 
208
321
  <NeonField
209
322
  v-if="isNew || isReady"
@@ -211,14 +324,18 @@ const rejectedAbsensi = async () => {
211
324
  v-bind="fields.notes"
212
325
  />
213
326
 
214
- <NeonDivider v-if="values.type" is-dashed label="Keterangan" />
327
+ <NeonDivider
328
+ v-if="values.attendanceTypeId"
329
+ is-dashed
330
+ label="Keterangan"
331
+ />
215
332
 
216
333
  <NeonField
217
334
  v-if="
218
- values.type?.code === 'dayOff' ||
219
- values.type?.code === 'sick' ||
220
- values.type?.code === 'permission' ||
221
- values.type?.code === 'leave'
335
+ type == 'cuti' ||
336
+ type == 'dayOff' ||
337
+ type == 'sick' ||
338
+ type == 'izin'
222
339
  "
223
340
  v-model="values.submittedAt"
224
341
  v-bind="fields.submittedAt"
@@ -227,7 +344,7 @@ const rejectedAbsensi = async () => {
227
344
 
228
345
  <!-- EARLY GO HOME -->
229
346
  <div
230
- v-if="values.type?.code == 'homeEarly'"
347
+ v-if="type == 'pulangLebihAwal'"
231
348
  class="grid gap-2 sm:grid-cols-2"
232
349
  >
233
350
  <NeonField
@@ -275,7 +392,7 @@ const rejectedAbsensi = async () => {
275
392
 
276
393
  <!-- COME TOO LATE -->
277
394
  <div
278
- v-if="values.type?.code == 'comeLate'"
395
+ v-if="type == 'datangTerlambat'"
279
396
  class="grid gap-2 sm:grid-cols-2"
280
397
  >
281
398
  <NeonField
@@ -322,10 +439,7 @@ const rejectedAbsensi = async () => {
322
439
  </div>
323
440
 
324
441
  <!-- TIMEOUT -->
325
- <div
326
- v-if="values.type?.code == 'timeout'"
327
- class="grid gap-2 sm:grid-cols-2"
328
- >
442
+ <div v-if="type == 'timeout'" class="grid gap-2 sm:grid-cols-2">
329
443
  <NeonField
330
444
  v-model="values.startedAt"
331
445
  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