crud role and type
parent
427f1e9ed6
commit
3582ba5433
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Category;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return inertia('Category/Index', [
|
||||
'categories' => Category::paginate(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'short' => 'required|string|max:255',
|
||||
'duration' => 'required|numeric'
|
||||
]);
|
||||
|
||||
Category::create([
|
||||
'name' => $request->name,
|
||||
'short' => $request->short,
|
||||
'duration' => $request->duration,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, Category $category)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'short' => 'required|string|max:255',
|
||||
'duration' => 'required|numeric'
|
||||
]);
|
||||
|
||||
$category->update([
|
||||
'name' => $request->name,
|
||||
'short' => $request->short,
|
||||
'duration' => $request->duration,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Category $category)
|
||||
{
|
||||
$category->delete();
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Type;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TypeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return inertia('Type/Index', [
|
||||
'types' => Type::paginate(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255'
|
||||
]);
|
||||
|
||||
Type::create(['name' => $request->name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, Type $type)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255'
|
||||
]);
|
||||
|
||||
$type->update(['name' => $request->name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Type $type)
|
||||
{
|
||||
$type->delete();
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Category extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
"name",
|
||||
"short",
|
||||
"duration",
|
||||
];
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Type extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
"name",
|
||||
];
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('types', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('types');
|
||||
}
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('categories', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string("name");
|
||||
$table->string("short");
|
||||
$table->integer("duration");
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('categories');
|
||||
}
|
||||
};
|
@ -0,0 +1,153 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import { useForm, usePage } from '@inertiajs/react'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
export default function FormModal(props) {
|
||||
const { modalState } = props
|
||||
|
||||
const { data, setData, post, put, processing, errors, reset, clearErrors } = useForm({
|
||||
name: '',
|
||||
short: '',
|
||||
duration: 0
|
||||
})
|
||||
|
||||
const handleOnChange = (event) => {
|
||||
setData(event.target.name, event.target.type === 'checkbox' ? event.target.checked : event.target.value);
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
reset()
|
||||
clearErrors()
|
||||
modalState.setData(null)
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
handleReset()
|
||||
modalState.toggle()
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
const category = modalState.data
|
||||
if(category !== null) {
|
||||
put(route('categories.update', category), {
|
||||
onSuccess: () =>
|
||||
Promise.all([
|
||||
handleReset(),
|
||||
modalState.toggle(),
|
||||
toast.success('The Data has been changed'),
|
||||
]),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
post(route('categories.store'), {
|
||||
onSuccess: () =>
|
||||
Promise.all([
|
||||
handleReset(),
|
||||
modalState.toggle(),
|
||||
toast.success('The Data has been saved'),
|
||||
]),
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const category = modalState.data
|
||||
if (category !== null) {
|
||||
setData({
|
||||
name: category?.name,
|
||||
short: category?.short,
|
||||
duration: category?.duration,
|
||||
})
|
||||
}
|
||||
}, [modalState])
|
||||
|
||||
return (
|
||||
<div
|
||||
className="modal modal-bottom sm:modal-middle pb-10"
|
||||
style={
|
||||
modalState.isOpen
|
||||
? {
|
||||
opacity: 1,
|
||||
pointerEvents: 'auto',
|
||||
visibility: 'visible',
|
||||
overflowY: 'initial',
|
||||
}
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<div className="modal-box overflow-y-auto max-h-screen">
|
||||
<h1 className="font-bold text-2xl pb-8">Ketegori</h1>
|
||||
<div className="form-control">
|
||||
<label className="label">
|
||||
<span className="label-text font-semibold">Nama</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="nama"
|
||||
className={`input input-bordered ${
|
||||
errors.name && 'input-error'
|
||||
}`}
|
||||
name="name"
|
||||
value={data.name}
|
||||
onChange={handleOnChange}
|
||||
/>
|
||||
<label className="label">
|
||||
<span className="label-text-alt text-red-600">{errors.name}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<label className="label">
|
||||
<span className="label-text font-semibold">Singkatan</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="singkatan"
|
||||
className={`input input-bordered ${
|
||||
errors.short && 'input-error'
|
||||
}`}
|
||||
name="short"
|
||||
value={data.short}
|
||||
onChange={handleOnChange}
|
||||
/>
|
||||
<label className="label">
|
||||
<span className="label-text-alt text-red-600">{errors.short}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="form-control">
|
||||
<label className="label">
|
||||
<span className="label-text font-semibold">Durasi</span>
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
placeholder="nama"
|
||||
className={`input input-bordered ${
|
||||
errors.duration && 'input-error'
|
||||
}`}
|
||||
name="duration"
|
||||
value={data.duration}
|
||||
onChange={handleOnChange}
|
||||
/>
|
||||
<label className="label">
|
||||
<span className="label-text-alt text-red-600">{errors.duration}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="modal-action">
|
||||
<div
|
||||
onClick={handleSubmit}
|
||||
className="btn btn-primary"
|
||||
disabled={processing}
|
||||
>
|
||||
Simpan
|
||||
</div>
|
||||
<div
|
||||
onClick={handleCancel}
|
||||
className="btn btn-secondary"
|
||||
disabled={processing}
|
||||
>
|
||||
Batal
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
import React from 'react'
|
||||
import { Head } from '@inertiajs/react'
|
||||
import { router } from '@inertiajs/react'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import { useModalState } from '@/Hooks'
|
||||
import { hasPermission } from '@/utils'
|
||||
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'
|
||||
import Pagination from '@/Components/Pagination'
|
||||
import ModalConfirm from '@/Components/ModalConfirm'
|
||||
import FormModal from './FormModal'
|
||||
|
||||
export default function Categories(props) {
|
||||
const { data: categories, links } = props.categories
|
||||
|
||||
const formModal = useModalState(false)
|
||||
const toggle = (category = null) => {
|
||||
formModal.setData(category)
|
||||
formModal.toggle()
|
||||
}
|
||||
|
||||
const confirmModal = useModalState(false)
|
||||
const handleDelete = (category) => {
|
||||
confirmModal.setData(category)
|
||||
confirmModal.toggle()
|
||||
}
|
||||
|
||||
const onDelete = () => {
|
||||
const category = confirmModal.data
|
||||
if(category != null) {
|
||||
router.delete(route('categories.destroy', category), {
|
||||
onSuccess: () => toast.success('The Data has been deleted'),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const canCreate = hasPermission('create-category', props.auth.user)
|
||||
const canUpdate = hasPermission('update-category', props.auth.user)
|
||||
const canDelete = hasPermission('delete-category', props.auth.user)
|
||||
|
||||
return (
|
||||
<AuthenticatedLayout
|
||||
auth={props.auth}
|
||||
errors={props.errors}
|
||||
flash={props.flash}
|
||||
notify={props.notify}
|
||||
>
|
||||
<Head title="Roles" />
|
||||
<div className="flex flex-col w-full sm:px-6 lg:px-8 space-y-2">
|
||||
<div className="card bg-base-100 w-full">
|
||||
<div className="card-body">
|
||||
<div className="flex w-full mb-4 justify-between">
|
||||
{canCreate && (
|
||||
<div
|
||||
className="btn btn-neutral"
|
||||
onClick={() => toggle()}
|
||||
>
|
||||
Tambah
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="table w-full table-zebra">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>Nama</th>
|
||||
<th>Singkatan</th>
|
||||
<th>Durasi</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{categories?.map((category) => (
|
||||
<tr key={category.id}>
|
||||
<th>{category.id}</th>
|
||||
<td>{category.name}</td>
|
||||
<td>{category.short}</td>
|
||||
<td>{category.duration}</td>
|
||||
<td className="text-right">
|
||||
{canUpdate && (
|
||||
<div
|
||||
className="btn btn-primary mx-1"
|
||||
onClick={() =>
|
||||
toggle(category)
|
||||
}
|
||||
>
|
||||
Edit
|
||||
</div>
|
||||
)}
|
||||
{canDelete && (
|
||||
<div
|
||||
className="btn btn-secondary mx-1"
|
||||
onClick={() =>
|
||||
handleDelete(category)
|
||||
}
|
||||
>
|
||||
Delete
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<Pagination links={links} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FormModal
|
||||
modalState={formModal}
|
||||
/>
|
||||
<ModalConfirm
|
||||
isOpen={confirmModal.isOpen}
|
||||
toggle={confirmModal.toggle}
|
||||
onConfirm={onDelete}
|
||||
/>
|
||||
</AuthenticatedLayout>
|
||||
)
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import { useForm, usePage } from '@inertiajs/react'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
export default function FormModal(props) {
|
||||
const { modalState } = props
|
||||
|
||||
const { data, setData, post, put, processing, errors, reset, clearErrors } = useForm({
|
||||
name: '',
|
||||
})
|
||||
|
||||
const handleOnChange = (event) => {
|
||||
setData(event.target.name, event.target.type === 'checkbox' ? event.target.checked : event.target.value);
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
reset()
|
||||
clearErrors()
|
||||
modalState.setData(null)
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
handleReset()
|
||||
modalState.toggle()
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
const type = modalState.data
|
||||
if(type !== null) {
|
||||
put(route('types.update', type), {
|
||||
onSuccess: () =>
|
||||
Promise.all([
|
||||
handleReset(),
|
||||
modalState.toggle(),
|
||||
toast.success('The Data has been changed'),
|
||||
]),
|
||||
})
|
||||
return
|
||||
}
|
||||
post(route('types.store'), {
|
||||
onSuccess: () =>
|
||||
Promise.all([
|
||||
handleReset(),
|
||||
modalState.toggle(),
|
||||
toast.success('The Data has been saved'),
|
||||
]),
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const type = modalState.data
|
||||
if (type !== null) {
|
||||
setData({
|
||||
name: type?.name,
|
||||
})
|
||||
}
|
||||
}, [modalState])
|
||||
|
||||
return (
|
||||
<div
|
||||
className="modal modal-bottom sm:modal-middle pb-10"
|
||||
style={
|
||||
modalState.isOpen
|
||||
? {
|
||||
opacity: 1,
|
||||
pointerEvents: 'auto',
|
||||
visibility: 'visible',
|
||||
overflowY: 'initial',
|
||||
}
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<div className="modal-box overflow-y-auto max-h-screen">
|
||||
<h1 className="font-bold text-2xl pb-8">Jenis</h1>
|
||||
<div className="form-control">
|
||||
<label className="label">
|
||||
<span className="label-text font-semibold">Nama</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="nama"
|
||||
className={`input input-bordered ${
|
||||
errors.name && 'input-error'
|
||||
}`}
|
||||
name="name"
|
||||
value={data.name}
|
||||
onChange={handleOnChange}
|
||||
/>
|
||||
<label className="label">
|
||||
<span className="label-text-alt text-red-600">{errors.name}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="modal-action">
|
||||
<div
|
||||
onClick={handleSubmit}
|
||||
className="btn btn-primary"
|
||||
disabled={processing}
|
||||
>
|
||||
Simpan
|
||||
</div>
|
||||
<div
|
||||
onClick={handleCancel}
|
||||
className="btn btn-secondary"
|
||||
disabled={processing}
|
||||
>
|
||||
Batal
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
import React from 'react'
|
||||
import { Head } from '@inertiajs/react'
|
||||
import { router } from '@inertiajs/react'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import { useModalState } from '@/Hooks'
|
||||
import { hasPermission } from '@/utils'
|
||||
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'
|
||||
import Pagination from '@/Components/Pagination'
|
||||
import ModalConfirm from '@/Components/ModalConfirm'
|
||||
import FormModal from './FormModal'
|
||||
|
||||
export default function Types(props) {
|
||||
const { data: types, links } = props.types
|
||||
|
||||
const formModal = useModalState(false)
|
||||
const toggle = (type = null) => {
|
||||
formModal.setData(type)
|
||||
formModal.toggle()
|
||||
}
|
||||
|
||||
const confirmModal = useModalState(false)
|
||||
const handleDelete = (type) => {
|
||||
confirmModal.setData(type)
|
||||
confirmModal.toggle()
|
||||
}
|
||||
|
||||
const onDelete = () => {
|
||||
const type = confirmModal.data
|
||||
if(type != null) {
|
||||
router.delete(route('types.destroy', type), {
|
||||
onSuccess: () => toast.success('The Data has been deleted'),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const canCreate = hasPermission('create-type', props.auth.user)
|
||||
const canUpdate = hasPermission('update-type', props.auth.user)
|
||||
const canDelete = hasPermission('delete-type', props.auth.user)
|
||||
|
||||
return (
|
||||
<AuthenticatedLayout
|
||||
auth={props.auth}
|
||||
errors={props.errors}
|
||||
flash={props.flash}
|
||||
notify={props.notify}
|
||||
>
|
||||
<Head title="Roles" />
|
||||
<div className="flex flex-col w-full sm:px-6 lg:px-8 space-y-2">
|
||||
<div className="card bg-base-100 w-full">
|
||||
<div className="card-body">
|
||||
<div className="flex w-full mb-4 justify-between">
|
||||
{canCreate && (
|
||||
<div
|
||||
className="btn btn-neutral"
|
||||
onClick={() => toggle()}
|
||||
>
|
||||
Tambah
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="table w-full table-zebra">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>Nama</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{types?.map((type) => (
|
||||
<tr key={type.id}>
|
||||
<th>{type.id}</th>
|
||||
<td>{type.name}</td>
|
||||
<td className="text-right">
|
||||
{canUpdate && (
|
||||
<div
|
||||
className="btn btn-primary mx-1"
|
||||
onClick={() =>
|
||||
toggle(type)
|
||||
}
|
||||
>
|
||||
Edit
|
||||
</div>
|
||||
)}
|
||||
{canDelete && (
|
||||
<div
|
||||
className="btn btn-secondary mx-1"
|
||||
onClick={() =>
|
||||
handleDelete(type)
|
||||
}
|
||||
>
|
||||
Delete
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<Pagination links={links} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FormModal
|
||||
modalState={formModal}
|
||||
/>
|
||||
<ModalConfirm
|
||||
isOpen={confirmModal.isOpen}
|
||||
toggle={confirmModal.toggle}
|
||||
onConfirm={onDelete}
|
||||
/>
|
||||
</AuthenticatedLayout>
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue