crud jabatan done
parent
0397720ad4
commit
401f8575a8
@ -0,0 +1,40 @@
|
||||
import React from 'react'
|
||||
|
||||
export function Modal({ isOpen, toggleModal = () => {}, children }) {
|
||||
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-lg 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
|
||||
type="button"
|
||||
onClick={() => toggleModal()}
|
||||
className="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center dark:hover:bg-gray-800 dark:hover:text-white"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
||||
clipRule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="pt-2 p-6 text-gray-500 dark:text-gray-400">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
export function useDebounce(value, delay) {
|
||||
const [debouncedValue, setDebouncedValue] = useState(value)
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => {
|
||||
setDebouncedValue(value)
|
||||
}, delay)
|
||||
return () => {
|
||||
clearTimeout(handler)
|
||||
}
|
||||
}, [value, delay])
|
||||
return debouncedValue
|
||||
}
|
||||
|
||||
export function useModalState(state = false) {
|
||||
const [isOpen, setIsOpen] = useState(state)
|
||||
const toggle = () => {
|
||||
setIsOpen(!isOpen)
|
||||
}
|
||||
|
||||
const [data, setData] = useState(null)
|
||||
|
||||
return {
|
||||
isOpen,
|
||||
toggle,
|
||||
setIsOpen,
|
||||
data,
|
||||
setData,
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
import React from 'react';
|
||||
import Authenticated from '@/Layouts/Authenticated';
|
||||
import { Head } from '@inertiajs/inertia-react';
|
||||
import Button from '@/Components/Button';
|
||||
|
||||
export default function Jabatan(props) {
|
||||
return (
|
||||
<Authenticated
|
||||
auth={props.auth}
|
||||
errors={props.errors}
|
||||
>
|
||||
<Head title="Jabatan" />
|
||||
|
||||
<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">
|
||||
<Button>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">
|
||||
<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">
|
||||
Product name
|
||||
</th>
|
||||
<th scope="col" className="py-3 px-6">
|
||||
Color
|
||||
</th>
|
||||
<th scope="col" className="py-3 px-6">
|
||||
Category
|
||||
</th>
|
||||
<th scope="col" className="py-3 px-6">
|
||||
Price
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr 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">
|
||||
Apple MacBook Pro 17"
|
||||
</th>
|
||||
<td className="py-4 px-6">
|
||||
Sliver
|
||||
</td>
|
||||
<td className="py-4 px-6">
|
||||
Laptop
|
||||
</td>
|
||||
<td className="py-4 px-6">
|
||||
$2999
|
||||
</td>
|
||||
</tr>
|
||||
<tr 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">
|
||||
Microsoft Surface Pro
|
||||
</th>
|
||||
<td className="py-4 px-6">
|
||||
White
|
||||
</td>
|
||||
<td className="py-4 px-6">
|
||||
Laptop PC
|
||||
</td>
|
||||
<td className="py-4 px-6">
|
||||
$1999
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="bg-white dark:bg-gray-800">
|
||||
<th scope="row" className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
Magic Mouse 2
|
||||
</th>
|
||||
<td className="py-4 px-6">
|
||||
Black
|
||||
</td>
|
||||
<td className="py-4 px-6">
|
||||
Accessories
|
||||
</td>
|
||||
<td className="py-4 px-6">
|
||||
$99
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Authenticated>
|
||||
);
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
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 { create, update } from '@/Services/Jabatan'
|
||||
|
||||
export default function FormModal({ modalState, refresh }) {
|
||||
const [loading, setLoading] = useState(false)
|
||||
const { data, setData, reset } = useForm({
|
||||
nama: '',
|
||||
tunjangan: 0
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (modalState.isOpen === false) {
|
||||
reset()
|
||||
modalState.setData(null)
|
||||
}
|
||||
if (modalState.data !== null) {
|
||||
setData(modalState.data.data)
|
||||
}
|
||||
}, [modalState])
|
||||
|
||||
const onHandleChange = (event) => {
|
||||
setData(
|
||||
event.target.name,
|
||||
event.target.type === 'checkbox'
|
||||
? event.target.checked
|
||||
: event.target.value
|
||||
)
|
||||
}
|
||||
|
||||
const submit = (e) => {
|
||||
e.preventDefault()
|
||||
setLoading(true)
|
||||
if (modalState.data !== null) {
|
||||
update(data, modalState.data.id)
|
||||
.finally(() => {
|
||||
reset()
|
||||
toast.success("berhasil update")
|
||||
setLoading(false)
|
||||
modalState.toggle()
|
||||
refresh()
|
||||
})
|
||||
} else {
|
||||
create(data)
|
||||
.then((id) => console.log(id))
|
||||
.finally(() => {
|
||||
reset()
|
||||
toast.success("berhasil simpan")
|
||||
setLoading(false)
|
||||
modalState.toggle()
|
||||
refresh()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal isOpen={modalState.isOpen} toggleModal={modalState.toggle}>
|
||||
<div className="text-lg font-bold">Jabatan</div>
|
||||
<label className="block text-sm mt-4">
|
||||
<span className="text-gray-700 dark:text-gray-400">
|
||||
Nama
|
||||
</span>
|
||||
<Input
|
||||
placeholder="John Doe"
|
||||
name="nama"
|
||||
value={data.nama}
|
||||
handleChange={onHandleChange}
|
||||
/>
|
||||
</label>
|
||||
<label className="block text-sm mt-4">
|
||||
<span className="text-gray-700 dark:text-gray-400">
|
||||
Tunjangan
|
||||
</span>
|
||||
<Input
|
||||
placeholder="081XXX"
|
||||
name="tunjangan"
|
||||
value={data.tunjangan}
|
||||
handleChange={onHandleChange}
|
||||
type="number"
|
||||
/>
|
||||
</label>
|
||||
<Button className={'mt-4'} onClick={submit} disabled={loading} processing={loading}>
|
||||
Save
|
||||
</Button>
|
||||
</Modal>
|
||||
)
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import Authenticated from '@/Layouts/Authenticated';
|
||||
import { Head } from '@inertiajs/inertia-react';
|
||||
import { useModalState } from '@/Hooks'
|
||||
import Button from '@/Components/Button';
|
||||
import FormModal from './FormModal';
|
||||
import { getAll, deleteById } from '@/Services/Jabatan';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
export default function Jabatan(props) {
|
||||
const formModal = useModalState(false)
|
||||
const [items, setItems] = useState([])
|
||||
|
||||
const hanldeDeleteClick = (item) => {
|
||||
const con = confirm("delete item?")
|
||||
if (con) {
|
||||
deleteById(item.id)
|
||||
.then(() => toast.success('berhasil hapus'))
|
||||
.finally(() => fetchData())
|
||||
}
|
||||
}
|
||||
|
||||
const handleEditClick = (item) => {
|
||||
formModal.setData(item)
|
||||
formModal.toggle()
|
||||
}
|
||||
|
||||
const fetchData = () => {
|
||||
getAll()
|
||||
.then(items => setItems(items))
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchData()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Authenticated
|
||||
auth={props.auth}
|
||||
errors={props.errors}
|
||||
>
|
||||
<Head title="Jabatan" />
|
||||
|
||||
<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">
|
||||
<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">
|
||||
<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">
|
||||
ID
|
||||
</th>
|
||||
<th scope="col" className="py-3 px-6">
|
||||
Nama
|
||||
</th>
|
||||
<th scope="col" className="py-3 px-6">
|
||||
Tunjangan
|
||||
</th>
|
||||
<th></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.id}
|
||||
</th>
|
||||
<th scope="row" className="py-4 px-6 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
{item.data.nama}
|
||||
</th>
|
||||
<td className="py-4 px-6">
|
||||
Rp. {item.data.tunjangan}
|
||||
</td>
|
||||
<th>
|
||||
<div className='flex space-x-1'>
|
||||
<Button onClick={() => handleEditClick(item)}>Edit</Button>
|
||||
<Button onClick={() => hanldeDeleteClick(item)}>Hapus</Button>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<FormModal modalState={formModal} refresh={fetchData}/>
|
||||
</Authenticated>
|
||||
);
|
||||
}
|
@ -1,19 +1,41 @@
|
||||
import db from "@/firebase";
|
||||
import { collection, getDocs, doc, setDoc } from "firebase/firestore";
|
||||
import { collection, getDocs, doc, addDoc, deleteDoc, updateDoc } from "firebase/firestore";
|
||||
|
||||
async function getAllJabatan() {
|
||||
const collect = collection(db, 'jabatan')
|
||||
const COLLECTION = "jabatan"
|
||||
|
||||
async function getAll() {
|
||||
const collect = collection(db, COLLECTION)
|
||||
const data = await getDocs(collect)
|
||||
const lists = data.docs.map(doc => doc.data())
|
||||
const lists = data.docs.map(doc => {
|
||||
return {
|
||||
data: doc.data(),
|
||||
id: doc.id
|
||||
}
|
||||
})
|
||||
return lists
|
||||
}
|
||||
|
||||
async function createJabatan(payload) {
|
||||
const docRef = await setDoc(doc(db, "jabatan"), payload);
|
||||
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 {
|
||||
getAllJabatan,
|
||||
createJabatan
|
||||
getAll,
|
||||
create,
|
||||
update,
|
||||
deleteById
|
||||
}
|
Loading…
Reference in New Issue