Compare commits

...

18 Commits

Author SHA1 Message Date
arifal
f9e1aa1604 fix service scraping data 2025-03-18 06:42:42 +07:00
arifal
2e385f80cd fix optimize syncronize 2025-03-14 19:10:28 +07:00
arifal
e2c26e0eff fix reklame route index 2025-03-13 16:23:17 +07:00
arifal
ca5b8ad403 fix deploy code and readme 2025-03-13 15:59:11 +07:00
arifal
e97b7eb70d fix redirect back spatial plannings 2025-03-13 15:48:53 +07:00
arifal
0258ca9f04 fix redirect back umkm 2025-03-13 15:39:32 +07:00
arifal
0116147e06 fix redirect back reklame and tourisms 2025-03-13 15:24:59 +07:00
arifal
7787db02a3 fix redirect back business or industries 2025-03-13 14:13:06 +07:00
arifal
e47ab36d5e fix pdam redirect back and advertisement partial update redirect 2025-03-13 13:57:53 +07:00
arifal
e5db2294b4 fix redirect back data settings 2025-03-12 21:39:52 +07:00
arifal
4db457d7bd fix redirect back users crud 2025-03-12 21:17:49 +07:00
arifal
7a82ad5302 fix redirect back roles 2025-03-12 20:30:16 +07:00
arifal
b0d4d4c23b fix redirect back with params menu id 2025-03-12 17:52:11 +07:00
arifal
68ffc1c090 fix 503 page 2025-03-12 15:57:31 +07:00
arifal
a1f4bd7f81 fix seeder menu role and user assign, create 503 page and fix redirect home 2025-03-12 15:37:22 +07:00
arifal
238aaba96c fix seeder users role menu 2025-03-12 12:01:28 +07:00
arifal
c7152d9dbe fix resources report payment recaps 2025-03-12 11:50:56 +07:00
arifal
2a4b96d0b2 fix vite resources 2025-03-12 11:43:11 +07:00
93 changed files with 1918 additions and 923 deletions

View File

@@ -63,6 +63,12 @@ php artisan storage:link
php artisan migrate php artisan migrate
``` ```
- Running seeder
```
php artisan db:seed
```
- Create view table - Create view table
- excute all sql queries on folder database/view_query - excute all sql queries on folder database/view_query

View File

@@ -0,0 +1,89 @@
<?php
namespace App\Console\Commands;
use App\Models\ImportDatasource;
use App\Services\ServiceGoogleSheet;
use App\Services\ServicePbgTask;
use App\Services\ServiceTabPbgTask;
use GuzzleHttp\Client; // Import Guzzle Client
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;
class ScrapingData extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:scraping-data';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
private $client;
private $service_pbg_task;
private $service_tab_pbg_task;
/**
* Inject dependencies.
*/
public function __construct(Client $client, ServicePbgTask $service_pbg_task, ServiceTabPbgTask $serviceTabPbgTask)
{
parent::__construct();
$this->client = $client;
$this->service_pbg_task = $service_pbg_task;
$this->service_tab_pbg_task = $serviceTabPbgTask;
}
/**
* Execute the console command.
*/
public function handle()
{
try {
// Create a record with "processing" status
$import_datasource = ImportDatasource::create([
'message' => 'Initiating scraping...',
'response_body' => null,
'status' => 'processing'
]);
// Run the service
$service_google_sheet = new ServiceGoogleSheet($import_datasource->id);
$service_google_sheet->run_service();
// Run the ServicePbgTask with injected Guzzle Client
$this->service_pbg_task->run_service();
// run the service pbg task assignments
$this->service_tab_pbg_task->run_service();
// Update the record status to "success" after completion
$import_datasource->update([
'status' => 'success',
'message' => 'Scraping completed successfully.'
]);
} catch (\Exception $e) {
// Log the error for debugging
Log::error('Scraping failed: ' . $e->getMessage(), ['trace' => $e->getTraceAsString()]);
// Handle errors by updating the status to "failed"
if (isset($import_datasource)) {
$import_datasource->update([
'status' => 'failed',
'response_body' => 'Error: ' . $e->getMessage()
]);
}
}
}
}

View File

@@ -14,74 +14,30 @@ class BusinessOrIndustriesController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
$menuId = $request->query('menu_id'); $menuId = $request->query('menu_id') ?? $request->input('menu_id');
$user = Auth::user(); $permissions = $this->permissions[$menuId]?? []; // Avoid undefined index error
$userId = $user->id; $creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
// Ambil role_id yang dimiliki user $destroyer = $permissions['allow_destroy'] ?? 0;
$roleIds = DB::table('user_role') return view('business-industries.index', compact('creator', 'updater', 'destroyer','menuId'));
->where('user_id', $userId)
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('business-industries.index', compact('creator', 'updater', 'destroyer'));
} }
/** /**
* Show the form for creating a new resource. * Show the form for creating a new resource.
*/ */
public function create() public function create(Request $request)
{ {
return view("business-industries.create"); $menuId = $request->query('menu_id') ?? $request->input('menu_id');
} return view("business-industries.create", compact('menuId'));
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
} }
/** /**
* Show the form for editing the specified resource. * Show the form for editing the specified resource.
*/ */
public function edit(string $id) public function edit(string $id, Request $request)
{ {
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
$data = BusinessOrIndustry::findOrFail($id); $data = BusinessOrIndustry::findOrFail($id);
return view('business-industries.edit', compact('data')); return view('business-industries.edit', compact('data', 'menuId'));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
} }
} }

View File

@@ -11,38 +11,27 @@ class CustomersController extends Controller
{ {
public function index(Request $request) public function index(Request $request)
{ {
$menuId = $request->query('menu_id'); $menuId = $request->query('menu_id') ?? $request->input('menu_id');
$user = Auth::user(); $permissions = $this->permissions[$menuId]?? []; // Avoid undefined index error
$userId = $user->id; $creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
$destroyer = $permissions['allow_destroy'] ?? 0;
// Ambil role_id yang dimiliki user return view('customers.index', compact('creator', 'updater', 'destroyer', 'menuId'));
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('customers.index', compact('creator', 'updater', 'destroyer'));
} }
public function create() public function create(Request $request)
{ {
return view('customers.create'); $menuId = $request->query('menu_id');
return view('customers.create', compact('menuId'));
} }
public function edit(string $id) public function edit(Request $request, string $id)
{ {
$data = Customer::findOrFail($id); $data = Customer::findOrFail($id);
return view('customers.edit', compact('data')); $menuId = $request->query('menu_id');
return view('customers.edit', compact('data', 'menuId'));
} }
public function upload(){ public function upload(Request $request){
return view('customers.upload'); $menuId = $request->query('menu_id');
return view('customers.upload', compact('menuId'));
} }
} }

View File

@@ -15,27 +15,14 @@ class AdvertisementController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
$menuId = $request->query('menu_id'); $menuId = $request->query('menu_id', 0);
$user = Auth::user(); $permissions = $this->permissions[$menuId] ?? []; // Avoid undefined index error
$userId = $user->id;
// Ambil role_id yang dimiliki user $creator = $permissions['allow_create'] ?? 0;
$roleIds = DB::table('user_role') $updater = $permissions['allow_update'] ?? 0;
->where('user_id', $userId) $destroyer = $permissions['allow_destroy'] ?? 0;
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id return view('data.advertisements.index', compact('creator', 'updater', 'destroyer','menuId'));
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('data.advertisements.index', compact('creator', 'updater', 'destroyer'));
} }
/** /**
@@ -50,8 +37,9 @@ class AdvertisementController extends Controller
/** /**
* Show the form for creating a new resource. * Show the form for creating a new resource.
*/ */
public function create() public function create(Request $request)
{ {
$menuId = $request->query('menu_id', 0);
$title = 'Advertisement'; $title = 'Advertisement';
$subtitle = 'Create Data'; $subtitle = 'Create Data';
@@ -68,14 +56,15 @@ class AdvertisementController extends Controller
// $route = 'advertisements.create'; // $route = 'advertisements.create';
// info("AdvertisementController@edit diakses dengan ID: $title"); // info("AdvertisementController@edit diakses dengan ID: $title");
return view('data.advertisements.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions')); return view('data.advertisements.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions','menuId'));
} }
/** /**
* Show the form for editing the specified resource. * Show the form for editing the specified resource.
*/ */
public function edit($id) public function edit(Request $request, $id)
{ {
$menuId = $request->query('menu_id', 0);
info("AdvertisementController@edit diakses dengan ID: $id"); info("AdvertisementController@edit diakses dengan ID: $id");
$title = 'Advertisement'; $title = 'Advertisement';
$subtitle = 'Update Data'; $subtitle = 'Update Data';
@@ -107,7 +96,7 @@ class AdvertisementController extends Controller
// $route = 'advertisements.update'; // Menggunakan route update untuk form edit // $route = 'advertisements.update'; // Menggunakan route update untuk form edit
// info("AdvertisementController@edit diakses dengan route: $route"); // info("AdvertisementController@edit diakses dengan route: $route");
return view('data.advertisements.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions')); return view('data.advertisements.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions', 'menuId'));
} }
private function getFields() private function getFields()

View File

@@ -5,8 +5,6 @@ namespace App\Http\Controllers\Data;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\SpatialPlanning; use App\Models\SpatialPlanning;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
class SpatialPlanningController extends Controller class SpatialPlanningController extends Controller
{ {
@@ -15,42 +13,31 @@ class SpatialPlanningController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
$menuId = $request->query('menu_id'); $menuId = $request->query('menu_id', 0);
$user = Auth::user(); $permissions = $this->permissions[$menuId] ?? []; // Avoid undefined index error
$userId = $user->id;
// Ambil role_id yang dimiliki user $creator = $permissions['allow_create'] ?? 0;
$roleIds = DB::table('user_role') $updater = $permissions['allow_update'] ?? 0;
->where('user_id', $userId) $destroyer = $permissions['allow_destroy'] ?? 0;
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id return view('data.spatialPlannings.index', compact('creator', 'updater', 'destroyer','menuId'));
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('data.spatialPlannings.index', compact('creator', 'updater', 'destroyer'));
} }
/** /**
* show the form for creating a new resource. * show the form for creating a new resource.
*/ */
public function bulkCreate() public function bulkCreate(Request $request)
{ {
return view('data.spatialPlannings.form-upload'); $menuId = $request->query('menu_id', 0);
return view('data.spatialPlannings.form-upload', compact('menuId'));
} }
/** /**
* Show the form for creating a new resource. * Show the form for creating a new resource.
*/ */
public function create() public function create(Request $request)
{ {
$menuId = $request->query('menu_id', 0);
$title = 'Rencana Tata Ruang'; $title = 'Rencana Tata Ruang';
$subtitle = "Create Data"; $subtitle = "Create Data";
@@ -61,30 +48,15 @@ class SpatialPlanningController extends Controller
$fieldTypes = $this->getFieldTypes(); $fieldTypes = $this->getFieldTypes();
$apiUrl = url('/api/spatial-plannings'); $apiUrl = url('/api/spatial-plannings');
return view('data.spatialPlannings.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions')); return view('data.spatialPlannings.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions','menuId'));
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
} }
/** /**
* Show the form for editing the specified resource. * Show the form for editing the specified resource.
*/ */
public function edit(string $id) public function edit(Request $request,string $id)
{ {
$menuId = $request->query('menu_id', 0);
$title = 'Rencana Tata Ruang'; $title = 'Rencana Tata Ruang';
$subtitle = 'Update Data'; $subtitle = 'Update Data';
@@ -100,23 +72,7 @@ class SpatialPlanningController extends Controller
$fieldTypes = $this->getFieldTypes(); $fieldTypes = $this->getFieldTypes();
$apiUrl = url('/api/spatial-plannings'); $apiUrl = url('/api/spatial-plannings');
return view('data.spatialPlannings.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions')); return view('data.spatialPlannings.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions','menuId'));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
} }
private function getFields() private function getFields()

View File

@@ -15,41 +15,30 @@ class TourismController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
$menuId = $request->query('menu_id'); $menuId = $request->query('menu_id', 0);
$user = Auth::user(); $permissions = $this->permissions[$menuId] ?? []; // Avoid undefined index error
$userId = $user->id;
// Ambil role_id yang dimiliki user $creator = $permissions['allow_create'] ?? 0;
$roleIds = DB::table('user_role') $updater = $permissions['allow_update'] ?? 0;
->where('user_id', $userId) $destroyer = $permissions['allow_destroy'] ?? 0;
->pluck('role_id'); return view('data.tourisms.index', compact('creator', 'updater', 'destroyer', 'menuId'));
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('data.tourisms.index', compact('creator', 'updater', 'destroyer'));
} }
/** /**
* show the form for creating a new rsource. * show the form for creating a new rsource.
*/ */
public function bulkCreate() public function bulkCreate(Request $request)
{ {
return view('data.tourisms.form-upload'); $menuId = $request->query('menu_id', 0);
return view('data.tourisms.form-upload', compact('menuId'));
} }
/** /**
* Show th form for creating a new resource * Show th form for creating a new resource
*/ */
public function create() public function create(Request $request)
{ {
$menuId = $request->query('menu_id', 0);
$title = 'Pariwisata'; $title = 'Pariwisata';
$subtitle = 'Create Data'; $subtitle = 'Create Data';
@@ -64,14 +53,15 @@ class TourismController extends Controller
$apiUrl = url('/api/tourisms'); $apiUrl = url('/api/tourisms');
return view('data.tourisms.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions')); return view('data.tourisms.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions', 'menuId'));
} }
/** /**
* show the form for editing the specified resource. * show the form for editing the specified resource.
*/ */
public function edit($id) public function edit(Request $request, $id)
{ {
$menuId = $request->query('menu_id', 0);
$title = 'Pariwisata'; $title = 'Pariwisata';
$subtitle = 'Update Data'; $subtitle = 'Update Data';
@@ -98,7 +88,7 @@ class TourismController extends Controller
$apiUrl = url('/api/tourisms'); $apiUrl = url('/api/tourisms');
return view('data.tourisms.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions')); return view('data.tourisms.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions', 'menuId'));
} }
private function getFields() private function getFields()

View File

@@ -15,41 +15,30 @@ class UmkmController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
$menuId = $request->query('menu_id'); $menuId = $request->query('menu_id', 0);
$user = Auth::user(); $permissions = $this->permissions[$menuId] ?? []; // Avoid undefined index error
$userId = $user->id;
// Ambil role_id yang dimiliki user $creator = $permissions['allow_create'] ?? 0;
$roleIds = DB::table('user_role') $updater = $permissions['allow_update'] ?? 0;
->where('user_id', $userId) $destroyer = $permissions['allow_destroy'] ?? 0;
->pluck('role_id'); return view('data.umkm.index', compact('creator', 'updater', 'destroyer', 'menuId'));
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('data.umkm.index', compact('creator', 'updater', 'destroyer'));
} }
/** /**
* Show the form for creating a new resource. * Show the form for creating a new resource.
*/ */
public function bulkCreate() public function bulkCreate(Request $request)
{ {
return view('data.umkm.form-upload'); $menuId = $request->query('menu_id', 0);
return view('data.umkm.form-upload', compact('menuId'));
} }
/** /**
* Show the form for creating a new resource. * Show the form for creating a new resource.
*/ */
public function create() public function create(Request $request)
{ {
$menuId = $request->query('menu_id', 0);
$title = 'UMKM'; $title = 'UMKM';
$subtitle = 'Create Data'; $subtitle = 'Create Data';
@@ -67,14 +56,15 @@ class UmkmController extends Controller
$apiUrl = url('/api/umkm'); $apiUrl = url('/api/umkm');
return view('data.umkm.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions')); return view('data.umkm.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions','menuId'));
} }
/** /**
* Show the form for editing the specified resource. * Show the form for editing the specified resource.
*/ */
public function edit($id) public function edit(Request $request,$id)
{ {
$menuId = $request->query('menu_id', 0);
$title = 'UMKM'; $title = 'UMKM';
$subtitle = 'Update Data'; $subtitle = 'Update Data';
$modelInstance = Umkm::find($id); $modelInstance = Umkm::find($id);
@@ -116,7 +106,7 @@ class UmkmController extends Controller
$apiUrl = url('/api/umkm'); $apiUrl = url('/api/umkm');
// dd($modelInstance->business_form_id, $dropdownOptions['business_form']); // dd($modelInstance->business_form_id, $dropdownOptions['business_form']);
return view('data.umkm.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions')); return view('data.umkm.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions','menuId'));
} }
private function getFields() private function getFields()

View File

