master data klasifikasi menu dan master data karbohidrat sudah siap

This commit is contained in:
JokoPrasetio 2025-07-25 11:07:19 +07:00
parent 39b362a838
commit 6f9663004c
24 changed files with 1322 additions and 18 deletions

View File

@ -224,18 +224,18 @@ class CustomerController extends Controller
}
}
//code...
DB::commit();
return response()->json([
'status' => true,
'data' => $order,
'message' => 'Data berhasil disimpan'
]);
DB::commit();
return response()->json([
'status' => true,
'data' => $order,
'message' => 'Data berhasil disimpan'
]);
} catch (\Throwable $th) {
DB::rollBack();
return response()->json([
'status' => false,
'message' => 'Data gagal disimpan ' . $th->getMessage()
]);
DB::rollBack();
return response()->json([
'status' => false,
'message' => 'Data gagal disimpan ' . $th->getMessage()
]);
}
}

View File

@ -0,0 +1,130 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\Karbohidrat\RequestKarbohidrat;
use App\Http\Requests\Karbohidrat\RequestUpdateKarbohidrat;
use App\Models\Karbohidrat;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class KarbohidratController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
$payload = [
'title' => 'Karbohidrat'
];
return view('dashboard.karbohidrat.index', $payload);
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(RequestKarbohidrat $request)
{
DB::connection('dbOrderGizi')->beginTransaction();
try {
$request->validated();
$datas = $request->input('data');
foreach ($datas as $data) {
$payload = [
'pegawai_id_entry' => auth()->user()->id,
'pegawai_nama_entry' => auth()->user()->full_name,
'nama_karbohidrat' => $data['nama_karbohidrat']
];
Karbohidrat::create($payload);
};
DB::connection('dbOrderGizi')->commit();
return response()->json([
'status' => true,
'message' => 'Berhasil menambahkan data'
], 201);
} catch (\Throwable $th) {
DB::connection('dbOrderGizi')->rollBack();
return response()->json([
'status' => false,
'message' => 'Gagal menambahkan data'
], 500);
}
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(RequestUpdateKarbohidrat $request, string $id)
{
$request->validated();
try {
$karbohidrat = Karbohidrat::where('karbohidrat_id', $id)->first();
$payload = [
'nama_karbohidrat' => $request->input('nama_karbohidrat'),
'pegawai_id_entry' => auth()->user()->id,
'pegawai_nama_entry' => auth()->user()->full_name,
'modified_at' => Carbon::now()
];
$karbohidrat->update($payload);
return response()->json([
'status' => true,
'message' => 'Berhasil memperbarui data'
], 200);
} catch (\Throwable $th) {
return response()->json([
'status' => false,
'message' => 'Gagal memperbarui data'
], 500);
}
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
$data = Karbohidrat::where(['statusenabled' => true, 'karbohidrat_id' => $id])->first();
$payload = [
'statusenabled' => false,
'pegawai_id_entry' => auth()->user()->id,
'pegawai_nama_entry' => auth()->user()->full_name,
'modified_at' => Carbon::now()
];
$data->update($payload);
return response()->json([
'status' => true,
'message' => 'Berhasil menghapus data'
], 200);
}
public function datatable(){
$data = Karbohidrat::where('statusenabled', true)->get();
return $data;
}
}

View File

