done next login

dev
ajikamaludin 2 years ago
parent 4029cd099f
commit 724212f714
Signed by: ajikamaludin
GPG Key ID: 476C9A2B4B794EBB

@ -31,4 +31,14 @@ class GeneralController extends Controller
{
return Inertia::render('SettingPotongGaji/Index');
}
public function dataGaji()
{
return Inertia::render('Gaji/Index');
}
public function slipGaji()
{
return Inertia::render('Gaji/Slip');
}
}

51
package-lock.json generated

@ -6,6 +6,7 @@
"": {
"dependencies": {
"firebase": "^9.9.1",
"react-to-print": "^2.14.7",
"react-toastify": "^9.0.7"
},
"devDependencies": {
@ -2919,6 +2920,16 @@
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.3.tgz",
"integrity": "sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g=="
},
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
},
"node_modules/protobufjs": {
"version": "6.11.3",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz",
@ -3016,6 +3027,11 @@
"react": "17.0.2"
}
},
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/react-refresh": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
@ -3025,6 +3041,18 @@
"node": ">=0.10.0"
}
},
"node_modules/react-to-print": {
"version": "2.14.7",
"resolved": "https://registry.npmjs.org/react-to-print/-/react-to-print-2.14.7.tgz",
"integrity": "sha512-lWVVAs9Co25uyE0toxcWeFsmaZObwUozXrJD9WMpDPclpBgk+WIzxlt3Q3omL/BCBG/cpf0XNvhayUWa+99YGw==",
"dependencies": {
"prop-types": "^15.8.1"
},
"peerDependencies": {
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-toastify": {
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.0.7.tgz",
@ -5702,6 +5730,16 @@
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.3.tgz",
"integrity": "sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g=="
},
"prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
},
"protobufjs": {
"version": "6.11.3",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz",
@ -5762,12 +5800,25 @@
"scheduler": "^0.20.2"
}
},
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"react-refresh": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
"integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==",
"dev": true
},
"react-to-print": {
"version": "2.14.7",
"resolved": "https://registry.npmjs.org/react-to-print/-/react-to-print-2.14.7.tgz",
"integrity": "sha512-lWVVAs9Co25uyE0toxcWeFsmaZObwUozXrJD9WMpDPclpBgk+WIzxlt3Q3omL/BCBG/cpf0XNvhayUWa+99YGw==",
"requires": {
"prop-types": "^15.8.1"
}
},
"react-toastify": {
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.0.7.tgz",

@ -24,6 +24,7 @@
},
"dependencies": {
"firebase": "^9.9.1",
"react-to-print": "^2.14.7",
"react-toastify": "^9.0.7"
}
}

@ -4,4 +4,18 @@
.select {
@apply border mt-1 border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-28 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500
}
.print-only{
display: none;
}
@media print {
.no-print {
display: none;
}
.print-only{
display: block;
}
}

@ -1,13 +1,14 @@
import React from 'react'
export function Modal({ isOpen, toggleModal = () => {}, children, size = 'lg' }) {
export function Modal({ isOpen, toggleModal = () => {}, children, size = "md" }) {
return (
<div
className={`overflow-y-auto overflow-x-hidden bg-opacity-50 dark:bg-opacity-50 bg-gray-500 dark:bg-gray-400 fixed flex right-0 left-0 top-0 z-50 justify-center items-center h-full md:inset-0 ${
isOpen ? 'visible' : 'hidden'
}`}
>
<div className={`md:relative fixed bottom-0 md:px-4 w-full max-w-${size} h-auto`}>
<div className={`md:relative fixed bottom-0 md:px-4 w-full ${size == 'md' ? 'max-w-md' : 'max-w-4xl'} h-auto`}>
<div className="relative overflow-y-auto max-h-screen bg-white rounded-b-none rounded-t-lg md:rounded-lg shadow dark:bg-gray-800 pb-10 md:pb-0 ">
<div className="flex justify-end p-2">
<button

@ -88,6 +88,24 @@ export default function Authenticated({ auth, children }) {
<ResponsiveNavLink href={route('dashboard')} active={route().current('dashboard')}>
Dashboard
</ResponsiveNavLink>
<ResponsiveNavLink href={route('jabatan')} active={route().current('jabatan')}>
Jabatan
</ResponsiveNavLink>
<ResponsiveNavLink href={route('karyawan')} active={route().current('karyawan')}>
Karyawan
</ResponsiveNavLink>
<ResponsiveNavLink href={route('absensi')} active={route().current('absensi')}>
Data Absesnsi
</ResponsiveNavLink>
<ResponsiveNavLink href={route('setting.potongan.gaji')} active={route().current('setting.potongan.gaji')}>
Setting Potongan Gaji
</ResponsiveNavLink>
<ResponsiveNavLink href={route('gaji')} active={route().current('gaji')}>
Data Gaji
</ResponsiveNavLink>
<ResponsiveNavLink href={route('slip.gaji')} active={route().current('slip.gaji')}>
Slip Gaji
</ResponsiveNavLink>
</div>
<div className="pt-4 pb-1 border-t border-gray-200">
@ -136,18 +154,13 @@ export default function Authenticated({ auth, children }) {
</Link>
</li>
<li>
<Link href={route('dashboard')} className={`flex items-center p-2 text-base font-normal text-gray-900 rounded-lg dark:text-white ${route().current('cetak.slip.gaji') ? 'bg-gray-100' : 'hover:bg-gray-100'} dark:hover:bg-gray-700`}>
<Link href={route('gaji')} className={`flex items-center p-2 text-base font-normal text-gray-900 rounded-lg dark:text-white ${route().current('gaji') ? 'bg-gray-100' : 'hover:bg-gray-100'} dark:hover:bg-gray-700`}>
<span className="flex-1 ml-3 whitespace-nowrap">Data Gaji</span>
</Link>
</li>
<li>
<Link href={route('dashboard')} className={`flex items-center p-2 text-base font-normal text-gray-900 rounded-lg dark:text-white ${route().current('cetak.laporan.gaji') ? 'bg-gray-100' : 'hover:bg-gray-100'} dark:hover:bg-gray-700`}>
<span className="flex-1 ml-3 whitespace-nowrap">Cetak Laporan Gaji</span>
</Link>
</li>
<li>
<Link href={route('dashboard')} className={`flex items-center p-2 text-base font-normal text-gray-900 rounded-lg dark:text-white ${route().current('cetak.laporan.presensi') ? 'bg-gray-100' : 'hover:bg-gray-100'} dark:hover:bg-gray-700`}>
<span className="flex-1 ml-3 whitespace-nowrap">Cetak Laporan Presensi</span>
<Link href={route('slip.gaji')} className={`flex items-center p-2 text-base font-normal text-gray-900 rounded-lg dark:text-white ${route().current('slip.gaji') ? 'bg-gray-100' : 'hover:bg-gray-100'} dark:hover:bg-gray-700`}>
<span className="flex-1 ml-3 whitespace-nowrap">Slip Gaji</span>
</Link>
</li>
</ul>

@ -59,7 +59,7 @@ export default function FormModal({ modalState, periode }) {
}
return (
<Modal isOpen={modalState.isOpen} toggleModal={modalState.toggle} size="4xl">
<Modal isOpen={modalState.isOpen} toggleModal={modalState.toggle} size="2xl">
<div className="text-lg font-bold">Absensi Karyawan</div>
<div className="text-md">Periode : {periode}</div>
<div className="overflow-x-auto relative pt-5">

@ -1,15 +1,88 @@
import React, { useEffect, useState } from 'react';
import React, { useRef, useState } from 'react';
import Authenticated from '@/Layouts/Authenticated';
import { Head, useForm } from '@inertiajs/inertia-react';
import { useModalState } from '@/Hooks'
import Button from '@/Components/Button';
import FormModal from './FormModal';
import { useReactToPrint } from 'react-to-print';
import { getByPeriode } from '@/Services/Absensi';
import { toast } from 'react-toastify';
const ComponentToPrint = React.forwardRef(({ absensi, month, year }, ref) => {
const date = new Date()
return (
<div ref={ref} className="p-5 print-only">
<div className='w-full text-center p-2'>
<p className='font-bold text-3xl'>Koro Koro Family Karaoke</p>
<p className='text-xl'>Periode Absen Bulan {month} Tahun {year}</p>
</div>
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400 mt-5">
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" className="py-3 px-6">
NIK
</th>
<th scope="col" className="py-3 px-6">
Nama
</th>
<th scope="col" className="py-3 px-6">
Jenis Kelamin
</th>
<th scope="col" className="py-3 px-6">
Jabatan
</th>
<th scope="col" className="py-3 px-6">Hadir</th>
<th scope="col" className="py-3 px-6">Sakit</th>
<th scope="col" className="py-3 px-6">Alfa</th>
</tr>
</thead>
<tbody>
{absensi.data?.users?.map(item => (
<tr key={item.id} className="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
<th scope="row" className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{item.nik}
</th>
<td className="py-4 px-6">
{item.name}
</td>
<td className="py-4 px-6">
{item.jenisKelamin}
</td>
<td className="py-4 px-6">
{item.jabatan}
</td>
<td>
{item.hadir}
</td>
<td>
{item.sakit}
</td>
<td>
{item.alfa}
</td>
</tr>
))}
</tbody>
</table>
<div className='flex justify-end mt-5 mr-5'>
<div className='flex flex-col'>
<p>Pekanbaru, {date.getDate()}-{date.getMonth()}-{date.getFullYear()}</p>
<p>Finance</p>
<div className='border-black border-2 mt-20'/>
</div>
</div>
</div>
)
})
export default function Karyawan(props) {
const formModal = useModalState(false)
const componentRef = useRef();
const handlePrint = useReactToPrint({
content: () => componentRef.current,
});
const month = (new Date()).getMonth()
const year = (new Date()).getFullYear()
const months = [1,2,3,4,5,6,7,8,9,10,11,12]
@ -125,6 +198,12 @@ export default function Karyawan(props) {
))}
</tbody>
</table>
<ComponentToPrint ref={componentRef} absensi={absensi} month={data.month} year={data.year}/>
{absensi.data?.users?.length > 0 && (
<div className='flex justify-end'>
<Button onClick={handlePrint} className="mt-2">Cetak</Button>
</div>
)}
</div>
</div>
</div>

@ -0,0 +1,129 @@
import React, { useEffect, useState } from 'react'
import { toast } from 'react-toastify'
import { Modal } from '@/Components/Modal'
import { useForm } from '@inertiajs/inertia-react'
import Button from '@/Components/Button'
import Input from '@/Components/Input'
import { getAll } from '@/Services/Karyawan'
import { create } from '@/Services/Absensi'
export default function FormModal({ modalState, periode }) {
const [loading, setLoading] = useState(false)
const { data, setData, reset } = useForm({
users: []
})
useEffect(() => {
getAll()
.then(items => setData({
users: items.filter(item => item.data.jabatan.id != "1").map(item => {
return {
id: item.id,
name: item.data.name,
nik: item.data.nik,
jenisKelamin: item.data.jenisKelamin,
jabatan: item.data.jabatan.nama,
jabatan_id: item.data.jabatan.id,
hadir: 0,
sakit: 0,
alfa: 0,
}
})
}))
},[modalState])
const onHandleChange = (item, event) => {
setData({
users: data.users.map(user => {
if (user.id == item.id) {
user[event.target.name] = event.target.value
}
return user
})
})
}
const submit = (e) => {
e.preventDefault()
setLoading(true)
create({
...data,
periode: periode,
})
.then(() => {
reset()
modalState.toggle()
toast.success("berhasil menambahkan absensi")
})
.finally(() => setLoading(false))
}
return (
<Modal isOpen={modalState.isOpen} toggleModal={modalState.toggle} size="2xl">
<div className="text-lg font-bold">Absensi Karyawan</div>
<div className="text-md">Periode : {periode}</div>
<div className="overflow-x-auto relative pt-5">
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" className="py-3 px-6">
NIK
</th>
<th scope="col" className="py-3 px-6">
Nama
</th>
<th scope="col" className="py-3 px-6">
Jenis Kelamin
</th>
<th scope="col" className="py-3 px-6">
Jabatan
</th>
<th scope="col" className="py-3 px-6">Hadir</th>
<th scope="col" className="py-3 px-6">Sakit</th>
<th scope="col" className="py-3 px-6">Alfa</th>
</tr>
</thead>
<tbody>
{data.users.map(item => (
<tr key={item.id} className="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
<th scope="row" className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{item.nik}
</th>
<td className="py-4 px-6">
{item.name}
</td>
<td className="py-4 px-6">
{item.jenisKelamin}
</td>
<td className="py-4 px-6">
{item.jabatan}
</td>
<td>
<Input
name="hadir"
value={item.hadir}
handleChange={(e) => onHandleChange(item, e)}/>
</td>
<td>
<Input
name="sakit"
value={item.sakit}
handleChange={(e) => onHandleChange(item, e)}/>
</td>
<td>
<Input
name="alfa"
value={item.alfa}
handleChange={(e) => onHandleChange(item, e)}/>
</td>
</tr>
))}
</tbody>
</table>
</div>
<Button className={'mt-4'} onClick={submit} disabled={loading} processing={loading}>
Save
</Button>
</Modal>
)
}

@ -0,0 +1,265 @@
import React, { useRef, useState } from 'react';
import Authenticated from '@/Layouts/Authenticated';
import { Head, useForm } from '@inertiajs/inertia-react';
import { useModalState } from '@/Hooks'
import Button from '@/Components/Button';
import FormModal from './FormModal';
import { getDataGaji } from '@/Services/DataGaji';
import { useReactToPrint } from 'react-to-print';
import { formatIDR } from '@/Utils';
const ComponentToPrint = React.forwardRef(({ items, month, year }, ref) => {
const date = new Date()
return (
<div ref={ref} className="p-5 print-only">
<div className='w-full text-center p-2'>
<p className='font-bold text-3xl'>Koro Koro Family Karaoke</p>
<p className='text-xl'>Periode Gaji Bulan {month} Tahun {year}</p>
</div>
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400 mt-5 block whitespace-nowrap">
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" className="py-3 px-6">
NIK
</th>
<th scope="col" className="py-3 px-6">
Nama
</th>
<th>
Jabatan
</th>
<th scope="col" className='px-2'>
Gaji Pokok
</th>
<th scope="col" className='px-2'>
Tunjangan
</th>
<th scope="col" className='px-2'>
Fee Penjualan
</th>
<th scope="col" className='px-2'>
Uang Transport
</th>
<th scope="col" className='px-2'>
Uang Makan
</th>
<th scope="col" className='px-2'>
Bonus
</th>
<th scope="col" className='px-2'>
Potongan
</th>
<th scope="col" className='px-2'>
Total
</th>
</tr>
</thead>
<tbody>
{items.map(item => (
<tr key={item.id} className="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
<th scope="row" className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{item.nik}
</th>
<td>
{item.name}
</td>
<td>
{item.jabatan}
</td>
<td>
Rp. {formatIDR(item.gajiPokok)}
</td>
<td>
Rp. {formatIDR(item.tunjangan)}
</td>
<td>
Rp. {formatIDR(item.feePenjualan)}
</td>
<td>
Rp. {formatIDR(item.transport)}
</td>
<td>
Rp. {formatIDR(item.uangMakan)}
</td>
<td>
Rp. {formatIDR(item.bonus)}
</td>
<td>
Rp. {formatIDR(item.potongan)}
</td>
<td>
Rp. {formatIDR(item.total)}
</td>
</tr>
))}
</tbody>
</table>
<div className='flex justify-end mt-5 mr-5'>
<div className='flex flex-col'>
<p>Pekanbaru, {date.getDate()}-{date.getMonth()}-{date.getFullYear()}</p>
<p>Finance</p>
<div className='border-black border-2 mt-20'/>
</div>
</div>
</div>
)
})
export default function Gaji(props) {
const formModal = useModalState(false)
const componentRef = useRef();
const handlePrint = useReactToPrint({
content: () => componentRef.current,
});
const month = (new Date()).getMonth()
const year = (new Date()).getFullYear()
const months = [1,2,3,4,5,6,7,8,9,10,11,12]
const years = [+year-2, +year-1, year, +year+1, +year+2]
const {data, setData} = useForm({
month: month,
year: year
})
const onHandleChange = (event) => {
setData(
event.target.name,
event.target.type === 'checkbox'
? event.target.checked
: event.target.value
)
}
const [items, setItems] = useState([])
const onClickShow = () => {
getDataGaji(`${data.month}_${data.year}`, setItems)
}
return (
<Authenticated
auth={props.auth}
errors={props.errors}
>
<Head title="Data Gaji" />
<div className="py-0">
<div className="max-w-3xl xl:max-w-7xl w-full sm:px-6">
<div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div className="p-6 bg-white border-b border-gray-200">
<div className='mb-5 text-3xl font-semibold'>
Data Gaji
</div>
<div className='flex flex-col md:flex-row space-y-1 md:space-y-0 justify-between'>
<div className='flex space-x-1 items-center'>
<p>Periode Data :</p>
<select className='select' value={data.month} name="month" onChange={onHandleChange}>
<option value="">Bulan</option>
{months.map(month => (
<option key={month}>{month}</option>
))}
</select>
<select className='select' value={data.year} name="year" onChange={onHandleChange}>
<option>Tahun</option>
{years.map(year => (
<option key={year}>{year}</option>
))}
</select>
</div>
<div className='flex space-x-1'>
<Button onClick={onClickShow}>Tampilkan Data</Button>
</div>
</div>
<ComponentToPrint ref={componentRef} items={items} month={data.month} year={data.year}/>
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400 mt-5 block overflow-x-auto whitespace-nowrap">
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" className="py-3 px-6">
NIK
</th>
<th scope="col" className="py-3 px-6">
Nama
</th>
<th>
Jabatan
</th>
<th scope="col" className='px-2'>
Gaji Pokok
</th>
<th scope="col" className='px-2'>
Tunjangan
</th>
<th scope="col" className='px-2'>
Fee Penjualan
</th>
<th scope="col" className='px-2'>
Uang Transport
</th>
<th scope="col" className='px-2'>
Uang Makan
</th>
<th scope="col" className='px-2'>
Bonus
</th>
<th scope="col" className='px-2'>
Potongan
</th>
<th scope="col" className='px-2'>
Total
</th>
</tr>
</thead>
<tbody>
{items.map(item => (
<tr key={item.id} className="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
<th scope="row" className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white">
{item.nik}
</th>
<td className="py-4 px-6">
{item.name}
</td>
<td className="py-4 px-6">
{item.jabatan}
</td>
<td>
Rp. {formatIDR(item.gajiPokok)}
</td>
<td>
Rp. {formatIDR(item.tunjangan)}
</td>
<td>
Rp. {formatIDR(item.feePenjualan)}
</td>
<td>
Rp. {formatIDR(item.transport)}
</td>
<td>
Rp. {formatIDR(item.uangMakan)}
</td>
<td>
Rp. {formatIDR(item.bonus)}
</td>
<td>
Rp. {formatIDR(item.potongan)}
</td>
<td>
Rp. {formatIDR(item.total)}
</td>
</tr>
))}
</tbody>
</table>
{items.length > 0 && (
<div className='flex justify-end'>
<Button onClick={handlePrint} className="mt-2">Cetak</Button>
</div>
)}
</div>
</div>
</div>
</div>
<FormModal modalState={formModal} periode={`${data.month}_${data.year}`}/>
</Authenticated>
);
}

@ -0,0 +1,195 @@
import React, { useEffect, useRef, useState } from 'react';
import Authenticated from '@/Layouts/Authenticated';
import { Head, useForm } from '@inertiajs/inertia-react';
import { useModalState } from '@/Hooks'
import Button from '@/Components/Button';
import FormModal from './FormModal';
import { getDataGaji } from '@/Services/DataGaji';
import { useReactToPrint } from 'react-to-print';
import { formatIDR } from '@/Utils';
const ComponentToPrint = React.forwardRef(({ user, month, year }, ref) => {
const date = new Date()
return (
<div ref={ref} className="p-5 print-only">
<div className='w-full text-center p-2 flex flex-col justify-center items-center'>
<p className='font-bold text-3xl'>Koro Koro Family Karaoke</p>
<p className='text-xl border-b-2 w-2/3'>Slip Gaji Pegawai</p>
</div>
<table className='ml-10'>
<tbody>
<tr>
<td>Nama Karyawan </td>
<td>: {user?.name}</td>
</tr>
<tr>
<td>NIK </td>
<td>: {user?.nik}</td>
</tr>
<tr>
<td>Jabatan </td>
<td>: {user?.jabatan}</td>
</tr>
<tr>
<td>Bulan </td>
<td>: {month}</td>
</tr>
<tr>
<td>Tahun</td>
<td>: {year}</td>
</tr>
</tbody>
</table>
<table className="w-full text-sm text-left text-gray-800 dark:text-gray-400 mt-5" border={1}>
<tbody>
<tr className="bg-white border dark:bg-gray-800 dark:border-gray-700">
<td className="border px-2 py-2 font-bold">No</td>
<td className="border px-2 py-2 font-bold">Keterangan</td>
<td className="border px-2 py-2 font-bold">Jumlah</td>
</tr>
<tr className="bg-white border dark:bg-gray-800 dark:border-gray-700">
<td className="border px-2 py-2">1</td>
<td className="border px-2 py-2">Gaji Pokok</td>
<td className="border px-2 py-2">Rp. {formatIDR(user?.gajiPokok)}</td>
</tr>
<tr className="bg-white border dark:bg-gray-800 dark:border-gray-700">
<td className="border px-2 py-2">2</td>
<td className="border px-2 py-2">Tunjangan Jabatan</td>
<td className="border px-2 py-2">Rp. {formatIDR(user?.tunjangan)}</td>
</tr>
<tr className="bg-white border dark:bg-gray-800 dark:border-gray-700">
<td className="border px-2 py-2">3</td>
<td className="border px-2 py-2">Fee Penjualan</td>
<td className="border px-2 py-2">Rp. {formatIDR(user?.feePenjualan)}</td>
</tr>
<tr className="bg-white border dark:bg-gray-800 dark:border-gray-700">
<td className="border px-2 py-2">4</td>
<td className="border px-2 py-2">Tunjangan Transaportasi</td>
<td className="border px-2 py-2">Rp. {formatIDR(user?.transport)}</td>
</tr>
<tr className="bg-white border dark:bg-gray-800 dark:border-gray-700">
<td className="border px-2 py-2">5</td>
<td className="border px-2 py-2">Uang Makan</td>
<td className="border px-2 py-2">Rp. {formatIDR(user?.uangMakan)}</td>
</tr>
<tr className="bg-white border dark:bg-gray-800 dark:border-gray-700">
<td className="border px-2 py-2">6</td>
<td className="border px-2 py-2">Bonus</td>
<td className="border px-2 py-2">Rp. {formatIDR(user?.bonus)}</td>
</tr>
<tr className="bg-white border dark:bg-gray-800 dark:border-gray-700">
<td className="border px-2 py-2">7</td>
<td className="border px-2 py-2">Potongan</td>
<td className="border px-2 py-2">Rp. {formatIDR(user?.potongan)}</td>
</tr>
<tr className="bg-white border dark:bg-gray-800 dark:border-gray-700">
<td colSpan={2} className="text-right font-bold">Total Gaji</td>
<td className="border px-2 py-2">Rp. {formatIDR(user?.total)}</td>
</tr>
</tbody>
</table>
<div className='flex justify-between mt-5 mr-5'>
<div className='flex flex-col ml-10'>
<p>Pegawai</p>
<div className='mt-20'>{user?.name}</div>
</div>
<div className='flex flex-col'>
<p>Pekanbaru, {date.getDate()}-{date.getMonth()}-{date.getFullYear()}</p>
<p>Finance</p>
<div className='border-black border-2 mt-20'/>
</div>
</div>
</div>
)
})
export default function Gaji(props) {
const formModal = useModalState(false)
const componentRef = useRef();
const handlePrint = useReactToPrint({
content: () => componentRef.current,
});
const month = (new Date()).getMonth()
const year = (new Date()).getFullYear()
const months = [1,2,3,4,5,6,7,8,9,10,11,12]
const years = [+year-2, +year-1, year, +year+1, +year+2]
const {data, setData} = useForm({
month: month,
year: year,
userId: '',
})
console.log(data.userId)
const onHandleChange = (event) => {
setData(
event.target.name,
event.target.type === 'checkbox'
? event.target.checked
: event.target.value
)
}
const [items, setItems] = useState([])
const user = items.find(item => item.id == data.userId)
useEffect(() => {
getDataGaji(`${data.month}_${data.year}`, setItems)
}, [data])
return (
<Authenticated
auth={props.auth}
errors={props.errors}
>
<Head title="Slip Gaji" />
<div className="py-0">
<div className="max-w-3xl xl:max-w-7xl w-full sm:px-6">
<div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div className="p-6 bg-white border-b border-gray-200">
<div className='mb-5 text-3xl font-semibold'>
Slip Gaji
</div>
<div className='flex flex-col space-y-2 justify-center'>
<div className='flex flex-row items-center space-x-2'>
<label>Bulan</label>
<select className='select' value={data.month} name="month" onChange={onHandleChange}>
<option value="">Bulan</option>
{months.map(month => (
<option key={month}>{month}</option>
))}
</select>
</div>
<div className='flex flex-row items-center space-x-2'>
<label>Tahun</label>
<select className='select' value={data.year} name="year" onChange={onHandleChange}>
<option>Tahun</option>
{years.map(year => (
<option key={year}>{year}</option>
))}
</select>
</div>
<div className='flex flex-row items-center space-x-2'>
<label>Karyawan</label>
<select className='select' value={data.userId} name="userId" onChange={onHandleChange}>
<option value="">Karyawan</option>
{items.map(em => (
<option key={em.id} value={em.id}>{em.name}</option>
))}
</select>
</div>
<div>
<Button onClick={handlePrint}>Cetak</Button>
</div>
</div>
<ComponentToPrint ref={componentRef} user={user} month={data.month} year={data.year}/>
</div>
</div>
</div>
</div>
<FormModal modalState={formModal} periode={`${data.month}_${data.year}`}/>
</Authenticated>
);
}

@ -43,7 +43,7 @@ export default function Jabatan(props) {
<Head title="Jabatan" />
<div className="py-0">
<div className="max-w-7xl sm:px-6">
<div className="max-w-3xl lg:max-w-5xl sm:px-6">
<div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div className="p-6 bg-white border-b border-gray-200">
<div className='mb-5 text-3xl font-semibold'>
@ -51,7 +51,7 @@ export default function Jabatan(props) {
</div>
<Button onClick={formModal.toggle}>Tambah</Button>
<div className="overflow-x-auto relative pt-5">
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400 overflow-x-auto whitespace-nowrap block">
<thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" className="py-3 px-6">

@ -4,7 +4,7 @@ import { Head } from '@inertiajs/inertia-react';
import { useModalState } from '@/Hooks'
import Button from '@/Components/Button';
import FormModal from './FormModal';
import { getAll } from '@/Services/SettingPotonganGaji';
import { getAll, deleteById } from '@/Services/SettingPotonganGaji';
import { toast } from 'react-toastify';
import { formatIDR } from '@/Utils';
@ -30,7 +30,6 @@ export default function Karyawan(props) {
const fetchData = () => {
getAll()
.then(items => {
console.log(items)
setItems(items)
})
}

@ -0,0 +1,56 @@
import { getByPeriode } from './Absensi'
import { getAll as getJabatan } from './Jabatan'
import { getAll as getPotongan } from './SettingPotonganGaji'
import { toast } from "react-toastify";
async function getDataGaji(periode, setLists) {
let potongan = []
getJabatan()
.then(jabatans => {
getByPeriode(periode).then(items => {
if(items[0] == undefined) {
setLists([])
toast.error("data tidak tersedia")
return
}
getPotongan()
.then(p => p.map(item => {
potongan.push(item)
}))
.finally(() => {
let alfa = potongan.find(pot => pot.data.jenis == 'alfa')
let sakit = potongan.find(pot => pot.data.jenis == 'sakit')
let employees = items[0].data.users.map(employee => {
let jab = jabatans.find(item => item.id == employee.jabatan_id)
let potong = 0
if(alfa != undefined) {
potong += +alfa.data.potongan * +employee.alfa
}
if(sakit != undefined) {
potong += +sakit.data.potongan * +employee.sakit
}
return {
...employee,
gajiPokok: jab.data.gajiPokok,
tunjangan: jab.data.tunjangan,
feePenjualan: jab.data.feePenjualan,
transport: jab.data.transport,
uangMakan: jab.data.uangMakan,
bonus: jab.data.bonus,
potongan: potong,
total: +jab.data.total - +potong
}
})
setLists(employees)
})
})
})
}
export {
getDataGaji
}

@ -1,33 +0,0 @@
import { useState } from "react";
import db from "@/firebase";
import { collection, getDocs, doc, addDoc, deleteDoc, updateDoc, query, where } from "firebase/firestore";
import { getAll as getKaryawan } from './Karyawan'
import { getAll as getJabatan } from './Jabatan'
async function getDataGaji() {
const [lists, setLists] = useState([])
const [jabatans, setJabatan] = useState([])
Promise.all([
() => getJabatan().then(items => setJabatan(items)),
() => getKaryawan().then(items => {
const employees = items.map(employee => {
const jab = jabatans.find(item => item.id == employee.data.jabatan.id)
// TODO: fetch potongan
return {
...employee,
gajiPokok: jab.gajiPokok,
tunjangan: jab.tunjangan,
feePenjualan: jab.feePenjualan,
transport: jab.transport,
uangMakan: jab.uangMakan,
bonus: jab.bonus,
total: jab.total
}
})
setLists(employees)
}),
])
return lists
}

@ -27,7 +27,6 @@ async function update(payload, id){
}
async function deleteById(id) {
console.log(id)
const docRef = doc(db, COLLECTION, id)
const result = await deleteDoc(docRef);
return result

@ -27,7 +27,6 @@ async function update(payload, id){
}
async function deleteById(id) {
console.log(id)
const docRef = doc(db, COLLECTION, id)
const result = await deleteDoc(docRef);
return result

@ -33,5 +33,7 @@ Route::middleware([IsSessionAuth::class])->group(function () {
Route::get('/karyawan', [GeneralController::class, 'karyawan'])->name('karyawan');
Route::get('/absensi', [GeneralController::class, 'absensi'])->name('absensi');
Route::get('/setting-potong-gaji', [GeneralController::class, 'settingPotongGaji'])->name('setting.potongan.gaji');
Route::get('/data-gaji', [GeneralController::class, 'dataGaji'])->name('gaji');
Route::get('/slip-gaji', [GeneralController::class, 'slipGaji'])->name('slip.gaji');
Route::post('/logout', [AuthController::class, 'destroy'])->name('logout');
});

Loading…
Cancel
Save