Compare commits

..

1 Commits

Author SHA1 Message Date
@jamaludinarifrohman6661
38948b6633 bug-fix: map tourisms 2025-02-25 11:32:39 +07:00
46 changed files with 1147 additions and 1661 deletions

View File

@@ -1,241 +0,0 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\BigdataResume;
use App\Models\DataSetting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class BigDataResumeController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
try{
$filterDate = $request->get("filterByDate");
// If filterByDate is "latest" or empty, get the most recent record
if (!$filterDate || $filterDate === "latest") {
$big_data_resume = BigdataResume::latest()->first();
} else {
// Filter by specific date
$big_data_resume = BigdataResume::whereDate('created_at', $filterDate)
->orderBy('id', 'desc')
->first();
if (!$big_data_resume) {
return $this->response_empty_resume();
}
}
$data_settings = DataSetting::all();
if($data_settings->isEmpty()){
return response()->json(['message' => 'No data setting found']);
}
$target_pad = floatval(optional($data_settings->where('key', 'TARGET_PAD')->first())->value);
$tata_ruang = floatval(optional($data_settings->where('key', 'TATA_RUANG')->first())->value);
$realisasi_terbit_pbg_sum = floatval(optional($data_settings->where('key', 'REALISASI_TERBIT_PBG_SUM')->first())->value);
$realisasi_terbit_pbg_count = floatval(optional($data_settings->where('key', 'REALISASI_TERBIT_PBG_COUNT')->first())->value);
$menuggu_klik_dpmptsp_sum = floatval(optional($data_settings->where('key', 'MENUNGGU_KLIK_DPMPTSP_SUM')->first())->value);
$menuggu_klik_dpmptsp_count = floatval(optional($data_settings->where('key', 'MENUNGGU_KLIK_DPMPTSP_COUNT')->first())->value);
$proses_dinas_teknis_sum = floatval(optional($data_settings->where('key', 'PROSES_DINAS_TEKNIS_SUM')->first())->value);
$proses_dinas_teknis_count = floatval(optional($data_settings->where('key', 'PROSES_DINAS_TEKNIS_COUNT')->first())->value);
$kekurangan_potensi = $target_pad - $big_data_resume->potention_sum;
// percentage kekurangan potensi
$kekurangan_potensi_percentage = $target_pad > 0 && $target_pad > 0
? round(($kekurangan_potensi / $target_pad) * 100, 2) : 0;
// percentage total potensi
$total_potensi_percentage = $big_data_resume->potention_sum > 0 && $target_pad > 0
? round(($big_data_resume->potention_sum / $target_pad) * 100, 2) : 0;
// percentage verified document
$verified_percentage = $big_data_resume->verified_sum > 0 && $big_data_resume->potention_sum > 0
? round(($big_data_resume->verified_sum / $big_data_resume->potention_sum) * 100, 2) : 0;
// percentage non-verified document
$non_verified_percentage = $big_data_resume->non_verified_sum > 0 && $big_data_resume->potention_sum > 0
? round(($big_data_resume->non_verified_sum / $big_data_resume->potention_sum) * 100, 2) : 0;
// percentage business document
$business_percentage = $big_data_resume->business_sum > 0 && $big_data_resume->non_verified_sum > 0
? round(($big_data_resume->business_sum / $big_data_resume->non_verified_sum) * 100, 2) : 0;
// percentage non-business document
$non_business_percentage = $big_data_resume->non_business_sum > 0 && $big_data_resume->potention_sum > 0
? round(($big_data_resume->non_business_sum / $big_data_resume->potention_sum) * 100, 2) : 0;
// percentage tata ruang
$tata_ruang_percentage = $tata_ruang > 0 && $big_data_resume->potention_sum > 0
? round(($tata_ruang / $big_data_resume->potention_sum) * 100, 2) : 0;
// percentage realisasi terbit pbg
$realisasi_terbit_percentage = $big_data_resume->verified_sum > 0 && $realisasi_terbit_pbg_sum > 0
? round(($realisasi_terbit_pbg_sum / $big_data_resume->verified_sum) * 100, 2) : 0;
// percentage menunggu klik dpmptsp
$menunggu_klik_dpmptsp_percentage = $big_data_resume->verified_sum > 0 && $menuggu_klik_dpmptsp_sum > 0
? round(($menuggu_klik_dpmptsp_sum / $big_data_resume->verified_sum) * 100, 2) : 0;
// percentage proses_dinas_teknis
$proses_dinas_teknis_percentage = $big_data_resume->verified_sum > 0 && $proses_dinas_teknis_sum > 0
? round(($proses_dinas_teknis_sum / $big_data_resume->verified_sum) * 100, 2) : 0;
$result = [
'target_pad' => [
'sum' => $target_pad,
'percentage' => 100,
],
'tata_ruang' => [
'sum' => $tata_ruang,
'percentage' => $tata_ruang_percentage,
],
'kekurangan_potensi' => [
'sum' => $kekurangan_potensi,
'percentage' => $kekurangan_potensi_percentage
],
'total_potensi' => [
'sum' => (float) $big_data_resume->potention_sum,
'count' => $big_data_resume->potention_count,
'percentage' => $total_potensi_percentage
],
'verified_document' => [
'sum' => (float) $big_data_resume->verified_sum,
'count' => $big_data_resume->verified_count,
'percentage' => $verified_percentage
],
'non_verified_document' => [
'sum' => (float) $big_data_resume->non_verified_sum,
'count' => $big_data_resume->non_verified_count,
'percentage' => $non_verified_percentage
],
'business_document' => [
'sum' => (float) $big_data_resume->business_sum,
'count' => $big_data_resume->business_count,
'percentage' => $business_percentage
],
'non_business_document' => [
'sum' => (float) $big_data_resume->non_business_sum,
'count' => $big_data_resume->non_business_count,
'percentage' => $non_business_percentage
],
'realisasi_terbit' => [
'sum' => $realisasi_terbit_pbg_sum,
'count' => $realisasi_terbit_pbg_count,
'percentage' => $realisasi_terbit_percentage
],
'menunggu_klik_dpmptsp' => [
'sum' => $menuggu_klik_dpmptsp_sum,
'count' => $menuggu_klik_dpmptsp_count,
'percentage' => $menunggu_klik_dpmptsp_percentage
],
'proses_dinas_teknis' => [
'sum' => $proses_dinas_teknis_sum,
'count' => $proses_dinas_teknis_count,
'percentage' => $proses_dinas_teknis_percentage
]
];
return response()->json($result);
}catch(\Exception $e){
return response()->json(['message' => 'Error when fetching data'], 500);
}
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* 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 response_empty_resume(){
$result = [
'target_pad' => [
'sum' => 0,
'percentage' => 100,
],
'tata_ruang' => [
'sum' => 0,
'percentage' => 0,
],
'kekurangan_potensi' => [
'sum' => 0,
'percentage' => 0
],
'total_potensi' => [
'sum' => 0,
'count' => 0,
'percentage' => 0
],
'verified_document' => [
'sum' => 0,
'count' => 0,
'percentage' => 0
],
'non_verified_document' => [
'sum' => 0,
'count' => 0,
'percentage' => 0
],
'business_document' => [
'sum' => 0,
'count' => 0,
'percentage' => 0
],
'non_business_document' => [
'sum' => 0,
'count' => 0,
'percentage' => 0
],
'realisasi_terbit' => [
'sum' => 0,
'count' => 0,
'percentage' => 0
],
'menunggu_klik_dpmptsp' => [
'sum' => 0,
'count' => 0,
'percentage' => 0
],
'proses_dinas_teknis' => [
'sum' => 0,
'count' => 0,
'percentage' => 0
]
];
return response()->json($result);
}
}

View File

@@ -1,31 +0,0 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Advertisement;
use App\Models\Customer;
use App\Models\SpatialPlanning;
use Illuminate\Http\Request;
class LackOfPotentialController extends Controller
{
public function count_lack_of_potential(){
try{
$total_reklame = Advertisement::count();
$total_pdam = Customer::count();
$total_tata_ruang = SpatialPlanning::count();
return response()->json([
'total_reklame' => $total_reklame,
'total_pdam' => $total_pdam,
'total_tata_ruang' => $total_tata_ruang
], 200);
}catch(\Exception $e){
return response()->json([
'message' => 'Error: '.$e->getMessage()
], 500);
}
}
}

View File