@ -2,7 +2,12 @@
namespace App\Http\Controllers;
use App\Http\Requests\KlasifikasiMenu\RequestKlasifikasiMenu;
use App\Http\Requests\KlasifikasiMenu\RequestUpdateKlasifikasiMenu;
use App\Models\KlasifikasiMenu;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class KlasifikasiMenuController extends Controller
{
@ -11,7 +16,10 @@ class KlasifikasiMenuController extends Controller
*/
public function index()
{
//
$payload = [
'title' => 'Master Klasifikasi Menu'
];
return view('dashboard.klasifikasi_menu.index', $payload);
}
/**
@ -25,9 +33,32 @@ class KlasifikasiMenuController extends Controller
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
public function store(RequestKlasifikasiMenu $request)
{
//
DB::connection('dbOrderGizi')->beginTransaction();
try {
$request->validated();
$datas = $request->input('data');
foreach ($datas as $data) {
$payload = [
'pegawai_id_entry' => auth()->user()->id,
'pegawai_nama_entry' => auth()->user()->full_name,
'nama_kategori_diet' => $data['nama_kategori_diet']
];
KlasifikasiMenu::create($payload);
};
DB::connection('dbOrderGizi')->commit();
return response()->json([
'status' => true,
'message' => 'Berhasil menambahkan data'
], 201);
} catch (\Throwable $th) {
DB::connection('dbOrderGizi')->rollBack();
return response()->json([
'status' => false,
'message' => 'Gagal menambahkan data'
], 500);
}
}
/**
@ -49,9 +80,28 @@ class KlasifikasiMenuController extends Controller
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
public function update(RequestUpdateKlasifikasiMenu $request, string $id)
{
//
$request->validated();
try {
$km = KlasifikasiMenu::where('kategori_diet_id', $id)->first();
$payload = [
'nama_kategori_diet' => $request->input('nama_kategori_diet'),
'pegawai_id_entry' => auth()->user()->id,
'pegawai_nama_entry' => auth()->user()->full_name,
'modified_at' => Carbon::now()
];
$km->update($payload);
return response()->json([
'status' => true,
'message' => 'Berhasil memperbarui data'
], 200);
} catch (\Throwable $th) {
return response()->json([
'status' => false,
'message' => 'Gagal memperbarui data'
], 500);
}
}
/**
@ -59,6 +109,21 @@ class KlasifikasiMenuController extends Controller
*/
public function destroy(string $id)
{
//
$data = KlasifikasiMenu::where(['statusenabled' => true, 'kategori_diet_id' => $id])->first();
$payload = [
'statusenabled' => false,
'pegawai_id_entry' => auth()->user()->id,
'pegawai_nama_entry' => auth()->user()->full_name,
'modified_at' => Carbon::now()
];
$data->update($payload);
return response()->json([
'status' => true,
'message' => 'Berhasil menghapus data'
], 200);
}
public function datatable(){
return KlasifikasiMenu::where('statusenabled', true)->get();
}
}

View File

@ -0,0 +1,75 @@
<?php
namespace App\Http\Requests\Karbohidrat;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Support\Facades\DB;
class RequestKarbohidrat extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function rules(): array
{
return [
'data' => 'required|array|min:1',
'data.*.nama_karbohidrat' => 'required|string'
];
}
public function messages(){
return [
'data.array' => 'Format data harus berupa array',
'data.min' => 'Minimal harus ada satu data klasifikasi menu',
'data.*.nama_karbohidrat.required' => 'Nama Klasifikasi Menu wajib diisi',
'data.*.nama_karbohidrat.string' => 'Nama Kategori Soal harus berupa teks',
];
}
protected function failedValidation(Validator $validator){
throw new HttpResponseException(
response()->json([
'status' => 'VALIDATION_FAILED',
'message' => 'Validasi Gagal',
'errors' => $validator->errors()->messages(),
], 422)
);
}
public function withValidator($validator){
$validator->after(function ($validator){
$namaListAsli = collect($this->input('data'))->pluck('nama_karbohidrat')->filter();
$namaListLower = $namaListAsli->map(fn($n) => strtolower(trim($n)));
$duplicates = $namaListLower->duplicates();
if ($duplicates->isNotEmpty()) {
foreach ($namaListAsli as $index => $nama) {
if ($duplicates->contains(strtolower(trim($nama)))) {
$validator->errors()->add("data.$index.nama_kategori_diet", "Nama '$nama' duplikat dalam input.");
}
}
}
$namaList = $namaListAsli->map(fn($n) => strtolower(trim($n)));
if($namaList->isEmpty()) return;
$exists = DB::connection('dbOrderGizi')
->table('public.karbohidrat')
->where('statusenabled', true)
->whereIn(DB::raw('LOWER(nama_karbohidrat)'), $namaList->toArray())
->selectRaw('LOWER(nama_karbohidrat) as nama')
->pluck('nama')
->toArray();
foreach ($namaListAsli as $index => $nama) {
$lowerNama = strtolower(trim($nama));
if(in_array($lowerNama, $exists)){
$validator->errors()->add("data.$index.nama_karbohidrat", "Nama '$nama' Sudah digunakan.");
}
}
});
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace App\Http\Requests\Karbohidrat;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Support\Facades\DB;
class RequestUpdateKarbohidrat extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function rules(): array
{
return [
'nama_karbohidrat' => 'required|string'
];
}
public function messages(){
return [
'nama_karbohidrat.required' => 'Nama Karbohidrat wajib diisi'
];
}
protected function failedValidation(Validator $validator){
throw new HttpResponseException(
response()->json([
'status' => 'VALIDATION_FAILED',
'message' => 'Validasi Gagal',
'errors' => $validator->errors()->messages(),
], 422)
);
}
public function withValidator($validator){
$validator->after(function($validator){
$id = $this->route('karbohidrat') ?? $this->karbohidrat_id ?? null;
$exists = DB::connection('dbOrderGizi')
->table('public.karbohidrat')
->where('statusenabled', true)
->where('nama_karbohidrat', 'ILIKE', $this->input('nama_karbohidrat'));
if($id) $exists->where('karbohidrat_id', '!=', $id);
if($exists->exists()){
$validator->errors()->add(
'nama_karbohidrat',
'Nama Karbohidrat sudah digunakan'
);
}
});
}
}

