add crud general settings

This commit is contained in:
arifal hidayat
2025-01-28 05:22:50 +07:00
parent 14f68c0add
commit 538cdb87ae
12 changed files with 387 additions and 61 deletions

View File

@@ -3,15 +3,110 @@
namespace App\Http\Controllers\Settings; namespace App\Http\Controllers\Settings;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\GlobalSettingRequest;
use App\Http\Requests\UpdateGlobalSettingRequest;
use App\Models\GlobalSetting;
use Exception;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class SettingsController extends Controller class SettingsController extends Controller
{ {
public function index(){ /**
* Display a listing of the resource.
*/
public function index()
{
return view('settings.general.index'); return view('settings.general.index');
} }
public function create(){ /**
* Show the form for creating a new resource.
*/
public function create()
{
return view('settings.general.create'); return view('settings.general.create');
} }
/**
* Store a newly created resource in storage.
*/
public function store(GlobalSettingRequest $request)
{
try{
DB::beginTransaction();
GlobalSetting::create($request->validated());
DB::commit();
return redirect()->route('general.index')->with('success', 'Data saved successfully.');
}catch(Exception $e){
DB::rollBack();
return redirect()->back()
->withInput()
->with('error', 'Something went wrong while saving data. ' . $e->getMessage());
}
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
$data = GlobalSetting::find($id);
if(!$data){
return redirect()->route('general.index')->with('error', 'Invalid id');
}
return view('settings.general.show', compact('data'));
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
{
$data = GlobalSetting::find($id);
if(!$data){
return redirect()->route('general.index')->with('error', 'Invalid id');
}
return view('settings.general.edit', compact('data'));
}
/**
* Update the specified resource in storage.
*/
public function update(UpdateGlobalSettingRequest $request, string $id)
{
try{
DB::beginTransaction();
$data = GlobalSetting::findOrFail($id);
$data->update($request->validated());
DB::commit();
return redirect()->route('general.index')->with('success', 'Data updated successfully.');
}catch(Exception $e){
DB::rollBack();
return redirect()->back()
->withInput()
->with('error', 'Something went wrong while updating data. '. $e->getMessage());
}
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
try{
DB::beginTransaction();
$data = GlobalSetting::findOrFail($id);
$data->delete();
DB::commit();
return response()->json(['success' => true, 'message' => 'Item deleted successfully.']);
}catch(Exception $e){
DB::rollBack();
Log::error($e->getMessage());
return response()->json(['success' => false, 'message' => 'Failed to delete item.'], 500);
}
}
} }

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UpdateGlobalSettingRequest 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
{
$id = $this->route('general');
return [
'key' => 'required|unique:global_settings,key,' . $id,
'value' => 'required',
'type' => 'nullable',
'description' => 'nullable'
];
}
}

View File

@@ -22,7 +22,7 @@ return Application::configure(basePath: dirname(__DIR__))
} }
}); });
$exceptions->render(function (HttpException $exception, Request $request){ $exceptions->render(function (HttpException $exception, Request $request){
if($exception->getStatusCode() == 404 && $request->isNot('api/*')) { if($exception->getStatusCode() == 404 && !$request->is('api/*')) {
return response()->view('pages.404',[],404); return response()->view('pages.404',[],404);
} }
}); });

View File

