Initial commit, repo migration

This commit is contained in:
unknown
2024-05-14 22:19:14 +07:00
commit b51b940ac4
137 changed files with 19393 additions and 0 deletions
+367
View File
@@ -0,0 +1,367 @@
/* eslint-disable no-mixed-spaces-and-tabs */
import { CardCustom } from '@/components/CardCustom'
import { Belakang } from '@/components/Layouts'
import { Judul, SubJudul } from '@/components/TextCustom'
import { ddRekomendasi } from '@/constant/globalData'
import { TagihanGet, VerifikasiSave } from '@/services/otorisasi/verifikasi-service'
import { Formik } from 'formik'
import 'moment/locale/id'
import Head from 'next/head'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { Accordion, AccordionTab } from 'primereact/accordion'
import { BreadCrumb } from 'primereact/breadcrumb'
import { Button } from 'primereact/button'
import { Card } from 'primereact/card'
import { Dropdown } from 'primereact/dropdown'
import { InputText } from 'primereact/inputtext'
import { InputTextarea } from 'primereact/inputtextarea'
import { RadioButton } from 'primereact/radiobutton'
import { TabPanel, TabView } from 'primereact/tabview'
import { Toast } from 'primereact/toast'
import React, { useEffect, useRef, useState } from 'react'
import Swal from 'sweetalert2'
export default function FormRekomendasi() {
const router = useRouter()
const { tagihan_id } = router.query
const [dataTagihan, setDataTagihan] = useState([])
const [dataDetail, setDataDetail] = useState([])
useEffect(() => {
tagihan_id &&
TagihanGet({ ref_id: tagihan_id })
.then((res) => {
setDataTagihan(res.data[0])
setDataDetail(res.data[1])
})
.catch((err) => console.log(err))
}, [tagihan_id])
const toast = useRef(null)
const [activeIndex, setActiveIndex] = useState(0)
/**
* *Breadcrumb
*/
const items = [{ label: 'Verifikasi', url: '/otorisasi/verifikasi' }, { label: 'Form' }]
const home = { icon: 'pi pi-home', url: '/dashboard' }
const formikInitialValues = () => {
const detail =
dataDetail.length > 0 &&
dataDetail.map((value) => {
let cekTMS = []
value.syarat.map((valueTMS) => {
cekTMS.push(valueTMS.ms)
})
let cekTMSH = cekTMS.find((isi_tms) => isi_tms === 'tms')
return {
detail_id: value.detail_id,
jenis_belanja: value.jenis_belanja,
jenis_kegiatan: value.jenis_kegiatan,
akun: value.akun_id,
keperluan_untuk: value.keperluan,
syarat: value.syarat.map((valueSyarat) => {
return {
syarat_id: valueSyarat.syarat_id,
nama_persyaratan: valueSyarat.syarat_dokumen,
catatans: {
verif: valueSyarat.verif_note,
bendahara: valueSyarat.bendahara_note,
spm: valueSyarat.spm_note,
},
ms: valueSyarat.ms,
}
}),
rekom_kasub: cekTMSH === 'tms' ? 'Ditolak/dikembalikan' : '',
}
})
return { details: detail, persetujuan: true, tagihan_id: tagihan_id }
}
return (
<>
<Toast ref={toast} />
<Head>
<title>Form Rekomendasi</title>
</Head>
<Belakang>
<BreadCrumb model={items} home={home} />
<div className='mb-5'></div>
<Judul>Form Rekomendasi</Judul>
<Card>
<div className='grid grid-cols-2 gap-3'>
<CardCustom header={'No SPP'} content={dataTagihan && dataTagihan.no_spp} />
<CardCustom header={'Unit PPK'} content={dataTagihan && dataTagihan.unit} />
<CardCustom header={'Jenis Tagihan'} content={dataTagihan && dataTagihan.tagihan} />
</div>
</Card>
{dataDetail.length > 0 && (
<Formik
enableReinitialize
initialValues={formikInitialValues()}
onSubmit={async (values, { setSubmitting }) => {
VerifikasiSave(values)
.then((res) => {
if (res.status == 'ok') {
Swal.fire({
title: 'Success',
text: 'Verifikasi berhasil',
icon: 'success',
timer: 2000,
timerProgressBar: true,
}).then(() => {
router.push('/otorisasi/rekomendasi')
})
setSubmitting(false)
}
})
.catch((err) => {
setSubmitting(false)
console.log(err)
})
}}
validate={(data) => {
let errors = {}
data.details.map((values, indexTagihan) => {
const indexTagihanx = indexTagihan + 1
if (!values.rekom_kasub) {
errors.rekom = 'required'
toast.current.show({
severity: 'error',
summary: 'Error Message',
detail: 'Rekomendasi Tagihan ' + indexTagihanx + ' Tidak Boleh Kosong',
})
}
values.syarat.map((valuesSyarats, indexSyarat) => {
const indexSyaratx = indexSyarat + 1
if (!valuesSyarats.ms) {
errors.ms = 'required'
toast.current.show({
severity: 'error',
summary: 'Error Message',
detail: 'Tagihan ' + indexTagihanx + ' Syarat ke ' + indexSyaratx + ' MS/TMS Tidak Boleh Kosong',
})
} else if (valuesSyarats.ms === 'tms') {
if (!valuesSyarats.catatans.verif) {
errors.keterangan = 'required'
toast.current.show({
severity: 'error',
summary: 'Error Message',
detail:
'Tagihan ' + indexTagihanx + ' Syarat ke ' + indexSyaratx + ' Catatan Tidak Boleh Kosong',
})
}
}
})
})
return errors
}}
validateOnChange={false}
>
{({ values, handleChange, handleSubmit, isSubmitting, setFieldValue }) => {
return (
<React.Fragment>
<Accordion
activeIndex={activeIndex}
onTabChange={(e) => setActiveIndex(e.index)}
className='mt-3 shadow'
>
{dataDetail.map((dataTagihan, indexTagihan) => {
let cekTMS = []
values.details[indexTagihan].syarat.map((valueTMS) => {
cekTMS.push(valueTMS.ms)
})
let cekTMSH = cekTMS.find((isi_tms) => isi_tms === 'tms')
return (
<AccordionTab header={`Tagihan ${indexTagihan + 1}`} key={indexTagihan}>
<div className='grid grid-cols-2 gap-3'>
<CardCustom header={'Jenis Belanja'} content={dataTagihan.jenis_belanja} type='cream' />
<CardCustom header={'Jenis Kegiatan'} content={dataTagihan.jenis_kegiatan} type='cream' />
<CardCustom header={'Akun'} content={dataTagihan.akun_id} type='cream' />
<CardCustom header={'Keperluan Untuk'} content={dataTagihan.keperluan} type='cream' />
<div className='border text-center'>
<p className='font-semibold py-1 bg-green-100'>File</p>
<div className='flex items-center justify-center h-[40px]'>
<Link href={process.env.NEXT_PUBLIC_API_FILE + dataTagihan.filepath}>
<a target={'_blank'} className='flex items-center justify-center gap-x-1'>
<i className='pi pi-file-pdf' style={{ fontSize: '2em' }} />
<p className='text-sm hover:underline'>Klik disini untuk lihat file</p>
</a>
</Link>
</div>
</div>
</div>
<div className='my-3'>
<SubJudul className='text-lg mb-1'>Syarat</SubJudul>
<div className='flex border rounded py-1 px-3 text-xs gap-5 w-fit mb-1'>
<div className='flex gap-3 items-center'>
<span className='bg-logo-pink1 w-10 h-3 rounded'></span>
<p>Syarat dengan status TMS (Tidak memenuhi syarat)</p>
</div>
<div className='flex gap-3 items-center'>
<span className='bg-logo-kuning1 w-10 h-3 rounded'></span>
<p>Syarat dengan catatan</p>
</div>
</div>
<Accordion className='accordion-syarat'>
{dataTagihan.syarat.map((valueSyarat, indexSyarat) => {
return (
<AccordionTab
header={valueSyarat.syarat_dokumen}
key={indexSyarat}
headerClassName={`${
values.details[indexTagihan].syarat[indexSyarat].ms === 'tms'
? 'p-accordion-syarat-tms'
: values.details[indexTagihan].syarat[indexSyarat].catatans.verif
? 'p-accordion-syarat-catatan'
: ''
}`}
>
<div className='mx-32'>
<table className='custom-table'>
<thead>
<tr>
<th>MS</th>
<th>TMS</th>
</tr>
</thead>
<tbody>
<tr>
<td width={'10%'}>
<div className='flex flex-col justify-center items-center'>
<RadioButton
name={`details.${indexTagihan}.syarat.${indexSyarat}.ms`}
value='ms'
onChange={handleChange}
checked={values.details[indexTagihan].syarat[indexSyarat].ms === 'ms'}
/>
</div>
</td>
<td className='text-center' width={'10%'}>
<RadioButton
name={`details.${indexTagihan}.syarat.${indexSyarat}.ms`}
value='tms'
onChange={(e) => {
handleChange(e)
setFieldValue(
`details.${indexTagihan}.rekom_kasub`,
'Ditolak/dikembalikan'
)
}}
checked={values.details[indexTagihan].syarat[indexSyarat].ms === 'tms'}
/>
</td>
</tr>
<tr className=''>
<td colSpan={4}>
<p className='text-xl font-semibold mb-1'>Catatan</p>
<TabView key={indexSyarat}>
<TabPanel header='Catatan Verifikator'>
<InputTextarea
name={`details.${indexTagihan}.syarat.${indexSyarat}.catatans.verif`}
rows={5}
cols={30}
value={
values.details[indexTagihan].syarat[indexSyarat].catatans.verif
}
onChange={handleChange}
className='w-full'
placeholder='Masukkan catatan Verifikator'
/>
</TabPanel>
<TabPanel header='Catatan Bendahara'>
<InputTextarea
name={`details.${indexTagihan}.syarat.${indexSyarat}.catatans.bendahara`}
rows={5}
cols={30}
value={
values.details[indexTagihan].syarat[indexSyarat].catatans
.bendahara
}
onChange={handleChange}
className='w-full'
placeholder='Masukkan catatan Bendahara'
readOnly
/>
</TabPanel>
<TabPanel header='Catatan SPM'>
<InputTextarea
name={`details.${indexTagihan}.syarat.${indexSyarat}.catatans.spm`}
rows={5}
cols={30}
value={
values.details[indexTagihan].syarat[indexSyarat].catatans.spm
}
onChange={handleChange}
className='w-full'
placeholder='Masukkan catatan SPM'
readOnly
/>
</TabPanel>
</TabView>
</td>
</tr>
</tbody>
</table>
</div>
</AccordionTab>
)
})}
</Accordion>
</div>
<SubJudul className='text-lg mb-1'>Rekomendasi Verif</SubJudul>
<InputText
value={dataTagihan.rekomendasi_verifikator}
className='w-72'
readOnly
style={{ marginBottom: '12px' }}
/>
<SubJudul className='text-lg mb-1'>Rekomendasi Validasi</SubJudul>
<Dropdown
name={`details.${indexTagihan}.rekom_kasub`}
optionLabel='name'
optionValue='name'
value={values.details[indexTagihan].rekom_kasub}
options={
cekTMSH === 'tms'
? ddRekomendasi.filter((val) => val.name === 'Ditolak/dikembalikan')
: ddRekomendasi.filter((val) => val.name !== 'Ditolak/dikembalikan')
}
onChange={handleChange}
placeholder='Pilih rekomendasi'
className='w-80'
showClear={
values.details[indexTagihan].rekom_kasub
? values.details[indexTagihan].rekom_kasub === 'Ditolak/dikembalikan'
? false
: true
: false
}
readOnly={cekTMSH === 'tms' ? true : false}
/>
</AccordionTab>
)
})}
</Accordion>
<div className='mt-3 flex justify-center'>
<Button
type='submit'
label='Kirim'
onClick={handleSubmit}
className='p-button-sm'
loading={isSubmitting}
/>
</div>
</React.Fragment>
)
}}
</Formik>
)}
</Belakang>
</>
)
}
+171
View File
@@ -0,0 +1,171 @@
import { DatatablePrimeV2 } from '@/components/Datatables-v2'
import { Belakang } from '@/components/Layouts'
import { Judul } from '@/components/TextCustom'
import { VerifikasiList } from '@/services/otorisasi/verifikasi-service'
import { Formik } from 'formik'
import moment from 'moment'
import Head from 'next/head'
import Link from 'next/link'
import { Button } from 'primereact/button'
import { Calendar } from 'primereact/calendar'
import { Card } from 'primereact/card'
import { Column } from 'primereact/column'
import { InputText } from 'primereact/inputtext'
import { Toast } from 'primereact/toast'
import React, { useEffect, useRef, useState } from 'react'
export default function Rekomendasi() {
const toast = useRef(null)
const [data, setData] = useState([])
const [loading, setLoading] = useState(false)
const [search, setSearch] = useState({})
// DATATABLE
const [first, setFirst] = useState(0)
const [page, setPage] = useState(0)
const [length, setLength] = useState(10)
const [totalRecords, setTotalRecords] = useState(0)
const [orderDir, setOrderDir] = useState('desc')
const [orderCol, setOrderCol] = useState(2)
const [sort, setSort] = useState([])
useEffect(() => {
setLoading(true)
let params = {
draw: page,
start: first,
length: length,
order_col: orderCol,
order_dir: orderDir,
}
const { no_spp, tanggal_input } = search
params.no_spp = no_spp ? no_spp : ''
params.tanggal_input = tanggal_input ? moment(tanggal_input).format('YYYY-MM-DD') : ''
VerifikasiList(params).then((res) => {
setData(res.data)
setLoading(false)
setTotalRecords(
res.recordsFiltered === 1 ? 1 : res.recordsFiltered < 1 ? res.recordsFiltered : res.recordsFiltered
)
})
}, [page, first, length, search, orderCol, orderDir])
const actionBodyTemplate = (rowData) => {
return (
<div className='flex gap-x-2'>
<Link href={`/otorisasi/rekomendasi/form?tagihan_id=${rowData.tagihan_id}`}>
<Button icon='pi pi-play' label='Proses' className='p-button-sm p-button-rounded' />
</Link>
</div>
)
}
const Pencarian = (
<React.Fragment>
<Formik
initialValues={{ no_spp: '', tanggal_input: '' }}
onSubmit={(values) => {
const tempTanggalInput = values.tanggal_input
values.tanggal_input &&
Object.assign(values, { tanggal_input: moment(values.tanggal_input).format('YYYY-MM-D') })
setSearch(values)
values.tanggal_input = tempTanggalInput
}}
>
{({ values, handleChange, handleSubmit }) => {
return (
<form onSubmit={handleSubmit}>
<div className='flex gap-x-5 items-center justify-center'>
<div className='flex flex-col'>
<label htmlFor='no_spp'>No SPP</label>
<InputText
id='no_spp'
name='no_spp'
value={values.no_spp}
onChange={handleChange}
placeholder='Masukkan Nomor SPP'
/>
</div>
<div className='flex flex-col'>
<label htmlFor='no_spp'>Tanggal Kirim</label>
<Calendar
name='tanggal_input'
value={values.tanggal_input}
onChange={handleChange}
placeholder='e.g. 17 Agustus 1945'
dateFormat='dd MM yy'
showButtonBar
></Calendar>
</div>
<div className='flex flex-col'>
<label htmlFor=''>&nbsp;</label>
<Button type='submit' label='Cari' className='p-button-sm p-button-success' icon='pi pi-search' />
</div>
</div>
</form>
)
}}
</Formik>
</React.Fragment>
)
const bodyTanggal = (rowData) => {
return rowData.tanggal_kirim === '-' ? rowData.tanggal_kirim : moment(rowData.tanggal_kirim).format('DD MMMM YYYY')
}
return (
<>
<Toast ref={toast} />
<Head>
<title>Rekomendasi</title>
</Head>
<Belakang>
<Judul>Rekomendasi</Judul>
<Card className='card-search my-3'>{Pencarian}</Card>
<DatatablePrimeV2
data={data}
first={first}
length={length}
loading={loading}
page={page}
setFirst={setFirst}
setLength={setLength}
setPage={setPage}
totalRecords={totalRecords}
sort={sort}
onSort={(e) => {
setSort(e.multiSortMeta)
if (e.multiSortMeta.length > 0) {
switch (e.multiSortMeta[0].field) {
case 'no_spp':
setOrderCol(0)
break
case 'tanggal':
setOrderCol(2)
break
}
switch (e.multiSortMeta[0].order) {
case -1:
setOrderDir('desc')
break
case 1:
setOrderDir('asc')
break
}
}
}}
>
<Column field='no_spp' header='Nomor SPP' sortable></Column>
<Column field='unit' header='Unit'></Column>
<Column field='tanggal' header='Tanggal Kirim' body={bodyTanggal} sortable></Column>
<Column header='Action' body={actionBodyTemplate} exportable={false}></Column>
</DatatablePrimeV2>
</Belakang>
</>
)
}