View File

@ -0,0 +1,89 @@
<?php
namespace App\Http\Requests\KlasifikasiMenu;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Support\Facades\DB;
class RequestKlasifikasiMenu extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'data' => 'required|array|min:1',
'data.*.nama_kategori_diet' => 'required|string'
];
}
public function messages(){
return [
'data.array' => 'Format data harus berupa array',
'data.min' => 'Minimal harus ada satu data klasifikasi menu',
'data.*.nama_kategori_diet.required' => 'Nama Klasifikasi Menu wajib diisi',
'data.*.nama_kategori_diet.string' => 'Nama Kategori Soal harus berupa teks',
];
}
protected function failedValidation(Validator $validator){
throw new HttpResponseException(
response()->json([
'status' => 'VALIDATION_FAILED',
'message' => 'Validasi Gagal',
'errors' => $validator->errors()->messages(),
], 422)
);
}
public function withValidator($validator){
$validator->after(function ($validator){
$namaListAsli = collect($this->input('data'))->pluck('nama_kategori_diet')->filter();
$namaListLower = $namaListAsli->map(fn($n) => strtolower(trim($n)));
// ✅ Cek duplikat antar input user
$duplicates = $namaListLower->duplicates();
if ($duplicates->isNotEmpty()) {
foreach ($namaListAsli as $index => $nama) {
if ($duplicates->contains(strtolower(trim($nama)))) {
$validator->errors()->add("data.$index.nama_kategori_diet", "Nama '$nama' duplikat dalam input.");
}
}
}
$namaList = $namaListAsli->map(fn($n) => strtolower(trim($n)));
if($namaList->isEmpty()) return;
$exists = DB::connection('dbOrderGizi')
->table('public.kategori_diet')
->where('statusenabled', true)
->whereIn(DB::raw('LOWER(nama_kategori_diet)'), $namaList->toArray())
->selectRaw('LOWER(nama_kategori_diet) as nama')
->pluck('nama')
->toArray();
foreach ($namaListAsli as $index => $nama) {
$lowerNama = strtolower(trim($nama));
if(in_array($lowerNama, $exists)){
$validator->errors()->add("data.$index.nama_kategori_diet", "Nama '$nama' Sudah digunakan.");
}
}
});
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace App\Http\Requests\KlasifikasiMenu;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Support\Facades\DB;
class RequestUpdateKlasifikasiMenu extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'nama_kategori_diet' => 'required|string'
];
}
public function messages(){
return [
'nama_kategori_diet.required' => 'Nama Klasifikasi Menu wajib diisi'
];
}
protected function failedValidation(Validator $validator){
throw new HttpResponseException(
response()->json([
'status' => 'VALIDATION_FAILED',
'message' => 'Validasi Gagal',
'errors' => $validator->errors()->messages(),
], 422)
);
}
public function withValidator($validator){
$validator->after(function($validator){
$id = $this->route('klasifikasi_menu') ?? $this->kategori_diet_id ?? null;
$exists = DB::connection('dbOrderGizi')
->table('public.kategori_diet')
->where('nama_kategori_diet', 'ILIKE', $this->input('nama_kategori_diet'));
if($id) $exists->where('kategori_diet_id', '!=', $id);
if($exists->exists()){
$validator->errors()->add(
'nama_kategori_diet',
'Nama Klasifikasi Menu sudah digunakan'
);
}
});
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Karbohidrat extends Model
{
protected $connection = 'dbOrderGizi';
protected $table = 'public.karbohidrat';
public $timestamps = false;
protected $primaryKey = "karbohidrat_id";
protected $fillable =[
'entry_at',
'pegawai_id_entry',
'pegawai_nama_entry',
'modified_at',
'pegawai_id_modified',
'pegawai_nama_modified',
'statusenabled',
'nama_karbohidrat'
];
}

View File

@ -0,0 +1,6 @@
const datatableKarbohidrat = $("#datatableKarbohidrat")
const modalKarbohidrat = document.getElementById("modalKarbohidrat")
const formKarbohidrat = $("#formKarbohidrat")
const modalKarbohidratEdit = document.getElementById("modalKarbohidratEdit")
const formKarbohidratEdit = $("#formKarbohidratEdit")

View File

@ -0,0 +1,194 @@
function addKarbohidrat(){
new bootstrap.Modal(modalKarbohidrat).show();
formKarbohidrat.attr('action', `/dashboard/karbohidrat`)
}
formKarbohidrat.on('submit', function(e){
e.preventDefault();
const form = this;
const actionUrl = formKarbohidrat.attr('action');
const formData = new FormData(form);
fetch(actionUrl, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('input[name="_token"]').value,
},
body: formData
}).then(async(res) => {
const responseData = await res.json();
if (res.status === 422) {
// Tampilkan semua error ke swal
const errors = responseData.errors || {};
let htmlList = '<ul class="text-start">';
for (const key in errors) {
errors[key].forEach(message => {
htmlList += `<li>${message}</li>`;
});
}
htmlList += '</ul>';
Swal.fire({
icon: 'error',
title: 'Validasi Gagal',
html: htmlList,
});
throw new Error(); // Supaya masuk ke catch, tapi tidak tampil swal lagi
}
if (responseData.status) {
const handler = function () {
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: responseData.message || 'Berhasil melakukan aksi!',
timer: 2000,
showConfirmButton: false,
backdrop: true,
});
$("#col_add_karbohidrat").html('');
colCount = 0; // reset counter
formKarbohidrat[0].reset();
datatableKarbohidrat.bootstrapTable('refresh');
modalKarbohidrat.removeEventListener('hidden.bs.modal', handler);
};
modalKarbohidrat.addEventListener('hidden.bs.modal', handler);
bootstrap.Modal.getInstance(modalKarbohidrat).hide();
} else {
throw new Error(responseData.message || 'Terjadi kesalahan saat menyimpan data.');
}
}).catch(err => {
if (err.message) {
Swal.fire({
icon: 'error',
title: 'Gagal',
text: err.message
});
}
});
});
function deleteKarbohidrat(e){
let id =$(e).data('karbohidrat_id')
Swal.fire({
title: "Apakah kamu yakin ingin menghapus data ini?",
text : $(e).data('nama'),
icon: "warning",
showCancelButton: true,
backdrop: true,
}).then((result) => {
if(result.isConfirmed){
fetch(`/dashboard/karbohidrat/${id}`, {
method:'DELETE',
headers: {
"X-CSRF-TOKEN": document.querySelector('input[name="_token"]').value,
"Content-Type": "application/json"
}
}).then((response) => {
if(!response.ok){
throw new Error("Network response was not ok");
}
return response.json();
})
.then((data) => {
if(data.status){
Swal.fire({
title: "Success",
text: "Data berhasil dihapus",
icon:"success",
showConfirmButton: false,
timer: 1000
}).then(() => {
datatableKarbohidrat.bootstrapTable("refresh")
})
}else{
Swal.fire({
title: "Error!",
text: data.message || "Failed to delete Item.",
icon: "error"
});
}
})
.catch(error => {
Swal.fire({
title: "Error!",
text: "Something went wrong. Please try again later.",
icon: "error"
});
});
}
})
}
function editKarbohidrat(e){
const data = $(e).data();
new bootstrap.Modal(modalKarbohidratEdit).show();
formKarbohidratEdit.attr('action', `/dashboard/karbohidrat/${data?.karbohidrat_id}`)
$("#nama_karbohidrat").val(data.nama)
}
formKarbohidratEdit.on('submit', function(e){
e.preventDefault();
const form = this;
const actionUrl = formKarbohidratEdit.attr('action');
const formData = new FormData(form);
formData.append('_method', 'PUT')
fetch(actionUrl, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('input[name="_token"]').value,
},
body: formData
}).then(async(res) => {
const responseData = await res.json();
if (res.status === 422) {
// Tampilkan semua error ke swal
const errors = responseData.errors || {};
Swal.fire({
icon: 'error',
title: 'Validasi Gagal',
html: errors.nama_karbohidrat[0],
});
throw new Error(); // Supaya masuk ke catch, tapi tidak tampil swal lagi
}
if (responseData.status) {
const handler = function () {
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: responseData.message || 'Berhasil melakukan aksi!',
timer: 2000,
showConfirmButton: false,
backdrop: true,
});
$("#nama_kategori_diet").val('');
colCount = 0; // reset counter
formKarbohidratEdit[0].reset();
datatableKarbohidrat.bootstrapTable('refresh');
modalKarbohidratEdit.removeEventListener('hidden.bs.modal', handler);
};
modalKarbohidratEdit.addEventListener('hidden.bs.modal', handler);
bootstrap.Modal.getInstance(modalKarbohidratEdit).hide();
} else {
throw new Error(responseData.message || 'Terjadi kesalahan saat menyimpan data.');
}
}).catch(err => {
if (err.message) {
Swal.fire({
icon: 'error',
title: 'Gagal',
text: err.message
});
}
});
});

View File

@ -0,0 +1,51 @@
datatableKarbohidrat.bootstrapTable({
url: "/dashboard/datatable/karbohidrat",
showColumns: true,
showColumnsToggleAll: true,
showRefresh: true,
sortable: true,
search: true,
searchOnEnterKey: false,
searchHighlight: true,
pagination: true,
serverSide:true,
pageSize: 10,
pageList: [10, 20, 30],
cookie: true,
cookieIdTable: "datatableKlasifikasiMenu",
icons: {
refresh: "fas fa-sync-alt", // atau ganti ke icon lain
columns: "fas fa-th-large"
},
columns: [
{
title: "Action",
field: 'karbohidrat_id',
formatter: function(value, row) {
let buttons = ''
buttons += `
<button class="btn btn-sm btn-primary me-2" onclick="editKarbohidrat(this)" data-karbohidrat_id="${row.karbohidrat_id}" data-nama="${row?.nama_karbohidrat}">
<i class="fa-solid fa-pencil"></i>
</button>
`
buttons += `
<button class="btn btn-sm btn-danger me-2" onclick="deleteKarbohidrat(this)" data-karbohidrat_id="${row.karbohidrat_id}" data-nama="${row?.nama_karbohidrat}">
<i class="fa-solid fa-trash"></i>
</button>
`
return `
<div class="d-flex space-x">
${buttons}
</div>
`;
},
width: 120
},
{
title:"Nama Karbohidrat",
field:"nama_karbohidrat"
}
],
});

