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;
use App\Http\Controllers\Controller;
use App\Http\Requests\MenuRequest;
use App\Http\Resources\MenuResource;
use App\Models\Menu;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class MenusController extends Controller
{
@@ -16,7 +13,7 @@ class MenusController extends Controller
*/
public function index(Request $request)
{
$query = Menu::query()->orderBy('id', 'desc');
$query = Menu::query();
if($request->has("search") && !empty($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.
*/
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)
{
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.
*/
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)
{
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;
use App\Http\Controllers\Controller;
use App\Http\Requests\RoleRequest;
use App\Models\Role;
use Illuminate\Http\Request;
@@ -14,7 +13,7 @@ class RolesController extends Controller
*/
public function index(Request $request)
{
$query = Role::query()->orderBy('id', 'desc');
$query = Role::query();
if($request->has('search') && !empty($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.
*/
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)
{
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.
*/
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)
{
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
{
$id = $this->route('data_setting_id');
$id = $this->route('data_setting');
return [
"key" => "required|unique:data_settings,key," . $id,
"value" => "required",

View File

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

View File

@@ -21,7 +21,7 @@ class RoleRequest extends FormRequest
*/
public function rules(): array
{
$roleId = $this->route('role_id');
$roleId = $this->route('role');
return [
'name' => 'required|string|max:255|unique:roles,name,' . ($roleId ?? 'NULL') . ',id',
'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,37 +61,32 @@ class ServiceSIMBG
}
}
public function syncIndexIntegration($uuids, $token)
public function syncIndexIntegration($uuid, $token)
{
try{
if(empty($uuids)){
$url = "/api/pbg/v1/detail/" . $uuid . "/retribution/indeks-terintegrasi/";
$headers = [
'Authorization' => "Bearer " . $token,
];
$res = $this->service_client->get($url, $headers);
if (empty($res->original['success']) || !$res->original['success']) {
// Log error
Log::error("API response indicates failure", ['url' => $url, 'uuid' => $uuid]);
return false;
}
$integrations = [];
foreach($uuids as $uuid){
$url = "/api/pbg/v1/detail/" . $uuid . "/retribution/indeks-terintegrasi/";
$headers = [
'Authorization' => "Bearer " . $token,
];
$res = $this->service_client->get($url, $headers);
if (empty($res->original['success']) || !$res->original['success']) {
// Log error
Log::error("API response indicates failure", ['url' => $url, 'uuid' => $uuid]);
return false;
}
$data = $res->original['data']['data'] ?? null;
if (!$data) {
Log::error("No valid data returned from API", ['url' => $url, 'uuid' => $uuid]);
return false;
}
$integrations[] = [
'pbg_task_uid' => $uuid,
$data = $res->original['data']['data'] ?? null;
if (!$data) {
Log::error("No valid data returned from API", ['url' => $url, 'uuid' => $uuid]);
return false;
}
$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,
@@ -99,24 +94,8 @@ class ServiceSIMBG
'faktor_kepemilikan' => $data['faktor_kepemilikan'] ?? null,
'indeks_terintegrasi' => $data['indeks_terintegrasi'] ?? 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;
}catch (Exception $e){
@@ -211,7 +190,7 @@ class ServiceSIMBG
'created_at' => now(),
];
// $this->syncIndexIntegration($item['uid'], $token);
$this->syncIndexIntegration($item['uid'], $token);
$this->syncTaskDetailSubmit($item['uid'], $token);
@@ -236,11 +215,8 @@ class ServiceSIMBG
'slf_status', 'slf_status_name', 'function_type', 'consultation_type', 'due_date',
'land_certificate_phase', 'task_created_at', 'updated_at'
]);
$uuids = array_column($tasksCollective, 'uuid');
$this->syncIndexIntegration($uuids, $token);
}
$importDatasource->update([
'status' => ImportDatasourceStatus::Success->value,
'message' => "Successfully processed: $savedCount, Failed: $failedCount"
@@ -335,4 +311,5 @@ class ServiceSIMBG
}
}
}
}

View File

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

2
package-lock.json generated
View File

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

View File

@@ -2,30 +2,6 @@ import bootstrap from "bootstrap/dist/js/bootstrap";
window.bootstrap = bootstrap;
import "iconify-icon";
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 {
initBootstrapComponents() {
@@ -131,7 +107,6 @@ class FormValidation {
}
document.addEventListener("DOMContentLoaded", function (e) {
new Components().init(), new FormValidation().init();
// new InitDatePicker().init();
});
class ThemeLayout {
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/dist/gridjs.umd.js";
import GlobalConfig from "../global-config.js";
import Swal from "sweetalert2";
class BusinessIndustries {
constructor() {
this.toastMessage = document.getElementById("toast-message");
this.toastElement = document.getElementById("toastNotification");
this.toast = new bootstrap.Toast(this.toastElement);
this.table = null;
// Initialize functions
this.initTableBusinessIndustries();
this.initEvents();
this.table = null; // Store Grid.js instance
}
initEvents() {
document.body.addEventListener("click", async (event) => {
const deleteButton = event.target.closest(
".btn-delete-business-industry"
);
if (deleteButton) {
event.preventDefault();
await this.handleDelete(deleteButton);
}
});
init() {
this.getFetchApiData();
}
initTableBusinessIndustries() {
getFetchApiData() {
let tableContainer = document.getElementById(
"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({
columns: [
{ name: "ID", width: "80px", hidden: false },
@@ -49,20 +71,27 @@ class BusinessIndustries {
{ name: "Tahun Pajak", width: "120px" },
{ name: "Created", width: "180px" },
{
name: "Action",
formatter: (cell) =>
gridjs.html(`
<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">
<i class='bx bx-edit'></i>
</a>
<button data-id="${cell}" class="btn btn-sm btn-red btn-delete-business-industry d-inline-flex align-items-center justify-content-center">
<i class='bx bxs-trash' ></i>
</button>
</div>
`),
name: "Actions",
width: "120px",
formatter: function (cell) {
return gridjs.html(`
<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">
<i class='bx bx-edit'></i>
</a>
<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>
</button>
</div>
`);
},
},
],
search: {
server: {
url: (prev, keyword) => `${prev}?search=${keyword}`,
},
},
pagination: {
limit: 15,
server: {
@@ -73,11 +102,6 @@ class BusinessIndustries {
},
},
sort: true,
search: {
server: {
url: (prev, keyword) => `${prev}?search=${keyword}`,
},
},
server: {
url: `${GlobalConfig.apiHost}/api/api-business-industries`,
headers: {
@@ -107,26 +131,98 @@ class BusinessIndustries {
total: (data) => data.total,
},
}).render(tableContainer);
document.addEventListener("click", this.handleDelete.bind(this));
}
async handleDelete(deleteButton) {
const id = deleteButton.getAttribute("data-id");
handleDelete(event) {
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({
title: "Are you sure?",
text: "You won't be able to revert this!",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: "Yes, delete it!",
});
if (!modalElement) {
console.error("Modal element not found!");
return;
}
if (result.isConfirmed) {
try {
let response = await fetch(
`${GlobalConfig.apiHost}/api/api-business-industries/${id}`,
{
method: "DELETE",
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-business-industries-id", id);
// Show the modal
modal.show();
btnSaveConfirmation.addEventListener("click", async () => {
let deletedId = btnSaveConfirmation.getAttribute(
"data-business-industries-id"
);
try {
let response = await fetch(
`${GlobalConfig.apiHost}/api/api-business-industries/${deletedId}`,
{
method: "DELETE",
credentials: "include",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
"Content-Type": "application/json",
},
}
);
if (response.ok) {
let result = await response.json();
toastMessage.innerText =
result.message || "Deleted successfully!";
toast.show();
// Hide modal
modal.hide();
// Refresh Grid.js table
this.refreshDataSettings();
} 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();
}
});
}
}
refreshDataSettings() {
if (this.table) {
this.table
.updateConfig({
server: {
url: `${GlobalConfig.apiHost}/api/api-business-industries`,
credentials: "include",
headers: {
Authorization: `Bearer ${document
@@ -134,34 +230,31 @@ class BusinessIndustries {
.getAttribute("content")}`,
"Content-Type": "application/json",
},
}
);
if (response.ok) {
let result = await response.json();
this.toastMessage.innerText =
result.message || "Deleted successfully!";
this.toast.show();
// Refresh Grid.js table
if (typeof this.table !== "undefined") {
this.table.updateConfig({}).forceRender();
}
} else {
let error = await response.json();
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();
}
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) {
new BusinessIndustries();
new BusinessIndustries().init();
});

View File

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

View File

@@ -12,7 +12,7 @@ class Customers {
this.table = null;
// Initialize functions
this.initTableCustomers();
this.initTableSpatialPlannings();
this.initEvents();
}
initEvents() {
@@ -25,7 +25,7 @@ class Customers {
});
}
initTableCustomers() {
initTableSpatialPlannings() {
let tableContainer = document.getElementById("table-customers");
// Create a new Grid.js instance only if it doesn't exist
this.table = new Grid({

View File

@@ -1,141 +1,165 @@
import Big from "big.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 {
async init() {
try {
new InitDatePicker(
"#datepicker-dashboard-bigdata",
this.handleChangeDate.bind(this)
).init();
this.filterYear = new Date().getFullYear(); // Set initial year
let yearSelect = document.querySelector("#yearPicker");
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
this.updateData("latest");
await this.updateData(this.filterYear);
} catch (error) {
console.error("Error initializing data:", error);
}
}
handleChangeDate(filterDate) {
if (!filterDate) return;
this.updateData(filterDate);
updateYear(value) {
let inputYear = parseInt(value, 10);
if (!isNaN(inputYear)) {
this.filterYear = inputYear;
this.updateData(this.filterYear);
} else {
console.error("Invalid year input");
}
}
async updateData(filterDate) {
async updateData(year) {
try {
console.log("Filtering data for date:", filterDate);
this.resumeBigData = await this.getBigDataResume(filterDate);
// this.totalTargetPAD = await this.getDataSettings("TARGET_PAD");
// this.resultDataTotal = await this.getDataTotalPotensi(year);
// this.dataVerification = await this.getDataVerfication(year);
// this.dataNonVerification = await this.getDataNonVerfication(year);
// this.dataBusiness = await this.getDataBusiness(year);
// this.dataNonBusiness = await this.getDataNonBusiness(year);
// this.dataTataRuang = await this.getDataSettings("TATA_RUANG");
// this.dataSumRealisasiTerbit = await this.getDataSettings(
// "REALISASI_TERBIT_PBG_SUM"
// );
// this.dataCountRealisasiTerbit = await this.getDataSettings(
// "REALISASI_TERBIT_PBG_COUNT"
// );
// this.dataSumMenungguKlikDPMPTSP = await this.getDataSettings(
// "MENUNGGU_KLIK_DPMPTSP_SUM"
// );
// this.dataCountMenungguKlikDPMPTSP = await this.getDataSettings(
// "MENUNGGU_KLIK_DPMPTSP_COUNT"
// );
// this.dataSumProsesDinasTeknis = await this.getDataSettings(
// "PROSES_DINAS_TEKNIS_SUM"
// );
// this.dataCountProsesDinasTeknis = await this.getDataSettings(
// "PROSES_DINAS_TEKNIS_COUNT"
// );
this.totalTargetPAD = await this.getDataSettings("TARGET_PAD");
this.resultDataTotal = await this.getDataTotalPotensi(year);
this.dataVerification = await this.getDataVerfication(year);
this.dataNonVerification = await this.getDataNonVerfication(year);
this.dataBusiness = await this.getDataBusiness(year);
this.dataNonBusiness = await this.getDataNonBusiness(year);
this.dataTataRuang = await this.getDataSettings("TATA_RUANG");
this.dataSumRealisasiTerbit = await this.getDataSettings(
"REALISASI_TERBIT_PBG_SUM"
);
this.dataCountRealisasiTerbit = await this.getDataSettings(
"REALISASI_TERBIT_PBG_COUNT"
);
this.dataSumMenungguKlikDPMPTSP = await this.getDataSettings(
"MENUNGGU_KLIK_DPMPTSP_SUM"
);
this.dataCountMenungguKlikDPMPTSP = await this.getDataSettings(
"MENUNGGU_KLIK_DPMPTSP_COUNT"
);
this.dataSumProsesDinasTeknis = await this.getDataSettings(
"PROSES_DINAS_TEKNIS_SUM"
);
this.dataCountProsesDinasTeknis = await this.getDataSettings(
"PROSES_DINAS_TEKNIS_COUNT"
);
// // total potensi
// this.bigTargetPAD = new Big(this.totalTargetPAD ?? 0);
// this.bigTotalPotensi = new Big(this.resultDataTotal.totalData ?? 0);
// total potensi
this.bigTargetPAD = new Big(this.totalTargetPAD ?? 0);
this.bigTotalPotensi = new Big(this.resultDataTotal.totalData ?? 0);
// this.resultPercentage = 0;
// if (this.bigTotalPotensi > 0 && this.bigTargetPAD > 0) {
// this.resultPercentage = this.bigTotalPotensi
// .div(this.bigTargetPAD)
// .times(100)
// .toFixed(2);
// if (this.resultPercentage > 100) {
// this.resultPercentage = 100;
// }
// }
this.resultPercentage = 0;
if (this.bigTotalPotensi > 0 && this.bigTargetPAD > 0) {
this.resultPercentage = this.bigTotalPotensi
.div(this.bigTargetPAD)
.times(100)
.toFixed(2);
if (this.resultPercentage > 100) {
this.resultPercentage = 100;
}
}
// // tata ruang
// this.bigTotalTataRuang = new Big(this.dataTataRuang);
// this.percentageResultTataRuang =
// this.bigTotalTataRuang <= 0 || this.bigTotalPotensi <= 0
// ? 0
// : this.bigTotalTataRuang
// .div(this.bigTotalPotensi)
// .times(100)
// .toFixed(2);
// tata ruang
this.bigTotalTataRuang = new Big(this.dataTataRuang);
this.percentageResultTataRuang =
this.bigTotalTataRuang <= 0 || this.bigTotalPotensi <= 0
? 0
: this.bigTotalTataRuang
.div(this.bigTotalPotensi)
.times(100)
.toFixed(2);
// // kekurangan potensi
// this.totalKekuranganPotensi = new Big(
// this.bigTargetPAD - this.bigTotalPotensi
// );
// kekurangan potensi
this.totalKekuranganPotensi = new Big(
this.bigTargetPAD - this.bigTotalPotensi
);
// this.percentageKekuranganPotensi =
// this.totalKekuranganPotensi <= 0 || this.bigTargetPAD <= 0
// ? 0
// : this.totalKekuranganPotensi
// .div(this.bigTargetPAD)
// .times(100)
// .toFixed(2);
this.percentageKekuranganPotensi =
this.totalKekuranganPotensi <= 0 || this.bigTargetPAD <= 0
? 0
: this.totalKekuranganPotensi
.div(this.bigTargetPAD)
.times(100)
.toFixed(2);
// // non-verification documents
// this.bigTotalNonVerification = new Big(
// this.dataNonVerification.total
// );
// this.percentageResultNonVerification =
// this.bigTotalNonVerification <= 0 || this.bigTotalPotensi <= 0
// ? 0
// : this.bigTotalNonVerification
// .div(this.bigTotalPotensi)
// .times(100)
// .toFixed(2);
// non-verification documents
this.bigTotalNonVerification = new Big(
this.dataNonVerification.total
);
this.percentageResultNonVerification =
this.bigTotalNonVerification <= 0 || this.bigTotalPotensi <= 0
? 0
: this.bigTotalNonVerification
.div(this.bigTotalPotensi)
.times(100)
.toFixed(2);
// // verification documents
// this.bigTotalVerification = new Big(this.dataVerification.total);
// this.percetageResultVerification =
// this.bigTotalVerification <= 0 || this.bigTotalPotensi <= 0
// ? 0
// : this.bigTotalVerification
// .div(this.bigTargetPAD)
// .times(100)
// .toFixed(2);
// verification documents
this.bigTotalVerification = new Big(this.dataVerification.total);
this.percetageResultVerification =
this.bigTotalVerification <= 0 || this.bigTotalPotensi <= 0
? 0
: this.bigTotalVerification
.div(this.bigTargetPAD)
.times(100)
.toFixed(2);
// // business documents
// this.bigTotalBusiness = new Big(this.dataBusiness.total);
// this.percentageResultBusiness =
// this.bigTotalNonVerification <= 0 || this.bigTotalBusiness <= 0
// ? 0
// : this.bigTotalBusiness
// .div(this.bigTotalNonVerification)
// .times(100)
// .toFixed(2);
// business documents
this.bigTotalBusiness = new Big(this.dataBusiness.total);
this.percentageResultBusiness =
this.bigTotalNonVerification <= 0 || this.bigTotalBusiness <= 0
? 0
: this.bigTotalBusiness
.div(this.bigTotalNonVerification)
.times(100)
.toFixed(2);
// // non-business documents
// this.bigTotalNonBusiness = new Big(this.dataNonBusiness.total);
// this.percentageResultNonBusiness =
// this.bigTotalNonBusiness <= 0 ||
// this.bigTotalNonVerification <= 0
// ? 0
// : this.bigTotalNonBusiness
// .div(this.bigTotalNonVerification)
// .times(100)
// .toFixed(2);
// non-business documents
this.bigTotalNonBusiness = new Big(this.dataNonBusiness.total);
this.percentageResultNonBusiness =
this.bigTotalNonBusiness <= 0 ||
this.bigTotalNonVerification <= 0
? 0
: this.bigTotalNonBusiness
.div(this.bigTotalNonVerification)
.times(100)
.toFixed(2);
// if (!this.bigTargetPAD) {
// console.error("Failed to load chart data");
// return;
// }
if (!this.bigTargetPAD) {
console.error("Failed to load chart data");
return;
}
this.initChartTargetPAD();
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) {
try {
const response = await fetch(
@@ -373,60 +370,53 @@ class BigData {
.querySelectorAll(".document-total.chart-target-pad")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
// this.bigTargetPAD.toString()
this.resumeBigData.target_pad.sum.toString()
this.bigTargetPAD.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-target-pad")
.forEach((element) => {
element.innerText = `${this.resumeBigData.target_pad.percentage}%`;
element.innerText = `${100}%`;
});
}
initChartTotalPotensi() {
// const countAll = this.resultDataTotal.countData ?? 0;
const countAll = this.resultDataTotal.countData ?? 0;
document
.querySelectorAll(".document-count.chart-total-potensi")
.forEach((element) => {
// element.innerText = `${countAll}`;
element.innerText = `${this.resumeBigData.total_potensi.count}`;
element.innerText = `${countAll}`;
});
document
.querySelectorAll(".document-total.chart-total-potensi")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
// this.bigTotalPotensi.toString()
this.resumeBigData.total_potensi.sum.toString()
this.bigTotalPotensi.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-total-potensi")
.forEach((element) => {
// element.innerText = `${this.resultPercentage}%`;
element.innerText = `${this.resumeBigData.total_potensi.percentage}%`;
element.innerText = `${this.resultPercentage}%`;
});
}
initChartVerificationDocuments() {
document
.querySelectorAll(".document-count.chart-berkas-terverifikasi")
.forEach((element) => {
// element.innerText = `${this.dataVerification.count}`;
element.innerText = `${this.resumeBigData.verified_document.count}`;
element.innerText = `${this.dataVerification.count}`;
});
document
.querySelectorAll(".document-total.chart-berkas-terverifikasi")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
// this.bigTotalVerification.toString()
this.resumeBigData.verified_document.sum.toString()
this.bigTotalVerification.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-berkas-terverifikasi")
.forEach((element) => {
// element.innerText = `${this.percetageResultVerification}%`;
element.innerText = `${this.resumeBigData.verified_document.percentage}%`;
element.innerText = `${this.percetageResultVerification}%`;
});
}
initChartNonVerificationDocuments() {
@@ -435,8 +425,7 @@ class BigData {
".document-count.chart-berkas-belum-terverifikasi"
)
.forEach((element) => {
// element.innerText = `${this.dataNonVerification.count}`;
element.innerText = `${this.resumeBigData.non_verified_document.count}`;
element.innerText = `${this.dataNonVerification.count}`;
});
document
.querySelectorAll(
@@ -444,8 +433,7 @@ class BigData {
)
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
// this.bigTotalNonVerification.toString()
this.resumeBigData.non_verified_document.sum.toString()
this.bigTotalNonVerification.toString()
)}`;
});
document
@@ -453,52 +441,45 @@ class BigData {
".small-percentage.chart-berkas-belum-terverifikasi"
)
.forEach((element) => {
// element.innerText = `${this.percentageResultNonVerification}%`;
element.innerText = `${this.resumeBigData.non_verified_document.percentage}%`;
element.innerText = `${this.percentageResultNonVerification}%`;
});
}
initChartUsaha() {
document
.querySelectorAll(".document-count.chart-business")
.forEach((element) => {
// element.innerText = `${this.dataBusiness.count}`;
element.innerText = `${this.resumeBigData.business_document.count}`;
element.innerText = `${this.dataBusiness.count}`;
});
document
.querySelectorAll(".document-total.chart-business")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
// this.bigTotalBusiness.toString()
this.resumeBigData.business_document.sum.toString()
this.bigTotalBusiness.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-business")
.forEach((element) => {
// element.innerText = `${this.percentageResultBusiness}%`;
element.innerText = `${this.resumeBigData.business_document.percentage}%`;
element.innerText = `${this.percentageResultBusiness}%`;
});
}
initChartNonUsaha() {
document
.querySelectorAll(".document-count.chart-non-business")
.forEach((element) => {
// element.innerText = `${this.dataNonBusiness.count}`;
element.innerText = `${this.resumeBigData.non_business_document.count}`;
element.innerText = `${this.dataNonBusiness.count}`;
});
document
.querySelectorAll(".document-total.chart-non-business")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
// this.bigTotalNonBusiness.toString()
this.resumeBigData.non_business_document.sum.toString()
this.bigTotalNonBusiness.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-non-business")
.forEach((element) => {
// element.innerText = `${this.percentageResultNonBusiness}%`;
element.innerText = `${this.resumeBigData.non_business_document.percentage}%`;
element.innerText = `${this.percentageResultNonBusiness}%`;
});
}
initChartKekuranganPotensi() {
@@ -511,78 +492,70 @@ class BigData {
.querySelectorAll(".document-total.chart-kekurangan-potensi")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
// this.totalKekuranganPotensi.toString()
this.resumeBigData.kekurangan_potensi.sum.toString()
this.totalKekuranganPotensi.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-kekurangan-potensi")
.forEach((element) => {
// element.innerText = `${this.percentageKekuranganPotensi}%`;
element.innerText = `${this.resumeBigData.kekurangan_potensi.percentage}%`;
element.innerText = `${this.percentageKekuranganPotensi}%`;
});
}
initChartRealisasiTerbitPBG() {
document
.querySelectorAll(".document-count.chart-realisasi-tebit-pbg")
.forEach((element) => {
// element.innerText = `${this.dataCountRealisasiTerbit}`;
element.innerText = `${this.resumeBigData.realisasi_terbit.count}`;
element.innerText = `${this.dataCountRealisasiTerbit}`;
});
document
.querySelectorAll(".document-total.chart-realisasi-tebit-pbg")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
// this.dataSumRealisasiTerbit
this.resumeBigData.realisasi_terbit.sum.toString()
this.dataSumRealisasiTerbit
)}`;
});
document
.querySelectorAll(".small-percentage.chart-realisasi-tebit-pbg")
.forEach((element) => {
element.innerText = `${this.resumeBigData.realisasi_terbit.percentage}%`;
element.innerText = `0.00%`;
});
}
initChartMenungguKlikDPMPTSP() {
document
.querySelectorAll(".document-count.chart-menunggu-klik-dpmptsp")
.forEach((element) => {
// element.innerText = `${this.dataCountMenungguKlikDPMPTSP}`;
element.innerText = `${this.resumeBigData.menunggu_klik_dpmptsp.count}`;
element.innerText = `${this.dataCountMenungguKlikDPMPTSP}`;
});
document
.querySelectorAll(".document-total.chart-menunggu-klik-dpmptsp")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
// this.dataSumMenungguKlikDPMPTSP
this.resumeBigData.menunggu_klik_dpmptsp.sum.toString()
this.dataSumMenungguKlikDPMPTSP
)}`;
});
document
.querySelectorAll(".small-percentage.chart-menunggu-klik-dpmptsp")
.forEach((element) => {
element.innerText = `${this.resumeBigData.menunggu_klik_dpmptsp.percentage}%`;
element.innerText = `0.00%`;
});
}
initChartProsesDinasTeknis() {
document
.querySelectorAll(".document-count.chart-proses-dinas-teknis")
.forEach((element) => {
// element.innerText = `${this.dataCountProsesDinasTeknis}`;
element.innerText = `${this.resumeBigData.proses_dinas_teknis.count}`;
element.innerText = `${this.dataCountProsesDinasTeknis}`;
});
document
.querySelectorAll(".document-total.chart-proses-dinas-teknis")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
// this.dataSumProsesDinasTeknis
this.resumeBigData.proses_dinas_teknis.sum.toString()
this.dataSumProsesDinasTeknis
)}`;
});
document
.querySelectorAll(".small-percentage.chart-proses-dinas-teknis")
.forEach((element) => {
element.innerText = `${this.resumeBigData.proses_dinas_teknis.percentage}%`;
element.innerText = `0.00%`;
});
}
initChartPotensiTataRuang() {
@@ -595,15 +568,13 @@ class BigData {
.querySelectorAll(".document-total.chart-potensi-tata-ruang")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
// this.bigTotalTataRuang.toString()
this.resumeBigData.tata_ruang.sum.toString()
this.bigTotalTataRuang.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-potensi-tata-ruang")
.forEach((element) => {
// element.innerText = `${this.percentageResultTataRuang}%`;
element.innerText = `${this.resumeBigData.tata_ruang.percentage}%`;
element.innerText = `${this.percentageResultTataRuang}%`;
});
}
}

View File

@@ -1,42 +1,21 @@
import Big from "big.js";
import GlobalConfig, { addThousandSeparators } from "../global-config.js";
import InitDatePicker from "../utils/InitDatePicker.js";
class LackOfPotential {
async init() {
new InitDatePicker(
"#datepicker-lack-of-potential",
this.handleChangedDate.bind(this)
).init();
this.bigTotalLackPotential = 0;
this.totalPotensi = await this.getDataTotalPotensi("latest");
this.totalPotensi = await this.getDataTotalPotensi(2025);
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.bigTotalPotensi = new Big(this.totalPotensi.total ?? 0);
this.bigTotalLackPotential = this.bigTargetPAD.minus(
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.bigTotalPotensi = new Big(this.totalPotensi.totalData ?? 0);
this.bigTotalLackPotential = this.bigTargetPAD - this.bigTotalPotensi;
this.initChartKekuranganPotensi();
}
async getDataTotalPotensi(filterDate) {
async getDataTotalPotensi(year) {
try {
const response = await fetch(
`${GlobalConfig.apiHost}/api/bigdata-resume?filterByDate=${filterDate}`,
`${GlobalConfig.apiHost}/api/all-task-documents?year=${year}`,
{
credentials: "include",
headers: {
@@ -55,7 +34,8 @@ class LackOfPotential {
const data = await response.json();
return {
total: data.total_potensi.sum,
countData: data.data.count,
totalData: data.data.total,
};
} catch (error) {
console.error("Error fetching chart data:", error);
@@ -65,7 +45,7 @@ class LackOfPotential {
async getDataSettings(string_key) {
try {
const response = await fetch(
`${GlobalConfig.apiHost}/api/data-settings?search=${string_key}`,
`${GlobalConfig.apiHost}/api/api-data-settings?search=${string_key}`,
{
credentials: "include",
headers: {
@@ -89,33 +69,6 @@ class LackOfPotential {
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() {
document
.querySelectorAll(".document-count.chart-lack-of-potential")
@@ -135,12 +88,6 @@ class LackOfPotential {
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) {
await new LackOfPotential().init();

View File

@@ -24,9 +24,10 @@ document.addEventListener("DOMContentLoaded", function (e) {
method: "POST",
credentials: "include",
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
"Content-Type": "application/json",
},
body: formData,
});
@@ -34,7 +35,7 @@ document.addEventListener("DOMContentLoaded", function (e) {
if (response.ok) {
let result = await response.json();
document.getElementById("toast-message").innerText =
result.data.message;
result.message;
toast.show();
setTimeout(() => {
window.location.href = "/data-settings";
@@ -45,8 +46,6 @@ document.addEventListener("DOMContentLoaded", function (e) {
error.message;
toast.show();
console.error("Error:", error);
submitButton.disabled = false;
spinner.classList.add("d-none");
}
} catch (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/dist/gridjs.umd.js";
import GlobalConfig from "../global-config.js";
import Swal from "sweetalert2";
class DataSettings {
constructor() {
this.toastMessage = document.getElementById("toast-message");
this.toastElement = document.getElementById("toastNotification");
this.toast = new bootstrap.Toast(this.toastElement);
this.table = null;
// Initialize functions
this.initTableDataSettings();
this.initEvents();
this.table = null; // Store Grid.js instance
}
initEvents() {
document.body.addEventListener("click", async (event) => {
const deleteButton = event.target.closest(
".btn-delete-data-settings"
);
if (deleteButton) {
event.preventDefault();
await this.handleDelete(deleteButton);
}
});
init() {
this.getFetchApiData();
}
initTableDataSettings() {
getFetchApiData() {
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({
columns: [
"ID",
@@ -53,6 +65,11 @@ class DataSettings {
},
},
],
search: {
server: {
url: (prev, keyword) => `${prev}?search=${keyword}`,
},
},
pagination: {
limit: 15,
server: {
@@ -63,13 +80,8 @@ class DataSettings {
},
},
sort: true,
search: {
server: {
url: (prev, keyword) => `${prev}?search=${keyword}`,
},
},
server: {
url: `${GlobalConfig.apiHost}/api/data-settings`,
url: `${GlobalConfig.apiHost}/api/api-data-settings`,
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
@@ -87,26 +99,94 @@ class DataSettings {
total: (data) => data.meta.total,
},
}).render(tableContainer);
document.addEventListener("click", this.handleDelete.bind(this));
}
async handleDelete(deleteButton) {
const id = deleteButton.getAttribute("data-id");
handleDelete(event) {
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({
title: "Are you sure?",
text: "You won't be able to revert this!",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: "Yes, delete it!",
});
if (!modalElement) {
console.error("Modal element not found!");
return;
}
if (result.isConfirmed) {
try {
let response = await fetch(
`${GlobalConfig.apiHost}/api/data-settings/${id}`,
{
method: "DELETE",
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-settings-id", id);
// Show the modal
modal.show();
btnSaveConfirmation.addEventListener("click", async () => {
let dataSettingId =
btnSaveConfirmation.getAttribute("data-settings-id");
try {
let response = await fetch(
`/data-settings/${dataSettingId}`,
{
method: "DELETE",
credentials: "include",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
"Content-Type": "application/json",
},
}
);
if (response.ok) {
let result = await response.json();
toastMessage.innerText =
result.message || "Deleted successfully!";
toast.show();
// Hide modal
modal.hide();
// Refresh Grid.js table
this.refreshDataSettings();
} 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();
}
});
}
}
refreshDataSettings() {
if (this.table) {
this.table
.updateConfig({
server: {
url: `${GlobalConfig.apiHost}/api/api-data-settings`,
credentials: "include",
headers: {
Authorization: `Bearer ${document
@@ -114,34 +194,21 @@ class DataSettings {
.getAttribute("content")}`,
"Content-Type": "application/json",
},
}
);
if (response.ok) {
let result = await response.json();
this.toastMessage.innerText =
result.message || "Deleted successfully!";
this.toast.show();
// Refresh Grid.js table
if (typeof this.table !== "undefined") {
this.table.updateConfig({}).forceRender();
}
} else {
let error = await response.json();
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();
}
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) {
new DataSettings();
new DataSettings().init();
});

View File

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

View File

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

View File

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

View File

@@ -1,67 +1,55 @@
class CreateMenu {
constructor() {
this.initCreateMenu();
}
document.addEventListener("DOMContentLoaded", function (e) {
const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification);
document
.getElementById("btnCreateMenus")
.addEventListener("click", async function () {
let submitButton = this;
let spinner = document.getElementById("spinner");
let form = document.getElementById("formCreateMenus");
initCreateMenu() {
const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification);
document
.getElementById("btnCreateMenus")
.addEventListener("click", async function () {
let submitButton = this;
let spinner = document.getElementById("spinner");
let form = document.getElementById("formCreateMenus");
if (!form) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
if (!form) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
// Disable button and show spinner
submitButton.disabled = true;
spinner.classList.remove("d-none");
// Disable button and show spinner
submitButton.disabled = true;
spinner.classList.remove("d-none");
try {
let response = await fetch(form.action, {
method: "POST",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
},
body: formData,
});
try {
let response = await fetch(form.action, {
method: "POST",
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
},
body: formData,
});
if (response.ok) {
let result = await response.json();
document.getElementById("toast-message").innerText =
result.message;
toast.show();
setTimeout(() => {
window.location.href = "/menus";
}, 2000);
} else {
let error = await response.json();
document.getElementById("toast-message").innerText =
error.message;
toast.show();
console.error("Error:", error);
submitButton.disabled = false;
spinner.classList.add("d-none");
}
} catch (error) {
console.error("Request failed:", error);
if (response.ok) {
let result = await response.json();
document.getElementById("toast-message").innerText =
result.message;
toast.show();
setTimeout(() => {
window.location.href = "/menus";
}, 2000);
} else {
let error = await response.json();
document.getElementById("toast-message").innerText =
error.message;
toast.show();
console.error("Error:", error);
}
});
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new CreateMenu();
} catch (error) {
console.error("Request failed:", error);
document.getElementById("toast-message").innerText =
error.message;
toast.show();
}
});
});

View File

@@ -2,27 +2,13 @@ import { Grid } from "gridjs/dist/gridjs.umd.js";
import gridjs from "gridjs/dist/gridjs.umd.js";
import "gridjs/dist/gridjs.umd.js";
import GlobalConfig from "../global-config";
import Swal from "sweetalert2";
class Menus {
constructor() {
this.toastMessage = document.getElementById("toast-message");
this.toastElement = document.getElementById("toastNotification");
this.toast = new bootstrap.Toast(this.toastElement);
this.table = null;
// Initialize functions
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);
}
});
init() {
this.initTableMenus();
}
initTableMenus() {
@@ -33,7 +19,7 @@ class Menus {
this.table
.updateConfig({
server: {
url: `${GlobalConfig.apiHost}/api/menus`,
url: `${GlobalConfig.apiHost}/api/api-menus`,
credentials: "include",
headers: {
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">
<i class='bx bx-edit'></i>
</a>
<button data-id="${cell}"
class="btn btn-red btn-sm btn-delete-menu d-inline-flex align-items-center justify-content-center">
<button data-id="${cell}" class="btn btn-red btn-sm btn-delete-menu d-inline-flex align-items-center justify-content-center">
<i class='bx bxs-trash' ></i>
</button>
</div>
@@ -98,7 +83,7 @@ class Menus {
},
},
server: {
url: `${GlobalConfig.apiHost}/api/menus`,
url: `${GlobalConfig.apiHost}/api/api-menus`,
credentials: "include",
headers: {
Authorization: `Bearer ${document
@@ -119,63 +104,118 @@ class Menus {
total: (data) => data.total,
},
}).render(tableContainer);
document.addEventListener("click", this.handleDelete.bind(this));
}
async handleDelete(button) {
const id = button.getAttribute("data-id");
handleDelete(event) {
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({
title: "Are you sure?",
text: "You won't be able to revert this!",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: "Yes, delete it!",
});
if (!modalElement) {
console.error("Modal element not found!");
return;
}
if (result.isConfirmed) {
try {
let response = await fetch(
`${GlobalConfig.apiHost}/api/menus/${id}`,
{
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-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 (response.ok) {
let result = await response.json();
toastMessage.innerText =
result.message || "Deleted successfully!";
toast.show();
// 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",
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
"Content-Type": "application/json",
},
}
);
if (response.ok) {
let result = await response.json();
this.toastMessage.innerText =
result.message || "Deleted successfully!";
this.toast.show();
// Refresh Grid.js table
if (typeof this.table !== "undefined") {
this.table.updateConfig({}).forceRender();
}
} else {
let error = await response.json();
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();
}
then: (data) =>
data.data.map((item) => [
item.id,
item.name,
item.url,
item.icon,
item.parent_id,
item.sort_order,
item.id,
]),
total: (data) => data.total,
},
})
.forceRender();
} else {
this.initTableMenus(); // If no table exists, reinitialize it
}
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new Menus();
new Menus().init();
});

View File

@@ -1,67 +1,53 @@
class UpdateMenu {
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");
if (!form) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
// Disable button and show spinner
submitButton.disabled = true;
spinner.classList.remove("d-none");
try {
let response = await fetch(form.action, {
method: "POST",
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
},
body: formData,
});
if (response.ok) {
let result = await response.json();
document.getElementById("toast-message").innerText =
result.message;
toast.show();
setTimeout(() => {
window.location.href = "/menus";
}, 2000);
} else {
let error = await response.json();
document.getElementById("toast-message").innerText =
error.message;
toast.show();
console.error("Error:", error);
submitButton.disabled = false;
spinner.classList.add("d-none");
}
} catch (error) {
console.error("Request failed:", error);
document.getElementById("toast-message").innerText =
error.message;
toast.show();
}
});
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new UpdateMenu();
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) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
// Disable button and show spinner
submitButton.disabled = true;
spinner.classList.remove("d-none");
try {
let response = await fetch(form.action, {
method: "POST",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
},
body: formData,
});
if (response.ok) {
let result = await response.json();
toastMessage.innerText = result.message;
toast.show();
setTimeout(() => {
window.location.href = "/menus";
}, 2000);
} else {
let error = await response.json();
toastMessage.innerText = error.message;
toast.show();
console.error("Error:", error);
}
} catch (error) {
console.error("Request failed:", error);
toastMessage.innerText = error.message;
toast.show();
}
});
});

View File

@@ -1,67 +1,55 @@
class CreateRoles {
constructor() {
this.initCreateRole();
}
document.addEventListener("DOMContentLoaded", function (e) {
const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification);
document
.getElementById("btnCreateRole")
.addEventListener("click", async function () {
let submitButton = this;
let spinner = document.getElementById("spinner");
let form = document.getElementById("formCreateRole");
initCreateRole() {
const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification);
document
.getElementById("btnCreateRole")
.addEventListener("click", async function () {
let submitButton = this;
let spinner = document.getElementById("spinner");
let form = document.getElementById("formCreateRole");
if (!form) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
if (!form) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
// Disable button and show spinner
submitButton.disabled = true;
spinner.classList.remove("d-none");
// Disable button and show spinner
submitButton.disabled = true;
spinner.classList.remove("d-none");
try {
let response = await fetch(form.action, {
method: "POST",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
},
body: formData,
});
try {
let response = await fetch(form.action, {
method: "POST",
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
},
body: formData,
});
if (response.ok) {
let result = await response.json();
document.getElementById("toast-message").innerText =
result.message;
toast.show();
setTimeout(() => {
window.location.href = "/roles";
}, 2000);
} else {
let error = await response.json();
document.getElementById("toast-message").innerText =
error.message;
toast.show();
console.error("Error:", error);
submitButton.disabled = false;
spinner.classList.add("d-none");
}
} catch (error) {
console.error("Request failed:", error);
if (response.ok) {
let result = await response.json();
document.getElementById("toast-message").innerText =
result.message;
toast.show();
setTimeout(() => {
window.location.href = "/roles";
}, 2000);
} else {
let error = await response.json();
document.getElementById("toast-message").innerText =
error.message;
toast.show();
console.error("Error:", error);
}
});
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new CreateRoles();
} catch (error) {
console.error("Request failed:", error);
document.getElementById("toast-message").innerText =
error.message;
toast.show();
}
});
});

View File

@@ -2,31 +2,46 @@ import { Grid } from "gridjs/dist/gridjs.umd.js";
import gridjs from "gridjs/dist/gridjs.umd.js";
import "gridjs/dist/gridjs.umd.js";
import GlobalConfig from "../global-config";
import Swal from "sweetalert2";
class Roles {
constructor() {
this.toastMessage = document.getElementById("toast-message");
this.toastElement = document.getElementById("toastNotification");
this.toast = new bootstrap.Toast(this.toastElement);
this.table = null;
// Initialize functions
this.initTableRoles();
this.initEvents();
this.table = null; // Store Grid.js instance
}
initEvents() {
document.body.addEventListener("click", async (event) => {
const deleteButton = event.target.closest(".btn-delete-role");
if (deleteButton) {
event.preventDefault();
await this.handleDelete(deleteButton);
}
});
init() {
this.initTableRoles();
}
initTableRoles() {
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
this.table = new gridjs.Grid({
columns: [
@@ -67,7 +82,7 @@ class Roles {
},
},
server: {
url: `${GlobalConfig.apiHost}/api/roles`,
url: `${GlobalConfig.apiHost}/api/api-roles`,
credentials: "include",
headers: {
Authorization: `Bearer ${document
@@ -85,63 +100,116 @@ class Roles {
total: (data) => data.total,
},
}).render(tableContainer);
document.addEventListener("click", this.handleDelete.bind(this));
}
async handleDelete(deleteButton) {
const id = deleteButton.getAttribute("data-id");
handleDelete(event) {
if (event.target.classList.contains("btn-delete-role")) {
event.preventDefault();
const result = await Swal.fire({
title: "Are you sure?",
text: "You won't be able to revert this!",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: "Yes, delete it!",
});
const id = event.target.getAttribute("data-id");
let modalElement = document.getElementById("modalConfirmation");
let toastMessage = document.getElementById("toast-message");
if (result.isConfirmed) {
try {
let response = await fetch(
`${GlobalConfig.apiHost}/api/roles/${id}`,
{
if (!modalElement) {
console.error("Modal element not found!");
return;
}
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 (response.ok) {
let result = await response.json();
toastMessage.innerText =
result.message || "Deleted successfully!";
toast.show();
// 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",
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
"Content-Type": "application/json",
},
}
);
if (response.ok) {
let result = await response.json();
this.toastMessage.innerText =
result.message || "Deleted successfully!";
this.toast.show();
// Refresh Grid.js table
if (typeof this.table !== "undefined") {
this.table.updateConfig({}).forceRender();
}
} else {
let error = await response.json();
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();
}
then: (data) =>
data.data.map((item) => [
item.id,
item.name,
item.description,
item.id,
]),
total: (data) => data.total,
},
})
.forceRender();
} else {
this.initTableRoles(); // If the table is null, reinitialize
}
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new Roles();
new Roles().init();
});

View File

@@ -1,67 +1,53 @@
class UpdateRoles {
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");
if (!form) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
// Disable button and show spinner
submitButton.disabled = true;
spinner.classList.remove("d-none");
try {
let response = await fetch(form.action, {
method: "POST",
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
},
body: formData,
});
if (response.ok) {
let result = await response.json();
document.getElementById("toast-message").innerText =
result.message;
toast.show();
setTimeout(() => {
window.location.href = "/roles";
}, 2000);
} else {
let error = await response.json();
document.getElementById("toast-message").innerText =
error.message;
toast.show();
console.error("Error:", error);
submitButton.disabled = false;
spinner.classList.add("d-none");
}
} catch (error) {
console.error("Request failed:", error);
document.getElementById("toast-message").innerText =
error.message;
toast.show();
}
});
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new UpdateRoles();
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) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
// Disable button and show spinner
submitButton.disabled = true;
spinner.classList.remove("d-none");
try {
let response = await fetch(form.action, {
method: "POST",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
},
body: formData,
});
if (response.ok) {
let result = await response.json();
toastMessage.innerText = result.message;
toast.show();
setTimeout(() => {
window.location.href = "/roles";
}, 2000);
} else {
let error = await response.json();
toastMessage.innerText = error.message;
toast.show();
console.error("Error:", error);
}
} catch (error) {
console.error("Request failed:", error);
toastMessage.innerText = error.message;
toast.show();
}
});
});

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-body">
<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 id="table-business-industries"></div>
</div>

View File

@@ -1,5 +1,5 @@
@props(['title' => 'title component', 'visible_data' => false, 'data_count' => '', 'visible_data_type' => false,
'data_type' => '','style' => '', 'size' => '', 'line' => [], 'data_id' => ''])
@props(['title' => 'title component', 'visible_data' => false, 'data' => 'data text', 'visible_data_type' => false,
'data_type' => '','style' => '', 'size' => '', 'line' => []])
@section('css')
@vite(['resources/scss/components/_custom_circle.scss'])
@@ -9,7 +9,7 @@
<div class="custom-circle-content">
<p class="custom-circle-text">{{ $title }}</p>
@if ($visible_data === "true")
<div class="custom-circle-data" id="{{ $data_id }}">{{ $data_count }}</div>
<div class="custom-circle-data">{{ $data }}</div>
@endif
@if ($visible_data_type === "true")
<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="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" style="max-width: 125px;" id="datepicker-dashboard-bigdata" placeholder="Filter Date" />
<div class="d-flex flex-sm-nowrap flex-wrap justify-content-end gap-2">
<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>

View File

@@ -15,103 +15,100 @@
</h3>
</div>
</div>
<div class="wrapper">
<div class="row d-flex justify-content-end">
<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 class="">
<div class="">
<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;">
<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>
<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>
<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>
<div style="position: absolute; top: 300px; left: 200px;">
<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>
<x-custom-circle title="BAPENDA" 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;" />
</div>
<div style="position: absolute; top: 0px; left: 270px;">
<div class="square" style="width:5px;height:600px;background-color:black;left:70px;top:50px;"></div>
<div class="square dia-top-left-bottom-right" style="top:350px;left:-50px;width:120px;height:120px;"></div>
<div class="square dia-top-right-bottom-left" style="top:350px;left:70px;width:120px;height:120px;"></div>
<x-custom-circle title="Rumah Tinggal" size="small" style="background-color: #234f6c;margin:auto;" />
<x-custom-circle title="Non Usaha" size="large" style="background-color: #3a968b;margin-top:20px;" />
<x-custom-circle title="USAHA" size="large" style="background-color: #627c8b;margin-top:150px;" />
</div>
<div style="position: absolute; top: 650px; left: 110px;">
<div class="square dia-top-right-bottom-left" style="top:-110px;left:40px;width:200px;height:120px;"></div>
<div class="square dia-top-right-bottom-left" style="top:-110px;left:90px;width:150px;height:170px;"></div>
<div class="square dia-top-left-bottom-right" style="top:-110px;left:230px;width:150px;height:170px;"></div>
<div class="square dia-top-left-bottom-right" style="top:-110px;left:260px;width:200px;height:180px;"></div>
<x-custom-circle title="Villa" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="Pabrik" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="Jalan Protocol" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="Ruko" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="Pariwisata" size="small" style="float:left;background-color: #234f6c; margin-right: 20px;" />
<div class="square" style="width:150px;height:2px;background-color:black;left:350px;top:50px;"></div>
<x-custom-circle title="DISBUDPAR" size="small" style="background-color: #3a968b;" />
</div>
<div style="position: absolute; top: 280px; left: 550px;">
<div class="square dia-top-left-bottom-right" style="top:-110px;left:-150px;width:200px;height:180px;"></div>
<div class="square dia-top-right-bottom-left" style="top:70px;left:-150px;width:200px;height:130px;"></div>
<x-custom-circle title="Tim Wasdal Gabungan" size="large" style="background-color: #da6635;float:left" />
<div class="square" style="width:650px;height:5px;background-color:black;left:100px;top:75px;"></div>
@component('components.circle', [
'document_title' => 'Kekurangan Potensi',
'document_color' => '#ff5757',
'document_type' => '',
'document_id' => 'chart-lack-of-potential',
'visible_small_circle' => false,
'style' => 'margin-left:180px;top:-20px;'
])
@endcomponent
<x-custom-circle title="Tata Ruang" size="large" style="background-color: #da6635;float:left;margin-left:250px;" />
</div>
<div style="position: absolute; top: 310px; left: 1150px;">
<div class="square dia-top-left-bottom-right" style="top:90px;left:-100px;width:100px;height:100px;"></div>
<div class="square dia-top-right-bottom-left" style="top:-110px;left:-100px;width:100px;height:100px;"></div>
<x-custom-circle title="Peta" visible_data_type="true" data_type="1:5000" size="small" style="background-color: #224f6d;float:left;" />
<x-custom-circle title="Tapak Bangunan" size="small" style="background-color: #2390af;float:left;margin-left:20px;" />
</div>
<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 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:-50px;left:100px;width:100px;height:100px;"></div>
<div class="square dia-top-left-bottom-right" style="top:-50px;left:180px;width:100px;height:100px;"></div>
<div class="square dia-top-left-bottom-right" style="top:-60px;left:240px;width:120px;height:120px;"></div>
<x-custom-circle title="UPT Wasdal" size="small" style="background-color: #0f4853;float:left;" />
<x-custom-circle title="Satpol PP" size="small" style="background-color: #0f4853;float:left;" />
<x-custom-circle title="KEJARI" size="small" style="background-color: #0f4853;float:left;" />
<x-custom-circle title="TNI & POLRI" size="small" style="background-color: #0f4853;float:left;" />
</div>
<x-custom-circle title="UUCK" size="small" style="background-color: #2390af;position:absolute;left:980px;top:500px;" />
<div style="position: absolute; top: 50px; left: 1100px;">
<x-custom-circle title="Non Usaha" size="large" style="background-color: #3a968b;margin-top:20px;" />
<x-custom-circle title="USAHA" size="large" style="background-color: #627c8b;margin-top:260px;" />
</div>
</div>
</div>
<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;">
<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>
<x-custom-circle title="PBB Bangunan" visible_data="true" data_id="pbb-bangunan-count" data_count="0" size="small" style="background-color: #0e4753;" />
<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;" />
<div class="square dia-top-right-bottom-left" style="top:140px;left:50px;width:150px;height:120px;"></div>
</div>
<div style="position: absolute; top: 300px; left: 200px;">
<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>
<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="KECAMATAN" size="small" style="float:left;background-color: #234f6c;" />
</div>
<div style="position: absolute; top: 0px; left: 270px;">
<div class="square" style="width:5px;height:600px;background-color:black;left:70px;top:50px;"></div>
<div class="square dia-top-left-bottom-right" style="top:350px;left:-50px;width:120px;height:120px;"></div>
<div class="square dia-top-right-bottom-left" style="top:350px;left:70px;width:120px;height:120px;"></div>
<x-custom-circle title="Rumah Tinggal" size="small" style="background-color: #234f6c;margin:auto;" />
<x-custom-circle title="Non Usaha" size="large" style="background-color: #3a968b;margin-top:20px;" />
<x-custom-circle title="USAHA" size="large" style="background-color: #627c8b;margin-top:150px;" />
</div>
<div style="position: absolute; top: 650px; left: 110px;">
<div class="square dia-top-right-bottom-left" style="top:-110px;left:40px;width:200px;height:120px;"></div>
<div class="square dia-top-right-bottom-left" style="top:-110px;left:90px;width:150px;height:170px;"></div>
<div class="square dia-top-left-bottom-right" style="top:-110px;left:230px;width:150px;height:170px;"></div>
<div class="square dia-top-left-bottom-right" style="top:-110px;left:260px;width:200px;height:180px;"></div>
<x-custom-circle title="Villa" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="Pabrik" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="Jalan Protocol" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="Ruko" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="Pariwisata" size="small" style="float:left;background-color: #234f6c; margin-right: 20px;" />
<div class="square" style="width:150px;height:2px;background-color:black;left:350px;top:50px;"></div>
<x-custom-circle title="DISBUDPAR" size="small" style="background-color: #3a968b;" />
</div>
<div style="position: absolute; top: 280px; left: 550px;">
<div class="square dia-top-left-bottom-right" style="top:-110px;left:-150px;width:200px;height:180px;"></div>
<div class="square dia-top-right-bottom-left" style="top:70px;left:-150px;width:200px;height:130px;"></div>
<x-custom-circle title="Tim Wasdal Gabungan" size="large" style="background-color: #da6635;float:left" />
<div class="square" style="width:650px;height:5px;background-color:black;left:100px;top:75px;"></div>
@component('components.circle', [
'document_title' => 'Kekurangan Potensi',
'document_color' => '#ff5757',
'document_type' => '',
'document_id' => 'chart-lack-of-potential',
'visible_small_circle' => false,
'style' => 'margin-left:180px;top:-20px;'
])
@endcomponent
<x-custom-circle title="Tata Ruang" size="large" style="background-color: #da6635;float:left;margin-left:250px;" />
</div>
<div style="position: absolute; top: 310px; left: 1150px;">
<div class="square dia-top-left-bottom-right" style="top:90px;left:-100px;width:100px;height:100px;"></div>
<div class="square dia-top-right-bottom-left" style="top:-110px;left:-100px;width:100px;height:100px;"></div>
<x-custom-circle title="Peta" visible_data_type="true" data_type="1:5000" size="small" style="background-color: #224f6d;float:left;" />
<x-custom-circle title="Tapak Bangunan" size="small" style="background-color: #2390af;float:left;margin-left:20px;" />
</div>
<x-custom-circle title="BPN" size="small" style="background-color: #2390af;position:absolute;left:1270px;top:440px;" />
<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:-50px;left:100px;width:100px;height:100px;"></div>
<div class="square dia-top-left-bottom-right" style="top:-50px;left:180px;width:100px;height:100px;"></div>
<div class="square dia-top-left-bottom-right" style="top:-60px;left:240px;width:120px;height:120px;"></div>
<x-custom-circle title="UPT Wasdal" size="small" style="background-color: #0f4853;float:left;" />
<x-custom-circle title="Satpol PP" size="small" style="background-color: #0f4853;float:left;" />
<x-custom-circle title="KEJARI" size="small" style="background-color: #0f4853;float:left;" />
<x-custom-circle title="TNI & POLRI" size="small" style="background-color: #0f4853;float:left;" />
</div>
<x-custom-circle title="UUCK" size="small" style="background-color: #2390af;position:absolute;left:980px;top:500px;" />
<div style="position: absolute; top: 50px; left: 1100px;">
<x-custom-circle title="Non Usaha" size="large" style="background-color: #3a968b;margin-top:20px;" />
<x-custom-circle title="USAHA" size="large" style="background-color: #627c8b;margin-top:260px;" />
</div>
</div>
</div>
</div>
@endsection

View File

@@ -8,11 +8,8 @@
<div class="row d-flex justify-content-center">
<div class="col-lg-6">
<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">
<form id="formDataSettings" action="{{ route('api.data-settings.store') }}" method="POST">
<form id="formDataSettings" action="{{ route('data-settings.store') }}" method="POST">
@csrf
<div class="mb-3">
<label for="key" class="form-label">Key</label>

View File

@@ -8,11 +8,8 @@
<div class="row d-flex justify-content-center">
<div class="col-lg-6">
<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">
<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
@method('PUT')
<div class="mb-3">

View File

@@ -9,6 +9,7 @@
@include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard'])
<x-toast-notification />
<x-modal-confirmation buttonText="Delete" confirmationMessage="Are you sure you want to delete this?" />
<div class="row">
<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="col-md-6">
<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">
<form id="formCreateMenus" action="{{route("api.menus.store")}}" method="post">
<form id="formCreateMenus" action="{{route("menus.store")}}" method="post">
@csrf
<div class="mb-3">
<label class="form-label" for="name">Name</label>

View File

@@ -12,11 +12,8 @@
<div class="row d-flex justify-content-center">
<div class="col-md-6">
<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">
<form id="formUpdateMenus" action="{{route("api.menus.update", $menu->id)}}" method="post">
<form id="formUpdateMenus" action="{{route("menus.update", $menu->id)}}" method="post">
@csrf
@method("put")
<div class="mb-3">

View File

@@ -8,11 +8,8 @@
<div class="row d-flex justify-content-center">
<div class="col-md-6">
<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">
<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
<div class="mb-3">
<label class="form-label" for="name">Name</label>

View File

@@ -8,11 +8,8 @@
<div class="row d-flex justify-content-center">
<div class="col-md-6">
<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">
<form id="formUpdateRole" action="{{route("api.roles.update", $role->id)}}" method="post" >
<form id="formUpdateRole" action="{{route("roles.update", $role->id)}}" method="post" >
@csrf
@method("put")
<div class="mb-3">

View File

@@ -7,9 +7,6 @@
<div class="row d-flex justify-content-center">
<div class="col-md-12">
<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">
<h5>Manage Permissions for Role: {{ $role->name }}</h5>
<form action="{{route("role-menu.permission.update", $role->id)}}" method="post">

View File

@@ -1,6 +1,5 @@
<?php
use App\Http\Controllers\Api\BigDataResumeController;
use App\Http\Controllers\Api\BusinessOrIndustriesController;
use App\Http\Controllers\Api\CustomersController;
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\GoogleSheetController;
use App\Http\Controllers\Api\ImportDatasourceController;
use App\Http\Controllers\Api\LackOfPotentialController;
use App\Http\Controllers\Api\MenusController;
use App\Http\Controllers\Api\PbgTaskController;
use App\Http\Controllers\Api\RequestAssignmentController;
@@ -82,13 +80,7 @@ Route::group(['middleware' => 'auth:sanctum'], function (){
Route::get('/download-template-spatialPlannings', [SpatialPlanningController::class, 'downloadExcelSpatialPlanning']);
// data-settings
// 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-data-settings', DataSettingController::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');
// menus api
Route::controller(MenusController::class)->group(function (){
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');
});
Route::apiResource('api-menus', MenusController::class);
// roles api
Route::controller(RolesController::class)->group(function (){
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');
});
Route::apiResource('api-roles', RolesController::class);
//business industries api
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::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\DataSettingController;
use App\Http\Controllers\Dashboards\BigDataController;
use App\Http\Controllers\GoogleApisController;
use App\Http\Controllers\Home\HomeController;
use App\Http\Controllers\Master\UsersController;
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('/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('/maps', [GoogleApisController::class, 'index'])->name('dashboard.maps');
});
// settings

File diff suppressed because one or more lines are too long