@@ -1,36 +1,108 @@
import { Grid } from "gridjs/dist/gridjs.umd.js"; import { Grid } from "gridjs/dist/gridjs.umd.js";
import gridjs from 'gridjs/dist/gridjs.umd.js' import gridjs from "gridjs/dist/gridjs.umd.js";
import 'gridjs/dist/gridjs.umd.js' import "gridjs/dist/gridjs.umd.js";
import GlobalConfig from "../../global-config.js"; import GlobalConfig from "../../global-config.js";
class SyncronizeTask { class SyncronizeTask {
init(){ init() {
this.initTableGeneralSettings(); this.initTableGeneralSettings();
} }
initTableGeneralSettings(){ initTableGeneralSettings() {
new Grid({ const table = new Grid({
columns: [ columns: [
"ID", "Key", "Value", "Description", "Created", "ID",
], "Key",
pagination: { "Value",
limit: 10, "Description",
server: { "Created",
url: (prev, page, limit) => `${prev}?page=${page}` {
} name: "Actions",
}, width: "120px",
sort: true, formatter: function (cell) {
search: { console.log("cell data", cell);
server: { return gridjs.html(`
url: (prev, page, keyword) => `${prev}?page=${page}&search=${keyword}` <div class="d-flex justify-items-end gap-10">
} <a href="/settings/general/${cell}/edit" class="btn btn-warning me-2">Update</a>
}, <button class="btn btn-delete btn-delete-global-settings" data-id="${cell}">Delete</button>
server: { </div>
url: `${GlobalConfig.apiHost}/api/global-settings`, `);
then: data => data.data.map((item) => [item.id, item.key, item.value, item.description, item.created_at]) },
} },
}).render(document.getElementById("general-setting-table")); ],
} pagination: {
limit: 15,
server: {
url: (prev, page, limit) => `${prev}?page=${page}`,
},
},
sort: true,
search: {
server: {
url: (prev, page, keyword) =>
`${prev}?page=${page}&search=${keyword}`,
},
},
server: {
url: `${GlobalConfig.apiHost}/api/global-settings`,
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content")}`,
"Content-Type": "application/json",
},
then: (data) =>
data.data.map((item) => [
item.id,
item.key,
item.value,
item.description,
item.created_at,
item.id,
]),
},
});
table.render(document.getElementById("general-setting-table"));
document.addEventListener("click", this.handleDelete);
}
handleDelete(event) {
if (event.target.classList.contains("btn-delete-global-settings")) {
event.preventDefault();
const id = event.target.getAttribute("data-id");
if (confirm("Are you sure you want to delete this item?")) {
fetch(`/settings/general/${id}`, {
method: "DELETE",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
"Content-Type": "application/json",
},
})
.then((response) => {
if (response.ok) {
alert("Item deleted successfully!");
window.location.reload();
} else {
return response.json().then((error) => {
throw new Error(
error.message || "Failed to delete item."
);
});
}
})
.catch((error) => {
console.error("Error deleting item:", error);
alert("Something went wrong. Please try again.");
});
}
}
}
} }
document.addEventListener('DOMContentLoaded', function (e) { document.addEventListener("click", function (e) {
new SyncronizeTask().init(); handleDelete(e); // Call the function on click event
}); });
document.addEventListener("DOMContentLoaded", function (e) {
new SyncronizeTask().init();
});

View File

@@ -69,7 +69,7 @@
<div class="collapse" id="sidebarSettings"> <div class="collapse" id="sidebarSettings">
<ul class="nav sub-navbar-nav"> <ul class="nav sub-navbar-nav">
<li class="sub-nav-item"> <li class="sub-nav-item">
<a class="sub-nav-link" href="{{ route ('settings.general' ) }}">General</a> <a class="sub-nav-link" href="{{ route ('general.index' ) }}">General</a>
</li> </li>
<li class="sub-nav-item"> <li class="sub-nav-item">
<a class="sub-nav-link" href="{{ route ('settings.syncronize' ) }}">Syncronize</a> <a class="sub-nav-link" href="{{ route ('settings.syncronize' ) }}">Syncronize</a>
@@ -78,6 +78,22 @@
</div> </div>
</li> </li>
<li class="nav-item">
<a class="nav-link menu-arrow" href="#sidebarSettings" data-bs-toggle="collapse" role="button"
aria-expanded="false" aria-controls="sidebarSettings">
<span class="nav-icon">
<iconify-icon icon="mingcute:task-line"></iconify-icon>
</span>
<span class="nav-text">Request Assignment</span>
</a>
<div class="collapse" id="sidebarSettings">
<ul class="nav sub-navbar-nav">
<li class="sub-nav-item">
<a class="sub-nav-link" href="{{ route ('request-assignments.index' ) }}">Task</a>
</li>
</ul>
</div>
</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -1,4 +1,4 @@
@extends('layouts.vertical', ['subtitle' => 'Master'])\ @extends('layouts.vertical', ['subtitle' => 'Master'])
@section('css') @section('css')
@vite(['node_modules/gridjs/dist/theme/mermaid.min.css']) @vite(['node_modules/gridjs/dist/theme/mermaid.min.css'])

View File

@@ -1,3 +1,23 @@
<div> @extends('layouts.vertical', ['subtitle' => 'Request Assignments'])
<!-- The biggest battle is the war against ignorance. - Mustafa Kemal Atatürk -->
@section('css')
@vite(['node_modules/gridjs/dist/theme/mermaid.min.css'])
@endsection
@section('content')
@include('layouts.partials/page-title', ['title' => 'Request Assignment', 'subtitle' => 'Task'])
<div class="row">
<div>
<h1>Request Assignment Page</h1>
</div>
<div>
<div id="table-import-datasources"></div>
</div>
</div> </div>
@endsection
@section('scripts')
@endsection

View File

@@ -5,22 +5,46 @@
@include('layouts.partials/page-title', ['title' => 'Se', 'subtitle' => 'Syncronize']) @include('layouts.partials/page-title', ['title' => 'Se', 'subtitle' => 'Syncronize'])
<div class="row"> <div class="row">
@if (session('error'))
<div class="alert alert-danger">
{{ session('error') }}
</div>
@endif
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<div class="columns-md"> <div class="columns-md">
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<form> <form action="{{ route('general.store') }}" method="POST">
<div class="mb-3"> @csrf
<label for="keyInput" class="form-label">Key</label> <div class="mb-3">
<input type="text" id="simpleinput" class="form-control"> <label for="key" class="form-label">Key</label>
</div> <input type="text" id="key" class="form-control" name="key">
<div class="mb-3">
<label for="valueInput" class="form-label">Value</label>
<input type="text" id="simpleinput" class="form-control">
</div>
<button type="button" class="btn btn-outline-success width-lg">Create</button>
</form>
</div> </div>
<div class="mb-3">
<label for="value" class="form-label">Value</label>
<input type="text" id="value" class="form-control" name="value">
</div>
<div class="mb-3">
<label for="type" class="form-label">Type</label>
<input type="text" id="type" class="form-control" name="type">
</div>
<div class="mb-3">
<label for="description" class="form-label">Description</label>
<input type="text" id="description" class="form-control" name="description">
</div>
<button type="submit" class="btn btn-success width-lg">Create</button>
</form>
</div> </div>
</div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,56 @@
@extends('layouts.vertical', ['subtitle' => 'Create User'])
@section('content')
@include('layouts.partials/page-title', ['title' => 'Se', 'subtitle' => 'Syncronize'])
<div class="row">
@if (session('error'))
<div class="alert alert-danger">
{{ session('error') }}
</div>
@endif
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<div class="columns-md">
<div class="card">
<div class="card-body">
<form action="{{ route('general.update', $data->id) }}" method="POST">
@csrf
@method('PUT')
<div class="mb-3">
<label for="key" class="form-label">Key</label>
<input type="text" id="key" class="form-control" name="key" value="{{ $data->key }}" readonly>
</div>
<div class="mb-3">
<label for="value" class="form-label">Value</label>
<input type="text" id="value" class="form-control" name="value" value="{{ $data->value }}">
</div>
<div class="mb-3">
<label for="type" class="form-label">Type</label>
<input type="text" id="type" class="form-control" name="type" value="{{ $data->type }}">
</div>
<div class="mb-3">
<label for="description" class="form-label">Description</label>
<input type="text" id="description" class="form-control" name="description" value="{{ $data->description }}">
</div>
<button type="submit" class="btn btn-success width-lg">Update</button>
</form>
</div>
</div>
</div>
</div>
@endsection
@section('scripts')
@vite(['resources/js/tables/common-table.js'])
@endsection

View File

@@ -9,12 +9,12 @@
@include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Syncronize']) @include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Syncronize'])
<div class="row"> <div class="row">
<div class="d-flex justify-content-end pb-3"> <div class="d-flex justify-content-end pb-3">
<button type="button" class="btn btn-outline-success width-lg">Create</button> <a href="{{ route('general.create') }}" class="btn btn-success width-lg">Create</a>
</div> </div>
<div> <div>
<div id="general-setting-table"></div> <div id="general-setting-table"></div>
</div> </div>
</div> </div>
@endsection @endsection

View File

@@ -16,7 +16,7 @@ Route::get('/user', function (Request $request) {
})->middleware('auth:sanctum'); })->middleware('auth:sanctum');
Route::group(['middleware' => 'auth:scantum'], function (){ Route::group(['middleware' => 'auth:scantum'], function (){
Route::apiResource('global-settings', GlobalSettingsController::class);
}); });
Route::controller(DashboardController::class)->group(function(){ Route::controller(DashboardController::class)->group(function(){
Route::get('/business-documents','businnessDocument'); Route::get('/business-documents','businnessDocument');
@@ -36,7 +36,7 @@ Route::get('/sync-task-submit/{uuid}', [SyncronizeController::class, 'syncTaskDe
Route::apiResource('import-datasource',ImportDatasourceController::class); Route::apiResource('import-datasource',ImportDatasourceController::class);
// global setting // global setting
Route::apiResource('global-settings', GlobalSettingsController::class);
// request assignment // request assignment
Route::apiResource('request-assignments',RequestAssignmentController::class); Route::apiResource('request-assignments',RequestAssignmentController::class);

View File

@@ -3,6 +3,7 @@
use App\Http\Controllers\Dashboards\BigDataController; use App\Http\Controllers\Dashboards\BigDataController;
use App\Http\Controllers\Home\HomeController; use App\Http\Controllers\Home\HomeController;
use App\Http\Controllers\Master\UsersController; use App\Http\Controllers\Master\UsersController;
use App\Http\Controllers\RequestAssignment\PbgTaskController;
use App\Http\Controllers\Settings\SettingsController; use App\Http\Controllers\Settings\SettingsController;
use App\Http\Controllers\Settings\SyncronizeController; use App\Http\Controllers\Settings\SyncronizeController;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
@@ -29,8 +30,9 @@ Route::group(['middleware' => 'auth'], function(){
// settings // settings
Route::group(['prefix' => '/settings'], function(){ Route::group(['prefix' => '/settings'], function(){
Route::resource('/general', SettingsController::class);
Route::get('/syncronize', [SyncronizeController::class, 'index'])->name('settings.syncronize'); Route::get('/syncronize', [SyncronizeController::class, 'index'])->name('settings.syncronize');
Route::get('/general', [SettingsController::class, 'index'])->name('settings.general'); // Route::get('/general', [SettingsController::class, 'index'])->name('settings.general');
Route::post('/syncronize', [SyncronizeController::class, 'syncronizeTask'])->name('settings.sync'); Route::post('/syncronize', [SyncronizeController::class, 'syncronizeTask'])->name('settings.sync');
}); });
@@ -51,4 +53,12 @@ Route::group(['middleware' => 'auth'], function(){
Route::delete('/users/delete/{id}', [UsersController::class, 'delete'])->name('master.users.delete'); Route::delete('/users/delete/{id}', [UsersController::class, 'delete'])->name('master.users.delete');
Route::delete('/users/show/{id}', [UsersController::class, 'show'])->name('master.users.show'); Route::delete('/users/show/{id}', [UsersController::class, 'show'])->name('master.users.show');
}); });
// request assignments
Route::group(['prefix' => '/request-assignments'], function(){
Route::controller(PbgTaskController::class)->group(function(){
Route::get('/index', 'index')->name('request-assignments.index');
});
});
}); });