View File

@ -0,0 +1,27 @@
let colCount = 1;
function addForm(){
let col = $("#col_add_karbohidrat")
let html = '';
html += `
<div class="col mt-2 d-flex align-items-start gap-2" id="col-${colCount}">
<div class="form-floating flex-grow-1">
<input type="text" class="form-control" name="data[${colCount}][nama_karbohidrat]" placeholder="exp : Nasi" required>
<label>Nama Klasifikasi Menu</label>
</div>
<div class="invalid-feedback"></div>
<button type="button" class="btn btn-danger mt-2 me-2" onclick="removeCol(${colCount})"><i class="fa-solid fa-trash"></i></button>
</div>
`
col.append(html)
colCount++;
}
function removeCol(count){
$(`#col-${count}`).remove()
}

View File

@ -0,0 +1,6 @@
const datatableKlasifikasiMenu = $("#datatableKlasifikasiMenu")
const modalKlasifikasiMenu = document.getElementById("modalKlasifikasiMenu")
const formKlasifikasiMenu = $("#formKlasifikasiMenu")
const modalKlasifikasiMenuEdit = document.getElementById("modalKlasifikasiMenuEdit")
const formKlasifikasiMenuEdit = $("#formKlasifikasiMenuEdit")

View File

@ -0,0 +1,195 @@
function addKlasifikasi(){
new bootstrap.Modal(modalKlasifikasiMenu).show();
formKlasifikasiMenu.attr('action', `/dashboard/klasifikasi-menu`)
}
formKlasifikasiMenu.on('submit', function(e){
e.preventDefault();
const form = this;
const actionUrl = formKlasifikasiMenu.attr('action');
const formData = new FormData(form);
fetch(actionUrl, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('input[name="_token"]').value,
},
body: formData
}).then(async(res) => {
const responseData = await res.json();
if (res.status === 422) {
// Tampilkan semua error ke swal
const errors = responseData.errors || {};
let htmlList = '<ul class="text-start">';
for (const key in errors) {
errors[key].forEach(message => {
htmlList += `<li>${message}</li>`;
});
}
htmlList += '</ul>';
Swal.fire({
icon: 'error',
title: 'Validasi Gagal',
html: htmlList,
});
throw new Error(); // Supaya masuk ke catch, tapi tidak tampil swal lagi
}
if (responseData.status) {
const handler = function () {
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: responseData.message || 'Berhasil melakukan aksi!',
timer: 2000,
showConfirmButton: false,
backdrop: true,
});
$("#col_add_klasifikasi").html('');
colCount = 0; // reset counter
formKlasifikasiMenu[0].reset();
datatableKlasifikasiMenu.bootstrapTable('refresh');
modalKlasifikasiMenu.removeEventListener('hidden.bs.modal', handler);
};
modalKlasifikasiMenu.addEventListener('hidden.bs.modal', handler);
bootstrap.Modal.getInstance(modalKlasifikasiMenu).hide();
} else {
throw new Error(responseData.message || 'Terjadi kesalahan saat menyimpan data.');
}
}).catch(err => {
if (err.message) {
Swal.fire({
icon: 'error',
title: 'Gagal',
text: err.message
});
}
});
});
function editKlasifikasi(e){
const data = $(e).data();
new bootstrap.Modal(modalKlasifikasiMenuEdit).show();
formKlasifikasiMenuEdit.attr('action', `/dashboard/klasifikasi-menu/${data?.kategori_diet_id}`)
$("#nama_kategori_diet").val(data.nama)
}
formKlasifikasiMenuEdit.on('submit', function(e){
e.preventDefault();
const form = this;
const actionUrl = formKlasifikasiMenuEdit.attr('action');
const formData = new FormData(form);
formData.append('_method', 'PUT')
fetch(actionUrl, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('input[name="_token"]').value,
},
body: formData
}).then(async(res) => {
const responseData = await res.json();
if (res.status === 422) {
// Tampilkan semua error ke swal
const errors = responseData.errors || {};
Swal.fire({
icon: 'error',
title: 'Validasi Gagal',
html: errors.nama_kategori_diet[0],
});
throw new Error(); // Supaya masuk ke catch, tapi tidak tampil swal lagi
}
if (responseData.status) {
const handler = function () {
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: responseData.message || 'Berhasil melakukan aksi!',
timer: 2000,
showConfirmButton: false,
backdrop: true,
});
$("#nama_kategori_diet").val('');
colCount = 0; // reset counter
formKlasifikasiMenuEdit[0].reset();
datatableKlasifikasiMenu.bootstrapTable('refresh');
modalKlasifikasiMenuEdit.removeEventListener('hidden.bs.modal', handler);
};
modalKlasifikasiMenuEdit.addEventListener('hidden.bs.modal', handler);
bootstrap.Modal.getInstance(modalKlasifikasiMenuEdit).hide();
} else {
throw new Error(responseData.message || 'Terjadi kesalahan saat menyimpan data.');
}
}).catch(err => {
if (err.message) {
Swal.fire({
icon: 'error',
title: 'Gagal',
text: err.message
});
}
});
});
function deleteKlasifikasi(e){
let id =$(e).data('kategori_diet_id')
Swal.fire({
title: "Apakah kamu yakin ingin menghapus data ini?",
text : $(e).data('nama'),
icon: "warning",
showCancelButton: true,
backdrop: true,
}).then((result) => {
if(result.isConfirmed){
fetch(`/dashboard/klasifikasi-menu/${id}`, {
method:'DELETE',
headers: {
"X-CSRF-TOKEN": document.querySelector('input[name="_token"]').value,
"Content-Type": "application/json"
}
}).then((response) => {
if(!response.ok){
throw new Error("Network response was not ok");
}
return response.json();
})
.then((data) => {
if(data.status){
Swal.fire({
title: "Success",
text: "Data berhasil dihapus",
icon:"success",
showConfirmButton: false,
timer: 1000
}).then(() => {
datatableKlasifikasiMenu.bootstrapTable("refresh")
})
}else{
Swal.fire({
title: "Error!",
text: data.message || "Failed to delete Item.",
icon: "error"
});
}
})
.catch(error => {
Swal.fire({
title: "Error!",
text: "Something went wrong. Please try again later.",
icon: "error"
});
});
}
})
}

View File

@ -0,0 +1,51 @@
datatableKlasifikasiMenu.bootstrapTable({
url: "/dashboard/datatable/klasifikasi-menu",
showColumns: true,
showColumnsToggleAll: true,
showRefresh: true,
sortable: true,
search: true,
searchOnEnterKey: false,
searchHighlight: true,
pagination: true,
serverSide:true,
pageSize: 10,
pageList: [10, 20, 30],
cookie: true,
cookieIdTable: "datatableKlasifikasiMenu",
icons: {
refresh: "fas fa-sync-alt", // atau ganti ke icon lain
columns: "fas fa-th-large"
},
columns: [
{
title: "Action",
field: 'kategori_diet_id',
formatter: function(value, row) {
let buttons = ''
buttons += `
<button class="btn btn-sm btn-primary me-2" onclick="editKlasifikasi(this)" data-kategori_diet_id="${row.kategori_diet_id}" data-nama="${row?.nama_kategori_diet}">
<i class="fa-solid fa-pencil"></i>
</button>
`
buttons += `
<button class="btn btn-sm btn-danger me-2" onclick="deleteKlasifikasi(this)" data-kategori_diet_id="${row.kategori_diet_id}" data-nama="${row?.nama_kategori_diet}">
<i class="fa-solid fa-trash"></i>
</button>
`
return `
<div class="d-flex space-x">
${buttons}
</div>
`;
},
width: 120
},
{
title:"Nama Klasifikasi Menu",
field:"nama_kategori_diet"
}
],
});

View File

@ -0,0 +1,27 @@
let colCount = 1;
function addForm(){
let col = $("#col_add_klasifikasi")
let html = '';
html += `
<div class="col mt-2 d-flex align-items-start gap-2" id="col-${colCount}">
<div class="form-floating flex-grow-1">
<input type="text" class="form-control" name="data[${colCount}][nama_kategori_diet]" placeholder="exp : Diet Rendah Gula" required>
<label>Nama Klasifikasi Menu</label>
</div>
<div class="invalid-feedback"></div>
<button type="button" class="btn btn-danger mt-2 me-2" onclick="removeCol(${colCount})"><i class="fa-solid fa-trash"></i></button>
</div>
`
col.append(html)
colCount++;
}
function removeCol(count){
$(`#col-${count}`).remove()
}

View File

@ -0,0 +1,30 @@
@extends('dashboard.layouts.main')
@section('body_main')
<div class="container-xxl flex-grow-1 container-p-y">
<!-- Breadcrumb -->
<h4 class="fw-bold py-3 mb-4">
<span class="text-muted fw-light">Dashboard /</span> Master Karbohidrat
</h4>
<!-- Card Master Menu -->
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Karbohidrat</h5>
<button type="button" class="btn btn-primary" onclick="addKarbohidrat()">
Tambah
</button>
</div>
<div class="card-body">
<table class="table" id="datatableKarbohidrat"></table>
</div>
</div>
</div>
@include('dashboard.karbohidrat.modal.create')
@include('dashboard.karbohidrat.modal.edit')
<script src="{{ ver('/js/karbohidrat/_init.js') }}"></script>
<script src="{{ ver('/js/karbohidrat/dt.js') }}"></script>
<script src="{{ ver('/js/karbohidrat/action.js') }}"></script>
<script src="{{ ver('/js/karbohidrat/function.js') }}"></script>
@endsection

View File

@ -0,0 +1,41 @@
<!-- Modal -->
<div class="modal fade" id="modalKarbohidrat" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h1 class="modal-title fs-5">Aksi Master Karbohidrat</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<!-- Modal Form -->
<form enctype="multipart/form-data" method="POST" id="formKarbohidrat">
@csrf
<div class="modal-body">
<div class="container" id="container_create">
<div class="row">
<div class="col">
<div class="form-floating">
<input type="text" class="form-control" name="data[0][nama_karbohidrat]" placeholder="exp : Nasi" required>
<label>Nama Karbohidrat</label>
</div>
</div>
<div id="col_add_karbohidrat"></div>
</div>
<button type="button" class="btn btn-outline-primary btn-sm mt-2" onclick="addForm()">
+ Tambah Karbohidrat
</button>
</div>
</div>
<!-- Modal Footer -->
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Tutup</button>
<button type="submit" class="btn btn-primary">Simpan</button>
</div>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,40 @@
<!-- Modal -->
<div class="modal fade" id="modalKarbohidratEdit" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h1 class="modal-title fs-5">Aksi Master Karbohidrat</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<!-- Modal Form -->
<form enctype="multipart/form-data" method="PUT" id="formKarbohidratEdit">
@method('put')
@csrf
<div class="modal-body">
<div class="container">
<div class="row">
<div class="col">
<div class="form-floating">
<input type="text" class="form-control" name="nama_karbohidrat" id="nama_karbohidrat" placeholder="Nasi" required>
<label>Nama Karbohidrat</label>
</div>
</div>
</div>
</div>
</div>
<!-- Modal Footer -->
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Tutup</button>
<button type="submit" class="btn btn-primary">Simpan</button>
</div>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,30 @@
@extends('dashboard.layouts.main')
@section('body_main')
<div class="container-xxl flex-grow-1 container-p-y">
<!-- Breadcrumb -->
<h4 class="fw-bold py-3 mb-4">
<span class="text-muted fw-light">Dashboard /</span> Master Klasifikasi Menu
</h4>
<!-- Card Master Menu -->
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Klasifikasi Menu</h5>
<button type="button" class="btn btn-primary" onclick="addKlasifikasi()">
Tambah
</button>
</div>
<div class="card-body">
<table class="table" id="datatableKlasifikasiMenu"></table>
</div>
</div>
</div>
@include('dashboard.klasifikasi_menu.modal.create')
@include('dashboard.klasifikasi_menu.modal.edit')
<script src="{{ ver('/js/klasifikasi_menu/_init.js') }}"></script>
<script src="{{ ver('/js/klasifikasi_menu/dt.js') }}"></script>
<script src="{{ ver('/js/klasifikasi_menu/action.js') }}"></script>
<script src="{{ ver('/js/klasifikasi_menu/function.js') }}"></script>
@endsection

View File

@ -0,0 +1,41 @@
<!-- Modal -->
<div class="modal fade" id="modalKlasifikasiMenu" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h1 class="modal-title fs-5">Aksi Master Klasifikasi Menu</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<!-- Modal Form -->
<form enctype="multipart/form-data" method="POST" id="formKlasifikasiMenu">
@csrf
<div class="modal-body">
<div class="container" id="container_create">
<div class="row">
<div class="col">
<div class="form-floating">
<input type="text" class="form-control" name="data[0][nama_kategori_diet]" placeholder="exp : Diet Rendah Gula" required>
<label>Nama Klasifikasi Menu</label>
</div>
</div>
<div id="col_add_klasifikasi"></div>
</div>
<button type="button" class="btn btn-outline-primary btn-sm mt-2" onclick="addForm()">
+ Tambah Klasifikasi
</button>
</div>
</div>
<!-- Modal Footer -->
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Tutup</button>
<button type="submit" class="btn btn-primary">Simpan</button>
</div>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,40 @@
<!-- Modal -->
<div class="modal fade" id="modalKlasifikasiMenuEdit" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h1 class="modal-title fs-5">Aksi Master Klasifikasi Menu</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<!-- Modal Form -->
<form enctype="multipart/form-data" method="PUT" id="formKlasifikasiMenuEdit">
@method('put')
@csrf
<div class="modal-body">
<div class="container">
<div class="row">
<div class="col">
<div class="form-floating">
<input type="text" class="form-control" name="nama_kategori_diet" id="nama_kategori_diet" placeholder="exp : Diet Rendah Gula" required>
<label>Nama Klasifikasi Menu</label>
</div>
</div>
</div>
</div>
</div>
<!-- Modal Footer -->
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Tutup</button>
<button type="submit" class="btn btn-primary">Simpan</button>
</div>
</form>
</div>
</div>
</div>

View File

@ -17,7 +17,7 @@
<ul class="menu-inner py-1">
<!-- Dashboard -->
<li class="menu-item">
<a href="index.html" class="menu-link">
<a href="/dashboard" class="menu-link">
<i class="menu-icon tf-icons bx bx-home-circle"></i>
<div data-i18n="Analytics">Dashboard</div>
</a>
@ -34,6 +34,12 @@
<div data-i18n="Account Settings">Klasifikasi Menu</div>
</a>
</li>
<li class="menu-item {{ Request::is('dashboard/karbohidrat') ? 'active' : '' }}">
<a href="/dashboard/karbohidrat" class="menu-link">
<i class="menu-icon tf-icons bx bx-dock-top"></i>
<div data-i18n="Account Settings">Karbohidrat</div>
</a>
</li>
<li class="menu-item {{ Request::is('dashboard/menu') ? 'active' : '' }}">
<a href="/dashboard/menu" class="menu-link">
<i class="menu-icon tf-icons bx bx-dock-top"></i>

View File

@ -3,6 +3,7 @@
use App\Http\Controllers\AuthController;
use App\Http\Controllers\CustomerController;
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\KarbohidratController;
use App\Http\Controllers\KlasifikasiMenuController;
use App\Http\Controllers\MenuController;
use App\Http\Controllers\PesananController;
@ -19,15 +20,28 @@ Route::resource('/dashboard/menu', MenuController::class);
Route::group(['middleware' => ['auth']], function(){
Route::group(['prefix' => 'dashboard'], function(){
Route::get('/', [DashboardController::class, 'index']);
Route::resource('/klasifikasi-menu', KlasifikasiMenuController::class);
Route::get('/datatable/klasifikasi-menu', [KlasifikasiMenuController::class, 'datatable']);
Route::resource('/karbohidrat', KarbohidratController::class);
Route::get('/datatable/karbohidrat', [KarbohidratController::class, 'datatable']);
Route::get('/pending', [PesananController::class, 'index']);
Route::get('datatable/pending', [PesananController::class, 'getDataPending']);
Route::put('/pending/action/{order_id}', [PesananController::class, 'actionOrder']);
});
Route::post('/logout', [AuthController::class, 'logout']);
});
Route::get('/', [CustomerController::class, 'index']);
Route::get('/checkout', [CustomerController::class, 'checkout']);
Route::get('/datamenu', [CustomerController::class, 'dataOrder']);