@@ -3,11 +3,8 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\MenuRequest;
use App\Http\Resources\MenuResource;
use App\Models\Menu; use App\Models\Menu;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class MenusController extends Controller class MenusController extends Controller
{ {
@@ -16,7 +13,7 @@ class MenusController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
$query = Menu::query()->orderBy('id', 'desc'); $query = Menu::query();
if($request->has("search") && !empty($request->get("search"))){ if($request->has("search") && !empty($request->get("search"))){
$query = $query->where("name", "like", "%".$request->get("search")."%"); $query = $query->where("name", "like", "%".$request->get("search")."%");
@@ -28,15 +25,9 @@ class MenusController extends Controller
/** /**
* Store a newly created resource in storage. * Store a newly created resource in storage.
*/ */
public function store(MenuRequest $request) public function store(Request $request)
{ {
try{ //
$menu = Menu::create($request->validated());
return response()->json(['message' => 'Menu created successfully', 'data' => new MenuResource($menu)]);
}catch(\Exception $e){
Log::error($e);
return response()->json(['message' => 'Error when creating menu'], 500);
}
} }
/** /**
@@ -44,37 +35,15 @@ class MenusController extends Controller
*/ */
public function show(string $id) public function show(string $id)
{ {
try{ //
$menu = Menu::find($id);
if($menu){
return response()->json(['message' => 'Menu found', 'data' => new MenuResource($menu)]);
} else {
return response()->json(['message' => 'Menu not found'], 404);
}
}catch(\Exception $e){
Log::error($e);
Log::error($e->getMessage());
return response()->json(['message' => 'Error when finding menu'], 500);
}
} }
/** /**
* Update the specified resource in storage. * Update the specified resource in storage.
*/ */
public function update(MenuRequest $request, string $id) public function update(Request $request, string $id)
{ {
try{ //
$menu = Menu::findOrFail($id);
if($menu){
$menu->update($request->validated());
return response()->json(['message' => 'Menu updated successfully', 'data' => new MenuResource($menu)]);
} else {
return response()->json(['message' => 'Menu not found'], 404);
}
}catch(\Exception $e){
Log::error($e);
return response()->json(['message' => 'Error when updating menu'], 500);
}
} }
/** /**
@@ -82,28 +51,6 @@ class MenusController extends Controller
*/ */
public function destroy(string $id) public function destroy(string $id)
{ {
try{ //
$menu = Menu::findOrFail($id);
if($menu){
$this->deleteChildren($menu);
$menu->roles()->detach();
$menu->delete();
return response()->json(['message' => 'Menu deleted successfully']);
} else {
return response()->json(['message' => 'Menu not found'], 404);
}
}catch(\Exception $e){
Log::error($e);
return response()->json(['message' => 'Error when deleting menu'], 500);
}
}
private function deleteChildren($menu)
{
foreach ($menu->children as $child) {
$this->deleteChildren($child); // Recursively delete its children
$child->roles()->detach(); // Detach roles before deleting
$child->delete();
}
} }
} }

View File

@@ -3,7 +3,6 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\RoleRequest;
use App\Models\Role; use App\Models\Role;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@@ -14,7 +13,7 @@ class RolesController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
$query = Role::query()->orderBy('id', 'desc'); $query = Role::query();
if($request->has('search') && !empty($request->get('search'))){ if($request->has('search') && !empty($request->get('search'))){
$query = $query->where('name', 'like', '%'. $request->get('search') . '%'); $query = $query->where('name', 'like', '%'. $request->get('search') . '%');
@@ -26,14 +25,9 @@ class RolesController extends Controller
/** /**
* Store a newly created resource in storage. * Store a newly created resource in storage.
*/ */
public function store(RoleRequest $request) public function store(Request $request)
{ {
try{ //
$role = Role::create($request->validated());
return response()->json(['message' => 'Successfully created', 'data' => $role]);
}catch(\Exception $e){
return response()->json(['message' => 'Error when creating role', 'error' => $e->getMessage()], 500);
}
} }
/** /**
@@ -41,34 +35,15 @@ class RolesController extends Controller
*/ */
public function show(string $id) public function show(string $id)
{ {
try{ //
$role = Role::find($id);
if($role){
return response()->json(['data' => $role]);
} else {
return response()->json(['message' => 'Role not found'], 404);
}
}catch(\Exception $e){
return response()->json(['message' => 'Error when getting role', 'error' => $e->getMessage()], 500);
}
} }
/** /**
* Update the specified resource in storage. * Update the specified resource in storage.
*/ */
public function update(RoleRequest $request, string $id) public function update(Request $request, string $id)
{ {
try{ //
$role = Role::find($id);
if($role){
$role->update($request->validated());
return response()->json(['message' => 'Successfully updated', 'data' => $role]);
} else {
return response()->json(['message' => 'Role not found'], 404);
}
}catch(\Exception $e){
return response()->json(['message' => 'Error when updating role', 'error' => $e->getMessage()], 500);
}
} }
/** /**
@@ -76,16 +51,6 @@ class RolesController extends Controller
*/ */
public function destroy(string $id) public function destroy(string $id)
{ {
try{ //
$role = Role::find($id);
if($role){
$role->delete();
return response()->json(['message' => 'Successfully deleted']);
} else {
return response()->json(['message' => 'Role not found'], 404);
}
}catch(\Exception $e){
return response()->json(['message' => 'Error when deleting role', 'error' => $e->getMessage()], 500);
}
} }
} }

View File

@@ -1,12 +0,0 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class GoogleApisController extends Controller
{
public function index(){
return view('maps.google-api');
}
}

View File

@@ -21,7 +21,7 @@ class DataSettingRequest extends FormRequest
*/ */
public function rules(): array public function rules(): array
{ {
$id = $this->route('data_setting_id'); $id = $this->route('data_setting');
return [ return [
"key" => "required|unique:data_settings,key," . $id, "key" => "required|unique:data_settings,key," . $id,
"value" => "required", "value" => "required",

View File

@@ -3,7 +3,6 @@
namespace App\Http\Requests; namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest; use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class MenuRequest extends FormRequest class MenuRequest extends FormRequest
{ {
@@ -22,10 +21,8 @@ class MenuRequest extends FormRequest
*/ */
public function rules(): array public function rules(): array
{ {
$menuId = $this->route('menu_id'); // Get the menu ID if updating
return [ return [
'name' => ['required', 'string', 'max:255', Rule::unique('menus', 'name')->ignore($menuId)], 'name' => ['required','string','max:255'],
'url' => ['nullable','string','max:255'], 'url' => ['nullable','string','max:255'],
'icon' => ['nullable','string','max:255'], 'icon' => ['nullable','string','max:255'],
'parent_id' => ['nullable','exists:menus,id'], 'parent_id' => ['nullable','exists:menus,id'],

View File

@@ -21,7 +21,7 @@ class RoleRequest extends FormRequest
*/ */
public function rules(): array public function rules(): array
{ {
$roleId = $this->route('role_id'); $roleId = $this->route('role');
return [ return [
'name' => 'required|string|max:255|unique:roles,name,' . ($roleId ?? 'NULL') . ',id', 'name' => 'required|string|max:255|unique:roles,name,' . ($roleId ?? 'NULL') . ',id',
'description' => 'nullable|string', 'description' => 'nullable|string',

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class MenuResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return parent::toArray($request);
}
}

View File

@@ -61,15 +61,9 @@ class ServiceSIMBG
} }
} }
public function syncIndexIntegration($uuids, $token) public function syncIndexIntegration($uuid, $token)
{ {
try{ try{
if(empty($uuids)){
return false;
}
$integrations = [];
foreach($uuids as $uuid){
$url = "/api/pbg/v1/detail/" . $uuid . "/retribution/indeks-terintegrasi/"; $url = "/api/pbg/v1/detail/" . $uuid . "/retribution/indeks-terintegrasi/";
$headers = [ $headers = [
@@ -90,8 +84,9 @@ class ServiceSIMBG
return false; return false;
} }
$integrations[] = [ $resultData = PbgTaskIndexIntegrations::updateOrCreate(
'pbg_task_uid' => $uuid, ['pbg_task_uid' => $uuid],
[
'indeks_fungsi_bangunan' => $data['indeks_fungsi_bangunan'] ?? null, 'indeks_fungsi_bangunan' => $data['indeks_fungsi_bangunan'] ?? null,
'indeks_parameter_kompleksitas' => $data['indeks_parameter_kompleksitas'] ?? null, 'indeks_parameter_kompleksitas' => $data['indeks_parameter_kompleksitas'] ?? null,
'indeks_parameter_permanensi' => $data['indeks_parameter_permanensi'] ?? null, 'indeks_parameter_permanensi' => $data['indeks_parameter_permanensi'] ?? null,
@@ -99,24 +94,8 @@ class ServiceSIMBG
'faktor_kepemilikan' => $data['faktor_kepemilikan'] ?? null, 'faktor_kepemilikan' => $data['faktor_kepemilikan'] ?? null,
'indeks_terintegrasi' => $data['indeks_terintegrasi'] ?? null, 'indeks_terintegrasi' => $data['indeks_terintegrasi'] ?? null,
'total' => $data['total'] ?? null, 'total' => $data['total'] ?? null,
]; ]
} );
PbgTaskIndexIntegrations::upsert($integrations, ['pbg_task_uid'], ['indeks_fungsi_bangunan',
'indeks_parameter_kompleksitas', 'indeks_parameter_permanensi', 'indeks_parameter_ketinggian', 'faktor_kepemilikan', 'indeks_terintegrasi', 'total']);
// $resultData = PbgTaskIndexIntegrations::updateOrCreate(
// ['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,
// ]
// );
return true; return true;
}catch (Exception $e){ }catch (Exception $e){
@@ -211,7 +190,7 @@ class ServiceSIMBG
'created_at' => now(), 'created_at' => now(),
]; ];
// $this->syncIndexIntegration($item['uid'], $token); $this->syncIndexIntegration($item['uid'], $token);
$this->syncTaskDetailSubmit($item['uid'], $token); $this->syncTaskDetailSubmit($item['uid'], $token);
@@ -236,9 +215,6 @@ class ServiceSIMBG
'slf_status', 'slf_status_name', 'function_type', 'consultation_type', 'due_date', 'slf_status', 'slf_status_name', 'function_type', 'consultation_type', 'due_date',
'land_certificate_phase', 'task_created_at', 'updated_at' 'land_certificate_phase', 'task_created_at', 'updated_at'
]); ]);
$uuids = array_column($tasksCollective, 'uuid');
$this->syncIndexIntegration($uuids, $token);
} }
$importDatasource->update([ $importDatasource->update([
@@ -336,3 +312,4 @@ class ServiceSIMBG
} }
} }

View File

@@ -116,13 +116,6 @@ class UsersRoleMenuSeeder extends Seeder
"parent_id" => $dashboard->id, "parent_id" => $dashboard->id,
"sort_order" => 3, "sort_order" => 3,
], ],
[
"name" => "PETA",
"url" => "dashboard.maps",
"icon" => null,
"parent_id" => $dashboard->id,
"sort_order" => 4,
],
[ [
"name" => "Users", "name" => "Users",
"url" => "users.index", "url" => "users.index",
@@ -236,7 +229,6 @@ class UsersRoleMenuSeeder extends Seeder
$lack_of_potentials = Menu::where('name', 'Dashboard Potensi')->first(); $lack_of_potentials = Menu::where('name', 'Dashboard Potensi')->first();
$spatial_plannings = Menu::where('name', 'Tata Ruang')->first(); $spatial_plannings = Menu::where('name', 'Tata Ruang')->first();
$pdam = Menu::where('name', 'PDAM')->first(); $pdam = Menu::where('name', 'PDAM')->first();
$peta = Menu::where('name', 'PETA')->first();
// Superadmin gets all menus // Superadmin gets all menus
$superadmin->menus()->sync([ $superadmin->menus()->sync([
@@ -264,7 +256,6 @@ class UsersRoleMenuSeeder extends Seeder
$lack_of_potentials->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], $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], $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],
]); ]);
// Admin gets limited menus // Admin gets limited menus

2
package-lock.json generated
View File

@@ -1,5 +1,5 @@
{ {
"name": "sibedas-pbg-web", "name": "sibedas-pbg",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {

View File

@@ -2,30 +2,6 @@ import bootstrap from "bootstrap/dist/js/bootstrap";
window.bootstrap = bootstrap; window.bootstrap = bootstrap;
import "iconify-icon"; import "iconify-icon";
import "simplebar/dist/simplebar"; import "simplebar/dist/simplebar";
// import flatpickr from "flatpickr";
// import "flatpickr/dist/flatpickr.min.css";
// class InitDatePicker {
// constructor(selector = ".datepicker") {
// this.selector = selector;
// }
// init() {
// const elements = document.querySelectorAll(this.selector);
// if (elements.length === 0) return; // Skip if no elements found
// const today = new Date();
// const minYear = today.getFullYear() - 5;
// elements.forEach((element) => {
// flatpickr(element, {
// enableTime: false,
// dateFormat: "Y-m-d",
// minDate: `${minYear}-01-01`,
// maxDate: today,
// });
// });
// }
// }
class Components { class Components {
initBootstrapComponents() { initBootstrapComponents() {
@@ -131,7 +107,6 @@ class FormValidation {
} }
document.addEventListener("DOMContentLoaded", function (e) { document.addEventListener("DOMContentLoaded", function (e) {
new Components().init(), new FormValidation().init(); new Components().init(), new FormValidation().init();
// new InitDatePicker().init();
}); });
class ThemeLayout { class ThemeLayout {
constructor() { constructor() {

View File

@@ -2,36 +2,58 @@ import { Grid } from "gridjs/dist/gridjs.umd.js";
import gridjs from "gridjs/dist/gridjs.umd.js"; import gridjs from "gridjs/dist/gridjs.umd.js";
import "gridjs/dist/gridjs.umd.js"; import "gridjs/dist/gridjs.umd.js";
import GlobalConfig from "../global-config.js"; import GlobalConfig from "../global-config.js";
import Swal from "sweetalert2";
class BusinessIndustries { class BusinessIndustries {
constructor() { constructor() {
this.toastMessage = document.getElementById("toast-message"); this.table = null; // Store Grid.js instance
this.toastElement = document.getElementById("toastNotification");
this.toast = new bootstrap.Toast(this.toastElement);
this.table = null;
// Initialize functions
this.initTableBusinessIndustries();
this.initEvents();
} }
initEvents() { init() {
document.body.addEventListener("click", async (event) => { this.getFetchApiData();
const deleteButton = event.target.closest(
".btn-delete-business-industry"
);
if (deleteButton) {
event.preventDefault();
await this.handleDelete(deleteButton);
}
});
} }
initTableBusinessIndustries() { getFetchApiData() {
let tableContainer = document.getElementById( let tableContainer = document.getElementById(
"table-business-industries" "table-business-industries"
); );
// Create a new Grid.js instance only if it doesn't exist
if (this.table) {
// If table exists, update its data instead of recreating
this.table
.updateConfig({
server: {
url: `${GlobalConfig.apiHost}/api/api-business-industries`,
credentials: "include",
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
"Content-Type": "application/json",
},
then: (data) =>
data.data.map((item) => [
item.id,
item.nama_kecamatan,
item.nama_kelurahan,
item.nop,
item.nama_wajib_pajak,
item.alamat_wajib_pajak,
item.alamat_objek_pajak,
item.luas_bumi,
item.luas_bangunan,
item.njop_bumi,
item.njop_bangunan,
item.ketetapan,
item.tahun_pajak,
item.created_at,
item.id,
]),
total: (data) => data.total,
},
})
.forceRender();
return;
}
this.table = new Grid({ this.table = new Grid({
columns: [ columns: [
{ name: "ID", width: "80px", hidden: false }, { name: "ID", width: "80px", hidden: false },
@@ -49,20 +71,27 @@ class BusinessIndustries {
{ name: "Tahun Pajak", width: "120px" }, { name: "Tahun Pajak", width: "120px" },
{ name: "Created", width: "180px" }, { name: "Created", width: "180px" },
{ {
name: "Action", name: "Actions",
formatter: (cell) => width: "120px",
gridjs.html(` formatter: function (cell) {
return gridjs.html(`
<div class="d-flex justify-content-center gap-2"> <div class="d-flex justify-content-center gap-2">
<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" 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>
<button data-id="${cell}" class="btn btn-sm btn-red btn-delete-business-industry d-inline-flex align-items-center justify-content-center"> <button class="btn btn-sm btn-red d-inline-flex align-items-center justify-content-center btn-delete-business-industries" data-id="${cell}">
<i class='bx bxs-trash'></i> <i class='bx bxs-trash'></i>
</button> </button>
</div> </div>
`), `);
},
}, },
], ],
search: {
server: {
url: (prev, keyword) => `${prev}?search=${keyword}`,
},
},
pagination: { pagination: {
limit: 15, limit: 15,
server: { server: {
@@ -73,11 +102,6 @@ class BusinessIndustries {
}, },
}, },
sort: true, sort: true,
search: {
server: {
url: (prev, keyword) => `${prev}?search=${keyword}`,
},
},
server: { server: {
url: `${GlobalConfig.apiHost}/api/api-business-industries`, url: `${GlobalConfig.apiHost}/api/api-business-industries`,
headers: { headers: {
@@ -107,28 +131,57 @@ class BusinessIndustries {
total: (data) => data.total, total: (data) => data.total,
}, },
}).render(tableContainer); }).render(tableContainer);
document.addEventListener("click", this.handleDelete.bind(this));
} }
async handleDelete(deleteButton) { handleDelete(event) {
const id = deleteButton.getAttribute("data-id"); if (event.target.classList.contains("btn-delete-business-industries")) {
event.preventDefault();
const id = event.target.getAttribute("data-id");
let modalElement = document.getElementById("modalConfirmation");
let toastMessage = document.getElementById("toast-message");
const result = await Swal.fire({ if (!modalElement) {
title: "Are you sure?", console.error("Modal element not found!");
text: "You won't be able to revert this!", return;
icon: "warning", }
showCancelButton: true,
confirmButtonColor: "#3085d6", let modal = new bootstrap.Modal(modalElement);
cancelButtonColor: "#d33", let btnSaveConfirmation = document.getElementById(
confirmButtonText: "Yes, delete it!", "btnSaveConfirmation"
}); );
let toastElement = document.getElementById("toastNotification");
let toast = new bootstrap.Toast(toastElement);
// Remove previous event listeners to avoid multiple bindings
btnSaveConfirmation.replaceWith(
btnSaveConfirmation.cloneNode(true)
);
btnSaveConfirmation = document.getElementById(
"btnSaveConfirmation"
);
// Set the role ID on the confirm button inside the modal
btnSaveConfirmation.setAttribute("data-business-industries-id", id);
// Show the modal
modal.show();
btnSaveConfirmation.addEventListener("click", async () => {
let deletedId = btnSaveConfirmation.getAttribute(
"data-business-industries-id"
);
if (result.isConfirmed) {
try { try {
let response = await fetch( let response = await fetch(
`${GlobalConfig.apiHost}/api/api-business-industries/${id}`, `${GlobalConfig.apiHost}/api/api-business-industries/${deletedId}`,
{ {
method: "DELETE", method: "DELETE",
credentials: "include", credentials: "include",
headers: { headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
Authorization: `Bearer ${document Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]') .querySelector('meta[name="api-token"]')
.getAttribute("content")}`, .getAttribute("content")}`,
@@ -139,29 +192,69 @@ class BusinessIndustries {
if (response.ok) { if (response.ok) {
let result = await response.json(); let result = await response.json();
this.toastMessage.innerText = toastMessage.innerText =
result.message || "Deleted successfully!"; result.message || "Deleted successfully!";
this.toast.show(); toast.show();
// Hide modal
modal.hide();
// Refresh Grid.js table // Refresh Grid.js table
if (typeof this.table !== "undefined") { this.refreshDataSettings();
this.table.updateConfig({}).forceRender();
}
} else { } else {
let error = await response.json(); let error = await response.json();
console.error("Delete failed:", error); console.error("Delete failed:", error);
this.toastMessage.innerText = toastMessage.innerText =
error.message || "Delete failed!"; error.message || "Delete failed!";
this.toast.show(); toast.show();
} }
} catch (error) { } catch (error) {
console.error("Error deleting item:", error); console.error("Error deleting item:", error);
this.toastMessage.innerText = "An error occurred!"; toastMessage.innerText = "An error occurred!";
this.toast.show(); toast.show();
} }
});
}
}
refreshDataSettings() {
if (this.table) {
this.table
.updateConfig({
server: {
url: `${GlobalConfig.apiHost}/api/api-business-industries`,
credentials: "include",
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
"Content-Type": "application/json",
},
then: (data) =>
data.data.map((item) => [
item.id,
item.nama_kecamatan,
item.nama_kelurahan,
item.nop,
item.nama_wajib_pajak,
item.alamat_wajib_pajak,
item.alamat_objek_pajak,
item.luas_bumi,
item.luas_bangunan,
item.njop_bumi,
item.njop_bangunan,
item.ketetapan,
item.tahun_pajak,
item.created_at,
item.id, // ID for Actions column
]),
total: (data) => data.total,
},
})
.forceRender();
} }
} }
} }
document.addEventListener("DOMContentLoaded", function (e) { document.addEventListener("DOMContentLoaded", function (e) {
new BusinessIndustries(); new BusinessIndustries().init();
}); });

View File

@@ -1,9 +1,9 @@
class UpdateCustomer { class UpdateCustomer {
constructor() { constructor() {
this.initUpdateCustomer(); this.initUpdateSpatial();
} }
initUpdateCustomer() { initUpdateSpatial() {
const toastNotification = document.getElementById("toastNotification"); const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification); const toast = new bootstrap.Toast(toastNotification);
document document

View File

@@ -12,7 +12,7 @@ class Customers {
this.table = null; this.table = null;
// Initialize functions // Initialize functions
this.initTableCustomers(); this.initTableSpatialPlannings();
this.initEvents(); this.initEvents();
} }
initEvents() { initEvents() {
@@ -25,7 +25,7 @@ class Customers {
}); });
} }
initTableCustomers() { initTableSpatialPlannings() {
let tableContainer = document.getElementById("table-customers"); let tableContainer = document.getElementById("table-customers");
// 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({

View File

@@ -1,141 +1,165 @@
import Big from "big.js"; import Big from "big.js";
import GlobalConfig, { addThousandSeparators } from "../global-config.js"; import GlobalConfig, { addThousandSeparators } from "../global-config.js";
import InitDatePicker from "../utils/InitDatePicker.js"; import flatpickr from "flatpickr";
import "flatpickr/dist/flatpickr.min.css";
class BigData { class BigData {
async init() { async init() {
try { try {
new InitDatePicker( this.filterYear = new Date().getFullYear(); // Set initial year
"#datepicker-dashboard-bigdata",
this.handleChangeDate.bind(this) let yearSelect = document.querySelector("#yearPicker");
).init(); let filterButton = document.querySelector("#btnFilterYear");
if (!yearSelect || !filterButton) {
console.error(
"Element #yearPicker or #btnFilterYear not found."
);
return;
}
// Set default value for input
yearSelect.value = this.filterYear;
yearSelect.addEventListener("change", () => {
this.updateYear(yearSelect.value);
});
// Handle button click
filterButton.addEventListener("click", () => {
this.updateYear(yearSelect.value);
});
console.log("init filter this year", this.filterYear);
// Load initial data // Load initial data
this.updateData("latest"); await this.updateData(this.filterYear);
} catch (error) { } catch (error) {
console.error("Error initializing data:", error); console.error("Error initializing data:", error);
} }
} }
updateYear(value) {
handleChangeDate(filterDate) { let inputYear = parseInt(value, 10);
if (!filterDate) return; if (!isNaN(inputYear)) {
this.updateData(filterDate); this.filterYear = inputYear;
this.updateData(this.filterYear);
} else {
console.error("Invalid year input");
} }
async updateData(filterDate) { }
async updateData(year) {
try { try {
console.log("Filtering data for date:", filterDate); this.totalTargetPAD = await this.getDataSettings("TARGET_PAD");
this.resumeBigData = await this.getBigDataResume(filterDate); this.resultDataTotal = await this.getDataTotalPotensi(year);
// this.totalTargetPAD = await this.getDataSettings("TARGET_PAD"); this.dataVerification = await this.getDataVerfication(year);
// this.resultDataTotal = await this.getDataTotalPotensi(year); this.dataNonVerification = await this.getDataNonVerfication(year);
// this.dataVerification = await this.getDataVerfication(year); this.dataBusiness = await this.getDataBusiness(year);
// this.dataNonVerification = await this.getDataNonVerfication(year); this.dataNonBusiness = await this.getDataNonBusiness(year);
// this.dataBusiness = await this.getDataBusiness(year); this.dataTataRuang = await this.getDataSettings("TATA_RUANG");
// this.dataNonBusiness = await this.getDataNonBusiness(year); this.dataSumRealisasiTerbit = await this.getDataSettings(
// this.dataTataRuang = await this.getDataSettings("TATA_RUANG"); "REALISASI_TERBIT_PBG_SUM"
// this.dataSumRealisasiTerbit = await this.getDataSettings( );
// "REALISASI_TERBIT_PBG_SUM" this.dataCountRealisasiTerbit = await this.getDataSettings(
// ); "REALISASI_TERBIT_PBG_COUNT"
// this.dataCountRealisasiTerbit = await this.getDataSettings( );
// "REALISASI_TERBIT_PBG_COUNT" this.dataSumMenungguKlikDPMPTSP = await this.getDataSettings(
// ); "MENUNGGU_KLIK_DPMPTSP_SUM"
// this.dataSumMenungguKlikDPMPTSP = await this.getDataSettings( );
// "MENUNGGU_KLIK_DPMPTSP_SUM" this.dataCountMenungguKlikDPMPTSP = await this.getDataSettings(
// ); "MENUNGGU_KLIK_DPMPTSP_COUNT"
// this.dataCountMenungguKlikDPMPTSP = await this.getDataSettings( );
// "MENUNGGU_KLIK_DPMPTSP_COUNT" this.dataSumProsesDinasTeknis = await this.getDataSettings(
// ); "PROSES_DINAS_TEKNIS_SUM"
// this.dataSumProsesDinasTeknis = await this.getDataSettings( );
// "PROSES_DINAS_TEKNIS_SUM" this.dataCountProsesDinasTeknis = await this.getDataSettings(
// ); "PROSES_DINAS_TEKNIS_COUNT"
// this.dataCountProsesDinasTeknis = await this.getDataSettings( );
// "PROSES_DINAS_TEKNIS_COUNT"
// );
// // total potensi // total potensi
// this.bigTargetPAD = new Big(this.totalTargetPAD ?? 0); this.bigTargetPAD = new Big(this.totalTargetPAD ?? 0);
// this.bigTotalPotensi = new Big(this.resultDataTotal.totalData ?? 0); this.bigTotalPotensi = new Big(this.resultDataTotal.totalData ?? 0);
// this.resultPercentage = 0; this.resultPercentage = 0;
// if (this.bigTotalPotensi > 0 && this.bigTargetPAD > 0) { if (this.bigTotalPotensi > 0 && this.bigTargetPAD > 0) {
// this.resultPercentage = this.bigTotalPotensi this.resultPercentage = this.bigTotalPotensi
// .div(this.bigTargetPAD) .div(this.bigTargetPAD)
// .times(100) .times(100)
// .toFixed(2); .toFixed(2);
// if (this.resultPercentage > 100) { if (this.resultPercentage > 100) {
// this.resultPercentage = 100; this.resultPercentage = 100;
// } }
// } }
// // tata ruang // tata ruang
// this.bigTotalTataRuang = new Big(this.dataTataRuang); this.bigTotalTataRuang = new Big(this.dataTataRuang);
// this.percentageResultTataRuang = this.percentageResultTataRuang =
// this.bigTotalTataRuang <= 0 || this.bigTotalPotensi <= 0 this.bigTotalTataRuang <= 0 || this.bigTotalPotensi <= 0
// ? 0 ? 0
// : this.bigTotalTataRuang : this.bigTotalTataRuang
// .div(this.bigTotalPotensi) .div(this.bigTotalPotensi)
// .times(100) .times(100)
// .toFixed(2); .toFixed(2);
// // kekurangan potensi // kekurangan potensi
// this.totalKekuranganPotensi = new Big( this.totalKekuranganPotensi = new Big(
// this.bigTargetPAD - this.bigTotalPotensi this.bigTargetPAD - this.bigTotalPotensi
// ); );
// this.percentageKekuranganPotensi = this.percentageKekuranganPotensi =
// this.totalKekuranganPotensi <= 0 || this.bigTargetPAD <= 0 this.totalKekuranganPotensi <= 0 || this.bigTargetPAD <= 0
// ? 0 ? 0
// : this.totalKekuranganPotensi : this.totalKekuranganPotensi
// .div(this.bigTargetPAD) .div(this.bigTargetPAD)
// .times(100) .times(100)
// .toFixed(2); .toFixed(2);
// // non-verification documents // non-verification documents
// this.bigTotalNonVerification = new Big( this.bigTotalNonVerification = new Big(
// this.dataNonVerification.total this.dataNonVerification.total
// ); );
// this.percentageResultNonVerification = this.percentageResultNonVerification =
// this.bigTotalNonVerification <= 0 || this.bigTotalPotensi <= 0 this.bigTotalNonVerification <= 0 || this.bigTotalPotensi <= 0
// ? 0 ? 0
// : this.bigTotalNonVerification : this.bigTotalNonVerification
// .div(this.bigTotalPotensi) .div(this.bigTotalPotensi)
// .times(100) .times(100)
// .toFixed(2); .toFixed(2);
// // verification documents // verification documents
// this.bigTotalVerification = new Big(this.dataVerification.total); this.bigTotalVerification = new Big(this.dataVerification.total);
// this.percetageResultVerification = this.percetageResultVerification =
// this.bigTotalVerification <= 0 || this.bigTotalPotensi <= 0 this.bigTotalVerification <= 0 || this.bigTotalPotensi <= 0
// ? 0 ? 0
// : this.bigTotalVerification : this.bigTotalVerification
// .div(this.bigTargetPAD) .div(this.bigTargetPAD)
// .times(100) .times(100)
// .toFixed(2); .toFixed(2);
// // business documents // business documents
// this.bigTotalBusiness = new Big(this.dataBusiness.total); this.bigTotalBusiness = new Big(this.dataBusiness.total);
// this.percentageResultBusiness = this.percentageResultBusiness =
// this.bigTotalNonVerification <= 0 || this.bigTotalBusiness <= 0 this.bigTotalNonVerification <= 0 || this.bigTotalBusiness <= 0
// ? 0 ? 0
// : this.bigTotalBusiness : this.bigTotalBusiness
// .div(this.bigTotalNonVerification) .div(this.bigTotalNonVerification)
// .times(100) .times(100)
// .toFixed(2); .toFixed(2);
// // non-business documents // non-business documents
// this.bigTotalNonBusiness = new Big(this.dataNonBusiness.total); this.bigTotalNonBusiness = new Big(this.dataNonBusiness.total);
// this.percentageResultNonBusiness = this.percentageResultNonBusiness =
// this.bigTotalNonBusiness <= 0 || this.bigTotalNonBusiness <= 0 ||
// this.bigTotalNonVerification <= 0 this.bigTotalNonVerification <= 0
// ? 0 ? 0
// : this.bigTotalNonBusiness : this.bigTotalNonBusiness
// .div(this.bigTotalNonVerification) .div(this.bigTotalNonVerification)
// .times(100) .times(100)
// .toFixed(2); .toFixed(2);
// if (!this.bigTargetPAD) { if (!this.bigTargetPAD) {
// console.error("Failed to load chart data"); console.error("Failed to load chart data");
// return; return;
// } }
this.initChartTargetPAD(); this.initChartTargetPAD();
this.initChartUsaha(); this.initChartUsaha();
@@ -153,33 +177,6 @@ class BigData {
} }
} }
async getBigDataResume(filterByDate) {
try {
const response = await fetch(
`${GlobalConfig.apiHost}/api/bigdata-resume?filterByDate=${filterByDate}`,
{
credentials: "include",
headers: {
Authorization: `Bearer ${
document.querySelector("meta[name='api-token']")
.content
}`,
"Content-Type": "application/json",
},
}
);
if (!response.ok) {
console.error("Network response was not ok", response);
}
const data = await response.json();
return data;
} catch (error) {
console.error("Error fetching chart data:", error);
return null;
}
}
async getDataTotalPotensi(year) { async getDataTotalPotensi(year) {
try { try {
const response = await fetch( const response = await fetch(
@@ -373,60 +370,53 @@ class BigData {
.querySelectorAll(".document-total.chart-target-pad") .querySelectorAll(".document-total.chart-target-pad")
.forEach((element) => { .forEach((element) => {
element.innerText = `Rp.${addThousandSeparators( element.innerText = `Rp.${addThousandSeparators(
// this.bigTargetPAD.toString() this.bigTargetPAD.toString()
this.resumeBigData.target_pad.sum.toString()
)}`; )}`;
}); });
document document
.querySelectorAll(".small-percentage.chart-target-pad") .querySelectorAll(".small-percentage.chart-target-pad")
.forEach((element) => { .forEach((element) => {
element.innerText = `${this.resumeBigData.target_pad.percentage}%`; element.innerText = `${100}%`;
}); });
} }
initChartTotalPotensi() { initChartTotalPotensi() {
// const countAll = this.resultDataTotal.countData ?? 0; const countAll = this.resultDataTotal.countData ?? 0;
document document
.querySelectorAll(".document-count.chart-total-potensi") .querySelectorAll(".document-count.chart-total-potensi")
.forEach((element) => { .forEach((element) => {
// element.innerText = `${countAll}`; element.innerText = `${countAll}`;
element.innerText = `${this.resumeBigData.total_potensi.count}`;
}); });
document document
.querySelectorAll(".document-total.chart-total-potensi") .querySelectorAll(".document-total.chart-total-potensi")
.forEach((element) => { .forEach((element) => {
element.innerText = `Rp.${addThousandSeparators( element.innerText = `Rp.${addThousandSeparators(
// this.bigTotalPotensi.toString() this.bigTotalPotensi.toString()
this.resumeBigData.total_potensi.sum.toString()
)}`; )}`;
}); });
document document
.querySelectorAll(".small-percentage.chart-total-potensi") .querySelectorAll(".small-percentage.chart-total-potensi")
.forEach((element) => { .forEach((element) => {
// element.innerText = `${this.resultPercentage}%`; element.innerText = `${this.resultPercentage}%`;
element.innerText = `${this.resumeBigData.total_potensi.percentage}%`;
}); });
} }
initChartVerificationDocuments() { initChartVerificationDocuments() {
document document
.querySelectorAll(".document-count.chart-berkas-terverifikasi") .querySelectorAll(".document-count.chart-berkas-terverifikasi")
.forEach((element) => { .forEach((element) => {
// element.innerText = `${this.dataVerification.count}`; element.innerText = `${this.dataVerification.count}`;
element.innerText = `${this.resumeBigData.verified_document.count}`;
}); });
document document
.querySelectorAll(".document-total.chart-berkas-terverifikasi") .querySelectorAll(".document-total.chart-berkas-terverifikasi")
.forEach((element) => { .forEach((element) => {
element.innerText = `Rp.${addThousandSeparators( element.innerText = `Rp.${addThousandSeparators(
// this.bigTotalVerification.toString() this.bigTotalVerification.toString()
this.resumeBigData.verified_document.sum.toString()
)}`; )}`;
}); });
document document
.querySelectorAll(".small-percentage.chart-berkas-terverifikasi") .querySelectorAll(".small-percentage.chart-berkas-terverifikasi")
.forEach((element) => { .forEach((element) => {
// element.innerText = `${this.percetageResultVerification}%`; element.innerText = `${this.percetageResultVerification}%`;
element.innerText = `${this.resumeBigData.verified_document.percentage}%`;
}); });
} }
initChartNonVerificationDocuments() { initChartNonVerificationDocuments() {
@@ -435,8 +425,7 @@ class BigData {
".document-count.chart-berkas-belum-terverifikasi" ".document-count.chart-berkas-belum-terverifikasi"
) )
.forEach((element) => { .forEach((element) => {
// element.innerText = `${this.dataNonVerification.count}`; element.innerText = `${this.dataNonVerification.count}`;
element.innerText = `${this.resumeBigData.non_verified_document.count}`;
}); });
document document
.querySelectorAll( .querySelectorAll(
@@ -444,8 +433,7 @@ class BigData {
) )
.forEach((element) => { .forEach((element) => {
element.innerText = `Rp.${addThousandSeparators( element.innerText = `Rp.${addThousandSeparators(
// this.bigTotalNonVerification.toString() this.bigTotalNonVerification.toString()
this.resumeBigData.non_verified_document.sum.toString()
)}`; )}`;
}); });
document document
@@ -453,52 +441,45 @@ class BigData {
".small-percentage.chart-berkas-belum-terverifikasi" ".small-percentage.chart-berkas-belum-terverifikasi"
) )
.forEach((element) => { .forEach((element) => {
// element.innerText = `${this.percentageResultNonVerification}%`; element.innerText = `${this.percentageResultNonVerification}%`;
element.innerText = `${this.resumeBigData.non_verified_document.percentage}%`;
}); });
} }
initChartUsaha() { initChartUsaha() {
document document
.querySelectorAll(".document-count.chart-business") .querySelectorAll(".document-count.chart-business")
.forEach((element) => { .forEach((element) => {
// element.innerText = `${this.dataBusiness.count}`; element.innerText = `${this.dataBusiness.count}`;
element.innerText = `${this.resumeBigData.business_document.count}`;
}); });
document document
.querySelectorAll(".document-total.chart-business") .querySelectorAll(".document-total.chart-business")
.forEach((element) => { .forEach((element) => {
element.innerText = `Rp.${addThousandSeparators( element.innerText = `Rp.${addThousandSeparators(
// this.bigTotalBusiness.toString() this.bigTotalBusiness.toString()
this.resumeBigData.business_document.sum.toString()
)}`; )}`;
}); });
document document
.querySelectorAll(".small-percentage.chart-business") .querySelectorAll(".small-percentage.chart-business")
.forEach((element) => { .forEach((element) => {
// element.innerText = `${this.percentageResultBusiness}%`; element.innerText = `${this.percentageResultBusiness}%`;
element.innerText = `${this.resumeBigData.business_document.percentage}%`;
}); });
} }
initChartNonUsaha() { initChartNonUsaha() {
document document
.querySelectorAll(".document-count.chart-non-business") .querySelectorAll(".document-count.chart-non-business")
.forEach((element) => { .forEach((element) => {
// element.innerText = `${this.dataNonBusiness.count}`; element.innerText = `${this.dataNonBusiness.count}`;
element.innerText = `${this.resumeBigData.non_business_document.count}`;
}); });
document document
.querySelectorAll(".document-total.chart-non-business") .querySelectorAll(".document-total.chart-non-business")
.forEach((element) => { .forEach((element) => {
element.innerText = `Rp.${addThousandSeparators( element.innerText = `Rp.${addThousandSeparators(
// this.bigTotalNonBusiness.toString() this.bigTotalNonBusiness.toString()
this.resumeBigData.non_business_document.sum.toString()
)}`; )}`;
}); });
document document
.querySelectorAll(".small-percentage.chart-non-business") .querySelectorAll(".small-percentage.chart-non-business")
.forEach((element) => { .forEach((element) => {
// element.innerText = `${this.percentageResultNonBusiness}%`; element.innerText = `${this.percentageResultNonBusiness}%`;
element.innerText = `${this.resumeBigData.non_business_document.percentage}%`;
}); });
} }
initChartKekuranganPotensi() { initChartKekuranganPotensi() {
@@ -511,78 +492,70 @@ class BigData {
.querySelectorAll(".document-total.chart-kekurangan-potensi") .querySelectorAll(".document-total.chart-kekurangan-potensi")
.forEach((element) => { .forEach((element) => {
element.innerText = `Rp.${addThousandSeparators( element.innerText = `Rp.${addThousandSeparators(
// this.totalKekuranganPotensi.toString() this.totalKekuranganPotensi.toString()
this.resumeBigData.kekurangan_potensi.sum.toString()
)}`; )}`;
}); });
document document
.querySelectorAll(".small-percentage.chart-kekurangan-potensi") .querySelectorAll(".small-percentage.chart-kekurangan-potensi")
.forEach((element) => { .forEach((element) => {
// element.innerText = `${this.percentageKekuranganPotensi}%`; element.innerText = `${this.percentageKekuranganPotensi}%`;
element.innerText = `${this.resumeBigData.kekurangan_potensi.percentage}%`;
}); });
} }
initChartRealisasiTerbitPBG() { initChartRealisasiTerbitPBG() {
document document
.querySelectorAll(".document-count.chart-realisasi-tebit-pbg") .querySelectorAll(".document-count.chart-realisasi-tebit-pbg")
.forEach((element) => { .forEach((element) => {
// element.innerText = `${this.dataCountRealisasiTerbit}`; element.innerText = `${this.dataCountRealisasiTerbit}`;
element.innerText = `${this.resumeBigData.realisasi_terbit.count}`;
}); });
document document
.querySelectorAll(".document-total.chart-realisasi-tebit-pbg") .querySelectorAll(".document-total.chart-realisasi-tebit-pbg")
.forEach((element) => { .forEach((element) => {
element.innerText = `Rp.${addThousandSeparators( element.innerText = `Rp.${addThousandSeparators(
// this.dataSumRealisasiTerbit this.dataSumRealisasiTerbit
this.resumeBigData.realisasi_terbit.sum.toString()
)}`; )}`;
}); });
document document
.querySelectorAll(".small-percentage.chart-realisasi-tebit-pbg") .querySelectorAll(".small-percentage.chart-realisasi-tebit-pbg")
.forEach((element) => { .forEach((element) => {
element.innerText = `${this.resumeBigData.realisasi_terbit.percentage}%`; element.innerText = `0.00%`;
}); });
} }
initChartMenungguKlikDPMPTSP() { initChartMenungguKlikDPMPTSP() {
document document
.querySelectorAll(".document-count.chart-menunggu-klik-dpmptsp") .querySelectorAll(".document-count.chart-menunggu-klik-dpmptsp")
.forEach((element) => { .forEach((element) => {
// element.innerText = `${this.dataCountMenungguKlikDPMPTSP}`; element.innerText = `${this.dataCountMenungguKlikDPMPTSP}`;
element.innerText = `${this.resumeBigData.menunggu_klik_dpmptsp.count}`;
}); });
document document
.querySelectorAll(".document-total.chart-menunggu-klik-dpmptsp") .querySelectorAll(".document-total.chart-menunggu-klik-dpmptsp")
.forEach((element) => { .forEach((element) => {
element.innerText = `Rp.${addThousandSeparators( element.innerText = `Rp.${addThousandSeparators(
// this.dataSumMenungguKlikDPMPTSP this.dataSumMenungguKlikDPMPTSP
this.resumeBigData.menunggu_klik_dpmptsp.sum.toString()
)}`; )}`;
}); });
document document
.querySelectorAll(".small-percentage.chart-menunggu-klik-dpmptsp") .querySelectorAll(".small-percentage.chart-menunggu-klik-dpmptsp")
.forEach((element) => { .forEach((element) => {
element.innerText = `${this.resumeBigData.menunggu_klik_dpmptsp.percentage}%`; element.innerText = `0.00%`;
}); });
} }
initChartProsesDinasTeknis() { initChartProsesDinasTeknis() {
document document
.querySelectorAll(".document-count.chart-proses-dinas-teknis") .querySelectorAll(".document-count.chart-proses-dinas-teknis")
.forEach((element) => { .forEach((element) => {
// element.innerText = `${this.dataCountProsesDinasTeknis}`; element.innerText = `${this.dataCountProsesDinasTeknis}`;
element.innerText = `${this.resumeBigData.proses_dinas_teknis.count}`;
}); });
document document
.querySelectorAll(".document-total.chart-proses-dinas-teknis") .querySelectorAll(".document-total.chart-proses-dinas-teknis")
.forEach((element) => { .forEach((element) => {
element.innerText = `Rp.${addThousandSeparators( element.innerText = `Rp.${addThousandSeparators(
// this.dataSumProsesDinasTeknis this.dataSumProsesDinasTeknis
this.resumeBigData.proses_dinas_teknis.sum.toString()
)}`; )}`;
}); });
document document
.querySelectorAll(".small-percentage.chart-proses-dinas-teknis") .querySelectorAll(".small-percentage.chart-proses-dinas-teknis")
.forEach((element) => { .forEach((element) => {
element.innerText = `${this.resumeBigData.proses_dinas_teknis.percentage}%`; element.innerText = `0.00%`;
}); });
} }
initChartPotensiTataRuang() { initChartPotensiTataRuang() {
@@ -595,15 +568,13 @@ class BigData {
.querySelectorAll(".document-total.chart-potensi-tata-ruang") .querySelectorAll(".document-total.chart-potensi-tata-ruang")
.forEach((element) => { .forEach((element) => {
element.innerText = `Rp.${addThousandSeparators( element.innerText = `Rp.${addThousandSeparators(
// this.bigTotalTataRuang.toString() this.bigTotalTataRuang.toString()
this.resumeBigData.tata_ruang.sum.toString()
)}`; )}`;
}); });
document document
.querySelectorAll(".small-percentage.chart-potensi-tata-ruang") .querySelectorAll(".small-percentage.chart-potensi-tata-ruang")
.forEach((element) => { .forEach((element) => {
// element.innerText = `${this.percentageResultTataRuang}%`; element.innerText = `${this.percentageResultTataRuang}%`;
element.innerText = `${this.resumeBigData.tata_ruang.percentage}%`;
}); });
} }
} }

View File

@@ -1,42 +1,21 @@
import Big from "big.js"; import Big from "big.js";
import GlobalConfig, { addThousandSeparators } from "../global-config.js"; import GlobalConfig, { addThousandSeparators } from "../global-config.js";
import InitDatePicker from "../utils/InitDatePicker.js";
class LackOfPotential { class LackOfPotential {
async init() { async init() {
new InitDatePicker(
"#datepicker-lack-of-potential",
this.handleChangedDate.bind(this)
).init();
this.bigTotalLackPotential = 0; this.bigTotalLackPotential = 0;
this.totalPotensi = await this.getDataTotalPotensi("latest"); this.totalPotensi = await this.getDataTotalPotensi(2025);
this.totalTargetPAD = await this.getDataSettings("TARGET_PAD"); this.totalTargetPAD = await this.getDataSettings("TARGET_PAD");
this.allCountData = await this.getValueDashboard();
this.reklameCount = this.allCountData.total_reklame ?? 0;
this.pdamCount = this.allCountData.total_pdam ?? 0;
this.tataRuangCount = this.allCountData.total_tata_ruang ?? 0;
this.bigTargetPAD = new Big(this.totalTargetPAD ?? 0); this.bigTargetPAD = new Big(this.totalTargetPAD ?? 0);
this.bigTotalPotensi = new Big(this.totalPotensi.total ?? 0); this.bigTotalPotensi = new Big(this.totalPotensi.totalData ?? 0);
this.bigTotalLackPotential = this.bigTargetPAD.minus( this.bigTotalLackPotential = this.bigTargetPAD - this.bigTotalPotensi;
this.bigTotalPotensi
);
this.initChartKekuranganPotensi();
this.initDataValueDashboard();
}
async handleChangedDate(filterDate) {
const totalPotensi = await this.getDataTotalPotensi(filterDate);
this.bigTotalPotensi = new Big(totalPotensi.total ?? 0);
this.bigTotalLackPotential = this.bigTargetPAD.minus(
this.bigTotalPotensi
);
this.initChartKekuranganPotensi(); this.initChartKekuranganPotensi();
} }
async getDataTotalPotensi(filterDate) { async getDataTotalPotensi(year) {
try { try {
const response = await fetch( const response = await fetch(
`${GlobalConfig.apiHost}/api/bigdata-resume?filterByDate=${filterDate}`, `${GlobalConfig.apiHost}/api/all-task-documents?year=${year}`,
{ {
credentials: "include", credentials: "include",
headers: { headers: {
@@ -55,7 +34,8 @@ class LackOfPotential {
const data = await response.json(); const data = await response.json();
return { return {
total: data.total_potensi.sum, countData: data.data.count,
totalData: data.data.total,
}; };
} catch (error) { } catch (error) {
console.error("Error fetching chart data:", error); console.error("Error fetching chart data:", error);
@@ -65,7 +45,7 @@ class LackOfPotential {
async getDataSettings(string_key) { async getDataSettings(string_key) {
try { try {
const response = await fetch( const response = await fetch(
`${GlobalConfig.apiHost}/api/data-settings?search=${string_key}`, `${GlobalConfig.apiHost}/api/api-data-settings?search=${string_key}`,
{ {
credentials: "include", credentials: "include",
headers: { headers: {
@@ -89,33 +69,6 @@ class LackOfPotential {
return 0; return 0;
} }
} }
async getValueDashboard() {
try {
const response = await fetch(
`${GlobalConfig.apiHost}/api/dashboard-potential-count`,
{
credentials: "include",
headers: {
Authorization: `Bearer ${
document.querySelector("meta[name='api-token']")
.content
}`,
"Content-Type": "application/json",
},
}
);
if (!response.ok) {
console.error("Network response was not ok", response);
}
const data = await response.json();
return data;
} catch (error) {
console.error("Error fetching chart data:", error);
return 0;
}
}
initChartKekuranganPotensi() { initChartKekuranganPotensi() {
document document
.querySelectorAll(".document-count.chart-lack-of-potential") .querySelectorAll(".document-count.chart-lack-of-potential")
@@ -135,12 +88,6 @@ class LackOfPotential {
element.innerText = ``; element.innerText = ``;
}); });
} }
initDataValueDashboard() {
document.getElementById("reklame-count").innerText = this.reklameCount;
document.getElementById("pdam-count").innerText = this.pdamCount;
document.getElementById("pbb-bangunan-count").innerText =
this.tataRuangCount;
}
} }
document.addEventListener("DOMContentLoaded", async function (e) { document.addEventListener("DOMContentLoaded", async function (e) {
await new LackOfPotential().init(); await new LackOfPotential().init();

View File

@@ -24,9 +24,10 @@ document.addEventListener("DOMContentLoaded", function (e) {
method: "POST", method: "POST",
credentials: "include", credentials: "include",
headers: { headers: {
Authorization: `Bearer ${document "X-CSRF-TOKEN": document
.querySelector('meta[name="api-token"]') .querySelector('meta[name="csrf-token"]')
.getAttribute("content")}`, .getAttribute("content"),
"Content-Type": "application/json",
}, },
body: formData, body: formData,
}); });
@@ -34,7 +35,7 @@ document.addEventListener("DOMContentLoaded", function (e) {
if (response.ok) { if (response.ok) {
let result = await response.json(); let result = await response.json();
document.getElementById("toast-message").innerText = document.getElementById("toast-message").innerText =
result.data.message; result.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/data-settings"; window.location.href = "/data-settings";
@@ -45,8 +46,6 @@ document.addEventListener("DOMContentLoaded", function (e) {
error.message; error.message;
toast.show(); toast.show();
console.error("Error:", error); console.error("Error:", error);
submitButton.disabled = false;
spinner.classList.add("d-none");
} }
} catch (error) { } catch (error) {
console.error("Request failed:", error); console.error("Request failed:", error);

View File

@@ -2,34 +2,46 @@ import { Grid } from "gridjs/dist/gridjs.umd.js";
import gridjs from "gridjs/dist/gridjs.umd.js"; import gridjs from "gridjs/dist/gridjs.umd.js";
import "gridjs/dist/gridjs.umd.js"; import "gridjs/dist/gridjs.umd.js";
import GlobalConfig from "../global-config.js"; import GlobalConfig from "../global-config.js";
import Swal from "sweetalert2";
class DataSettings { class DataSettings {
constructor() { constructor() {
this.toastMessage = document.getElementById("toast-message"); this.table = null; // Store Grid.js instance
this.toastElement = document.getElementById("toastNotification");
this.toast = new bootstrap.Toast(this.toastElement);
this.table = null;
// Initialize functions
this.initTableDataSettings();
this.initEvents();
} }
initEvents() { init() {
document.body.addEventListener("click", async (event) => { this.getFetchApiData();
const deleteButton = event.target.closest(
".btn-delete-data-settings"
);
if (deleteButton) {
event.preventDefault();
await this.handleDelete(deleteButton);
}
});
} }
initTableDataSettings() { getFetchApiData() {
let tableContainer = document.getElementById("table-data-settings"); let tableContainer = document.getElementById("table-data-settings");
// Create a new Grid.js instance only if it doesn't exist
if (this.table) {
// If table exists, update its data instead of recreating
this.table
.updateConfig({
server: {
url: `${GlobalConfig.apiHost}/api/api-data-settings`,
credentials: "include",
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
"Content-Type": "application/json",
},
then: (data) =>
data.data.map((item) => [
item.id,
item.key,
item.value,
item.created_at,
item.id,
]),
total: (data) => data.meta.total,
},
})
.forceRender();
return;
}
this.table = new Grid({ this.table = new Grid({
columns: [ columns: [
"ID", "ID",
@@ -53,6 +65,11 @@ class DataSettings {
}, },
}, },
], ],
search: {
server: {
url: (prev, keyword) => `${prev}?search=${keyword}`,
},
},
pagination: { pagination: {
limit: 15, limit: 15,
server: { server: {
@@ -63,13 +80,8 @@ class DataSettings {
}, },
}, },
sort: true, sort: true,
search: {
server: { server: {
url: (prev, keyword) => `${prev}?search=${keyword}`, url: `${GlobalConfig.apiHost}/api/api-data-settings`,
},
},
server: {
url: `${GlobalConfig.apiHost}/api/data-settings`,
headers: { headers: {
Authorization: `Bearer ${document Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]') .querySelector('meta[name="api-token"]')
@@ -87,31 +99,56 @@ class DataSettings {
total: (data) => data.meta.total, total: (data) => data.meta.total,
}, },
}).render(tableContainer); }).render(tableContainer);
document.addEventListener("click", this.handleDelete.bind(this));
} }
async handleDelete(deleteButton) { handleDelete(event) {
const id = deleteButton.getAttribute("data-id"); if (event.target.classList.contains("btn-delete-data-settings")) {
event.preventDefault();
const id = event.target.getAttribute("data-id");
let modalElement = document.getElementById("modalConfirmation");
let toastMessage = document.getElementById("toast-message");
const result = await Swal.fire({ if (!modalElement) {
title: "Are you sure?", console.error("Modal element not found!");
text: "You won't be able to revert this!", return;
icon: "warning", }
showCancelButton: true,
confirmButtonColor: "#3085d6", let modal = new bootstrap.Modal(modalElement);
cancelButtonColor: "#d33", let btnSaveConfirmation = document.getElementById(
confirmButtonText: "Yes, delete it!", "btnSaveConfirmation"
}); );
let toastElement = document.getElementById("toastNotification");
let toast = new bootstrap.Toast(toastElement);
// Remove previous event listeners to avoid multiple bindings
btnSaveConfirmation.replaceWith(
btnSaveConfirmation.cloneNode(true)
);
btnSaveConfirmation = document.getElementById(
"btnSaveConfirmation"
);
// Set the role ID on the confirm button inside the modal
btnSaveConfirmation.setAttribute("data-settings-id", id);
// Show the modal
modal.show();
btnSaveConfirmation.addEventListener("click", async () => {
let dataSettingId =
btnSaveConfirmation.getAttribute("data-settings-id");
if (result.isConfirmed) {
try { try {
let response = await fetch( let response = await fetch(
`${GlobalConfig.apiHost}/api/data-settings/${id}`, `/data-settings/${dataSettingId}`,
{ {
method: "DELETE", method: "DELETE",
credentials: "include", credentials: "include",
headers: { headers: {
Authorization: `Bearer ${document "X-CSRF-TOKEN": document
.querySelector('meta[name="api-token"]') .querySelector('meta[name="csrf-token"]')
.getAttribute("content")}`, .getAttribute("content"),
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
} }
@@ -119,29 +156,59 @@ class DataSettings {
if (response.ok) { if (response.ok) {
let result = await response.json(); let result = await response.json();
this.toastMessage.innerText = toastMessage.innerText =
result.message || "Deleted successfully!"; result.message || "Deleted successfully!";
this.toast.show(); toast.show();
// Hide modal
modal.hide();
// Refresh Grid.js table // Refresh Grid.js table
if (typeof this.table !== "undefined") { this.refreshDataSettings();
this.table.updateConfig({}).forceRender();
}
} else { } else {
let error = await response.json(); let error = await response.json();
console.error("Delete failed:", error); console.error("Delete failed:", error);
this.toastMessage.innerText = toastMessage.innerText =
error.message || "Delete failed!"; error.message || "Delete failed!";
this.toast.show(); toast.show();
} }
} catch (error) { } catch (error) {
console.error("Error deleting item:", error); console.error("Error deleting item:", error);
this.toastMessage.innerText = "An error occurred!"; toastMessage.innerText = "An error occurred!";
this.toast.show(); toast.show();
} }
});
}
}
refreshDataSettings() {
if (this.table) {
this.table
.updateConfig({
server: {
url: `${GlobalConfig.apiHost}/api/api-data-settings`,
credentials: "include",
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
"Content-Type": "application/json",
},
then: (data) =>
data.data.map((item) => [
item.id,
item.key,
item.value,
item.created_at,
item.id,
]),
total: (data) => data.meta.total,
},
})
.forceRender();
} }
} }
} }
document.addEventListener("DOMContentLoaded", function (e) { document.addEventListener("DOMContentLoaded", function (e) {
new DataSettings(); new DataSettings().init();
}); });

View File

@@ -24,16 +24,16 @@ document.addEventListener("DOMContentLoaded", function (e) {
let response = await fetch(form.action, { let response = await fetch(form.action, {
method: "POST", method: "POST",
headers: { headers: {
Authorization: `Bearer ${document "X-CSRF-TOKEN": document
.querySelector('meta[name="api-token"]') .querySelector('meta[name="csrf-token"]')
.getAttribute("content")}`, .getAttribute("content"),
}, },
body: formData, body: formData,
}); });
if (response.ok) { if (response.ok) {
let result = await response.json(); let result = await response.json();
toastMessage.innerText = result.data.message; toastMessage.innerText = result.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/data-settings"; window.location.href = "/data-settings";
@@ -43,8 +43,6 @@ document.addEventListener("DOMContentLoaded", function (e) {
toastMessage.innerText = error.message; toastMessage.innerText = error.message;
toast.show(); toast.show();
console.error("Error:", error); console.error("Error:", error);
submitButton.disabled = false;
spinner.classList.add("d-none");
} }
} catch (error) { } catch (error) {
console.error("Request failed:", error); console.error("Request failed:", error);

View File

@@ -20,9 +20,9 @@ const dataTourismsColumns = [
name: "Actions", name: "Actions",
widht: "120px", widht: "120px",
formatter: function (cell, row) { formatter: function (cell, row) {
const id = row.cells[10].data; const id = row.cells[11].data;
const long = row.cells[8].data; const long = row.cells[9].data;
const lat = row.cells[9].data; const lat = row.cells[10].data;
const model = "data/tourisms"; const model = "data/tourisms";
return gridjs.html(` return gridjs.html(`
<div class="d-flex justify-items-end gap-10"> <div class="d-flex justify-items-end gap-10">

View File

@@ -27,7 +27,7 @@ const dataUMKMColumns = [
name: "Actions", name: "Actions",
widht: "120px", widht: "120px",
formatter: function(cell, row) { formatter: function(cell, row) {
const id = row.cells[18].data; const id = row.cells[19].data;
const model = "data/umkm"; const model = "data/umkm";
return gridjs.html(` return gridjs.html(`
<div class="d-flex justify-items-end gap-10"> <div class="d-flex justify-items-end gap-10">

View File

@@ -1,9 +1,4 @@
class CreateMenu { document.addEventListener("DOMContentLoaded", function (e) {
constructor() {
this.initCreateMenu();
}
initCreateMenu() {
const toastNotification = document.getElementById("toastNotification"); const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification); const toast = new bootstrap.Toast(toastNotification);
document document
@@ -28,9 +23,9 @@ class CreateMenu {
let response = await fetch(form.action, { let response = await fetch(form.action, {
method: "POST", method: "POST",
headers: { headers: {
Authorization: `Bearer ${document "X-CSRF-TOKEN": document
.querySelector('meta[name="api-token"]') .querySelector('meta[name="csrf-token"]')
.getAttribute("content")}`, .getAttribute("content"),
}, },
body: formData, body: formData,
}); });
@@ -49,8 +44,6 @@ class CreateMenu {
error.message; error.message;
toast.show(); toast.show();
console.error("Error:", error); console.error("Error:", error);
submitButton.disabled = false;
spinner.classList.add("d-none");
} }
} catch (error) { } catch (error) {
console.error("Request failed:", error); console.error("Request failed:", error);
@@ -59,9 +52,4 @@ class CreateMenu {
toast.show(); toast.show();
} }
}); });
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new CreateMenu();
}); });

View File

@@ -2,27 +2,13 @@ import { Grid } from "gridjs/dist/gridjs.umd.js";
import gridjs from "gridjs/dist/gridjs.umd.js"; import gridjs from "gridjs/dist/gridjs.umd.js";
import "gridjs/dist/gridjs.umd.js"; import "gridjs/dist/gridjs.umd.js";
import GlobalConfig from "../global-config"; import GlobalConfig from "../global-config";
import Swal from "sweetalert2";
class Menus { class Menus {
constructor() { constructor() {
this.toastMessage = document.getElementById("toast-message");
this.toastElement = document.getElementById("toastNotification");
this.toast = new bootstrap.Toast(this.toastElement);
this.table = null; this.table = null;
}
// Initialize functions init() {
this.initTableMenus(); this.initTableMenus();
this.initEvents();
}
initEvents() {
document.body.addEventListener("click", async (event) => {
const deleteButton = event.target.closest(".btn-delete-menu");
if (deleteButton) {
event.preventDefault();
await this.handleDelete(deleteButton);
}
});
} }
initTableMenus() { initTableMenus() {
@@ -33,7 +19,7 @@ class Menus {
this.table this.table
.updateConfig({ .updateConfig({
server: { server: {
url: `${GlobalConfig.apiHost}/api/menus`, url: `${GlobalConfig.apiHost}/api/api-menus`,
credentials: "include", credentials: "include",
headers: { headers: {
Authorization: `Bearer ${document Authorization: `Bearer ${document
@@ -74,8 +60,7 @@ class Menus {
<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" 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>
<button data-id="${cell}" <button data-id="${cell}" class="btn btn-red btn-sm btn-delete-menu d-inline-flex align-items-center justify-content-center">
class="btn btn-red btn-sm btn-delete-menu d-inline-flex align-items-center justify-content-center">
<i class='bx bxs-trash' ></i> <i class='bx bxs-trash' ></i>
</button> </button>
</div> </div>
@@ -98,7 +83,7 @@ class Menus {
}, },
}, },
server: { server: {
url: `${GlobalConfig.apiHost}/api/menus`, url: `${GlobalConfig.apiHost}/api/api-menus`,
credentials: "include", credentials: "include",
headers: { headers: {
Authorization: `Bearer ${document Authorization: `Bearer ${document
@@ -119,27 +104,91 @@ class Menus {
total: (data) => data.total, total: (data) => data.total,
}, },
}).render(tableContainer); }).render(tableContainer);
document.addEventListener("click", this.handleDelete.bind(this));
} }
async handleDelete(button) { handleDelete(event) {
const id = button.getAttribute("data-id"); if (event.target.classList.contains("btn-delete-menu")) {
event.preventDefault();
const id = event.target.getAttribute("data-id");
let modalElement = document.getElementById("modalConfirmation");
let toastMessage = document.getElementById("toast-message");
const result = await Swal.fire({ if (!modalElement) {
title: "Are you sure?", console.error("Modal element not found!");
text: "You won't be able to revert this!", return;
icon: "warning", }
showCancelButton: true,
confirmButtonColor: "#3085d6", let modal = new bootstrap.Modal(modalElement);
cancelButtonColor: "#d33", let btnSaveConfirmation = document.getElementById(
confirmButtonText: "Yes, delete it!", "btnSaveConfirmation"
);
let toastElement = document.getElementById("toastNotification");
let toast = new bootstrap.Toast(toastElement);
// Remove previous event listeners to avoid multiple bindings
btnSaveConfirmation.replaceWith(
btnSaveConfirmation.cloneNode(true)
);
btnSaveConfirmation = document.getElementById(
"btnSaveConfirmation"
);
// Set the role ID on the confirm button inside the modal
btnSaveConfirmation.setAttribute("data-menu-id", id);
// Show the modal
modal.show();
btnSaveConfirmation.addEventListener("click", async () => {
let menuId = btnSaveConfirmation.getAttribute("data-menu-id");
try {
let response = await fetch(`/menus/${menuId}`, {
method: "DELETE",
credentials: "include",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
"Content-Type": "application/json",
},
}); });
if (result.isConfirmed) { if (response.ok) {
try { let result = await response.json();
let response = await fetch( toastMessage.innerText =
`${GlobalConfig.apiHost}/api/menus/${id}`, result.message || "Deleted successfully!";
{ toast.show();
method: "DELETE",
// Hide modal
modal.hide();
// Refresh Grid.js table
this.refreshTableMenus();
} else {
let error = await response.json();
console.error("Delete failed:", error);
toastMessage.innerText =
error.message || "Delete failed!";
toast.show();
}
} catch (error) {
console.error("Error deleting item:", error);
toastMessage.innerText = "An error occurred!";
toast.show();
}
});
}
}
refreshTableMenus() {
if (this.table) {
this.table
.updateConfig({
server: {
url: `${GlobalConfig.apiHost}/api/api-menus`,
credentials: "include", credentials: "include",
headers: { headers: {
Authorization: `Bearer ${document Authorization: `Bearer ${document
@@ -147,35 +196,26 @@ class Menus {
.getAttribute("content")}`, .getAttribute("content")}`,
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
} then: (data) =>
); data.data.map((item) => [
item.id,
if (response.ok) { item.name,
let result = await response.json(); item.url,
this.toastMessage.innerText = item.icon,
result.message || "Deleted successfully!"; item.parent_id,
this.toast.show(); item.sort_order,
item.id,
// Refresh Grid.js table ]),
if (typeof this.table !== "undefined") { total: (data) => data.total,
this.table.updateConfig({}).forceRender(); },
} })
.forceRender();
} else { } else {
let error = await response.json(); this.initTableMenus(); // If no table exists, reinitialize it
console.error("Delete failed:", error);
this.toastMessage.innerText =
error.message || "Delete failed!";
this.toast.show();
}
} catch (error) {
console.error("Error deleting item:", error);
this.toastMessage.innerText = "An error occurred!";
this.toast.show();
}
} }
} }
} }
document.addEventListener("DOMContentLoaded", function (e) { document.addEventListener("DOMContentLoaded", function (e) {
new Menus(); new Menus().init();
}); });

View File

@@ -1,17 +1,13 @@
class UpdateMenu { document.addEventListener("DOMContentLoaded", function (e) {
constructor() {
this.initUpdateMenu();
}
initUpdateMenu() {
const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification);
document
.getElementById("btnUpdateMenus")
.addEventListener("click", async function () {
let submitButton = this;
let spinner = document.getElementById("spinner");
let form = document.getElementById("formUpdateMenus"); let form = document.getElementById("formUpdateMenus");
let submitButton = document.getElementById("btnUpdateMenus");
let spinner = document.getElementById("spinner");
let toastMessage = document.getElementById("toast-message");
let toast = new bootstrap.Toast(
document.getElementById("toastNotification")
);
submitButton.addEventListener("click", async function () {
let submitButton = this;
if (!form) { if (!form) {
console.error("Form element not found!"); console.error("Form element not found!");
@@ -28,40 +24,30 @@ class UpdateMenu {
let response = await fetch(form.action, { let response = await fetch(form.action, {
method: "POST", method: "POST",
headers: { headers: {
Authorization: `Bearer ${document "X-CSRF-TOKEN": document
.querySelector('meta[name="api-token"]') .querySelector('meta[name="csrf-token"]')
.getAttribute("content")}`, .getAttribute("content"),
}, },
body: formData, body: formData,
}); });
if (response.ok) { if (response.ok) {
let result = await response.json(); let result = await response.json();
document.getElementById("toast-message").innerText = toastMessage.innerText = result.message;
result.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/menus"; window.location.href = "/menus";
}, 2000); }, 2000);
} else { } else {
let error = await response.json(); let error = await response.json();
document.getElementById("toast-message").innerText = toastMessage.innerText = error.message;
error.message;
toast.show(); toast.show();
console.error("Error:", error); console.error("Error:", error);
submitButton.disabled = false;
spinner.classList.add("d-none");
} }
} catch (error) { } catch (error) {
console.error("Request failed:", error); console.error("Request failed:", error);
document.getElementById("toast-message").innerText = toastMessage.innerText = error.message;
error.message;
toast.show(); toast.show();
} }
}); });
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new UpdateMenu();
}); });

View File

@@ -1,9 +1,4 @@
class CreateRoles { document.addEventListener("DOMContentLoaded", function (e) {
constructor() {
this.initCreateRole();
}
initCreateRole() {
const toastNotification = document.getElementById("toastNotification"); const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification); const toast = new bootstrap.Toast(toastNotification);
document document
@@ -28,9 +23,9 @@ class CreateRoles {
let response = await fetch(form.action, { let response = await fetch(form.action, {
method: "POST", method: "POST",
headers: { headers: {
Authorization: `Bearer ${document "X-CSRF-TOKEN": document
.querySelector('meta[name="api-token"]') .querySelector('meta[name="csrf-token"]')
.getAttribute("content")}`, .getAttribute("content"),
}, },
body: formData, body: formData,
}); });
@@ -49,8 +44,6 @@ class CreateRoles {
error.message; error.message;
toast.show(); toast.show();
console.error("Error:", error); console.error("Error:", error);
submitButton.disabled = false;
spinner.classList.add("d-none");
} }
} catch (error) { } catch (error) {
console.error("Request failed:", error); console.error("Request failed:", error);
@@ -59,9 +52,4 @@ class CreateRoles {
toast.show(); toast.show();
} }
}); });
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new CreateRoles();
}); });

View File

@@ -2,31 +2,46 @@ import { Grid } from "gridjs/dist/gridjs.umd.js";
import gridjs from "gridjs/dist/gridjs.umd.js"; import gridjs from "gridjs/dist/gridjs.umd.js";
import "gridjs/dist/gridjs.umd.js"; import "gridjs/dist/gridjs.umd.js";
import GlobalConfig from "../global-config"; import GlobalConfig from "../global-config";
import Swal from "sweetalert2";
class Roles { class Roles {
constructor() { constructor() {
this.toastMessage = document.getElementById("toast-message"); this.table = null; // Store Grid.js instance
this.toastElement = document.getElementById("toastNotification"); }
this.toast = new bootstrap.Toast(this.toastElement);
this.table = null;
// Initialize functions init() {
this.initTableRoles(); this.initTableRoles();
this.initEvents();
}
initEvents() {
document.body.addEventListener("click", async (event) => {
const deleteButton = event.target.closest(".btn-delete-role");
if (deleteButton) {
event.preventDefault();
await this.handleDelete(deleteButton);
}
});
} }
initTableRoles() { initTableRoles() {
let tableContainer = document.getElementById("table-roles"); let tableContainer = document.getElementById("table-roles");
// If table instance already exists, update it instead of re-creating
if (this.table) {
this.table
.updateConfig({
server: {
url: `${GlobalConfig.apiHost}/api/api-roles`,
credentials: "include",
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
"Content-Type": "application/json",
},
then: (data) =>
data.data.map((item) => [
item.id,
item.name,
item.description,
item.id,
]),
total: (data) => data.total,
},
})
.forceRender();
return;
}
// 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: [
@@ -67,7 +82,7 @@ class Roles {
}, },
}, },
server: { server: {
url: `${GlobalConfig.apiHost}/api/roles`, url: `${GlobalConfig.apiHost}/api/api-roles`,
credentials: "include", credentials: "include",
headers: { headers: {
Authorization: `Bearer ${document Authorization: `Bearer ${document
@@ -85,27 +100,92 @@ class Roles {
total: (data) => data.total, total: (data) => data.total,
}, },
}).render(tableContainer); }).render(tableContainer);
document.addEventListener("click", this.handleDelete.bind(this));
} }
async handleDelete(deleteButton) { handleDelete(event) {
const id = deleteButton.getAttribute("data-id"); if (event.target.classList.contains("btn-delete-role")) {
event.preventDefault();
const result = await Swal.fire({ const id = event.target.getAttribute("data-id");
title: "Are you sure?", let modalElement = document.getElementById("modalConfirmation");
text: "You won't be able to revert this!", let toastMessage = document.getElementById("toast-message");
icon: "warning",
showCancelButton: true, if (!modalElement) {
confirmButtonColor: "#3085d6", console.error("Modal element not found!");
cancelButtonColor: "#d33", return;
confirmButtonText: "Yes, delete it!", }
let modal = new bootstrap.Modal(modalElement);
let btnSaveConfirmation = document.getElementById(
"btnSaveConfirmation"
);
let toastElement = document.getElementById("toastNotification");
let toast = new bootstrap.Toast(toastElement);
// Remove previous event listeners to avoid multiple bindings
btnSaveConfirmation.replaceWith(
btnSaveConfirmation.cloneNode(true)
);
btnSaveConfirmation = document.getElementById(
"btnSaveConfirmation"
);
// Set the role ID on the confirm button inside the modal
btnSaveConfirmation.setAttribute("data-role-id", id);
// Show the modal
modal.show();
btnSaveConfirmation.addEventListener("click", async () => {
let roleId = btnSaveConfirmation.getAttribute("data-role-id");
try {
let response = await fetch(`/roles/${roleId}`, {
method: "DELETE",
credentials: "include",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
"Content-Type": "application/json",
},
}); });
if (result.isConfirmed) { if (response.ok) {
try { let result = await response.json();
let response = await fetch( toastMessage.innerText =
`${GlobalConfig.apiHost}/api/roles/${id}`, result.message || "Deleted successfully!";
{ toast.show();
method: "DELETE",
// Hide modal
modal.hide();
// Refresh Grid.js table
this.refreshRolesTable();
} else {
let error = await response.json();
console.error("Delete failed:", error);
toastMessage.innerText =
error.message || "Delete failed!";
toast.show();
}
} catch (error) {
console.error("Error deleting item:", error);
toastMessage.innerText = "An error occurred!";
toast.show();
}
});
}
}
refreshRolesTable() {
if (this.table) {
this.table
.updateConfig({
server: {
url: `${GlobalConfig.apiHost}/api/api-roles`,
credentials: "include", credentials: "include",
headers: { headers: {
Authorization: `Bearer ${document Authorization: `Bearer ${document
@@ -113,35 +193,23 @@ class Roles {
.getAttribute("content")}`, .getAttribute("content")}`,
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
} then: (data) =>
); data.data.map((item) => [
item.id,
if (response.ok) { item.name,
let result = await response.json(); item.description,
this.toastMessage.innerText = item.id,
result.message || "Deleted successfully!"; ]),
this.toast.show(); total: (data) => data.total,
},
// Refresh Grid.js table })
if (typeof this.table !== "undefined") { .forceRender();
this.table.updateConfig({}).forceRender();
}
} else { } else {
let error = await response.json(); this.initTableRoles(); // If the table is null, reinitialize
console.error("Delete failed:", error);
this.toastMessage.innerText =
error.message || "Delete failed!";
this.toast.show();
}
} catch (error) {
console.error("Error deleting item:", error);
this.toastMessage.innerText = "An error occurred!";
this.toast.show();
}
} }
} }
} }
document.addEventListener("DOMContentLoaded", function (e) { document.addEventListener("DOMContentLoaded", function (e) {
new Roles(); new Roles().init();
}); });

View File

@@ -1,17 +1,13 @@
class UpdateRoles { document.addEventListener("DOMContentLoaded", function (e) {
constructor() {
this.initUpdateRole();
}
initUpdateRole() {
const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification);
document
.getElementById("btnUpdateRole")
.addEventListener("click", async function () {
let submitButton = this;
let spinner = document.getElementById("spinner");
let form = document.getElementById("formUpdateRole"); let form = document.getElementById("formUpdateRole");
let submitButton = document.getElementById("btnUpdateRole");
let spinner = document.getElementById("spinner");
let toastMessage = document.getElementById("toast-message");
let toast = new bootstrap.Toast(
document.getElementById("toastNotification")
);
submitButton.addEventListener("click", async function () {
let submitButton = this;
if (!form) { if (!form) {
console.error("Form element not found!"); console.error("Form element not found!");
@@ -28,40 +24,30 @@ class UpdateRoles {
let response = await fetch(form.action, { let response = await fetch(form.action, {
method: "POST", method: "POST",
headers: { headers: {
Authorization: `Bearer ${document "X-CSRF-TOKEN": document
.querySelector('meta[name="api-token"]') .querySelector('meta[name="csrf-token"]')
.getAttribute("content")}`, .getAttribute("content"),
}, },
body: formData, body: formData,
}); });
if (response.ok) { if (response.ok) {
let result = await response.json(); let result = await response.json();
document.getElementById("toast-message").innerText = toastMessage.innerText = result.message;
result.message;
toast.show(); toast.show();
setTimeout(() => { setTimeout(() => {
window.location.href = "/roles"; window.location.href = "/roles";
}, 2000); }, 2000);
} else { } else {
let error = await response.json(); let error = await response.json();
document.getElementById("toast-message").innerText = toastMessage.innerText = error.message;
error.message;
toast.show(); toast.show();
console.error("Error:", error); console.error("Error:", error);
submitButton.disabled = false;
spinner.classList.add("d-none");
} }
} catch (error) { } catch (error) {
console.error("Request failed:", error); console.error("Request failed:", error);
document.getElementById("toast-message").innerText = toastMessage.innerText = error.message;
error.message;
toast.show(); toast.show();
} }
}); });
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new UpdateRoles();
}); });

View File

@@ -1,34 +0,0 @@
import flatpickr from "flatpickr";
import "flatpickr/dist/flatpickr.min.css";
class InitDatePicker {
constructor(selector = ".datepicker", onChangeCallback = null) {
this.selector = selector;
this.onChangeCallback = onChangeCallback;
}
init() {
const today = new Date();
document.querySelectorAll(this.selector).forEach((element) => {
flatpickr(element, {
enableTime: false,
dateFormat: "Y-m-d",
maxDate: today,
onChange: (selectedDates, dateStr) => {
if (this.onChangeCallback) {
this.onChangeCallback(dateStr); // Call callback with selected date
}
},
onReady: (selectedDates, dateStr, instance) => {
// Call the callback with the default date when initialized
if (this.onChangeCallback && dateStr) {
this.onChangeCallback(dateStr);
}
},
});
});
}
}
export default InitDatePicker;

View File

@@ -16,7 +16,7 @@
<div class="card w-100"> <div class="card w-100">
<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">
<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')}}" class="btn btn-success btn-sm d-block d-sm-inline w-auto">Create</a>
</div> </div>
<div id="table-business-industries"></div> <div id="table-business-industries"></div>
</div> </div>

View File

@@ -1,5 +1,5 @@
@props(['title' => 'title component', 'visible_data' => false, 'data_count' => '', 'visible_data_type' => false, @props(['title' => 'title component', 'visible_data' => false, 'data' => 'data text', 'visible_data_type' => false,
'data_type' => '','style' => '', 'size' => '', 'line' => [], 'data_id' => '']) 'data_type' => '','style' => '', 'size' => '', 'line' => []])
@section('css') @section('css')
@vite(['resources/scss/components/_custom_circle.scss']) @vite(['resources/scss/components/_custom_circle.scss'])
@@ -9,7 +9,7 @@
<div class="custom-circle-content"> <div class="custom-circle-content">
<p class="custom-circle-text">{{ $title }}</p> <p class="custom-circle-text">{{ $title }}</p>
@if ($visible_data === "true") @if ($visible_data === "true")
<div class="custom-circle-data" id="{{ $data_id }}">{{ $data_count }}</div> <div class="custom-circle-data">{{ $data }}</div>
@endif @endif
@if ($visible_data_type === "true") @if ($visible_data_type === "true")
<div class="custom-circle-data-type">{{ $data_type }}</div> <div class="custom-circle-data-type">{{ $data_type }}</div>

View File

@@ -20,8 +20,13 @@
<div class="row d-flex justify-content-end"> <div class="row d-flex justify-content-end">
<div class="col-12 col-sm-6 col-md-3"> <div class="col-12 col-sm-6 col-md-3">
<div class="d-flex flex-sm-nowrap flex-wrap justify-content-end"> <div class="d-flex flex-sm-nowrap flex-wrap justify-content-end gap-2">
<input type="text" class="form-control" style="max-width: 125px;" id="datepicker-dashboard-bigdata" placeholder="Filter Date" /> <select class="form-select w-auto" id="yearPicker" name="year" style="min-width: 100px;">
@for ($i = date('Y'); $i > date('Y') - 5; $i--)
<option value="{{ $i }}" {{ $i == date('Y') ? 'selected' : '' }}>{{ $i }}</option>
@endfor
</select>
<button class="btn btn-sm btn-primary" id="btnFilterYear">Filter</button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -15,21 +15,15 @@
</h3> </h3>
</div> </div>
</div> </div>
<div class="wrapper"> <div class="">
<div class="row d-flex justify-content-end"> <div class="">
<div class="col-12 col-sm-6 col-md-3">
<div class="d-flex flex-sm-nowrap flex-wrap justify-content-end">
<input type="text" class="form-control me-3" style="max-width: 125px;" id="datepicker-lack-of-potential" placeholder="Filter Date" />
</div>
</div>
</div>
<div id="lack-of-potential-fixed-container" class="" style="width:1400px;height:770px;position:relative;margin:auto;z-index:1;"> <div id="lack-of-potential-fixed-container" class="" style="width:1400px;height:770px;position:relative;margin:auto;z-index:1;">
<div style="position: absolute; top: 200px; left: 50px;"> <div style="position: absolute; top: 200px; left: 50px;">
<x-custom-circle title="Restoran" size="small" style="background-color: #0e4753;" /> <x-custom-circle title="Restoran" size="small" style="background-color: #0e4753;" />
<div class="square dia-top-left-bottom-right" style="top:30px;left:50px;width:150px;height:120px;"></div> <div class="square dia-top-left-bottom-right" style="top:30px;left:50px;width:150px;height:120px;"></div>
<x-custom-circle title="PBB Bangunan" visible_data="true" data_id="pbb-bangunan-count" data_count="0" size="small" style="background-color: #0e4753;" /> <x-custom-circle title="PBB Bangunan" visible_data="true" data="649.157" size="small" style="background-color: #0e4753;" />
<div class="square" style="width:150px;height:2px;background-color:black;left:50px;top:150px;"></div> <div class="square" style="width:150px;height:2px;background-color:black;left:50px;top:150px;"></div>
<x-custom-circle title="Reklame" visible_data="true" data_id="reklame-count" data_count="0" size="small" style="background-color: #0e4753;" /> <x-custom-circle title="Reklame" visible_data="true" data="2.428" size="small" style="background-color: #0e4753;" />
<div class="square dia-top-right-bottom-left" style="top:140px;left:50px;width:150px;height:120px;"></div> <div class="square dia-top-right-bottom-left" style="top:140px;left:50px;width:150px;height:120px;"></div>
</div> </div>
@@ -37,7 +31,7 @@
<div class="square dia-top-right-bottom-left" style="top:-100px;left:30px;width:150px;height:120px;"></div> <div class="square dia-top-right-bottom-left" style="top:-100px;left:30px;width:150px;height:120px;"></div>
<div class="square dia-top-left-bottom-right" style="top:-100px;left:120px;width:120px;height:120px;"></div> <div class="square dia-top-left-bottom-right" style="top:-100px;left:120px;width:120px;height:120px;"></div>
<x-custom-circle title="BAPENDA" size="small" style="float:left;background-color: #234f6c;" /> <x-custom-circle title="BAPENDA" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="PDAM" visible_data="true" data_id="pdam-count" data_count="0" visible_data_type="true" data_type="Pelanggan" size="small" style="float:left;background-color: #234f6c;" /> <x-custom-circle title="PDAM" visible_data="true" data="9.022" visible_data_type="true" data_type="Pelanggan" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="KECAMATAN" size="small" style="float:left;background-color: #234f6c;" /> <x-custom-circle title="KECAMATAN" size="small" style="float:left;background-color: #234f6c;" />
</div> </div>
@@ -92,7 +86,7 @@
</div> </div>
<x-custom-circle title="BPN" size="small" style="background-color: #2390af;position:absolute;left:1270px;top:440px;" /> <x-custom-circle title="UUCK" size="small" style="background-color: #2390af;position:absolute;left:1270px;top:440px;" />
<div style="position: absolute; top: 470px; left: 430px;"> <div style="position: absolute; top: 470px; left: 430px;">
<div class="square dia-top-right-bottom-left" style="top:-80px;left:20px;width:150px;height:120px;"></div> <div class="square dia-top-right-bottom-left" style="top:-80px;left:20px;width:150px;height:120px;"></div>
@@ -113,6 +107,9 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>
@endsection @endsection

View File

@@ -8,11 +8,8 @@
<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">
<a href="{{ route('data-settings.index') }}" class="btn btn-sm btn-secondary">Back</a>
</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('data-settings.store') }}" method="POST">
@csrf @csrf
<div class="mb-3"> <div class="mb-3">
<label for="key" class="form-label">Key</label> <label for="key" class="form-label">Key</label>

View File

@@ -8,11 +8,8 @@
<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">
<a href="{{ route('data-settings.index') }}" class="btn btn-sm btn-secondary">Back</a>
</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('data-settings.update', $data->id) }}" method="POST">
@csrf @csrf
@method('PUT') @method('PUT')
<div class="mb-3"> <div class="mb-3">

View File

@@ -9,6 +9,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 />
<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">

View File

@@ -1,45 +0,0 @@
@extends('layouts.vertical', ['subtitle' => 'Google Maps'])
@section('css')
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
@endsection
@section('content')
@include('layouts.partials/page-title', ['title' => 'Maps', 'subtitle' => 'Google Maps'])
<div id="map" style="width: 100%; height: 90vh;"></div>
@endsection
@section('scripts')
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://unpkg.com/togeojson@0.16.0"></script>
<script src="https://unpkg.com/leaflet-omnivore@0.3.4/leaflet-omnivore.min.js"></script>
<script src="https://unpkg.com/leaflet-kml/L.KML.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
var map = L.map('map').setView([-6.9175, 107.6191], 10); // Jakarta
// Tambahkan peta dasar dari OpenStreetMap
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; OpenStreetMap contributors'
}).addTo(map);
// Muat file KMZ
omnivore.kml("{{ asset('storage/maps/rencanapolaruang_rtrw_2024_2044__rencana_pola_ruang.kml') }}")
.on('ready', function () {
try {
var bounds = this.getBounds();
if (bounds.isValid()) {
map.fitBounds(bounds);
} else {
console.warn("Bounds tidak valid, gunakan fallback.");
map.setView([-6.9175, 107.6191], 10); // Default ke Jakarta
}
} catch (error) {
console.error("Error setting bounds:", error);
map.setView([-6.1751, 106.8650], 10);
}
})
.addTo(map);
});
</script>
@endsection

View File

@@ -12,11 +12,8 @@
<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">
<a href="{{ route('menus.index') }}" class="btn btn-sm btn-secondary">Back</a>
</div>
<div class="card-body"> <div class="card-body">
<form id="formCreateMenus" action="{{route("api.menus.store")}}" method="post"> <form id="formCreateMenus" action="{{route("menus.store")}}" method="post">
@csrf @csrf
<div class="mb-3"> <div class="mb-3">
<label class="form-label" for="name">Name</label> <label class="form-label" for="name">Name</label>

View File

@@ -12,11 +12,8 @@
<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">
<a href="{{ route('menus.index') }}" class="btn btn-sm btn-secondary">Back</a>
</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("menus.update", $menu->id)}}" method="post">
@csrf @csrf
@method("put") @method("put")
<div class="mb-3"> <div class="mb-3">

View File

@@ -8,11 +8,8 @@
<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">
<a href="{{ route('roles.index') }}" class="btn btn-sm btn-secondary">Back</a>
</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("roles.store")}}" method="post" id="formCreateRole" data-redirect="{{route("roles.index")}}">
@csrf @csrf
<div class="mb-3"> <div class="mb-3">
<label class="form-label" for="name">Name</label> <label class="form-label" for="name">Name</label>

View File

@@ -8,11 +8,8 @@
<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">
<a href="{{ route('roles.index') }}" class="btn btn-sm btn-secondary">Back</a>
</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("roles.update", $role->id)}}" method="post" >
@csrf @csrf
@method("put") @method("put")
<div class="mb-3"> <div class="mb-3">

View File

@@ -7,9 +7,6 @@
<div class="row d-flex justify-content-center"> <div class="row d-flex justify-content-center">
<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">
<a href="{{ route('roles.index') }}" class="btn btn-sm btn-secondary">Back</a>
</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)}}" method="post">

View File

@@ -1,6 +1,5 @@
<?php <?php
use App\Http\Controllers\Api\BigDataResumeController;
use App\Http\Controllers\Api\BusinessOrIndustriesController; use App\Http\Controllers\Api\BusinessOrIndustriesController;
use App\Http\Controllers\Api\CustomersController; use App\Http\Controllers\Api\CustomersController;
use App\Http\Controllers\Api\DashboardController; use App\Http\Controllers\Api\DashboardController;
@@ -8,7 +7,6 @@ use App\Http\Controllers\Api\DataSettingController;
use App\Http\Controllers\Api\GlobalSettingsController; use App\Http\Controllers\Api\GlobalSettingsController;
use App\Http\Controllers\Api\GoogleSheetController; use App\Http\Controllers\Api\GoogleSheetController;
use App\Http\Controllers\Api\ImportDatasourceController; use App\Http\Controllers\Api\ImportDatasourceController;
use App\Http\Controllers\Api\LackOfPotentialController;
use App\Http\Controllers\Api\MenusController; use App\Http\Controllers\Api\MenusController;
use App\Http\Controllers\Api\PbgTaskController; use App\Http\Controllers\Api\PbgTaskController;
use App\Http\Controllers\Api\RequestAssignmentController; use App\Http\Controllers\Api\RequestAssignmentController;
@@ -82,13 +80,7 @@ Route::group(['middleware' => 'auth:sanctum'], function (){
Route::get('/download-template-spatialPlannings', [SpatialPlanningController::class, 'downloadExcelSpatialPlanning']); Route::get('/download-template-spatialPlannings', [SpatialPlanningController::class, 'downloadExcelSpatialPlanning']);
// data-settings // data-settings
// Route::apiResource('/api-data-settings', DataSettingController::class); Route::apiResource('/api-data-settings', DataSettingController::class);
Route::controller(DataSettingController::class)->group(function (){
Route::get('/data-settings', 'index')->name('api.data-settings');
Route::post('/data-settings', 'store')->name('api.data-settings.store');
Route::put('/data-settings/{data_setting_id}', 'update')->name('api.data-settings.update');
Route::delete('/data-settings/{data_setting_id}', 'destroy')->name('api.data-settings.destroy');
});
Route::apiResource('/api-pbg-task', PbgTaskController::class); Route::apiResource('/api-pbg-task', PbgTaskController::class);
@@ -101,20 +93,10 @@ Route::group(['middleware' => 'auth:sanctum'], function (){
Route::get('/sync-task-submit/{uuid}', [SyncronizeController::class, 'syncTaskDetailSubmit'])->name('api.task.submit'); Route::get('/sync-task-submit/{uuid}', [SyncronizeController::class, 'syncTaskDetailSubmit'])->name('api.task.submit');
// menus api // menus api
Route::controller(MenusController::class)->group(function (){ Route::apiResource('api-menus', MenusController::class);
Route::get('/menus', 'index')->name('api.menus');
Route::post('/menus', 'store')->name('api.menus.store');
Route::put('/menus/{menu_id}', 'update')->name('api.menus.update');
Route::delete('/menus/{menu_id}', 'destroy')->name('api.menus.destroy');
});
// roles api // roles api
Route::controller(RolesController::class)->group(function (){ Route::apiResource('api-roles', RolesController::class);
Route::get('/roles', 'index')->name('api.roles');
Route::post('/roles', 'store')->name('api.roles.store');
Route::put('/roles/{role_id}', 'update')->name('api.roles.update');
Route::delete('/roles/{role_id}', 'destroy')->name('api.roles.destroy');
});
//business industries api //business industries api
Route::apiResource('api-business-industries', BusinessOrIndustriesController::class); Route::apiResource('api-business-industries', BusinessOrIndustriesController::class);
@@ -127,10 +109,4 @@ Route::group(['middleware' => 'auth:sanctum'], function (){
Route::delete('/customers/{id}', 'destroy')->name('api.customers.destroy'); Route::delete('/customers/{id}', 'destroy')->name('api.customers.destroy');
Route::post('/customers/upload', 'upload')->name('api.customers.upload'); Route::post('/customers/upload', 'upload')->name('api.customers.upload');
}); });
//dashboard potensi
Route::get('/dashboard-potential-count', [LackOfPotentialController::class, 'count_lack_of_potential'])->name('api.count-dashboard-potential');
// big data resume
Route::get('/bigdata-resume', [BigDataResumeController::class, 'index'])->name('api.bigdata-resume');
}); });

View File

@@ -5,7 +5,6 @@ use App\Http\Controllers\CustomersController;
use App\Http\Controllers\Dashboards\LackOfPotentialController; use App\Http\Controllers\Dashboards\LackOfPotentialController;
use App\Http\Controllers\DataSettingController; use App\Http\Controllers\DataSettingController;
use App\Http\Controllers\Dashboards\BigDataController; use App\Http\Controllers\Dashboards\BigDataController;
use App\Http\Controllers\GoogleApisController;
use App\Http\Controllers\Home\HomeController; use App\Http\Controllers\Home\HomeController;
use App\Http\Controllers\Master\UsersController; use App\Http\Controllers\Master\UsersController;
use App\Http\Controllers\MenusController; use App\Http\Controllers\MenusController;
@@ -33,7 +32,6 @@ Route::group(['middleware' => 'auth'], function(){
Route::get('/bigdata', [BigDataController::class, 'index'])->name('dashboard.home'); Route::get('/bigdata', [BigDataController::class, 'index'])->name('dashboard.home');
Route::get('/dashboard-pbg', [BigDataController::class, 'pbg'])->name('dashboard.pbg'); Route::get('/dashboard-pbg', [BigDataController::class, 'pbg'])->name('dashboard.pbg');
Route::get('/lack-of-potential', [LackOfPotentialController::class, 'lack_of_potential'])->name('dashboard.lack_of_potential'); Route::get('/lack-of-potential', [LackOfPotentialController::class, 'lack_of_potential'])->name('dashboard.lack_of_potential');
Route::get('/maps', [GoogleApisController::class, 'index'])->name('dashboard.maps');
}); });
// settings // settings

File diff suppressed because one or more lines are too long