absensi done
parent
4ff9f62274
commit
3a30d72203
@ -1,3 +1,7 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
.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
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
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, refresh }) {
|
||||
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()
|
||||
})
|
||||
.finally(() => setLoading(false))
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal isOpen={modalState.isOpen} toggleModal={modalState.toggle} size="4xl">
|
||||
<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,132 @@
|
||||
import React, { useEffect, 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 { getByPeriode } from '@/Services/Absensi';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
export default function Karyawan(props) {
|
||||
const formModal = useModalState(false)
|
||||
|
||||
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 [absensi, setAbsensi] = useState({})
|
||||
const onClickShow = () => {
|
||||
setAbsensi({})
|
||||
getByPeriode(`${data.month}_${data.year}`)
|
||||
.then(items => {
|
||||
if(items.length <= 0) {
|
||||
toast.error("No data found")
|
||||
return
|
||||
}
|
||||
setAbsensi(items[0])
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Authenticated
|
||||
auth={props.auth}
|
||||
errors={props.errors}
|
||||
>
|
||||
<Head title="Absensi" />
|
||||
|
||||
<div className="py-0">
|
||||
<div className="max-w-7xl 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='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>
|
||||
<Button onClick={formModal.toggle}>Tambah Absensi</Button>
|
||||
</div>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<FormModal modalState={formModal} periode={`${data.month}_${data.year}`}/>
|
||||
</Authenticated>
|
||||
);
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
import db from "@/firebase";
|
||||
import { collection, getDocs, doc, addDoc, deleteDoc, updateDoc, query, where } from "firebase/firestore";
|
||||
|
||||
const COLLECTION = "absensi"
|
||||
|
||||
async function getAll() {
|
||||
const collect = collection(db, COLLECTION)
|
||||
const data = await getDocs(collect)
|
||||
const lists = data.docs.map(doc => {
|
||||
return {
|
||||
data: doc.data(),
|
||||
id: doc.id
|
||||
}
|
||||
})
|
||||
return lists
|
||||
}
|
||||
|
||||
async function getByPeriode(periode) {
|
||||
const collect = query(collection(db, COLLECTION), where("periode", "==", periode))
|
||||
const data = await getDocs(collect)
|
||||
if (data.size <= 0) {
|
||||
return []
|
||||
}
|
||||
const lists = data.docs.map(doc => {
|
||||
return {
|
||||
data: doc.data(),
|
||||
id: doc.id
|
||||
}
|
||||
})
|
||||
return lists
|
||||
}
|
||||
|
||||
async function create(payload) {
|
||||
const docRef = await addDoc(collection(db, COLLECTION), payload)
|
||||
return docRef.id
|
||||
}
|
||||
|
||||
async function update(payload, id){
|
||||
const docRef = doc(db, COLLECTION, id)
|
||||
const result = await updateDoc(docRef, payload);
|
||||
return result
|
||||
}
|
||||
|
||||
async function deleteById(id) {
|
||||
console.log(id)
|
||||
const docRef = doc(db, COLLECTION, id)
|
||||
const result = await deleteDoc(docRef);
|
||||
return result
|
||||
}
|
||||
|
||||
export {
|
||||
getAll,
|
||||
create,
|
||||
update,
|
||||
deleteById,
|
||||
getByPeriode
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
export function formatIDR(amount) {
|
||||
const idFormatter = new Intl.NumberFormat('id-ID')
|
||||
return idFormatter.format(amount)
|
||||
}
|
Loading…
Reference in New Issue