@@ -18,34 +18,21 @@ class DataSettingController extends Controller
*/ */
public function index(IndexRequest $request) public function index(IndexRequest $request)
{ {
$menuId = $request->query('menu_id'); $menuId = $request->query('menu_id') ?? $request->input('menu_id');
$user = Auth::user(); $permissions = $this->permissions[$menuId]?? []; // Avoid undefined index error
$userId = $user->id; $creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
// Ambil role_id yang dimiliki user $destroyer = $permissions['allow_destroy'] ?? 0;
$roleIds = DB::table('user_role') return view("data-settings.index", compact('creator', 'updater', 'destroyer','menuId'));
->where('user_id', $userId)
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view("data-settings.index", compact('creator', 'updater', 'destroyer'));
} }
/** /**
* Show the form for creating a new resource. * Show the form for creating a new resource.
*/ */
public function create() public function create(IndexRequest $request)
{ {
return view("data-settings.create"); $menuId = $request->query('menu_id') ?? $request->input('menu_id');
return view("data-settings.create", compact('menuId'));
} }
/** /**
@@ -78,14 +65,15 @@ class DataSettingController extends Controller
/** /**
* Show the form for editing the specified resource. * Show the form for editing the specified resource.
*/ */
public function edit(string $id) public function edit(IndexRequest $request,string $id)
{ {
try{ try{
$data = DataSetting::findOrFail($id); $data = DataSetting::findOrFail($id);
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
if(empty($data)){ if(empty($data)){
return redirect()->route('data-settings.index')->with('error', 'Invalid id'); return redirect()->route('data-settings.index')->with('error', 'Invalid id');
} }
return view("data-settings.edit", compact("data")); return view("data-settings.edit", compact("data", 'menuId'));
}catch(Exception $ex){ }catch(Exception $ex){
return redirect()->route("data-settings.index")->with("error", "Invalid id"); return redirect()->route("data-settings.index")->with("error", "Invalid id");
} }

View File

@@ -23,32 +23,19 @@ class UsersController extends Controller
return $this->resSuccess($users); return $this->resSuccess($users);
} }
public function index(Request $request){ public function index(Request $request){
$menuId = $request->query('menu_id'); $menuId = $request->query('menu_id') ?? $request->input('menu_id');
$user = Auth::user(); $permissions = $this->permissions[$menuId]?? []; // Avoid undefined index error
$userId = $user->id; $creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
// Ambil role_id yang dimiliki user $destroyer = $permissions['allow_destroy'] ?? 0;
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
$users = User::paginate(); $users = User::paginate();
return view('master.users.index', compact('users', 'creator', 'updater', 'destroyer')); return view('master.users.index', compact('users', 'creator', 'updater', 'destroyer','menuId'));
} }
public function create(){ public function create(Request $request){
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
$roles = Role::all(); $roles = Role::all();
return view('master.users.create', compact('roles')); return view('master.users.create', compact('roles', 'menuId'));
} }
public function store(UsersRequest $request){ public function store(UsersRequest $request){
$request->validate([ $request->validate([
@@ -86,10 +73,11 @@ class UsersController extends Controller
$user = User::find($id); $user = User::find($id);
return view('master.users.show', compact('user')); return view('master.users.show', compact('user'));
} }
public function edit($id){ public function edit(Request $request, $id){
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
$user = User::find($id); $user = User::find($id);
$roles = Role::all(); $roles = Role::all();
return view('master.users.edit', compact('user', 'roles')); return view('master.users.edit', compact('user', 'roles', 'menuId'));
} }
public function update(Request $request, $id){ public function update(Request $request, $id){
$user = User::find($id); $user = User::find($id);

View File

@@ -6,7 +6,6 @@ use App\Http\Requests\MenuRequest;
use App\Models\Menu; use App\Models\Menu;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
class MenusController extends Controller class MenusController extends Controller
{ {
@@ -15,36 +14,33 @@ class MenusController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
$menuId = $request->query('menu_id'); $menuId = (int) $request->query('menu_id', 0);
$user = Auth::user(); $permissions = $this->permissions[$menuId] ?? []; // Avoid undefined index error
$userId = $user->id;
// Ambil role_id yang dimiliki user $creator = $permissions['allow_create'] ?? 0;
$roleIds = DB::table('user_role') $updater = $permissions['allow_update'] ?? 0;
->where('user_id', $userId) $destroyer = $permissions['allow_destroy'] ?? 0;
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id return view('menus.index', compact('creator', 'updater', 'destroyer', 'menuId'));
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('menus.index', compact('creator', 'updater', 'destroyer'));
} }
/** /**
* Show the form for creating a new resource. * Show the form for creating a new resource.
*/ */
public function create() public function create(Request $request)
{ {
$parent_menus = Menu::whereNull('parent_id')->get(); $menuId = $request->query('menu_id'); // Get menu_id from request
return view("menus.create", compact('parent_menus')); $menu = Menu::with('children')->find($menuId); // Find the menu
// Get IDs of all child menus to exclude
$excludedIds = $menu ? $this->getChildMenuIds($menu) : [$menuId];
// Fetch only menus that have children and are not in the excluded list
$parent_menus = Menu::whereHas('children')
->whereNotIn('id', $excludedIds)
->get();
return view("menus.create", compact('parent_menus', 'menuId'));
} }
/** /**
@@ -77,11 +73,16 @@ class MenusController extends Controller
/** /**
* Show the form for editing the specified resource. * Show the form for editing the specified resource.
*/ */
public function edit(string $id) public function edit(string $id, Request $request)
{ {
$menu = Menu::findOrFail($id); $menuId = $request->query('menu_id');
$parent_menus = Menu::whereNull('parent_id')->where('id','!=',$id)->get(); $menu = Menu::with('children')->find($id);
return view("menus.edit", compact('menu','parent_menus')); $excludedIds = $menu ? $this->getChildMenuIds($menu) : [$id];
$parent_menus = Menu::whereHas('children')
->whereNotIn('id', $excludedIds)
->get();
return view("menus.edit", compact('menu','parent_menus', 'menuId'));
} }
/** /**
@@ -131,4 +132,15 @@ class MenusController extends Controller
$child->delete(); $child->delete();
} }
} }
private function getChildMenuIds($menu)
{
$ids = [$menu->id]; // Start with current menu ID
foreach ($menu->children as $child) {
$ids = array_merge($ids, $this->getChildMenuIds($child)); // Recursively fetch children
}
return $ids;
}
} }

View File

@@ -19,35 +19,22 @@ class RolesController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
$menuId = $request->query('menu_id'); $menuId = $request->query('menu_id') ?? $request->input('menu_id');
$user = Auth::user(); $permissions = $this->permissions[$menuId]?? []; // Avoid undefined index error
$userId = $user->id; $creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
$destroyer = $permissions['allow_destroy'] ?? 0;
// Ambil role_id yang dimiliki user return view("roles.index", compact('creator', 'updater', 'destroyer', 'menuId'));
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view("roles.index", compact('creator', 'updater', 'destroyer'));
} }
/** /**
* Show the form for creating a new resource. * Show the form for creating a new resource.
*/ */
public function create() public function create(Request $request)
{ {
return view("roles.create"); $menuId = $request->query('menu_id');
return view("roles.create", compact('menuId'));
} }
/** /**
@@ -80,10 +67,11 @@ class RolesController extends Controller
/** /**
* Show the form for editing the specified resource. * Show the form for editing the specified resource.
*/ */
public function edit(string $id) public function edit(string $id, Request $request)
{ {
$menuId = $request->query('menu_id');
$role = Role::findOrFail($id); $role = Role::findOrFail($id);
return view("roles.edit", compact('role')); return view("roles.edit", compact('role', 'menuId'));
} }
/** /**
@@ -121,12 +109,13 @@ class RolesController extends Controller
} }
} }
public function menu_permission(string $role_id){ public function menu_permission(string $role_id, Request $request){
try{ try{
$menuId = $request->query('menu_id');
$role = Role::findOrFail($role_id); $role = Role::findOrFail($role_id);
$menus = Menu::all(); $menus = Menu::all();
$role_menus = RoleMenu::where('role_id', $role_id)->get() ?? collect(); $role_menus = RoleMenu::where('role_id', $role_id)->get() ?? collect();
return view('roles.role_menu', compact('role', 'menus', 'role_menus')); return view('roles.role_menu', compact('role', 'menus', 'role_menus', 'menuId'));
}catch(\Exception $e){ }catch(\Exception $e){
return redirect()->back()->with("error", $e->getMessage()); return redirect()->back()->with("error", $e->getMessage());
} }
@@ -134,8 +123,9 @@ class RolesController extends Controller
public function update_menu_permission(Request $request, string $role_id){ public function update_menu_permission(Request $request, string $role_id){
try{ try{
$menuId = $request->query('menu_id');
$validateData = $request->validate([ $validateData = $request->validate([
"permissions" => "array", "permissions" => "nullable|array",
"permissions.*.allow_show" => "nullable|boolean", "permissions.*.allow_show" => "nullable|boolean",
"permissions.*.allow_create" => "nullable|boolean", "permissions.*.allow_create" => "nullable|boolean",
"permissions.*.allow_update" => "nullable|boolean", "permissions.*.allow_update" => "nullable|boolean",
@@ -144,6 +134,13 @@ class RolesController extends Controller
$role = Role::find($role_id); $role = Role::find($role_id);
// Jika `permissions` tidak ada atau kosong, hapus semua permissions terkait
if (!isset($validateData['permissions']) || empty($validateData['permissions'])) {
$role->menus()->detach();
return redirect()->route("roles.index", ['menu_id' => $menuId])
->with('success', 'All menu permissions have been removed.');
}
$permissionsArray = []; $permissionsArray = [];
foreach ($validateData['permissions'] as $menu_id => $permission) { foreach ($validateData['permissions'] as $menu_id => $permission) {
$permissionsArray[$menu_id] = [ $permissionsArray[$menu_id] = [
@@ -158,7 +155,7 @@ class RolesController extends Controller
// Sync will update existing records and insert new ones // Sync will update existing records and insert new ones
$role->menus()->sync($permissionsArray); $role->menus()->sync($permissionsArray);
return redirect()->route("role-menu.permission", $role_id)->with('success','Menu Permission updated successfully'); return redirect()->route("roles.index", ['menu_id' => $menuId])->with('success','Menu Permission updated successfully');
}catch(\Exception $e){ }catch(\Exception $e){
Log::error("Error updating role_menu:", ["error" => $e->getMessage()]); Log::error("Error updating role_menu:", ["error" => $e->getMessage()]);
return redirect()->route("role-menu.permission", $role_id)->with("error", $e->getMessage()); return redirect()->route("role-menu.permission", $role_id)->with("error", $e->getMessage());

View File

@@ -0,0 +1,284 @@
<?php
namespace App\Services;
use App\Models\DataSetting;
use App\Models\ImportDatasource;
use App\Models\PbgTaskGoogleSheet;
use Carbon\Carbon;
use Google_Client;
use Google_Service_Sheets;
use Log;
class ServiceGoogleSheet
{
protected $client;
protected $service;
protected $spreadsheetID;
protected $service_sheets;
protected $import_datasource;
public function __construct(int $import_datasource_id)
{
$this->client = new Google_Client();
$this->client->setApplicationName("Sibedas Google Sheets API");
$this->client->setScopes([Google_Service_Sheets::SPREADSHEETS_READONLY]);
$this->client->setAuthConfig(storage_path("app/teak-banner-450003-s8-ea05661d9db0.json"));
$this->client->setAccessType("offline");
$this->service = new Google_Service_Sheets($this->client);
$this->spreadsheetID = env("SPREAD_SHEET_ID");
$this->service_sheets = new Google_Service_Sheets($this->client);
$this->import_datasource = ImportDatasource::findOrFail($import_datasource_id);
}
public function run_service(){
$run_one = $this->sync_big_data();
if(!$run_one){
$this->import_datasource->update(['status' => 'failed']);
return false;
}
$run_two = $this->sync_google_sheet_data();
if(!$run_two){
$this->import_datasource->update(['status' => 'failed']);
return false;
}
return true;
}
public function sync_google_sheet_data() {
try {
$sheet_data = $this->get_data_by_sheet(0);
if (empty($sheet_data) || count($sheet_data) < 2) {
Log::warning("sync_google_sheet_data: No valid data found.");
return false;
}
$cleanValue = function ($value) {
return (isset($value) && trim($value) !== '') ? trim($value) : null;
};
$mapUpsert = [];
foreach(array_slice($sheet_data, 1) as $row){
if(!is_array($row)){
continue;
}
$no_registrasi = $cleanValue($row[2] ?? null);
// Apply the same logic from your SQL UPDATE
if (strpos($no_registrasi, 'PBG-') === 0) {
$format_registrasi = $no_registrasi;
} else {
$format_registrasi = sprintf(
"PBG-%s-%s-%s",
substr($no_registrasi, 0, 6) ?: '',
substr($no_registrasi, 7, 8) ?: '',
substr($no_registrasi, -2) ?: ''
);
}
$mapUpsert[] = [
'jenis_konsultasi' => $cleanValue($row[1] ?? null),
'no_registrasi' => $no_registrasi,
'formatted_registration_number' => $format_registrasi,
'nama_pemilik' => $cleanValue($row[3] ?? null),
'lokasi_bg' => $cleanValue($row[4] ?? null),
'fungsi_bg' => $cleanValue($row[5] ?? null),
'nama_bangunan' => $cleanValue($row[6] ?? null),
'tgl_permohonan' => $this->convertToDate($cleanValue($row[7] ?? null)),
'status_verifikasi' => $cleanValue($row[8] ?? null),
'status_permohonan' => $cleanValue($row[9] ?? null),
'alamat_pemilik' => $cleanValue($row[10] ?? null),
'no_hp' => $cleanValue($row[11] ?? null),
'email' => $cleanValue($row[12] ?? null),
'tanggal_catatan' => $this->convertToDate($cleanValue($row[13] ?? null)),
'catatan_kekurangan_dokumen' => $cleanValue($row[14] ?? null),
'gambar' => $cleanValue($row[15] ?? null),
'krk_kkpr' => $cleanValue($row[16] ?? null),
'no_krk' => $cleanValue($row[17] ?? null),
'lh' => $cleanValue($row[18] ?? null),
'ska' => $cleanValue($row[19] ?? null),
'keterangan' => $cleanValue($row[20] ?? null),
'helpdesk' => $cleanValue($row[21] ?? null),
'pj' => $cleanValue($row[22] ?? null),
'kepemilikan' => $cleanValue($row[24] ?? null),
'potensi_taru' => $cleanValue($row[25] ?? null),
'validasi_dinas' => $cleanValue($row[26] ?? null),
'kategori_retribusi' => $cleanValue($row[27] ?? null),
'no_urut_ba_tpt' => $cleanValue($row[28] ?? null),
'tanggal_ba_tpt' => $this->convertToDate($cleanValue($row[29] ?? null)),
'no_urut_ba_tpa' => $cleanValue($row[30] ?? null),
'tanggal_ba_tpa' => $this->convertToDate($cleanValue($row[31] ?? null)),
'no_urut_skrd' => $cleanValue($row[32] ?? null),
'tanggal_skrd' => $this->convertToDate($cleanValue($row[33] ?? null)),
'ptsp' => $cleanValue($row[34] ?? null),
'selesai_terbit' => $cleanValue($row[35] ?? null),
'tanggal_pembayaran' => $cleanValue($row[36] ?? null),
'format_sts' => $cleanValue($row[37] ?? null),
'tahun_terbit' => (int) $cleanValue($row[38] ?? null),
'tahun_berjalan' => (int) $cleanValue($row[39] ?? null),
'kelurahan' => $cleanValue($row[40] ?? null),
'kecamatan' => $cleanValue($row[41] ?? null),
'lb' => $this->convertToDecimal($cleanValue($row[42] ?? 0)),
'tb' => $this->convertToDecimal($cleanValue($row[43] ?? 0)),
'jlb' => (int) $cleanValue($row[44] ?? null),
'unit' => (int) $cleanValue($row[45] ?? null),
'usulan_retribusi' => (int) $cleanValue($row[46] ?? null),
'nilai_retribusi_keseluruhan_simbg' => $this->convertToDecimal($cleanValue($row[47] ?? 0)),
'nilai_retribusi_keseluruhan_pad' => $this->convertToDecimal($cleanValue($row[48] ?? 0)),
'denda' => $this->convertToDecimal($cleanValue($row[49] ?? 0)),
'latitude' => $cleanValue($row[50] ?? null),
'longitude' => $cleanValue($row[51] ?? null),
'nik_nib' => $cleanValue($row[52] ?? null),
'dok_tanah' => $cleanValue($row[53] ?? null),
'temuan' => $cleanValue($row[54] ?? null),
'updated_at' => now()
];
}
// Count occurrences of each no_registrasi
$registrasiCounts = array_count_values(array_column($mapUpsert, 'no_registrasi'));
// Filter duplicates (those appearing more than once)
$duplicates = array_filter($registrasiCounts, function ($count) {
return $count > 1;
});
if (!empty($duplicates)) {
Log::warning("Duplicate no_registrasi found", ['duplicates' => array_keys($duplicates)]);
}
// Remove duplicates before upsert
$mapUpsert = collect($mapUpsert)->unique('no_registrasi')->values()->all();
$batchSize = 1000;
$chunks = array_chunk($mapUpsert, $batchSize);
foreach ($chunks as $chunk) {
PbgTaskGoogleSheet::upsert($chunk, ['no_registrasi']);
}
Log::info("sync google sheet done");
} catch (\Exception $e) {
Log::error("sync_google_sheet_data failed", ['error' => $e->getMessage()]);
return false;
}
}
public function sync_big_data(){
try {
$sheet_big_data = $this->get_data_by_sheet();
$data_setting_result = []; // Initialize result storage
$found_section = null; // Track which section is found
foreach ($sheet_big_data as $row) {
// Check for section headers
if (in_array("•PROSES PENERBITAN:", $row)) {
$found_section = "MENUNGGU_KLIK_DPMPTSP";
} elseif (in_array("•BERKAS AKTUAL TERVERIFIKASI DINAS TEKNIS 2024:", $row)) {
$found_section = "REALISASI_TERBIT_PBG";
} elseif (in_array("•TERPROSES DI DPUTR: belum selesai rekomtek'", $row)) {
$found_section = "PROSES_DINAS_TEKNIS";
}
// If a section is found and we reach "Grand Total", save the corresponding values
if ($found_section && isset($row[0]) && trim($row[0]) === "Grand Total") {
if ($found_section === "MENUNGGU_KLIK_DPMPTSP") {
$data_setting_result["MENUNGGU_KLIK_DPMPTSP_COUNT"] = $this->convertToInteger($row[2]) ?? null;
$data_setting_result["MENUNGGU_KLIK_DPMPTSP_SUM"] = $this->convertToDecimal($row[3]) ?? null;
} elseif ($found_section === "REALISASI_TERBIT_PBG") {
$data_setting_result["REALISASI_TERBIT_PBG_COUNT"] = $this->convertToInteger($row[2]) ?? null;
$data_setting_result["REALISASI_TERBIT_PBG_SUM"] = $this->convertToDecimal($row[4]) ?? null;
} elseif ($found_section === "PROSES_DINAS_TEKNIS") {
$data_setting_result["PROSES_DINAS_TEKNIS_COUNT"] = $this->convertToInteger($row[2]) ?? null;
$data_setting_result["PROSES_DINAS_TEKNIS_SUM"] = $this->convertToDecimal($row[3]) ?? null;
}
// Reset section tracking after capturing "Grand Total"
$found_section = null;
}
}
foreach ($data_setting_result as $key => $value) {
DataSetting::updateOrInsert(
["key" => $key], // Find by key
["value" => $value] // Update or insert value
);
}
return true;
} catch (\Exception $e) {
// **Log error**
Log::error("Error syncing Google Sheet data", ['error' => $e->getMessage()]);
return false;
}
}
private function get_data_by_sheet($no_sheet = 1){
$spreadsheet = $this->service->spreadsheets->get($this->spreadsheetID);
$sheets = $spreadsheet->getSheets();
$sheetTitle = $sheets[$no_sheet]->getProperties()->getTitle();
$range = "{$sheetTitle}";
$response = $this->service->spreadsheets_values->get($this->spreadsheetID, $range);
$values = $response->getValues();
return!empty($values)? $values : [];
}
private function convertToInteger($value) {
// Check if the value is an empty string, and return null if true
if (trim($value) === "") {
return null;
}
$cleaned = str_replace('.','', $value);
// Otherwise, cast to integer
return (int) $cleaned;
}
private function convertToDecimal(?string $value): ?float
{
if (empty($value)) {
return null; // Return null if the input is empty
}
// Remove all non-numeric characters except comma and dot
$value = preg_replace('/[^0-9,\.]/', '', $value);
// If the number contains both dot (.) and comma (,)
if (strpos($value, '.') !== false && strpos($value, ',') !== false) {
$value = str_replace('.', '', $value); // Remove thousands separator
$value = str_replace(',', '.', $value); // Convert decimal separator to dot
}
// If only a dot is present (assumed as thousands separator)
elseif (strpos($value, '.') !== false) {
$value = str_replace('.', '', $value); // Remove all dots (treat as thousands separators)
}
// If only a comma is present (assumed as decimal separator)
elseif (strpos($value, ',') !== false) {
$value = str_replace(',', '.', $value); // Convert comma to dot (decimal separator)
}
// Ensure the value is numeric before returning
return is_numeric($value) ? (float) number_format((float) $value, 2, '.', '') : null;
}
private function convertToDate($dateString)
{
try {
// Check if the string is empty
if (empty($dateString)) {
return null;
}
// Try to parse the date string
$date = Carbon::parse($dateString);
// Return the Carbon instance
return $date->format('Y-m-d');
} catch (\Exception $e) {
// Return null if an error occurs during parsing
return null;
}
}
}

View File

@@ -0,0 +1,173 @@
<?php
namespace App\Services;
use App\Models\GlobalSetting;
use App\Models\PbgTask;
use Carbon\Carbon;
use GuzzleHttp\Client;
use Exception;
use Illuminate\Support\Facades\Log;
class ServicePbgTask
{
private $client;
private $simbg_host;
private $fetch_per_page;
private $pbg_task_url;
private $service_token;
private $user_token;
private $user_refresh_token;
public function __construct(Client $client, ServiceTokenSIMBG $service_token)
{
$settings = GlobalSetting::whereIn('key', ['SIMBG_HOST', 'FETCH_PER_PAGE'])
->pluck('value', 'key');
$this->simbg_host = trim((string) ($settings['SIMBG_HOST'] ?? ""));
$this->fetch_per_page = trim((string) ($settings['FETCH_PER_PAGE'] ?? "10"));
$this->client = $client;
$this->service_token = $service_token;
$this->pbg_task_url = "{$this->simbg_host}/api/pbg/v1/list/?page=1&size={$this->fetch_per_page}&sort=ASC";
$auth_data = $this->service_token->get_token();
$this->user_token = $auth_data['access'];
$this->user_refresh_token = $auth_data['refresh'];
}
public function run_service()
{
try{
$this->fetch_pbg_task();
}catch(Exception $e){
throw $e;
}
}
private function fetch_pbg_task()
{
try {
$currentPage = 1;
$totalPage = 1;
$options = [
'headers' => [
'Authorization' => "Bearer {$this->user_token}",
'Content-Type' => 'application/json'
]
];
$maxRetries = 3; // Maximum number of retries
$initialDelay = 1; // Initial delay in seconds
$fetchData = function ($url) use (&$options, $maxRetries, $initialDelay) {
$retryCount = 0;
while ($retryCount < $maxRetries) {
try {
return $this->client->get($url, $options);
} catch (\GuzzleHttp\Exception\ClientException $e) {
if ($e->getCode() === 401) {
Log::warning("Unauthorized. Refreshing token...");
// Refresh token
$auth_data = $this->service_token->refresh_token($this->user_refresh_token);
if (!isset($auth_data['access'])) {
Log::error("Token refresh failed.");
throw new Exception("Token refresh failed.");
}
// Update tokens
$this->user_token = $auth_data['access'];
$this->user_refresh_token = $auth_data['refresh'];
// Update headers
$options['headers']['Authorization'] = "Bearer {$this->user_token}";
// Retry request
return $this->client->get($url, $options);
}
throw $e;
} catch (\GuzzleHttp\Exception\ServerException | \GuzzleHttp\Exception\ConnectException $e) {
// Handle 502 or connection issues
if ($e->getCode() === 502) {
Log::warning("502 Bad Gateway - Retrying in {$initialDelay} seconds...");
} else {
Log::error("Network error - Retrying in {$initialDelay} seconds...");
}
$retryCount++;
sleep($initialDelay);
$initialDelay *= 2; // Exponential backoff
}
}
Log::error("Max retries reached. Failing request.");
throw new Exception("Max retries reached. Failing request.");
};
do {
$url = "{$this->simbg_host}/api/pbg/v1/list/?page={$currentPage}&size={$this->fetch_per_page}&sort=ASC";
$fetch_data = $fetchData($url);
if (!$fetch_data) {
Log::error("Failed to fetch data on page {$currentPage} after retries.");
throw new Exception("Failed to fetch data on page {$currentPage} after retries.");
}
$response = json_decode($fetch_data->getBody()->getContents(), true);
if (!isset($response['data'])) {
Log::error("Invalid API response on page {$currentPage}");
throw new Exception("Invalid API response on page {$currentPage}");
}
$data = $response['data'];
$totalPage = isset($response['total_page']) ? (int) $response['total_page'] : 1;
$saved_data = [];
foreach ($data as $item) {
$saved_data[] = [
'uuid' => $item['uid'] ?? null,
'name' => $item['name'] ?? null,
'owner_name' => $item['owner_name'] ?? null,
'application_type' => $item['application_type'] ?? null,
'application_type_name' => $item['application_type_name'] ?? null,
'condition' => $item['condition'] ?? null,
'registration_number' => $item['registration_number'] ?? null,
'document_number' => $item['document_number'] ?? null,
'address' => $item['address'] ?? null,
'status' => $item['status'] ?? null,
'status_name' => $item['status_name'] ?? null,
'slf_status' => $item['slf_status'] ?? null,
'slf_status_name' => $item['slf_status_name'] ?? null,
'function_type' => $item['function_type'] ?? null,
'consultation_type' => $item['consultation_type'] ?? null,
'due_date' => $item['due_date'] ?? null,
'land_certificate_phase' => $item['land_certificate_phase'] ?? null,
'task_created_at' => isset($item['created_at']) ? Carbon::parse($item['created_at'])->format('Y-m-d H:i:s') : null,
'updated_at' => now(),
'created_at' => now(),
];
}
if (!empty($saved_data)) {
PbgTask::upsert($saved_data, ['uuid'], [
'name', 'owner_name', 'application_type', 'application_type_name', 'condition',
'registration_number', 'document_number', 'address', 'status', 'status_name',
'slf_status', 'slf_status_name', 'function_type', 'consultation_type', 'due_date',
'land_certificate_phase', 'task_created_at', 'updated_at'
]);
}
Log::info("Page {$currentPage} fetched & saved", ['records' => count($saved_data)]);
$currentPage++;
} while ($currentPage <= $totalPage);
return true;
} catch (Exception $e) {
Log::error("Error fetching PBG tasks", ['error' => $e->getMessage()]);
throw $e;
}
}
}

View File

@@ -180,58 +180,57 @@ class ServiceSIMBG
$mapToUpsert = []; $mapToUpsert = [];
foreach ($sheetData as $data) { foreach ($sheetData as $data) {
$mapToUpsert[] = $mapToUpsert[] = [
[ 'no_registrasi' => $this->cleanString($data['no__registrasi'] ?? null),
'no_registrasi' => $data['no__registrasi'] ?? null, 'jenis_konsultasi' => $this->cleanString($data['jenis_konsultasi'] ?? null),
'jenis_konsultasi' => $data['jenis_konsultasi'] ?? null, 'fungsi_bg' => $this->cleanString($data['fungsi_bg'] ?? null),
'fungsi_bg' => $data['fungsi_bg'] ?? null, 'tgl_permohonan' => $this->convertToDate($this->cleanString($data['tgl_permohonan'] ?? null)),
'tgl_permohonan' => $this->convertToDate($data['tgl_permohonan']), 'status_verifikasi' => $this->cleanString($data['status_verifikasi'] ?? null),
'status_verifikasi' => $data['status_verifikasi'] ?? null, 'status_permohonan' => $this->convertToDate($this->cleanString($data['status_permohonan'] ?? null)),
'status_permohonan' => $this->convertToDate($data['status_permohonan']), 'alamat_pemilik' => $this->cleanString($data['alamat_pemilik'] ?? null),
'alamat_pemilik' => $data['alamat_pemilik'] ?? null, 'no_hp' => $this->cleanString($data['no__hp'] ?? null),
'no_hp' => $data['no__hp'] ?? null, 'email' => $this->cleanString($data['e_mail'] ?? null),
'email' => $data['e_mail'] ?? null, 'tanggal_catatan' => $this->convertToDate($this->cleanString($data['tanggal_catatan'] ?? null)),
'tanggal_catatan' => $this->convertToDate($data['tanggal_catatan']), 'catatan_kekurangan_dokumen' => $this->cleanString($data['catatan_kekurangan_dokumen'] ?? null),
'catatan_kekurangan_dokumen' => $data['catatan_kekurangan_dokumen'] ?? null, 'gambar' => $this->cleanString($data['gambar'] ?? null),
'gambar' => $data['gambar'] ?? null, 'krk_kkpr' => $this->cleanString($data['krk_kkpr'] ?? null),
'krk_kkpr' => $data['krk_kkpr'] ?? null, 'no_krk' => $this->cleanString($data['no__krk'] ?? null),
'no_krk' => $data['no__krk'] ?? null, 'lh' => $this->cleanString($data['lh'] ?? null),
'lh' => $data['lh'] ?? null, 'ska' => $this->cleanString($data['ska'] ?? null),
'ska' => $data['ska'] ?? null, 'keterangan' => $this->cleanString($data['keterangan'] ?? null),
'keterangan' => $data['keterangan'] ?? null, 'helpdesk' => $this->cleanString($data['helpdesk'] ?? null),
'helpdesk' => $data['helpdesk'] ?? null, 'pj' => $this->cleanString($data['pj'] ?? null),
'pj' => $data['pj'] ?? null, 'kepemilikan' => $this->cleanString($data['kepemilikan'] ?? null),
'kepemilikan' => $data['kepemilikan'] ?? null, 'potensi_taru' => $this->cleanString($data['potensi_taru'] ?? null),
'potensi_taru' => $data['potensi_taru'] ?? null, 'validasi_dinas' => $this->cleanString($data['validasi_dinas'] ?? null),
'validasi_dinas' => $data['validasi_dinas'] ?? null, 'kategori_retribusi' => $this->cleanString($data['kategori_retribusi'] ?? null),
'kategori_retribusi' => $data['kategori_retribusi'] ?? null, 'no_urut_ba_tpt' => $this->cleanString($data['no__urut_ba_tpt__2024_0001_'] ?? null),
'no_urut_ba_tpt' => $data['no__urut_ba_tpt__2024_0001_'] ?? null, 'tanggal_ba_tpt' => $this->convertToDate($this->cleanString($data['tanggal_ba_tpt'] ?? null)),
'tanggal_ba_tpt' => $this->convertToDate($data['tanggal_ba_tpt']), 'no_urut_ba_tpa' => $this->cleanString($data['no__urut_ba_tpa'] ?? null),
'no_urut_ba_tpa' => $data['no__urut_ba_tpa'] ?? null, 'tanggal_ba_tpa' => $this->convertToDate($this->cleanString($data['tanggal_ba_tpa'] ?? null)),
'tanggal_ba_tpa' => $this->convertToDate($data['tanggal_ba_tpa']), 'no_urut_skrd' => $this->cleanString($data['no__urut_skrd__2024_0001_'] ?? null),
'no_urut_skrd' => $data['no__urut_skrd__2024_0001_'] ?? null, 'tanggal_skrd' => $this->convertToDate($this->cleanString($data['tanggal_skrd'] ?? null)),
'tanggal_skrd' => $this->convertToDate($data['tanggal_skrd']), 'ptsp' => $this->cleanString($data['ptsp'] ?? null),
'ptsp' => $data['ptsp'] ?? null, 'selesai_terbit' => $this->cleanString($data['selesai_terbit'] ?? null),
'selesai_terbit' => $data['selesai_terbit'] ?? null, 'tanggal_pembayaran' => $this->convertToDate($this->cleanString($data['tanggal_pembayaran__yyyy_mm_dd_'] ?? null)),
'tanggal_pembayaran' => $this->convertToDate($data['tanggal_pembayaran__yyyy_mm_dd_']), 'format_sts' => $this->cleanString($data['format_sts'] ?? null),
'format_sts' => $data['format_sts'] ?? null, 'tahun_terbit' => (int) ($data['tahun_terbit'] ?? null),
'tahun_terbit' => (int) $data['tahun_terbit'] ?? null, 'tahun_berjalan' => (int) ($data['tahun_berjalan'] ?? null),
'tahun_berjalan' => (int) $data['tahun_berjalan'] ?? null, 'kelurahan' => $this->cleanString($data['kelurahan'] ?? null),
'kelurahan' => $data['kelurahan'] ?? null, 'kecamatan' => $this->cleanString($data['kecamatan'] ?? null),
'kecamatan' => $data['kecamatan'] ?? null, 'lb' => $this->convertToDecimal($data['lb'] ?? null),
'lb' => $this->convertToDecimal($data['lb']) ?? null, 'tb' => $this->convertToDecimal($data['tb'] ?? null),
'tb' => $this->convertToDecimal($data['tb']) ?? null, 'jlb' => (int) ($data['jlb'] ?? null),
'jlb' => (int) $data['jlb'] ?? null, 'unit' => (int) ($data['unit'] ?? null),
'unit' => (int) $data['unit'] ?? null, 'usulan_retribusi' => (int) ($data['usulan_retribusi'] ?? null),
'usulan_retribusi' => (int) $data['usulan_retribusi'] ?? null, 'nilai_retribusi_keseluruhan_simbg' => $this->convertToDecimal($data['nilai_retribusi_keseluruhan__simbg_'] ?? null),
'nilai_retribusi_keseluruhan_simbg' => $this->convertToDecimal($data['nilai_retribusi_keseluruhan__simbg_']) ?? null, 'nilai_retribusi_keseluruhan_pad' => $this->convertToDecimal($data['nilai_retribusi_keseluruhan__pad_'] ?? null),
'nilai_retribusi_keseluruhan_pad' => $this->convertToDecimal($data['nilai_retribusi_keseluruhan__pad_']) ?? null, 'denda' => $this->convertToDecimal($data['denda'] ?? null),
'denda' => $this->convertToDecimal($data['denda']) ?? null, 'latitude' => $this->cleanString($data['latitude'] ?? null),
'latitude' => $data['latitude'] ?? null, 'longitude' => $this->cleanString($data['longitude'] ?? null),
'longitude' => $data['longitude'] ?? null, 'nik_nib' => $this->cleanString($data['nik_nib'] ?? null),
'nik_nib' => $data['nik_nib'] ?? null, 'dok_tanah' => $this->cleanString($data['dok__tanah'] ?? null),
'dok_tanah' => $data['dok__tanah'] ?? null, 'temuan' => $this->cleanString($data['temuan'] ?? null),
'temuan' => $data['temuan'] ?? null,
]; ];
} }
@@ -656,4 +655,9 @@ class ServiceSIMBG
return null; return null;
} }
} }
private function cleanString($value)
{
return isset($value) ? trim(strip_tags($value)) : null;
}
} }

View File

@@ -0,0 +1,351 @@
<?php
namespace App\Services;
use App\Models\GlobalSetting;
use App\Models\PbgTask;
use App\Models\PbgTaskIndexIntegrations;
use App\Models\PbgTaskPrasarana;
use App\Models\PbgTaskRetributions;
use App\Models\TaskAssignment;
use Carbon\Carbon;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Log;
class ServiceTabPbgTask
{
private $client;
private $simbg_host;
private $fetch_per_page;
private $service_token;
private $user_token;
private $user_refresh_token;
public function __construct(Client $client, ServiceTokenSIMBG $service_token)
{
$settings = GlobalSetting::whereIn('key', ['SIMBG_HOST', 'FETCH_PER_PAGE'])
->pluck('value', 'key');
$this->simbg_host = trim((string) ($settings['SIMBG_HOST'] ?? ""));
$this->fetch_per_page = trim((string) ($settings['FETCH_PER_PAGE'] ?? "10"));
$this->client = $client;
$this->service_token = $service_token;
$auth_data = $this->service_token->get_token();
$this->user_token = $auth_data['access'];
$this->user_refresh_token = $auth_data['refresh'];
}
public function run_service()
{
try {
$pbg_tasks = PbgTask::all();
foreach ($pbg_tasks as $pbg_task) {
$this->scraping_task_assignments($pbg_task->uuid);
$this->scraping_task_retributions($pbg_task->uuid);
$this->scraping_task_integrations($pbg_task->uuid);
// Process task assignments here if needed
Log::info("Successfully fetched for UUID: {$pbg_task->uuid}");
}
} catch (\Exception $e) {
Log::error("Failed to scrape task assignments: " . $e->getMessage());
throw $e;
}
}
private function scraping_task_assignments($uuid)
{
$url = "{$this->simbg_host}/api/pbg/v1/list-tim-penilai/{$uuid}/?page=1&size=10";
$options = [
'headers' => [
'Authorization' => "Bearer {$this->user_token}",
'Content-Type' => 'application/json'
]
];
$maxRetries = 3;
$initialDelay = 1;
$retriedAfter401 = false;
for ($retryCount = 0; $retryCount < $maxRetries; $retryCount++) {
try {
$response = $this->client->get($url, $options);
$responseData = json_decode($response->getBody()->getContents(), true);
if (empty($responseData['data']) || !is_array($responseData['data'])) {
return true;
}
$task_assignments = [];
foreach ($responseData['data'] as $data) {
$task_assignments[] = [
'pbg_task_uid' => $uuid,
'user_id' => $data['user_id'] ?? null,
'name' => $data['name'] ?? null,
'username' => $data['username'] ?? null,
'email' => $data['email'] ?? null,
'phone_number' => $data['phone_number'] ?? null,
'role' => $data['role'] ?? null,
'role_name' => $data['role_name'] ?? null,
'is_active' => $data['is_active'] ?? false,
'file' => !empty($data['file']) ? json_encode($data['file']) : null,
'expertise' => !empty($data['expertise']) ? json_encode($data['expertise']) : null,
'experience' => !empty($data['experience']) ? json_encode($data['experience']) : null,
'is_verif' => $data['is_verif'] ?? false,
'uid' => $data['uid'] ?? null,
'status' => $data['status'] ?? null,
'status_name' => $data['status_name'] ?? null,
'note' => $data['note'] ?? null,
'ta_id' => $data['id'] ?? null,
'created_at' => now(),
'updated_at' => now(),
];
}
if (!empty($task_assignments)) {
TaskAssignment::upsert(
$task_assignments,
['uid'],
['ta_id', 'name', 'username', 'email', 'phone_number', 'role', 'role_name', 'is_active', 'file', 'expertise', 'experience', 'is_verif', 'status', 'status_name', 'note', 'updated_at']
);
}
return $responseData;
} catch (\GuzzleHttp\Exception\ClientException $e) {
if ($e->getCode() === 401 && !$retriedAfter401) {
Log::warning("401 Unauthorized - Refreshing token and retrying...");
$this->refreshToken();
$options['headers']['Authorization'] = "Bearer {$this->user_token}";
$retriedAfter401 = true;
continue; // Retry with new token
}
throw $e;
} catch (\GuzzleHttp\Exception\ServerException | \GuzzleHttp\Exception\ConnectException $e) {
if ($e->getCode() === 502) {
Log::warning("502 Bad Gateway - Retrying in {$initialDelay} seconds...");
} else {
Log::error("Network error ({$e->getCode()}) - Retrying in {$initialDelay} seconds...");
}
sleep($initialDelay);
$initialDelay *= 2;
} catch (\Exception $e) {
Log::error("Unexpected error: " . $e->getMessage());
throw $e;
}
}
Log::error("Failed to fetch task assignments for UUID {$uuid} after {$maxRetries} retries.");
throw new \Exception("Failed to fetch task assignments for UUID {$uuid} after retries.");
}
private function scraping_task_retributions($uuid)
{
$url = "{$this->simbg_host}/api/pbg/v1/detail/" . $uuid . "/retribution/submit/";
$options = [
'headers' => [
'Authorization' => "Bearer {$this->user_token}",
'Content-Type' => 'application/json'
]
];
$maxRetries = 3;
$initialDelay = 1;
$retriedAfter401 = false;
for ($retryCount = 0; $retryCount < $maxRetries; $retryCount++) {
try {
$response = $this->client->get($url, $options);
$responseData = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
if (empty($responseData['data']) || !is_array($responseData['data'])) {
return true;
}
$data = $responseData['data'];
$detailCreatedAt = isset($data['created_at'])
? Carbon::parse($data['created_at'])->format('Y-m-d H:i:s')
: null;
$detailUpdatedAt = isset($data['updated_at'])
? Carbon::parse($data['updated_at'])->format('Y-m-d H:i:s')
: null;
$pbg_task_retributions = PbgTaskRetributions::updateOrCreate(
['detail_id' => $data['id']],
[
'detail_uid' => $data['uid'] ?? null,
'detail_created_at' => $detailCreatedAt ?? null,
'detail_updated_at' => $detailUpdatedAt ?? null,
'luas_bangunan' => $data['luas_bangunan'] ?? null,
'indeks_lokalitas' => $data['indeks_lokalitas'] ?? null,
'wilayah_shst' => $data['wilayah_shst'] ?? null,
'kegiatan_id' => $data['kegiatan']['id'] ?? null,
'kegiatan_name' => $data['kegiatan']['name'] ?? null,
'nilai_shst' => $data['nilai_shst'] ?? null,
'indeks_terintegrasi' => $data['indeks_terintegrasi'] ?? null,
'indeks_bg_terbangun' => $data['indeks_bg_terbangun'] ?? null,
'nilai_retribusi_bangunan' => $data['nilai_retribusi_bangunan'] ?? null,
'nilai_prasarana' => $data['nilai_prasarana'] ?? null,
'created_by' => $data['created_by'] ?? null,
'pbg_document' => $data['pbg_document'] ?? null,
'underpayment' => $data['underpayment'] ?? null,
'skrd_amount' => $data['skrd_amount'] ?? null,
'pbg_task_uid' => $uuid,
]
);
$pbg_task_retribution_id = $pbg_task_retributions->id;
$prasaranaData = $data['prasarana'] ?? [];
if (!empty($prasaranaData)) {
$insertData = array_map(fn($item) => [
'pbg_task_uid' => $uuid,
'pbg_task_retribution_id' => $pbg_task_retribution_id,
'prasarana_id' => $item['id'] ?? null,
'prasarana_type' => $item['prasarana_type'] ?? null,
'building_type' => $item['building_type'] ?? null,
'total' => $item['total'] ?? null,
'quantity' => $item['quantity'] ?? null,
'unit' => $item['unit'] ?? null,
'index_prasarana' => $item['index_prasarana'] ?? null,
], $prasaranaData);
PbgTaskPrasarana::upsert($insertData, ['prasarana_id']);
}
return $responseData;
} catch (\GuzzleHttp\Exception\ClientException $e) {
if ($e->getCode() === 401 && !$retriedAfter401) {
Log::warning("401 Unauthorized - Refreshing token and retrying...");
$this->refreshToken();
$options['headers']['Authorization'] = "Bearer {$this->user_token}";
$retriedAfter401 = true;
continue;
}
return false;
} catch (\GuzzleHttp\Exception\ServerException | \GuzzleHttp\Exception\ConnectException $e) {
if ($e->getCode() === 502) {
Log::warning("502 Bad Gateway - Retrying in {$initialDelay} seconds...");
} else {
Log::error("Network error ({$e->getCode()}) - Retrying in {$initialDelay} seconds...");
}
sleep($initialDelay);
$initialDelay *= 2;
} catch (\GuzzleHttp\Exception\RequestException $e) {
Log::error("Request error ({$e->getCode()}): " . $e->getMessage());
return false;
} catch (\JsonException $e) {
Log::error("JSON decoding error: " . $e->getMessage());
return false;
} catch (\Throwable $e) {
Log::critical("Unhandled error: " . $e->getMessage(), ['trace' => $e->getTraceAsString()]);
return false;
}
}
Log::error("Failed to fetch task retributions for UUID {$uuid} after retries.");
throw new \Exception("Failed to fetch task retributions for UUID {$uuid} after retries.");
}
private function scraping_task_integrations($uuid){
$url = "{$this->simbg_host}/api/pbg/v1/detail/" . $uuid . "/retribution/indeks-terintegrasi/";
$options = [
'headers' => [
'Authorization' => "Bearer {$this->user_token}",
'Content-Type' => 'application/json'
]
];
$maxRetries = 3;
$initialDelay = 1;
$retriedAfter401 = false;
for ($retryCount = 0; $retryCount < $maxRetries; $retryCount++) {
try {
$response = $this->client->get($url, $options);
$responseData = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
if (empty($responseData['data']) || !is_array($responseData['data'])) {
return true;
}
$data = $responseData['data'];
$integrations[] = [
'pbg_task_uid' => $uuid,
'indeks_fungsi_bangunan' => $data['indeks_fungsi_bangunan'] ?? null,
'indeks_parameter_kompleksitas' => $data['indeks_parameter_kompleksitas'] ?? null,
'indeks_parameter_permanensi' => $data['indeks_parameter_permanensi'] ?? null,
'indeks_parameter_ketinggian' => $data['indeks_parameter_ketinggian'] ?? null,
'faktor_kepemilikan' => $data['faktor_kepemilikan'] ?? null,
'indeks_terintegrasi' => $data['indeks_terintegrasi'] ?? null,
'total' => $data['total'] ?? null,
];
if (!empty($integrations)) {
PbgTaskIndexIntegrations::upsert($integrations, ['pbg_task_uid'], ['indeks_fungsi_bangunan',
'indeks_parameter_kompleksitas', 'indeks_parameter_permanensi', 'indeks_parameter_ketinggian', 'faktor_kepemilikan', 'indeks_terintegrasi', 'total']);
}
return $responseData;
} catch (\GuzzleHttp\Exception\ClientException $e) {
if ($e->getCode() === 401 && !$retriedAfter401) {
Log::warning("401 Unauthorized - Refreshing token and retrying...");
$this->refreshToken();
$options['headers']['Authorization'] = "Bearer {$this->user_token}";
$retriedAfter401 = true;
continue;
}
return false;
} catch (\GuzzleHttp\Exception\ServerException | \GuzzleHttp\Exception\ConnectException $e) {
if ($e->getCode() === 502) {
Log::warning("502 Bad Gateway - Retrying in {$initialDelay} seconds...");
} else {
Log::error("Network error ({$e->getCode()}) - Retrying in {$initialDelay} seconds...");
}
sleep($initialDelay);
$initialDelay *= 2;
} catch (\GuzzleHttp\Exception\RequestException $e) {
Log::error("Request error ({$e->getCode()}): " . $e->getMessage());
return false;
} catch (\JsonException $e) {
Log::error("JSON decoding error: " . $e->getMessage());
return false;
} catch (\Throwable $e) {
Log::critical("Unhandled error: " . $e->getMessage(), ['trace' => $e->getTraceAsString()]);
return false;
}
}
Log::error("Failed to fetch task index integration for UUID {$uuid} after retries.");
throw new \Exception("Failed to fetch task index integration for UUID {$uuid} after retries.");
}
private function refreshToken()
{
try {
$newAuthToken = $this->service_token->refresh_token($this->user_refresh_token);
$this->user_token = $newAuthToken['access'];
$this->user_refresh_token = $newAuthToken['refresh'];
if (!$this->user_token) {
Log::error("Token refresh failed: No token received.");
throw new \Exception("Failed to refresh token.");
}
Log::info("Token refreshed successfully.");
} catch (\Exception $e) {
Log::error("Token refresh error: " . $e->getMessage());
throw new \Exception("Token refresh failed.");
}
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace App\Services;
use App\Models\GlobalSetting;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Log;
class ServiceTokenSIMBG
{
private $client;
private $login_url;
private $email;
private $password;
private $simbg_host;
private $fetch_per_page;
private $refresh_url;
public function __construct()
{
$settings = GlobalSetting::whereIn('key', [
'SIMBG_EMAIL', 'SIMBG_PASSWORD', 'SIMBG_HOST', 'FETCH_PER_PAGE'
])->pluck('value', 'key');
$this->email = trim((string) ($settings['SIMBG_EMAIL'] ?? ""));
$this->password = trim((string) ($settings['SIMBG_PASSWORD'] ?? ""));
$this->simbg_host = trim((string) ($settings['SIMBG_HOST'] ?? ""));
$this->fetch_per_page = trim((string) ($settings['FETCH_PER_PAGE'] ?? ""));
$this->client = new Client();
$this->login_url = $this->simbg_host . "/api/user/v1/auth/login/";
$this->refresh_url = $this->simbg_host. "/api/user/v1/auth/token/refresh/";
}
public function get_token(){
try {
$response = $this->client->request('POST', $this->login_url, [
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'email' => $this->email,
'password' => $this->password
]
]);
$data = json_decode($response->getBody()->getContents(), true);
return $data['token'];
} catch (RequestException $e) {
Log::error("Failed to get token", [
'error' => $e->getMessage(),
'response' => $e->getResponse() ? $e->getResponse()->getBody()->getContents() : null
]);
return null;
}
}
public function refresh_token(string $refresh_token){
try {
$response = $this->client->request('POST', $this->refresh_url, [
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'json' => [
'refresh' => $refresh_token
]
]);
$data = json_decode($response->getBody()->getContents(), true);
return $data;
} catch (\Throwable $th) {
Log::error("Failed to refresh token", [
'error' => $th->getMessage()
]);
return null;
}
}
}

View File

@@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('task_assignments', function (Blueprint $table) {
$indexes = DB::select("SHOW INDEXES FROM task_assignments WHERE Key_name = 'task_assignments_email_unique'");
if (!empty($indexes)) {
$table->dropUnique('task_assignments_email_unique');
}
$indexes = DB::select("SHOW INDEXES FROM task_assignments WHERE Key_name = 'task_assignments_username_unique'");
if (!empty($indexes)) {
$table->dropUnique('task_assignments_username_unique');
}
$table->string('email')->nullable()->change();
$table->string('username')->nullable()->change();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('task_assignments', function (Blueprint $table) {
//
});
}
};

View File

@@ -15,17 +15,23 @@ class DatabaseSeeder extends Seeder
*/ */
public function run(): void public function run(): void
{ {
// User::factory(10)->create(); User::updateOrCreate(
['email' => 'user@demo.com'], // Kondisi pencarian
User::factory()->create([ [
'name' => 'Darkone', 'name' => 'Darkone',
'email' => 'user@demo.com',
'email_verified_at' => now(), 'email_verified_at' => now(),
'password' => Hash::make('password'), 'password' => Hash::make('password'),
'firstname' => 'John', 'firstname' => 'John',
'lastname' => 'Doe', 'lastname' => 'Doe',
'position' => 'crusial', 'position' => 'crusial',
'remember_token' => Str::random(10), 'remember_token' => Str::random(10),
]
);
$this->call([
RoleSeeder::class,
MenuSeeder::class,
UsersRoleMenuSeeder::class
]); ]);
} }
} }

View File

@@ -0,0 +1,287 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\Menu;
use Illuminate\Support\Arr;
class MenuSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$menus = [
[
"name" => "Dashboard",
"url" => "/dashboard",
"icon" => "mingcute:home-3-line",
"parent_id" => null,
"sort_order" => 1,
"children" => [
[
"name" => "Dashboard Pimpinan",
"url" => "dashboard.home",
"icon" => null,
"sort_order" => 1,
],
[
"name" => "Dashboard PBG",
"url" => "dashboard.pbg",
"icon" => null,
"sort_order" => 2,
],
[
"name" => "Dashboard Potensi",
"url" => '/potentials',
"icon" => null,
"sort_order" => 3,
"children" => [
[
"name" => "Luar Sistem",
"url" => "dashboard.potentials.inside_system",
"icon" => null,
"sort_order" => 1,
],
[
"name" => "Dalam Sistem",
"url" => "dashboard.potentials.outside_system",
"icon" => null,
"sort_order" => 2,
],
]
],
[
"name" => "PETA",
"url" => "dashboard.maps",
"icon" => null,
"sort_order" => 4,
],
],
],
[
"name" => "Master",
"url" => "/master",
"icon" => "mingcute:cylinder-line",
"parent_id" => null,
"sort_order" => 2,
"children" => [
[
"name" => "Users",
"url" => "users.index",
"icon" => null,
"sort_order" => 1,
],
]
],
[
"name" => "Settings",
"url" => "/settings",
"icon" => "mingcute:settings-6-line",
"parent_id" => null,
"sort_order" => 3,
"children" => [
[
"name" => "Syncronize",
"url" => "settings.syncronize",
"icon" => null,
"sort_order" => 1,
],
[
"name" => "Menu",
"url" => "menus.index",
"icon" => null,
"sort_order" => 2,
],
[
"name" => "Role",
"url" => "roles.index",
"icon" => null,
"sort_order" => 3,
],
]
],
[
"name" => "Data Settings",
"url" => "/data-settings",
"icon" => "mingcute:settings-1-line",
"parent_id" => null,
"sort_order" => 4,
"children" => [
[
"name" => "Setting Dashboard",
"url" => "data-settings.index",
"icon" => null,
"sort_order" => 1,
],
]
],
[
"name" => "Data",
"url" => "/data",
"icon" => "mingcute:task-line",
"parent_id" => null,
"sort_order" => 5,
"children" => [
[
"name" => "PBG",
"url" => "pbg-task.index",
"icon" => null,
"sort_order" => 1,
],
[
"name" => "Reklame",
"url" => "web-advertisements.index",
"icon" => null,
"sort_order" => 2,
],
[
"name" => "Usaha atau Industri",
"url" => "business-industries.index",
"icon" => null,
"sort_order" => 3,
],
[
"name" => "UMKM",
"url" => "web-umkm.index",
"icon" => null,
"sort_order" => 4,
],
[
"name" => "Pariwisata",
"url" => "web-tourisms.index",
"icon" => null,
"sort_order" => 5,
],
[
"name" => "Tata Ruang",
"url" => "web-spatial-plannings.index",
"icon" => null,
"sort_order" => 6,
],
[
"name" => "PDAM",
"url" => "customers",
"icon" => null,
"sort_order" => 7,
],
[
"name" => "Google Sheets",
"url" => "google-sheets",
"icon" => null,
"sort_order" => 8,
],
[
"name" => "TPA TPT",
"url" => "tpa-tpt.index",
"icon" => null,
"sort_order" => 9,
],
]
],
[
"name" => "Laporan",
"url" => "/laporan",
"icon" => "mingcute:report-line",
"parent_id" => null,
"sort_order" => 6,
"children" => [
[
"name" => "Lap Pariwisata",
"url" => "tourisms-report.index",
"icon" => null,
"sort_order" => 1,
],
[
"name" => "Lap Pimpinan",
"url" => "bigdata-resumes",
"icon" => null,
"sort_order" => 2,
],
[
"name" => "Rekap Pembayaran",
"url" => "payment-recaps",
"icon" => null,
"sort_order" => 3,
],
[
"name" => "Lap Rekap Data Pembayaran",
"url" => "report-payment-recaps",
"icon" => null,
"sort_order" => 4,
],
[
"name" => "Lap PBG (PTSP)",
"url" => "report-pbg-ptsp",
"icon" => null,
"sort_order" => 5,
],
]
],
[
"name" => "Neng Bedas",
"url" => "/chat",
"icon" => "mingcute:wechat-line",
"parent_id" => null,
"sort_order" => 7,
"children" => [
[
"name" => "Chat",
"url" => "main-chatbot.index",
"icon" => null,
"sort_order" => 1,
],
]
],
[
"name" => "Approval",
"url" => "/approval",
"icon" => "mingcute:user-follow-2-line",
"parent_id" => null,
"sort_order" => 8,
"children" => [
[
"name" => "Approval Pejabat",
"url" => "approval-list",
"icon" => null,
"sort_order" => 1,
],
]
],
[
"name" => "Tools",
"url" => "/tools",
"icon" => "mingcute:tool-line",
"parent_id" => null,
"sort_order" => 9,
"children" => [
[
"name" => "Undangan",
"url" => "invitations",
"icon" => null,
"sort_order" => 1,
],
]
],
];
foreach ($menus as $menuData) {
$this->createOrUpdateMenu($menuData);
}
}
private function createOrUpdateMenu($menuData, $parentId = null){
$menuData['parent_id'] = $parentId;
$menu = Menu::updateOrCreate(['name' => $menuData['name']], Arr::except($menuData, ['children']));
if(!empty($menuData['children'])){
foreach($menuData['children'] as $child){
$this->createOrUpdateMenu($child, $menu->id);
}
}
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Database\Seeders;
use App\Models\Role;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class RoleSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$roles = [
[
"name" => "superadmin",
"description" => "show all menus for super admins",
],
[
"name" => "admin",
"description" => "show only necessary menus for admins",
],
[
"name" => "operator",
"description" => "show only necessary menus for operators",
],
[
"name" => "user",
"description" => "show only necessary menus for users",
]
];
Role::upsert($roles, ['name']);
}
}

View File

@@ -15,398 +15,52 @@ class UsersRoleMenuSeeder extends Seeder
*/ */
public function run(): void public function run(): void
{ {
$roles = [ // Fetch roles in a single query
[ $roles = Role::whereIn('name', ['superadmin', 'admin', 'operator'])->get()->keyBy('name');
"name" => "superadmin",
"description" => "show all menus for super admins", // Fetch all menus in a single query and index by name
$menus = Menu::whereIn('name', [
'Dashboard', 'Master', 'Settings', 'Data Settings', 'Data', 'Laporan', 'Neng Bedas',
'Approval', 'Tools', 'Dashboard Pimpinan', 'Dashboard PBG', 'Users', 'Syncronize',
'Menu', 'Role', 'Setting Dashboard', 'PBG', 'Reklame', 'Usaha atau Industri', 'Pariwisata',
'Lap Pariwisata', 'UMKM', 'Dashboard Potensi', 'Tata Ruang', 'PDAM', 'PETA',
'Lap Pimpinan', 'Chat', 'Dalam Sistem', 'Luar Sistem', 'Google Sheets', 'TPA TPT',
'Approval Pejabat', 'Undangan', 'Rekap Pembayaran', 'Lap Rekap Data Pembayaran', 'Lap PBG (PTSP)'
])->get()->keyBy('name');
// Define access levels for each role
$permissions = [
'superadmin' => [
'Dashboard', 'Master', 'Settings', 'Data Settings', 'Data', 'Laporan', 'Neng Bedas',
'Approval', 'Tools', 'Dashboard Pimpinan', 'Dashboard PBG', 'Users', 'Syncronize',
'Menu', 'Role', 'Setting Dashboard', 'PBG', 'Reklame', 'Usaha atau Industri', 'Pariwisata',
'Lap Pariwisata', 'UMKM', 'Dashboard Potensi', 'Tata Ruang', 'PDAM', 'Dalam Sistem',
'Luar Sistem', 'Lap Pimpinan', 'Chat', 'Google Sheets', 'TPA TPT', 'Approval Pejabat',
'Undangan', 'Rekap Pembayaran', 'Lap Rekap Data Pembayaran', 'Lap PBG (PTSP)'
], ],
[ 'admin' => ['Dashboard', 'Master', 'Settings'],
"name" => "admin", 'operator' => ['Dashboard', 'Data', 'Laporan']
"description" => "show only necessary menus for admins",
],
[
"name" => "operator",
"description" => "show only necessary menus for operators",
]
]; ];
Role::upsert($roles, ['name']); // Define permission levels
$superadminPermissions = ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true];
$adminPermissions = ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true];
$operatorPermissions = ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false];
$parent_menus = [ // Assign menus to roles
[ foreach ($permissions as $roleName => $menuNames) {
"name" => "Dashboard", $role = $roles[$roleName] ?? null;
"url" => "/dashboard", if ($role) {
"icon" => "mingcute:home-3-line", $role->menus()->sync(
"parent_id" => null, collect($menuNames)->mapWithKeys(fn($menuName) => [
"sort_order" => 1, $menus[$menuName]->id => ($roleName === 'superadmin' ? $superadminPermissions :
], ($roleName === 'admin' ? $adminPermissions : $operatorPermissions))
[ ])->toArray()
"name" => "Master", );
"url" => "/master",
"icon" => "mingcute:cylinder-line",
"parent_id" => null,
"sort_order" => 2,
],
[
"name" => "Settings",
"url" => "/settings",
"icon" => "mingcute:settings-6-line",
"parent_id" => null,
"sort_order" => 3,
],
[
"name" => "Data Settings",
"url" => "/data-settings",
"icon" => "mingcute:settings-1-line",
"parent_id" => null,
"sort_order" => 4,
],
[
"name" => "Data",
"url" => "/data",
"icon" => "mingcute:task-line",
"parent_id" => null,
"sort_order" => 5,
],
[
"name" => "Laporan",
"url" => "/laporan",
"icon" => "mingcute:report-line",
"parent_id" => null,
"sort_order" => 6,
],
[
"name" => "Neng Bedas",
"url" => "/chat",
"icon" => "mingcute:wechat-line",
"parent_id" => null,
"sort_order" => 7,
],
[
"name" => "Approval",
"url" => "/approval",
"icon" => "mingcute:user-follow-2-line",
"parent_id" => null,
"sort_order" => 8,
],
[
"name" => "Tools",
"url" => "/tools",
"icon" => "mingcute:tool-line",
"parent_id" => null,
"sort_order" => 9,
],
];
foreach ($parent_menus as $parent_menu) {
Menu::firstOrCreate(['name' => $parent_menu['name']], $parent_menu);
} }
// Attach Menus to Roles
$superadmin = Role::where('name', 'superadmin')->first();
$admin = Role::where('name', 'admin')->first();
$operator = Role::where('name', 'operator')->first();
$dashboard = Menu::where('name', 'Dashboard')->first();
$master = Menu::where('name', 'Master')->first();
$settings = Menu::where('name', 'Settings')->first();
$dataSettings = Menu::where('name', 'Data Settings')->first();
$data = Menu::where('name', 'Data')->first();
$laporan = Menu::where('name', 'Laporan')->first();
$chat_bedas = Menu::where('name', 'Neng Bedas')->first();
$approval = Menu::where('name', 'Approval')->first();
$tools = Menu::where('name', 'Tools')->first();
// create children menu
$children_menus = [
[
"name" => "Dashboard Pimpinan",
"url" => "dashboard.home",
"icon" => null,
"parent_id" => $dashboard->id,
"sort_order" => 1,
],
[
"name" => "Dashboard PBG",
"url" => "dashboard.pbg",
"icon" => null,
"parent_id" => $dashboard->id,
"sort_order" => 2,
],
[
"name" => "Dashboard Potensi",
"url" => null,
"icon" => null,
"parent_id" => $dashboard->id,
"sort_order" => 3,
],
[
"name" => "PETA",
"url" => "dashboard.maps",
"icon" => null,
"parent_id" => $dashboard->id,
"sort_order" => 4,
],
[
"name" => "Users",
"url" => "users.index",
"icon" => null,
"parent_id" => $master->id,
"sort_order" => 1,
],
[
"name" => "Approval Pejabat",
"url" => "approval-list",
"icon" => null,
"parent_id" => $approval->id,
"sort_order" => 1,
],
[
"name" => "Syncronize",
"url" => "settings.syncronize",
"icon" => null,
"parent_id" => $settings->id,
"sort_order" => 1,
],
[
"name" => "Menu",
"url" => "menus.index",
"icon" => null,
"parent_id" => $settings->id,
"sort_order" => 2,
],
[
"name" => "Role",
"url" => "roles.index",
"icon" => null,
"parent_id" => $settings->id,
"sort_order" => 3,
],
[
"name" => "Setting Dashboard",
"url" => "data-settings.index",
"icon" => null,
"parent_id" => $dataSettings->id,
"sort_order" => 1,
],
[
"name" => "PBG",
"url" => "pbg-task.index",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 1,
],
[
"name" => "Reklame",
"url" => "web.advertisements.index",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 2,
],
[
"name" => "Usaha atau Industri",
"url" => "business-industries.index",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 3,
],
[
"name" => "UMKM",
"url" => "web-umkm.index",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 4,
],
[
"name" => "Pariwisata",
"url" => "web-tourisms.index",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 5,
],
[
"name" => "Tata Ruang",
"url" => "web-spatial-plannings.index",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 6,
],
[
"name" => "PDAM",
"url" => "customers",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 7,
],
[
"name" => "Google Sheets",
"url" => "google-sheets",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 8,
],
[
"name" => "TPA TPT",
"url" => "tpa-tpt",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 9,
],
[
"name" => "Lap Pariwisata",
"url" => "tourisms-report.index",
"icon" => null,
"parent_id" => $laporan->id,
"sort_order" => 1,
],
[
"name" => "Lap Pimpinan",
"url" => "bigdata-resumes",
"icon" => null,
"parent_id" => $laporan->id,
"sort_order" => 2,
],
[
"name" => "Rekap Pembayaran",
"url" => "payment-recaps",
"icon" => null,
"parent_id" => $laporan->id,
"sort_order" => 3,
],
[
"name" => "Lap Rekap Data Pembayaran",
"url" => "report-payment-recap",
"icon" => null,
"parent_id" => $laporan->id,
"sort_order" => 4,
],
[
"name" => "Lap PBG (PTSP)",
"url" => "report-pbg-ptsp",
"icon" => null,
"parent_id" => $laporan->id,
"sort_order" => 5,
],
[
"name" => "Chat",
"url" => "main-chatbot.index",
"icon" => null,
"parent_id" => $chat_bedas->id,
"sort_order" => 1,
],
[
"name" => "Luar Sistem",
"url" => "dashboard.potentials.inside_system",
"icon" => null,
"parent_id" => Menu::where('name', 'Dashboard Potensi')->first()->id,
"sort_order" => 1,
],
[
"name" => "Dalam Sistem",
"url" => "dashboard.potentials.outside_system",
"icon" => null,
"parent_id" => Menu::where('name', 'Dashboard Potensi')->first()->id,
"sort_order" => 2,
],
[
"name" => "Undangan",
"url" => "invitations",
"icon" => null,
"parent_id" => $tools->id,
"sort_order" => 1,
],
];
foreach ($children_menus as $child_menu) {
Menu::firstOrCreate(['name' => $child_menu['name']], $child_menu);
} }
$dashboard_pimpinan = Menu::where('name', 'Dashboard Pimpinan')->first();
$dashboard_pbg = Menu::where('name', 'Dashboard PBG')->first();
$users = Menu::where('name', 'Users')->first();
$syncronize = Menu::where('name', 'Syncronize')->first();
$setting_menu = Menu::where('name', 'Menu')->first();
$setting_role = Menu::where('name', 'Role')->first();
$setting_dashboard = Menu::where('name', 'Setting Dashboard')->first();
$setting_pbg = Menu::where('name', 'PBG')->first();
$reklame = Menu::where('name', 'Reklame')->first();
$businessIndustries = Menu::where('name', 'Usaha atau Industri')->first();
$pariwisata = Menu::where('name', 'Pariwisata')->first();
$laporan_pariwisata = Menu::where('name', 'Lap Pariwisata')->first();
$umkm = Menu::where('name', 'UMKM')->first();
$lack_of_potentials = Menu::where('name', 'Dashboard Potensi')->first();
$spatial_plannings = Menu::where('name', 'Tata Ruang')->first();
$pdam = Menu::where('name', 'PDAM')->first();
$peta = Menu::where('name', 'PETA')->first();
$bigdata_resume = Menu::where('name', 'Lap Pimpinan')->first();
$chatbot = Menu::where('name', 'Chat')->first();
$dalam_sistem = Menu::where('name', 'Dalam Sistem')->first();
$luar_sistem = Menu::where('name', 'Luar Sistem')->first();
$google_sheets = Menu::where('name', 'Google Sheets')->first();
$tpa_tpt = Menu::where('name', 'TPA TPT')->first();
$approval_pejabat = Menu::where('name', 'Approval Pejabat')->first();
$intivations = Menu::where('name', 'Undangan')->first();
$payment_recap = Menu::where('name', 'Rekap Pembayaran')->first();
$report_payment_recap = Menu::where('name', 'Lap Rekap Data Pembayaran')->first();
$report_pbg_ptsp = Menu::where('name', 'Lap PBG (PTSP)')->first();
// Superadmin gets all menus
$superadmin->menus()->sync([
// parent
$dashboard->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
$master->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
$settings->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
$dataSettings->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
$data->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
$laporan->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
$chat_bedas->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
$approval->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
$tools->id => ["allow_show" => true, "allow_create" => false, "allow_update" => false, "allow_destroy" => false],
// children
$dashboard_pimpinan->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$dashboard_pbg->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$users->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$syncronize->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$setting_menu->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$setting_role->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$setting_dashboard->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$setting_pbg->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$reklame->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$businessIndustries->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$pariwisata->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$laporan_pariwisata->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$umkm->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$lack_of_potentials->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$spatial_plannings->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$pdam->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
// $peta->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$dalam_sistem->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$luar_sistem->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$bigdata_resume->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$chatbot->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$google_sheets->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$tpa_tpt->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$approval_pejabat->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$intivations->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$payment_recap->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$report_payment_recap->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$report_pbg_ptsp->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
]);
// Admin gets limited menus
$admin->menus()->sync([
$dashboard->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$master->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$settings->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
]);
// Operator gets only basic menus with full permissions
$operator->menus()->sync([
$dashboard->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$data->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
]);
// Attach User to role super admin // Attach User to role super admin
User::findOrFail(1)->roles()->sync([$superadmin->id]); User::findOrFail(1)->roles()->sync([$roles['superadmin']->id]);
} }
} }

View File

@@ -19,6 +19,9 @@ COMPOSER_ALLOW_SUPERUSER=1 composer install --no-interaction --optimize-autoload
echo "🗄️ Running migrations..." echo "🗄️ Running migrations..."
php artisan migrate --force php artisan migrate --force
echo "Running seeders..."
php artisan db:seed
echo "⚡ Optimizing application..." echo "⚡ Optimizing application..."
php artisan optimize:clear php artisan optimize:clear

View File

@@ -12,6 +12,8 @@ const spinner = document.getElementById("spinner");
const toastNotification = document.getElementById("toastNotification"); const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification); const toast = new bootstrap.Toast(toastNotification);
let menuId = document.getElementById("menuId").value;
(dropzonePreviewNode.id = ""), (dropzonePreviewNode.id = ""),
dropzonePreviewNode && dropzonePreviewNode &&
((previewTemplate = dropzonePreviewNode.parentNode.innerHTML), ((previewTemplate = dropzonePreviewNode.parentNode.innerHTML),
@@ -34,7 +36,7 @@ const toast = new bootstrap.Toast(toastNotification);
response.message; response.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/data/business-industries"; window.location.href = `/data/business-industries?menu_id=${menuId}`;
}, 2000); }, 2000);
}); });
this.on("error", function (file, errorMessage) { this.on("error", function (file, errorMessage) {

View File

@@ -35,6 +35,7 @@ class BusinessIndustries {
tableContainer.innerHTML = ""; tableContainer.innerHTML = "";
let canUpdate = tableContainer.getAttribute("data-updater") === "1"; let canUpdate = tableContainer.getAttribute("data-updater") === "1";
let canDelete = tableContainer.getAttribute("data-destroyer") === "1"; let canDelete = tableContainer.getAttribute("data-destroyer") === "1";
let menuId = tableContainer.getAttribute("data-menuId");
// Create a new Grid.js instance only if it doesn't exist // Create a new Grid.js instance only if it doesn't exist
this.table = new Grid({ this.table = new Grid({
@@ -56,12 +57,11 @@ class BusinessIndustries {
{ {
name: "Action", name: "Action",
formatter: (cell) => { formatter: (cell) => {
let buttons = `<div class="d-flex justify-content-center gap-2">`; let buttons = `<div class="d-flex justify-content-center gap-2">`;
if (canUpdate) { if (canUpdate) {
buttons += ` buttons += `
<a href="/data/business-industries/${cell}/edit" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center"> <a href="/data/business-industries/${cell}/edit?menu_id=${menuId}" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center">
<i class='bx bx-edit'></i> <i class='bx bx-edit'></i>
</a> </a>
`; `;

View File

@@ -13,6 +13,8 @@ class UpdateBusinessIndustries {
const spinner = document.getElementById("spinner"); const spinner = document.getElementById("spinner");
const toast = new bootstrap.Toast(toastNotification); const toast = new bootstrap.Toast(toastNotification);
let menuId = document.getElementById("menuId").value;
if (!submitButton) { if (!submitButton) {
console.error("Error: Submit button not found!"); console.error("Error: Submit button not found!");
return; return;
@@ -53,7 +55,7 @@ class UpdateBusinessIndustries {
data.message; data.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/data/business-industries"; window.location.href = `/data/business-industries?menu_id=${menuId}`;
}, 2000); }, 2000);
} else { } else {
// Show error toast with message from API // Show error toast with message from API

View File

@@ -6,6 +6,7 @@ class CreateCustomer {
initCreateCustomer() { initCreateCustomer() {
const toastNotification = document.getElementById("toastNotification"); const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification); const toast = new bootstrap.Toast(toastNotification);
let menuId = document.getElementById("menuId").value;
document document
.getElementById("btnCreateCustomer") .getElementById("btnCreateCustomer")
.addEventListener("click", async function () { .addEventListener("click", async function () {
@@ -41,7 +42,7 @@ class CreateCustomer {
result.message; result.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/data/customers"; window.location.href = `/data/customers?menu_id=${menuId}`;
}, 2000); }, 2000);
} else { } else {
let error = await response.json(); let error = await response.json();

View File

@@ -6,6 +6,7 @@ class UpdateCustomer {
initUpdateCustomer() { initUpdateCustomer() {
const toastNotification = document.getElementById("toastNotification"); const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification); const toast = new bootstrap.Toast(toastNotification);
let menuId = document.getElementById("menuId").value;
document document
.getElementById("btnUpdateCustomer") .getElementById("btnUpdateCustomer")
.addEventListener("click", async function () { .addEventListener("click", async function () {
@@ -41,7 +42,7 @@ class UpdateCustomer {
result.message; result.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/data/customers"; window.location.href = `/data/customers?menu_id=${menuId}`;
}, 2000); }, 2000);
} else { } else {
let error = await response.json(); let error = await response.json();

View File

@@ -32,6 +32,7 @@ class Customers {
tableContainer.innerHTML = ""; tableContainer.innerHTML = "";
let canUpdate = tableContainer.getAttribute("data-updater") === "1"; let canUpdate = tableContainer.getAttribute("data-updater") === "1";
let canDelete = tableContainer.getAttribute("data-destroyer") === "1"; let canDelete = tableContainer.getAttribute("data-destroyer") === "1";
let menuId = tableContainer.getAttribute("data-menuId");
this.table = new Grid({ this.table = new Grid({
columns: [ columns: [
"ID", "ID",
@@ -48,7 +49,7 @@ class Customers {
if (canUpdate) { if (canUpdate) {
buttons += ` buttons += `
<a href="/data/customers/${cell}/edit" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center"> <a href="/data/customers/${cell}/edit?menu_id=${menuId}" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center">
<i class='bx bx-edit'></i> <i class='bx bx-edit'></i>
</a> </a>
`; `;
@@ -66,7 +67,9 @@ class Customers {
buttons = `<span class="text-muted">No Privilege</span>`; buttons = `<span class="text-muted">No Privilege</span>`;
} }
return gridjs.html(`<div class="d-flex justify-content-center gap-2">${buttons}</div>`); return gridjs.html(
`<div class="d-flex justify-content-center gap-2">${buttons}</div>`
);
}, },
}, },
], ],

View File

@@ -20,6 +20,7 @@ class UploadCustomers {
initDropzone() { initDropzone() {
const toastNotification = document.getElementById("toastNotification"); const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification); const toast = new bootstrap.Toast(toastNotification);
let menuId = document.getElementById("menuId").value;
var previewTemplate, var previewTemplate,
dropzonePreviewNode = document.querySelector( dropzonePreviewNode = document.querySelector(
"#dropzone-preview-list" "#dropzone-preview-list"
@@ -46,7 +47,7 @@ class UploadCustomers {
response.message; response.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/data/customers"; window.location.href = `/data/customers?menu_id=${menuId}`;
}, 2000); }, 2000);
}); });
this.on("error", function (file, errorMessage) { this.on("error", function (file, errorMessage) {

View File

@@ -1,6 +1,7 @@
document.addEventListener("DOMContentLoaded", function (e) { document.addEventListener("DOMContentLoaded", function (e) {
const toastNotification = document.getElementById("toastNotification"); const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification); const toast = new bootstrap.Toast(toastNotification);
let menuId = document.getElementById("menuId").value;
document document
.getElementById("btnCreateDataSettings") .getElementById("btnCreateDataSettings")
.addEventListener("click", async function () { .addEventListener("click", async function () {
@@ -37,7 +38,7 @@ document.addEventListener("DOMContentLoaded", function (e) {
result.data.message; result.data.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/data-settings"; window.location.href = `/data-settings?menu_id=${menuId}`;
}, 2000); }, 2000);
} else { } else {
let error = await response.json(); let error = await response.json();

View File

@@ -32,7 +32,8 @@ class DataSettings {
tableContainer.innerHTML = ""; tableContainer.innerHTML = "";
let canUpdate = tableContainer.getAttribute("data-updater") === "1"; let canUpdate = tableContainer.getAttribute("data-updater") === "1";
let canDelete = tableContainer.getAttribute("data-destroyer") === "1" let canDelete = tableContainer.getAttribute("data-destroyer") === "1";
let menuId = tableContainer.getAttribute("data-menuId");
// Create a new Grid.js instance only if it doesn't exist // Create a new Grid.js instance only if it doesn't exist
this.table = new Grid({ this.table = new Grid({
columns: [ columns: [
@@ -48,7 +49,7 @@ class DataSettings {
if (canUpdate) { if (canUpdate) {
buttons += ` buttons += `
<a href="/data-settings/${cell}/edit" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center"> <a href="/data-settings/${cell}/edit?menu_id=${menuId}" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center">
<i class='bx bx-edit'></i> <i class='bx bx-edit'></i>
</a> </a>
`; `;
@@ -66,7 +67,9 @@ class DataSettings {
buttons = `<span class="text-muted">No Privilege</span>`; buttons = `<span class="text-muted">No Privilege</span>`;
} }
return gridjs.html(`<div class="d-flex justify-content-center gap-2">${buttons}</div>`); return gridjs.html(
`<div class="d-flex justify-content-center gap-2">${buttons}</div>`
);
}, },
}, },
], ],

View File

@@ -6,6 +6,7 @@ document.addEventListener("DOMContentLoaded", function (e) {
let toast = new bootstrap.Toast( let toast = new bootstrap.Toast(
document.getElementById("toastNotification") document.getElementById("toastNotification")
); );
let menuId = document.getElementById("menuId").value;
submitButton.addEventListener("click", async function () { submitButton.addEventListener("click", async function () {
let submitButton = this; let submitButton = this;
@@ -36,7 +37,7 @@ document.addEventListener("DOMContentLoaded", function (e) {
toastMessage.innerText = result.data.message; toastMessage.innerText = result.data.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/data-settings"; window.location.href = `/data-settings?menu_id=${menuId}`;
}, 2000); }, 2000);
} else { } else {
let error = await response.json(); let error = await response.json();

View File

@@ -8,6 +8,7 @@ import GeneralTable from "../../table-generator.js";
const tableElement = document.getElementById("reklame-data-table"); const tableElement = document.getElementById("reklame-data-table");
const canUpdate = tableElement.getAttribute("data-updater") === "1"; const canUpdate = tableElement.getAttribute("data-updater") === "1";
const canDelete = tableElement.getAttribute("data-destroyer") === "1"; const canDelete = tableElement.getAttribute("data-destroyer") === "1";
let menuId = document.getElementById("menuId").value;
const dataAdvertisementsColumns = [ const dataAdvertisementsColumns = [
"No", "No",
@@ -25,7 +26,7 @@ const dataAdvertisementsColumns = [
width: "120px", width: "120px",
formatter: function (cell, row) { formatter: function (cell, row) {
const id = row.cells[10].data; const id = row.cells[10].data;
const model = "data/advertisements"; const model = `data/web-advertisements`;
let actionButtons = '<div class="d-flex justify-items-end gap-10">'; let actionButtons = '<div class="d-flex justify-items-end gap-10">';
let hasPrivilege = false; let hasPrivilege = false;
@@ -36,7 +37,8 @@ const dataAdvertisementsColumns = [
actionButtons += ` actionButtons += `
<button class="btn btn-warning me-2 btn-edit" <button class="btn btn-warning me-2 btn-edit"
data-id="${id}" data-id="${id}"
data-model="${model}"> data-model="${model}"
data-menu="${menuId}">
<i class='bx bx-edit'></i> <i class='bx bx-edit'></i>
</button>`; </button>`;
} }
@@ -51,12 +53,16 @@ const dataAdvertisementsColumns = [
</button>`; </button>`;
} }
actionButtons += '</div>'; actionButtons += "</div>";
// Jika tidak memiliki akses, tampilkan teks "No Privilege" // Jika tidak memiliki akses, tampilkan teks "No Privilege"
return gridjs.html(hasPrivilege ? actionButtons : '<span class="text-muted">No Privilege</span>'); return gridjs.html(
} hasPrivilege
} ? actionButtons
: '<span class="text-muted">No Privilege</span>'
);
},
},
]; ];
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {

View File

@@ -5,6 +5,8 @@ document.addEventListener("DOMContentLoaded", function () {
const modalButton = document.querySelector(".btn-modal"); const modalButton = document.querySelector(".btn-modal");
const form = document.querySelector("form#create-update-form"); const form = document.querySelector("form#create-update-form");
var authLogo = document.querySelector(".auth-logo"); var authLogo = document.querySelector(".auth-logo");
let menuId = document.getElementById("menuId").value;
console.log(menuId);
if (!saveButton || !form) return; if (!saveButton || !form) return;
@@ -73,7 +75,7 @@ document.addEventListener("DOMContentLoaded", function () {
}, 2000); }, 2000);
setTimeout(() => { setTimeout(() => {
window.location.href = "/data/web-advertisements"; window.location.href = `/data/web-advertisements?menu_id=${menuId}`;
}, 1000); }, 1000);
} else { } else {
if (authLogo) { if (authLogo) {

View File

@@ -28,6 +28,7 @@ console.log(dropzonePreviewNode);
.getAttribute("content")}`, .getAttribute("content")}`,
}, },
init: function () { init: function () {
let menuId = document.getElementById("menuId").value;
// Listen for the success event // Listen for the success event
this.on("success", function (file, response) { this.on("success", function (file, response) {
console.log("File successfully uploaded:", file); console.log("File successfully uploaded:", file);
@@ -39,7 +40,7 @@ console.log(dropzonePreviewNode);
"Upload Files"; "Upload Files";
// Tunggu sebentar lalu reload halaman // Tunggu sebentar lalu reload halaman
setTimeout(() => { setTimeout(() => {
window.location.href = "/data/web-advertisements"; window.location.href = `/data/web-advertisements?menu_id=${menuId}`;
}, 2000); }, 2000);
}); });
// Listen for the error event // Listen for the error event

View File

@@ -8,6 +8,7 @@ import GeneralTable from "../../table-generator.js";
const tableElement = document.getElementById("spatial-planning-data-table"); const tableElement = document.getElementById("spatial-planning-data-table");
const canUpdate = tableElement.getAttribute("data-updater") === "1"; const canUpdate = tableElement.getAttribute("data-updater") === "1";
const canDelete = tableElement.getAttribute("data-destroyer") === "1"; const canDelete = tableElement.getAttribute("data-destroyer") === "1";
let menuId = document.getElementById("menuId").value;
const dataSpatialPlanningColumns = [ const dataSpatialPlanningColumns = [
"No", "No",
@@ -23,7 +24,7 @@ const dataSpatialPlanningColumns = [
widht: "120px", widht: "120px",
formatter: function (cell, row) { formatter: function (cell, row) {
const id = row.cells[8].data; const id = row.cells[8].data;
const model = "data/spatial-plannings"; const model = "data/web-spatial-plannings";
let actionButtons = '<div class="d-flex justify-items-end gap-10">'; let actionButtons = '<div class="d-flex justify-items-end gap-10">';
let hasPrivilege = false; let hasPrivilege = false;
@@ -34,7 +35,8 @@ const dataSpatialPlanningColumns = [
actionButtons += ` actionButtons += `
<button class="btn btn-warning me-2 btn-edit" <button class="btn btn-warning me-2 btn-edit"
data-id="${id}" data-id="${id}"
data-model="${model}"> data-model="${model}"
data-menu="${menuId}">
<i class='bx bx-edit'></i> <i class='bx bx-edit'></i>
</button>`; </button>`;
} }
@@ -49,10 +51,14 @@ const dataSpatialPlanningColumns = [
</button>`; </button>`;
} }
actionButtons += '</div>'; actionButtons += "</div>";
// Jika tidak memiliki akses, tampilkan teks "No Privilege" // Jika tidak memiliki akses, tampilkan teks "No Privilege"
return gridjs.html(hasPrivilege ? actionButtons : '<span class="text-muted">No Privilege</span>'); return gridjs.html(
hasPrivilege
? actionButtons
: '<span class="text-muted">No Privilege</span>'
);
}, },
}, },
]; ];

View File

@@ -5,6 +5,7 @@ document.addEventListener("DOMContentLoaded", function () {
const modalButton = document.querySelector(".btn-modal"); const modalButton = document.querySelector(".btn-modal");
const form = document.querySelector("form#create-update-form"); const form = document.querySelector("form#create-update-form");
var authLogo = document.querySelector(".auth-logo"); var authLogo = document.querySelector(".auth-logo");
let menuId = document.getElementById("menuId").value;
if (!saveButton || !form) return; if (!saveButton || !form) return;
@@ -73,7 +74,7 @@ document.addEventListener("DOMContentLoaded", function () {
}, 3000); }, 3000);
setTimeout(() => { setTimeout(() => {
window.location.href = "/data/web-spatial-plannings"; window.location.href = `/data/web-spatial-plannings?menu_id=${menuId}`;
}, 3000); }, 3000);
} else { } else {
if (authLogo) { if (authLogo) {

View File

@@ -28,6 +28,7 @@ console.log(dropzonePreviewNode);
.getAttribute("content")}`, .getAttribute("content")}`,
}, },
init: function () { init: function () {
let menuId = document.getElementById("menuId").value;
// Listen for the success event // Listen for the success event
this.on("success", function (file, response) { this.on("success", function (file, response) {
console.log("File successfully uploaded:", file); console.log("File successfully uploaded:", file);
@@ -39,7 +40,7 @@ console.log(dropzonePreviewNode);
"Upload Files"; "Upload Files";
// Tunggu sebentar lalu reload halaman // Tunggu sebentar lalu reload halaman
setTimeout(() => { setTimeout(() => {
window.location.href = "/data/web-spatial-plannings"; window.location.href = `/data/web-spatial-plannings?menu_id=${menuId}`;
}, 2000); }, 2000);
}); });
// Listen for the error event // Listen for the error event

View File

@@ -11,6 +11,7 @@ const tableElement = document.getElementById("tourisms-data-table");
const canView = "1"; const canView = "1";
const canUpdate = tableElement.getAttribute("data-updater") === "1"; const canUpdate = tableElement.getAttribute("data-updater") === "1";
const canDelete = tableElement.getAttribute("data-destroyer") === "1"; const canDelete = tableElement.getAttribute("data-destroyer") === "1";
let menuId = document.getElementById("menuId").value;
const dataTourismsColumns = [ const dataTourismsColumns = [
"No", "No",
@@ -32,7 +33,7 @@ const dataTourismsColumns = [
const district = row.cells[4].data; const district = row.cells[4].data;
const long = row.cells[9].data; const long = row.cells[9].data;
const lat = row.cells[10].data; const lat = row.cells[10].data;
const model = "data/tourisms"; const model = "data/web-tourisms";
let actionButtons = '<div class="d-flex justify-items-end gap-10">'; let actionButtons = '<div class="d-flex justify-items-end gap-10">';
let hasPrivilege = false; let hasPrivilege = false;
@@ -53,7 +54,8 @@ const dataTourismsColumns = [
actionButtons += ` actionButtons += `
<button class="btn btn-warning me-2 btn-edit" <button class="btn btn-warning me-2 btn-edit"
data-id="${id}" data-id="${id}"
data-model="${model}"> data-model="${model}"
data-menu="${menuId}">
<i class='bx bx-edit'></i> <i class='bx bx-edit'></i>
</button>`; </button>`;
} }

View File

@@ -5,6 +5,7 @@ document.addEventListener("DOMContentLoaded", function () {
const modalButton = document.querySelector(".btn-modal"); const modalButton = document.querySelector(".btn-modal");
const form = document.querySelector("form#create-update-form"); const form = document.querySelector("form#create-update-form");
var authLogo = document.querySelector(".auth-logo"); var authLogo = document.querySelector(".auth-logo");
let menuId = document.getElementById("menuId").value;
if (!saveButton || !form) return; if (!saveButton || !form) return;
@@ -73,7 +74,7 @@ document.addEventListener("DOMContentLoaded", function () {
}, 3000); }, 3000);
setTimeout(() => { setTimeout(() => {
window.location.href = "/data/web-tourisms"; window.location.href = `/data/web-tourisms?menu_id=${menuId}`;
}, 3000); }, 3000);
} else { } else {
if (authLogo) { if (authLogo) {

View File

@@ -28,6 +28,7 @@ console.log(dropzonePreviewNode);
.getAttribute("content")}`, .getAttribute("content")}`,
}, },
init: function () { init: function () {
let menuId = document.getElementById("menuId").value;
// Listen for the success event // Listen for the success event
this.on("success", function (file, response) { this.on("success", function (file, response) {
console.log("File successfully uploaded:", file); console.log("File successfully uploaded:", file);
@@ -39,7 +40,7 @@ console.log(dropzonePreviewNode);
"Upload Files"; "Upload Files";
// Tunggu sebentar lalu reload halaman // Tunggu sebentar lalu reload halaman
setTimeout(() => { setTimeout(() => {
window.location.href = "/data/web-tourisms"; window.location.href = `/data/web-tourisms?menu_id=${menuId}`;
}, 2000); }, 2000);
}); });
// Listen for the error event // Listen for the error event

View File

@@ -7,6 +7,7 @@ import GeneralTable from "../../table-generator.js";
const tableElement = document.getElementById("umkm-data-table"); const tableElement = document.getElementById("umkm-data-table");
const canUpdate = tableElement.getAttribute("data-updater") === "1"; const canUpdate = tableElement.getAttribute("data-updater") === "1";
const canDelete = tableElement.getAttribute("data-destroyer") === "1"; const canDelete = tableElement.getAttribute("data-destroyer") === "1";
let menuId = document.getElementById("menuId").value;
const dataUMKMColumns = [ const dataUMKMColumns = [
"No", "No",
@@ -33,7 +34,7 @@ const dataUMKMColumns = [
widht: "120px", widht: "120px",
formatter: function (cell, row) { formatter: function (cell, row) {
const id = row.cells[19].data; const id = row.cells[19].data;
const model = "data/umkm"; const model = "data/web-umkm";
let actionButtons = '<div class="d-flex justify-items-end gap-10">'; let actionButtons = '<div class="d-flex justify-items-end gap-10">';
let hasPrivilege = false; let hasPrivilege = false;
@@ -44,7 +45,8 @@ const dataUMKMColumns = [
actionButtons += ` actionButtons += `
<button class="btn btn-warning me-2 btn-edit" <button class="btn btn-warning me-2 btn-edit"
data-id="${id}" data-id="${id}"
data-model="${model}"> data-model="${model}"
data-menu="${menuId}">
<i class='bx bx-edit'></i> <i class='bx bx-edit'></i>
</button>`; </button>`;
} }
@@ -59,12 +61,16 @@ const dataUMKMColumns = [
</button>`; </button>`;
} }
actionButtons += '</div>'; actionButtons += "</div>";
// Jika tidak memiliki akses, tampilkan teks "No Privilege" // Jika tidak memiliki akses, tampilkan teks "No Privilege"
return gridjs.html(hasPrivilege ? actionButtons : '<span class="text-muted">No Privilege</span>'); return gridjs.html(
} hasPrivilege
} ? actionButtons
: '<span class="text-muted">No Privilege</span>'
);
},
},
]; ];
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {

View File

@@ -5,6 +5,7 @@ document.addEventListener("DOMContentLoaded", function () {
const modalButton = document.querySelector(".btn-modal"); const modalButton = document.querySelector(".btn-modal");
const form = document.querySelector("form#create-update-form"); const form = document.querySelector("form#create-update-form");
var authLogo = document.querySelector(".auth-logo"); var authLogo = document.querySelector(".auth-logo");
let menuId = document.getElementById("menuId").value;
if (!saveButton || !form) return; if (!saveButton || !form) return;
@@ -74,7 +75,7 @@ document.addEventListener("DOMContentLoaded", function () {
}, 2000); }, 2000);
setTimeout(() => { setTimeout(() => {
window.location.href = "/data/web-umkm"; window.location.href = `/data/web-umkm?menu_id=${menuId}`;
}, 1000); }, 1000);
} else { } else {
if (authLogo) { if (authLogo) {

View File

@@ -28,6 +28,7 @@ console.log(dropzonePreviewNode);
.getAttribute("content")}`, .getAttribute("content")}`,
}, },
init: function () { init: function () {
let menuId = document.getElementById("menuId").value;
// Listen for the success event // Listen for the success event
this.on("success", function (file, response) { this.on("success", function (file, response) {
console.log("File successfully uploaded:", file); console.log("File successfully uploaded:", file);
@@ -39,7 +40,7 @@ console.log(dropzonePreviewNode);
"Upload Files"; "Upload Files";
// Tunggu sebentar lalu reload halaman // Tunggu sebentar lalu reload halaman
setTimeout(() => { setTimeout(() => {
window.location.href = "/data/web-umkm"; window.location.href = `/data/web-umkm?menu_id=${menuId}`;
}, 2000); }, 2000);
}); });
// Listen for the error event // Listen for the error event

View File

@@ -1,6 +1,7 @@
document.addEventListener("DOMContentLoaded", function (e) { document.addEventListener("DOMContentLoaded", function (e) {
const toastNotification = document.getElementById("toastNotification"); const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification); const toast = new bootstrap.Toast(toastNotification);
let menuId = document.getElementById("menuId").value;
document document
.getElementById("btnCreateUsers") .getElementById("btnCreateUsers")
.addEventListener("click", async function () { .addEventListener("click", async function () {
@@ -45,7 +46,7 @@ document.addEventListener("DOMContentLoaded", function (e) {
result.message; result.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/master/users"; window.location.href = `/master/users?menu_id=${menuId}`;
}, 2000); }, 2000);
} else { } else {
let error = await response.json(); let error = await response.json();

View File

@@ -6,6 +6,7 @@ document.addEventListener("DOMContentLoaded", function (e) {
let toast = new bootstrap.Toast( let toast = new bootstrap.Toast(
document.getElementById("toastNotification") document.getElementById("toastNotification")
); );
let menuId = document.getElementById("menuId").value;
submitButton.addEventListener("click", async function () { submitButton.addEventListener("click", async function () {
let submitButton = this; let submitButton = this;
@@ -36,7 +37,7 @@ document.addEventListener("DOMContentLoaded", function (e) {
toastMessage.innerText = result.message; toastMessage.innerText = result.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/master/users"; window.location.href = `/master/users?menu_id=${menuId}`;
}, 2000); }, 2000);
} else { } else {
let error = await response.json(); let error = await response.json();

View File

@@ -9,9 +9,8 @@ class UsersTable {
} }
initTableUsers() { initTableUsers() {
let tableContainer = document.getElementById( let tableContainer = document.getElementById("table-users");
"table-users" let menuId = tableContainer.getAttribute("data-menuId");
);
tableContainer.innerHTML = ""; tableContainer.innerHTML = "";
let canUpdate = tableContainer.getAttribute("data-updater") === "1"; let canUpdate = tableContainer.getAttribute("data-updater") === "1";
@@ -28,11 +27,13 @@ class UsersTable {
name: "Action", name: "Action",
formatter: (cell) => { formatter: (cell) => {
if (!canUpdate) { if (!canUpdate) {
return gridjs.html(`<span class="text-muted">No Privilege</span>`); return gridjs.html(
`<span class="text-muted">No Privilege</span>`
);
} }
return gridjs.html(` return gridjs.html(`
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
<a href="/master/users/${cell}/edit" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center"> <a href="/master/users/${cell}/edit?menu_id=${menuId}" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center">
<i class='bx bx-edit'></i> <i class='bx bx-edit'></i>
</a> </a>
</div> </div>

View File

@@ -6,6 +6,7 @@ class CreateMenu {
initCreateMenu() { initCreateMenu() {
const toastNotification = document.getElementById("toastNotification"); const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification); const toast = new bootstrap.Toast(toastNotification);
let menuId = document.getElementById("menuId").value;
document document
.getElementById("btnCreateMenus") .getElementById("btnCreateMenus")
.addEventListener("click", async function () { .addEventListener("click", async function () {
@@ -41,7 +42,7 @@ class CreateMenu {
result.message; result.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/menus"; window.location.href = `/menus?menu_id=${menuId}`;
}, 2000); }, 2000);
} else { } else {
let error = await response.json(); let error = await response.json();

View File

@@ -31,6 +31,7 @@ class Menus {
tableContainer.innerHTML = ""; tableContainer.innerHTML = "";
let canUpdate = tableContainer.getAttribute("data-updater") === "1"; let canUpdate = tableContainer.getAttribute("data-updater") === "1";
let canDelete = tableContainer.getAttribute("data-destroyer") === "1"; let canDelete = tableContainer.getAttribute("data-destroyer") === "1";
let menuId = tableContainer.getAttribute("data-menuId");
this.table = new Grid({ this.table = new Grid({
columns: [ columns: [
@@ -47,7 +48,7 @@ class Menus {
if (canUpdate) { if (canUpdate) {
buttons += ` buttons += `
<a href="/menus/${cell}/edit" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center"> <a href="/menus/${cell}/edit?menu_id=${menuId}" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center">
<i class='bx bx-edit'></i> <i class='bx bx-edit'></i>
</a> </a>
`; `;

View File

@@ -6,6 +6,7 @@ class UpdateMenu {
initUpdateMenu() { initUpdateMenu() {
const toastNotification = document.getElementById("toastNotification"); const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification); const toast = new bootstrap.Toast(toastNotification);
let menuId = document.getElementById("menuId").value;
document document
.getElementById("btnUpdateMenus") .getElementById("btnUpdateMenus")
.addEventListener("click", async function () { .addEventListener("click", async function () {
@@ -41,7 +42,7 @@ class UpdateMenu {
result.message; result.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/menus"; window.location.href = `/menus?menu_id=${menuId}`;
}, 2000); }, 2000);
} else { } else {
let error = await response.json(); let error = await response.json();

View File

@@ -6,6 +6,7 @@ class CreateRoles {
initCreateRole() { initCreateRole() {
const toastNotification = document.getElementById("toastNotification"); const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification); const toast = new bootstrap.Toast(toastNotification);
let menuId = document.getElementById("menuId").value;
document document
.getElementById("btnCreateRole") .getElementById("btnCreateRole")
.addEventListener("click", async function () { .addEventListener("click", async function () {
@@ -41,7 +42,7 @@ class CreateRoles {
result.message; result.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/roles"; window.location.href = `/roles?menu_id=${menuId}`;
}, 2000); }, 2000);
} else { } else {
let error = await response.json(); let error = await response.json();

View File

@@ -31,6 +31,7 @@ class Roles {
tableContainer.innerHTML = ""; tableContainer.innerHTML = "";
let canUpdate = tableContainer.getAttribute("data-updater") === "1"; let canUpdate = tableContainer.getAttribute("data-updater") === "1";
let canDelete = tableContainer.getAttribute("data-destroyer") === "1"; let canDelete = tableContainer.getAttribute("data-destroyer") === "1";
let menuId = tableContainer.getAttribute("data-menuId");
// Create a new Grid.js instance only if it doesn't exist // Create a new Grid.js instance only if it doesn't exist
this.table = new gridjs.Grid({ this.table = new gridjs.Grid({
columns: [ columns: [
@@ -44,10 +45,10 @@ class Roles {
if (canUpdate) { if (canUpdate) {
buttons += ` buttons += `
<a href="/roles/${cell}/edit" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center"> <a href="/roles/${cell}/edit?menu_id=${menuId}" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center">
<i class='bx bx-edit'></i> <i class='bx bx-edit'></i>
</a> </a>
<a href="/roles/role-menu/${cell}" class="btn btn-primary btn-sm d-inline-flex align-items-center justify-content-center"> <a href="/roles/role-menu/${cell}?menu_id=${menuId}" class="btn btn-primary btn-sm d-inline-flex align-items-center justify-content-center">
Role Menu Role Menu
</a> </a>
`; `;

View File

@@ -6,6 +6,7 @@ class UpdateRoles {
initUpdateRole() { initUpdateRole() {
const toastNotification = document.getElementById("toastNotification"); const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification); const toast = new bootstrap.Toast(toastNotification);
let menuId = document.getElementById("menuId").value;
document document
.getElementById("btnUpdateRole") .getElementById("btnUpdateRole")
.addEventListener("click", async function () { .addEventListener("click", async function () {
@@ -41,7 +42,7 @@ class UpdateRoles {
result.message; result.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/roles"; window.location.href = `/roles?menu_id=${menuId}`;
}, 2000); }, 2000);
} else { } else {
let error = await response.json(); let error = await response.json();

View File

@@ -88,13 +88,15 @@ class GeneralTable {
handleCreate(event) { handleCreate(event) {
// Menggunakan model dan ID untuk membangun URL dinamis // Menggunakan model dan ID untuk membangun URL dinamis
const model = event.target.getAttribute("data-model"); // Mengambil model dari data-model const model = event.target.getAttribute("data-model"); // Mengambil model dari data-model
window.location.href = `${this.baseUrl}/${model}/create`; let menuId = event.target.getAttribute("data-menu");
window.location.href = `${this.baseUrl}/${model}/create?menu_id=${menuId}`;
} }
handleBulkCreate(event) { handleBulkCreate(event) {
// Menggunakan model dan ID untuk membangun URL dinamis // Menggunakan model dan ID untuk membangun URL dinamis
const model = event.target.getAttribute("data-model"); const model = event.target.getAttribute("data-model");
window.location.href = `${this.baseUrl}/${model}/bulk-create`; let menuId = event.target.getAttribute("data-menu");
window.location.href = `${this.baseUrl}/${model}/bulk-create?menu_id=${menuId}`;
} }
// Fungsi untuk menangani edit // Fungsi untuk menangani edit
@@ -103,7 +105,8 @@ class GeneralTable {
const model = event.target.getAttribute("data-model"); // Mengambil model dari data-model const model = event.target.getAttribute("data-model"); // Mengambil model dari data-model
console.log("Editing record with ID:", id); console.log("Editing record with ID:", id);
// Menggunakan model dan ID untuk membangun URL dinamis // Menggunakan model dan ID untuk membangun URL dinamis
window.location.href = `${this.baseUrl}/${model}/${id}/edit`; let menuId = event.target.getAttribute("data-menu");
window.location.href = `${this.baseUrl}/${model}/${id}/edit?menu_id=${menuId}`;
} }
// Fungsi untuk menangani delete // Fungsi untuk menangani delete

View File

@@ -5,6 +5,7 @@
@include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'Business Industries']) @include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'Business Industries'])
<x-toast-notification /> <x-toast-notification />
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row"> <div class="row">
<div class="col-xl-12"> <div class="col-xl-12">
<div class="card"> <div class="card">

View File

@@ -5,6 +5,7 @@
@include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard']) @include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard'])
<x-toast-notification /> <x-toast-notification />
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
<div class="col-lg-6"> <div class="col-lg-6">
<div class="card"> <div class="card">

View File

@@ -16,12 +16,13 @@
<div class="card-body"> <div class="card-body">
<div class="d-flex flex-wrap justify-content-end align-items-center mb-2"> <div class="d-flex flex-wrap justify-content-end align-items-center mb-2">
@if ($creator) @if ($creator)
<a href="{{ route('business-industries.create')}}" class="btn btn-success btn-sm d-block d-sm-inline w-auto">Upload</a> <a href="{{ route('business-industries.create', ['menu_id' => $menuId])}}" class="btn btn-success btn-sm d-block d-sm-inline w-auto">Upload</a>
@endif @endif
</div> </div>
<div id="table-business-industries" <div id="table-business-industries"
data-updater="{{ $updater }}" data-updater="{{ $updater }}"
data-destroyer="{{ $destroyer }}"> data-destroyer="{{ $destroyer }}"
data-menuId="{{ $menuId }}">
</div> </div>
</div> </div>
</div> </div>

View File

@@ -5,11 +5,12 @@
@include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'PDAM']) @include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'PDAM'])
<x-toast-notification /> <x-toast-notification />
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<div class="card"> <div class="card">
<div class="card-header d-flex justify-content-end"> <div class="card-header d-flex justify-content-end">
<a href="{{ route('customers') }}" class="btn btn-sm btn-secondary">Back</a> <a href="{{ route('customers', ['menu_id' => $menuId]) }}" class="btn btn-sm btn-secondary">Back</a>
</div> </div>
<div class="card-body"> <div class="card-body">
<form id="formCreateCustomer" action="{{ route('api.customers.store') }}" method="post"> <form id="formCreateCustomer" action="{{ route('api.customers.store') }}" method="post">

View File

@@ -5,11 +5,12 @@
@include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'PDAM']) @include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'PDAM'])
<x-toast-notification /> <x-toast-notification />
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<div class="card"> <div class="card">
<div class="card-header d-flex justify-content-end"> <div class="card-header d-flex justify-content-end">
<a href="{{ route('customers') }}" class="btn btn-sm btn-secondary">Back</a> <a href="{{ route('customers', ['menu_id' => $menuId]) }}" class="btn btn-sm btn-secondary">Back</a>
</div> </div>
<div class="card-body"> <div class="card-body">
<form id="formUpdateCustomer" action="{{ route('api.customers.update', $data->id) }}" method="post"> <form id="formUpdateCustomer" action="{{ route('api.customers.update', $data->id) }}" method="post">

View File

@@ -16,13 +16,14 @@
<div class="card-body"> <div class="card-body">
<div class="d-flex flex-wrap justify-content-end align-items-center mb-2"> <div class="d-flex flex-wrap justify-content-end align-items-center mb-2">
@if ($creator) @if ($creator)
<a href="{{ route('customers.create')}}" class="btn btn-success btn-sm d-block d-sm-inline w-auto me-3">Create</a> <a href="{{ route('customers.create', ['menu_id' => $menuId]) }}" class="btn btn-success btn-sm d-block d-sm-inline w-auto me-3">Create</a>
<a href="{{ route('customers.upload')}}" class="btn btn-success btn-sm d-block d-sm-inline w-auto">Upload</a> <a href="{{ route('customers.upload', ['menu_id' => $menuId]) }}" class="btn btn-success btn-sm d-block d-sm-inline w-auto">Upload</a>
@endif @endif
</div> </div>
<div id="table-customers" <div id="table-customers"
data-updater="{{ $updater }}" data-updater="{{ $updater }}"
data-destroyer="{{ $destroyer }}"> data-destroyer="{{ $destroyer }}"
data-menuId="{{ $menuId }}">
</div> </div>
</div> </div>
</div> </div>

View File

@@ -5,6 +5,7 @@
@include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'PDAM']) @include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'PDAM'])
<x-toast-notification /> <x-toast-notification />
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row"> <div class="row">
<div class="col-xl-12"> <div class="col-xl-12">
<div class="card"> <div class="card">

View File

@@ -5,11 +5,12 @@
@include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard']) @include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard'])
<x-toast-notification /> <x-toast-notification />
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
<div class="col-lg-6"> <div class="col-lg-6">
<div class="card"> <div class="card">
<div class="card-header d-flex justify-content-end"> <div class="card-header d-flex justify-content-end">
<a href="{{ route('data-settings.index') }}" class="btn btn-sm btn-secondary">Back</a> <a href="{{ route('data-settings.index', ['menu_id' => $menuId]) }}" class="btn btn-sm btn-secondary">Back</a>
</div> </div>
<div class="card-body"> <div class="card-body">
<form id="formDataSettings" action="{{ route('api.data-settings.store') }}" method="POST"> <form id="formDataSettings" action="{{ route('api.data-settings.store') }}" method="POST">

View File

@@ -5,11 +5,12 @@
@include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard']) @include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard'])
<x-toast-notification /> <x-toast-notification />
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
<div class="col-lg-6"> <div class="col-lg-6">
<div class="card"> <div class="card">
<div class="card-header d-flex justify-content-end"> <div class="card-header d-flex justify-content-end">
<a href="{{ route('data-settings.index') }}" class="btn btn-sm btn-secondary">Back</a> <a href="{{ route('data-settings.index', ['menu_id' => $menuId]) }}" class="btn btn-sm btn-secondary">Back</a>
</div> </div>
<div class="card-body"> <div class="card-body">
<form id="formUpdateDataSettings" action="{{ route('api.data-settings.update', $data->id) }}" method="POST"> <form id="formUpdateDataSettings" action="{{ route('api.data-settings.update', $data->id) }}" method="POST">

View File

@@ -16,12 +16,13 @@
<div class="card-body"> <div class="card-body">
<div class="d-flex flex-wrap justify-content-end align-items-center mb-2"> <div class="d-flex flex-wrap justify-content-end align-items-center mb-2">
@if ($creator) @if ($creator)
<a href="{{ route('data-settings.create')}}" class="btn btn-success btn-sm d-block d-sm-inline w-auto">Create</a> <a href="{{ route('data-settings.create', ['menu_id' => $menuId])}}" class="btn btn-success btn-sm d-block d-sm-inline w-auto">Create</a>
@endif @endif
</div> </div>
<div id="table-data-settings" <div id="table-data-settings"
data-updater="{{ $updater }}" data-updater="{{ $updater }}"
data-destroyer="{{ $destroyer }}"> data-destroyer="{{ $destroyer }}"
data-menuId="{{ $menuId }}">
</div> </div>
</div> </div>
</div> </div>

View File

@@ -3,7 +3,7 @@
@section('content') @section('content')
@include('layouts.partials/page-title', ['title' => 'Form', 'subtitle' => 'File Uploads']) @include('layouts.partials/page-title', ['title' => 'Form', 'subtitle' => 'File Uploads'])
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row"> <div class="row">
<div class="col-xl-12"> <div class="col-xl-12">
<div class="card"> <div class="card">

View File

@@ -3,7 +3,7 @@
@section('content') @section('content')
@include('layouts.partials/page-title', ['title' => $title, 'subtitle' => $subtitle]) <!-- Menggunakan title dan subtitle dari controller --> @include('layouts.partials/page-title', ['title' => $title, 'subtitle' => $subtitle]) <!-- Menggunakan title dan subtitle dari controller -->
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
@if (session('error')) @if (session('error'))
<div class="alert alert-danger"> <div class="alert alert-danger">

View File

@@ -8,7 +8,7 @@
@include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'Reklame']) @include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'Reklame'])
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h5 class="card-title">Daftar Reklame</h5> <h5 class="card-title">Daftar Reklame</h5>
@@ -17,10 +17,10 @@
<div class="row"> <div class="row">
<div class="d-flex justify-content-end gap-10 pb-3"> <div class="d-flex justify-content-end gap-10 pb-3">
@if ($creator) @if ($creator)
<button class="btn btn-success me-2 width-lg btn-create" data-model="data/advertisements"> <button class="btn btn-success me-2 width-lg btn-create" data-model="data/advertisements" data-menu="{{ $menuId }}">
<i class='bx bxs-file-plus'></i> <i class='bx bxs-file-plus'></i>
Create</button> Create</button>
<button class="btn btn-primary width-lg btn-bulk-create" data-model="data/advertisements"> <button class="btn btn-primary width-lg btn-bulk-create" data-model="data/advertisements" data-menu="{{ $menuId }}">
<i class='bx bx-upload' ></i> <i class='bx bx-upload' ></i>
Bulk Create Bulk Create
</button> </button>

View File

@@ -3,7 +3,7 @@
@section('content') @section('content')
@include('layouts.partials/page-title', ['title' => 'Form', 'subtitle' => 'File Uploads']) @include('layouts.partials/page-title', ['title' => 'Form', 'subtitle' => 'File Uploads'])
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row"> <div class="row">
<div class="col-xl-12"> <div class="col-xl-12">
<div class="card"> <div class="card">

View File

@@ -3,7 +3,7 @@
@section('content') @section('content')
@include('layouts.partials/page-title', ['title' => $title, 'subtitle' => $subtitle]) <!-- Menggunakan title dan subtitle dari controller --> @include('layouts.partials/page-title', ['title' => $title, 'subtitle' => $subtitle]) <!-- Menggunakan title dan subtitle dari controller -->
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
@if (session('error')) @if (session('error'))
<div class="alert alert-danger"> <div class="alert alert-danger">

View File

@@ -6,7 +6,7 @@
@section('content') @section('content')
@include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'Rencana Tata Ruang']) @include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'Rencana Tata Ruang'])
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h5 class="card-title">Daftar Rencana Tata Ruang</h5> <h5 class="card-title">Daftar Rencana Tata Ruang</h5>
@@ -15,10 +15,10 @@
<div class="row"> <div class="row">
<div class="d-flex justify-content-end gap-10 pb-3"> <div class="d-flex justify-content-end gap-10 pb-3">
@if ($creator) @if ($creator)
<button class="btn btn-success me-2 width-lg btn-create" data-model="data/spatial-plannings"> <button class="btn btn-success me-2 width-lg btn-create" data-model="data/spatial-plannings" data-menu="{{ $menuId }}">
<i class='bx bxs-file-plus'></i> <i class='bx bxs-file-plus'></i>
Create</button> Create</button>
<button class="btn btn-primary width-lg btn-bulk-create" data-model="data/spatial-plannings"> <button class="btn btn-primary width-lg btn-bulk-create" data-model="data/spatial-plannings" data-menu="{{ $menuId }}">
<i class='bx bx-upload' ></i> <i class='bx bx-upload' ></i>
Bulk Create Bulk Create
</button> </button>

View File

@@ -3,7 +3,7 @@
@section('content') @section('content')
@include('layouts.partials/page-title', ['title' => 'Form', 'subtitle' => 'File Uploads']) @include('layouts.partials/page-title', ['title' => 'Form', 'subtitle' => 'File Uploads'])
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row"> <div class="row">
<div class="col-xl-12"> <div class="col-xl-12">
<div class="card"> <div class="card">

View File

@@ -3,7 +3,7 @@
@section('content') @section('content')
@include('layouts.partials/page-title', ['title' => $title, 'subtitle' => $subtitle]) <!-- Menggunakan title dan subtitle dari controller --> @include('layouts.partials/page-title', ['title' => $title, 'subtitle' => $subtitle]) <!-- Menggunakan title dan subtitle dari controller -->
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
@if (session('error')) @if (session('error'))
<div class="alert alert-danger"> <div class="alert alert-danger">

View File

@@ -7,6 +7,7 @@
@section('content') @section('content')
@include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'Pariwisata']) @include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'Pariwisata'])
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h5 class="card-title">Daftar Pariwisata</h5> <h5 class="card-title">Daftar Pariwisata</h5>
@@ -15,10 +16,10 @@
<div class="row"> <div class="row">
<div class="d-flex justify-content-end gap-10 pb-3"> <div class="d-flex justify-content-end gap-10 pb-3">
@if ($creator) @if ($creator)
<button class="btn btn-success me-2 width-lg btn-create" data-model="data/tourisms"> <button class="btn btn-success me-2 width-lg btn-create" data-model="data/tourisms" data-menu="{{ $menuId }}">
<i class='bx bxs-file-plus'></i> <i class='bx bxs-file-plus'></i>
Create</button> Create</button>
<button class="btn btn-primary width-lg btn-bulk-create" data-model="data/tourisms"> <button class="btn btn-primary width-lg btn-bulk-create" data-model="data/tourisms" data-menu="{{ $menuId }}">
<i class='bx bx-upload' ></i> <i class='bx bx-upload' ></i>
Bulk Create Bulk Create
</button> </button>

View File

@@ -3,7 +3,7 @@
@section('content') @section('content')
@include('layouts.partials/page-title', ['title' => 'Form', 'subtitle' => 'File Uploads']) @include('layouts.partials/page-title', ['title' => 'Form', 'subtitle' => 'File Uploads'])
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row"> <div class="row">
<div class="col-xl-12"> <div class="col-xl-12">
<div class="card"> <div class="card">

View File

@@ -3,7 +3,7 @@
@section('content') @section('content')
@include('layouts.partials/page-title', ['title' => $title, 'subtitle' => $subtitle]) <!-- Menggunakan title dan subtitle dari controller --> @include('layouts.partials/page-title', ['title' => $title, 'subtitle' => $subtitle]) <!-- Menggunakan title dan subtitle dari controller -->
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
@if (session('error')) @if (session('error'))
<div class="alert alert-danger"> <div class="alert alert-danger">

View File

@@ -6,7 +6,7 @@
@section('content') @section('content')
@include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'UMKM']) @include('layouts.partials/page-title', ['title' => 'Data', 'subtitle' => 'UMKM'])
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h5 class="card-title">Daftar UMKM</h5> <h5 class="card-title">Daftar UMKM</h5>
@@ -15,10 +15,10 @@
<div class="row"> <div class="row">
<div class="d-flex justify-content-end gap-10 pb-3"> <div class="d-flex justify-content-end gap-10 pb-3">
@if ($creator) @if ($creator)
<button class="btn btn-success me-2 width-lg btn-create" data-model="data/umkm"> <button class="btn btn-success me-2 width-lg btn-create" data-model="data/umkm" data-menu="{{ $menuId }}">
<i class='bx bxs-file-plus'></i> <i class='bx bxs-file-plus'></i>
Create</button> Create</button>
<button class="btn btn-primary width-lg btn-bulk-create" data-model="data/umkm"> <button class="btn btn-primary width-lg btn-bulk-create" data-model="data/umkm" data-menu="{{ $menuId }}">
<i class='bx bx-upload' ></i> <i class='bx bx-upload' ></i>
Bulk Create Bulk Create
</button> </button>

View File

@@ -0,0 +1,32 @@
@extends('layouts.base', ['subtitle' => 'Service Unavailable - 503'])
@section('body-attribuet')
class="authentication-bg"
@endsection
@section('content')
<div class="account-pages pt-2 pt-sm-5 pb-4 pb-sm-5">
<div class="container">
<div class="row justify-content-center">
<div class="col-xl-6">
<div class="card auth-card">
<div class="card-body p-0">
<div class="row align-items-center g-0">
<div class="col">
<div class="mx-auto mb-4 text-center">
<img src="/images/simbg-dputr.png" alt="auth" height="250" class="mt-5 mb-3" />
<h2 class="fs-22 lh-base">Service Unavailable!</h2>
<p class="text-muted mt-1 mb-4">Our site is currently undergoing scheduled maintenance.<br /> Please check back later.</p>
</div>
</div> <!-- end col -->
</div> <!-- end row -->
</div> <!-- end card-body -->
</div> <!-- end card -->
</div> <!-- end col -->
</div> <!-- end row -->
</div>
</div>
@endsection

View File

@@ -4,8 +4,22 @@
@include('layouts.partials/page-title', ['title' => 'Home', 'subtitle' => 'Home']) @include('layouts.partials/page-title', ['title' => 'Home', 'subtitle' => 'Home'])
@endsection <div className="container d-flex justify-content-center align-items-center min-vh-100 bg-light">
<div className="col-lg-8 col-md-10 col-sm-12">
<div className="card shadow-lg rounded-3 p-4">
<div className="card-body text-center">
<h1 className="card-title text-primary">Selamat Datang di SIBEDAS PBG!</h1>
<p className="card-text text-secondary mt-3">
Sistem Informasi Berbasis Data (SIBEDAS) adalah sebuah sistem yang dirancang untuk mengelola dan mengolah data pegawai secara efektif dan efisien.
Dengan teknologi modern, SIBEDAS memungkinkan pegawai untuk mendata, melihat, dan memanipulasi informasi pegawai dengan mudah.
</p>
<p className="card-text text-secondary">
PBG (Pegawai Badan Kepegawaian) merupakan unit kerja yang bertanggung jawab atas administrasi kepegawaian.
Melalui SIBEDAS PBG, proses manajemen data pegawai menjadi lebih terstruktur, transparan, dan mudah diakses kapan saja.
</p>
</div>
</div>
</div>
</div>
@section('scripts')
@vite(['resources/js/pages/dashboard.js'])
@endsection @endsection

View File

@@ -5,12 +5,13 @@
@include('layouts.partials/page-title', ['title' => 'Users', 'subtitle' => 'Create']) @include('layouts.partials/page-title', ['title' => 'Users', 'subtitle' => 'Create'])
<x-toast-notification /> <x-toast-notification />
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
<div class="col-lg-6"> <div class="col-lg-6">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<div class="d-flex justify-content-end"> <div class="d-flex justify-content-end">
<a href="{{ route('users.index') }}" class="btn btn-sm btn-secondary me-2">Back</a> <a href="{{ route('users.index', ['menu_id' => $menuId]) }}" class="btn btn-sm btn-secondary me-2">Back</a>
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">

View File

@@ -5,12 +5,13 @@
@include('layouts.partials/page-title', ['title' => 'Users', 'subtitle' => 'Create']) @include('layouts.partials/page-title', ['title' => 'Users', 'subtitle' => 'Create'])
<x-toast-notification /> <x-toast-notification />
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
<div class="col-lg-6"> <div class="col-lg-6">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<div class="d-flex justify-content-end"> <div class="d-flex justify-content-end">
<a href="{{ route('users.index') }}" class="btn btn-sm btn-secondary me-2">Back</a> <a href="{{ route('users.index', ['menu_id' => $menuId]) }}" class="btn btn-sm btn-secondary me-2">Back</a>
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">

View File

@@ -14,14 +14,15 @@
<div class="card-body"> <div class="card-body">
<div class="d-flex flex-wrap justify-content-end align-items-center mb-2"> <div class="d-flex flex-wrap justify-content-end align-items-center mb-2">
@if ($creator) @if ($creator)
<a href="{{ route('users.create') }}" class="btn btn-success btn-sm d-block d-sm-inline w-auto"> <a href="{{ route('users.create', ['menu_id' => $menuId]) }}" class="btn btn-success btn-sm d-block d-sm-inline w-auto">
Create Create
</a> </a>
@endif @endif
</div> </div>
<div id="table-users" <div id="table-users"
data-updater="{{ $updater }}" data-updater="{{ $updater }}"
data-destroyer="{{ $destroyer }}"> data-destroyer="{{ $destroyer }}"
data-menuId="{{ $menuId }}">
</div> </div>
</div> </div>
</div> </div>

View File

@@ -5,11 +5,12 @@
@include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Menu']) @include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Menu'])
<x-toast-notification /> <x-toast-notification />
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<div class="card"> <div class="card">
<div class="card-header d-flex justify-content-end"> <div class="card-header d-flex justify-content-end">
<a href="{{ route('menus.index') }}" class="btn btn-sm btn-secondary">Back</a> <a href="{{ route('menus.index', ['menu_id' => $menuId ?? 0]) }}" class="btn btn-sm btn-secondary">Back</a>
</div> </div>
<div class="card-body"> <div class="card-body">
<form id="formCreateMenus" action="{{route("api.menus.store")}}" method="post"> <form id="formCreateMenus" action="{{route("api.menus.store")}}" method="post">

View File

@@ -9,11 +9,12 @@
@include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Menu']) @include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Menu'])
<x-toast-notification/> <x-toast-notification/>
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<div class="card"> <div class="card">
<div class="card-header d-flex justify-content-end"> <div class="card-header d-flex justify-content-end">
<a href="{{ route('menus.index') }}" class="btn btn-sm btn-secondary">Back</a> <a href="{{ route('menus.index', ['menu_id' => $menuId]) }}" class="btn btn-sm btn-secondary">Back</a>
</div> </div>
<div class="card-body"> <div class="card-body">
<form id="formUpdateMenus" action="{{route("api.menus.update", $menu->id)}}" method="post"> <form id="formUpdateMenus" action="{{route("api.menus.update", $menu->id)}}" method="post">

View File

@@ -9,7 +9,6 @@
@include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Menu']) @include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Menu'])
<x-toast-notification /> <x-toast-notification />
<x-modal-confirmation buttonText="Delete" confirmationMessage="Are you sure you want to delete this?" />
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
@@ -17,13 +16,14 @@
<div class="card-body"> <div class="card-body">
<div class="d-flex flex-wrap justify-content-end align-items-center mb-2"> <div class="d-flex flex-wrap justify-content-end align-items-center mb-2">
@if ($creator) @if ($creator)
<a href="{{ route('menus.create')}}" class="btn btn-success btn-sm d-block d-sm-inline w-auto">Create</a> <a href="{{ route('menus.create', ['menu_id' => $menuId])}}" class="btn btn-success btn-sm d-block d-sm-inline w-auto">Create</a>
@endif @endif
</div> </div>
<div> <div>
<div id="table-menus" <div id="table-menus"
data-updater="{{ $updater }}" data-updater="{{ $updater }}"
data-destroyer="{{ $destroyer }}"> data-destroyer="{{ $destroyer }}"
data-menuId="{{ $menuId }}">
</div> </div>
</div> </div>
</div> </div>

View File

@@ -20,7 +20,7 @@
missing in the digital wilderness.</p> missing in the digital wilderness.</p>
<div class="text-center"> <div class="text-center">
<a href="{{ route('any', 'index') }}" class="btn btn-success">Back to Home</a> <a href="{{ route('home', 'index') }}" class="btn btn-success">Back to Home</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -32,7 +32,7 @@ class="authentication-bg"
<p class="text-muted mt-1 mb-4">The page you're trying to reach seems to have gone <br /> missing in the digital wilderness.</p> <p class="text-muted mt-1 mb-4">The page you're trying to reach seems to have gone <br /> missing in the digital wilderness.</p>
<div class="text-center"> <div class="text-center">
<a href="{{ route('dashboard.home') }}" class="btn btn-danger">Back to Home</a> <a href="{{ route('home') }}" class="btn btn-danger">Back to Home</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -5,11 +5,12 @@
@include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Role']) @include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Role'])
<x-toast-notification /> <x-toast-notification />
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<div class="card"> <div class="card">
<div class="card-header d-flex justify-content-end"> <div class="card-header d-flex justify-content-end">
<a href="{{ route('roles.index') }}" class="btn btn-sm btn-secondary">Back</a> <a href="{{ route('roles.index', ['menu_id' => $menuId]) }}" class="btn btn-sm btn-secondary">Back</a>
</div> </div>
<div class="card-body"> <div class="card-body">
<form action="{{route("api.roles.store")}}" method="post" id="formCreateRole" data-redirect="{{route("roles.index")}}"> <form action="{{route("api.roles.store")}}" method="post" id="formCreateRole" data-redirect="{{route("roles.index")}}">

View File

@@ -5,11 +5,12 @@
@include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Role']) @include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Role'])
<x-toast-notification/> <x-toast-notification/>
<input type="hidden" id="menuId" value="{{ $menuId ?? 0 }}">
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
<div class="col-md-6"> <div class="col-md-6">
<div class="card"> <div class="card">
<div class="card-header d-flex justify-content-end"> <div class="card-header d-flex justify-content-end">
<a href="{{ route('roles.index') }}" class="btn btn-sm btn-secondary">Back</a> <a href="{{ route('roles.index', ['menu_id' => $menuId]) }}" class="btn btn-sm btn-secondary">Back</a>
</div> </div>
<div class="card-body"> <div class="card-body">
<form id="formUpdateRole" action="{{route("api.roles.update", $role->id)}}" method="post" > <form id="formUpdateRole" action="{{route("api.roles.update", $role->id)}}" method="post" >

View File

@@ -9,7 +9,6 @@
@include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Role']) @include('layouts.partials/page-title', ['title' => 'Settings', 'subtitle' => 'Role'])
<x-toast-notification/> <x-toast-notification/>
<x-modal-confirmation buttonText="Delete" confirmationMessage="Are you sure you want to delete this?" />
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
@@ -17,12 +16,13 @@
<div class="card-body"> <div class="card-body">
<div class="d-flex flex-wrap justify-content-end align-items-center mb-2"> <div class="d-flex flex-wrap justify-content-end align-items-center mb-2">
@if ($creator) @if ($creator)
<a href="{{ route('roles.create')}}" class="btn btn-success btn-sm d-block d-sm-inline w-auto">Create</a> <a href="{{ route('roles.create', ['menu_id' => $menuId])}}" class="btn btn-success btn-sm d-block d-sm-inline w-auto">Create</a>
@endif @endif
</div> </div>
<div id="table-roles" <div id="table-roles"
data-updater="{{ $updater }}" data-updater="{{ $updater }}"
data-destroyer="{{ $destroyer }}"> data-destroyer="{{ $destroyer }}"
data-menuId="{{ $menuId }}">
</div> </div>
</div> </div>
</div> </div>

View File

@@ -8,11 +8,11 @@
<div class="col-md-12"> <div class="col-md-12">
<div class="card"> <div class="card">
<div class="card-header d-flex justify-content-end"> <div class="card-header d-flex justify-content-end">
<a href="{{ route('roles.index') }}" class="btn btn-sm btn-secondary">Back</a> <a href="{{ route('roles.index', ['menu_id' => $menuId]) }}" class="btn btn-sm btn-secondary">Back</a>
</div> </div>
<div class="card-body"> <div class="card-body">
<h5>Manage Permissions for Role: {{ $role->name }}</h5> <h5>Manage Permissions for Role: {{ $role->name }}</h5>
<form action="{{route("role-menu.permission.update", $role->id)}}" method="post"> <form action="{{ route('role-menu.permission.update', ['role_id' => $role->id]) }}?menu_id={{ $menuId }}" method="post">
@csrf @csrf
@method("put") @method("put")
<table class="table"> <table class="table">

View File

@@ -37,7 +37,7 @@ require __DIR__ . '/auth.php';
Route::group(['middleware' => 'auth'], function(){ Route::group(['middleware' => 'auth'], function(){
Route::get('', [BigDataController::class, 'index'])->name('any'); Route::get('', [BigDataController::class, 'index'])->name('any');
Route::get('/home', [HomeController::class, 'index']); Route::get('/home', [HomeController::class, 'index'])->name('home');
//dashboards //dashboards
Route::group(['prefix' => '/dashboards'], function(){ Route::group(['prefix' => '/dashboards'], function(){

View File

@@ -108,6 +108,13 @@ export default defineConfig({
"resources/js/pbg-task/show.js", "resources/js/pbg-task/show.js",
// google-sheets // google-sheets
"resources/js/data/google-sheet/index.js", "resources/js/data/google-sheet/index.js",
// dummy
"resources/js/approval/index.js",
"resources/js/invitations/index.js",
"resources/js/payment-recaps/index.js",
"resources/js/report-pbg-ptsp/index.js",
"resources/js/tpa-tpt/index.js",
"resources/js/report-payment-recaps/index.js",
], ],
refresh: true, refresh: true,
}), }),