Compare commits

..

28 Commits

Author SHA1 Message Date
arifal
93f0ac5ef7 Merge branch 'feature/dashboard-pbg' into fix/dashboard-resume 2025-02-25 10:23:41 +07:00
@jamaludinarifrohman6661
8bae33519f feature: sebaran lokasi project pariwisata 2025-02-24 21:47:24 +07:00
@jamaludinarifrohman6661
6865e353e6 feature: first check point 2025-02-24 20:03:36 +07:00
arifal
bb4ab5c769 add filter date for dashboard 2025-02-24 19:00:09 +07:00
arifal hidayat
e743b82087 add remove disabled if error on data settings 2025-02-23 07:11:14 +07:00
arifal hidayat
c3c7b8e3ec fix js roles and add back button on card header 2025-02-23 07:08:50 +07:00
arifal hidayat
d49035ce8d fix js menus and handle api menus 2025-02-23 06:42:13 +07:00
arifal hidayat
ffd9d3514c fix business industries and data settings front end 2025-02-22 16:08:59 +07:00
arifal
675477c734 fix service sync simbg upsert integrations 2025-02-21 18:49:42 +07:00
arifal
4350c466e3 add backup db from local 2025-02-21 18:18:45 +07:00
arifal
5ab407d672 change get value dashboard pimpinan from resume bigdata 2025-02-21 18:09:32 +07:00
arifal
2aaa487746 fix get total data from api 2025-02-21 14:49:09 +07:00
arifal
080582f7ab add new menu peta in dashboard 2025-02-21 11:12:35 +07:00
arifal
91475aeead Merge branch 'dev' into feat/load-map-from-kmz 2025-02-21 10:43:06 +07:00
arifal
a7afbd69fb fix conflict spatial-plannings jamal 2025-02-21 09:07:15 +07:00
arifal
1ff5587050 merge conflix spatial-plannings 2025-02-21 08:42:08 +07:00
arifal
9c8a1a3f3f add vite js customers 2025-02-21 00:49:29 +07:00
arifal
5c4be7635b partial update crud customer data 2025-02-21 00:46:33 +07:00
arifal
7a56735099 done crud spatial plannings 2025-02-20 15:35:06 +07:00
arifal
5d50d6d6cc fix height card 2025-02-19 15:34:28 +07:00
arifal
39717d184c partial update create google map from kmz file 2025-02-19 14:31:12 +07:00
arifal
54146c8c08 partial update spatial plannings crud 2025-02-19 12:08:18 +07:00
arifal
e8da7193ef fix crud users 2025-02-19 11:23:15 +07:00
arifal
006c008542 done dashboard-potential 2025-02-19 07:22:06 +07:00
root
39bb8e6d5f hot fix vite and create view 2025-02-18 23:49:48 +00:00
arifal
7994a62cea change name dashboard 2025-02-19 06:24:44 +07:00
arifal
3a09e2e68a Merge branch 'bug-fix/tourisms' into feat/dashboard-kekurangan-potensi 2025-02-19 06:17:16 +07:00
arifal
116dc1c8c7 add dashboard potential 2025-02-19 06:15:35 +07:00
169 changed files with 4068 additions and 3568 deletions

View File

@@ -0,0 +1,241 @@
<?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

@@ -0,0 +1,130 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\CustomersRequest;
use App\Http\Requests\ExcelUploadRequest;
use App\Http\Resources\CustomersResource;
use App\Imports\CustomersImport;
use App\Models\Customer;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;
class CustomersController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
$query = Customer::query()->orderBy('id', 'desc');
if ($request->has('search') &&!empty($request->get('search'))) {
$query = $query->where('nomor_pelanggan', 'LIKE', '%'.$request->get('search').'%')
->orWhere('nama', 'LIKE', '%'.$request->get('search').'%')
->orWhere('kota_palayanan', 'LIKE', '%'.$request->get('search').'%');
}
return CustomersResource::collection($query->paginate());
}
/**
* Store a newly created resource in storage.
*/
public function store(CustomersRequest $request)
{
try{
$customer = Customer::create($request->validated());
return response()->json(['message' => 'Successfully created', new CustomersResource($customer)]);
}catch(\Exception $e){
return response()->json([
'message' => 'Failed to create customer',
'error' => $e->getMessage()
], 500);
}
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
try{
$customer = Customer::find($id);
if($customer){
return new CustomersResource($customer);
} else {
return response()->json(['message' => 'Customer not found'], 404);
}
}catch(\Exception $e){
return response()->json([
'message' => 'Failed to retrieve customer',
'error' => $e->getMessage()
], 500);
}
}
/**
* Update the specified resource in storage.
*/
public function update(CustomersRequest $request, string $id)
{
try{
$customer = Customer::find($id);
if($customer){
$customer->update($request->validated());
return response()->json(['message' => 'Successfully updated', new CustomersResource($customer)]);
} else {
return response()->json(['message' => 'Customer not found'], 404);
}
}catch(\Exception $e) {
return response()->json([
'message' => 'Failed to update customer',
'error' => $e->getMessage()
], 500);
}
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
try{
$customer = Customer::find($id);
if($customer){
$customer->delete();
return response()->json(['message' => 'Successfully deleted']);
}else {
return response()->json(['message' => 'Customer not found'], 404);
}
}catch(\Exception $e) {
return response()->json([
'message' => 'Failed to delete customer',
'error' => $e->getMessage()
], 500);
}
}
public function upload(ExcelUploadRequest $request){
try{
if(!$request->hasFile('file')){
return response()->json([
'error' => 'No file provided'
], 400);
}
$file = $request->file('file');
Excel::import(new CustomersImport, $file);
return response()->json([
'message' => 'File uploaded successfully',
]);
}catch(\Exception $e){
\Log::info($e->getMessage());
return response()->json([
'error' => 'Failed to upload file',
'message' => $e->getMessage()
], 500);
}
}
}

View File

@@ -0,0 +1,31 @@
<?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,8 +3,11 @@
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
{
@@ -13,7 +16,7 @@ class MenusController extends Controller
*/
public function index(Request $request)
{
$query = Menu::query();
$query = Menu::query()->orderBy('id', 'desc');
if($request->has("search") && !empty($request->get("search"))){
$query = $query->where("name", "like", "%".$request->get("search")."%");
@@ -25,9 +28,15 @@ class MenusController extends Controller
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
public function store(MenuRequest $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);
}
}
/**
@@ -35,15 +44,37 @@ 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(Request $request, string $id)
public function update(MenuRequest $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);
}
}
/**
@@ -51,6 +82,28 @@ 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

@@ -21,9 +21,35 @@ class PbgTaskController extends Controller
public function __construct(GoogleSheetService $googleSheetService){
$this->googleSheetService = $googleSheetService;
}
public function index()
public function index(Request $request)
{
//
info($request);
$isLastUpdated = filter_var($request->query('isLastUpdated', false), FILTER_VALIDATE_BOOLEAN);
$query = PbgTask::query();
if ($isLastUpdated) {
$query->orderBy('updated_at', 'desc');
} else {
$query->where('status', 20);
}
// Ambil maksimal 10 data
$pbg_task = $query->limit(10)->get();
$totalData = $pbg_task->count();
// Tambahkan nomor urut
$data = $pbg_task->map(function ($item, $index) {
return array_merge($item->toArray(), ['no' => $index + 1]);
});
return response()->json([
'data' => $data,
'meta' => [
'total' => $totalData
]
]);
}
/**

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\RoleRequest;
use App\Models\Role;
use Illuminate\Http\Request;
@@ -13,7 +14,7 @@ class RolesController extends Controller
*/
public function index(Request $request)
{
$query = Role::query();
$query = Role::query()->orderBy('id', 'desc');
if($request->has('search') && !empty($request->get('search'))){
$query = $query->where('name', 'like', '%'. $request->get('search') . '%');
@@ -25,9 +26,14 @@ class RolesController extends Controller
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
public function store(RoleRequest $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);
}
}
/**
@@ -35,15 +41,34 @@ 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(Request $request, string $id)
public function update(RoleRequest $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);
}
}
/**
@@ -51,6 +76,16 @@ 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

@@ -106,6 +106,18 @@ class TourismController extends Controller
}
}
public function getAllLocation()
{
$locations = Tourism::whereNotNull('longitude')
->whereNotNull('latitude')
->select('project_name', 'longitude', 'latitude')
->get();
return response()->json([
'data' => $locations
]);
}
/**
* Display the specified resource.
*/

View File

@@ -38,20 +38,20 @@ class UsersController extends Controller
return response()->json(['message' => 'logged out successfully']);
}
public function store(UsersRequest $request){
$validate_data = $request->validated();
$validate_data = $request->validated();
DB::beginTransaction();
try{
$user = User::create([
'name' => $validate_data->name,
'email' => $validate_data->email,
'password' => Hash::make($validate_data->password),
'firstname' => $validate_data->firstname,
'lastname' => $validate_data->lastname,
'position' => $validate_data->position
'name' => $validate_data['name'],
'email' => $validate_data['email'],
'password' => Hash::make($validate_data['password']),
'firstname' => $validate_data['firstname'],
'lastname' => $validate_data['lastname'],
'position' => $validate_data['position'],
]);
$user->roles()->attach($request->role_id);
$user->roles()->attach((int) $validate_data['role_id']);
DB::commit();
return response()->json(['message' => 'Successfully created'],201);
@@ -60,4 +60,27 @@ class UsersController extends Controller
return response()->json(['message' => $e->getMessage()],500);
};
}
public function update(UsersRequest $request, $id){
try{
$validate_data = $request->validated();
$user = User::findOrFail($id);
DB::beginTransaction();
$user->update([
'name' => $validate_data['name'],
'email' => $validate_data['email'],
'firstname' => $validate_data['firstname'],
'lastname' => $validate_data['lastname'],
'position' => $validate_data['position']
]);
$user->roles()->sync($request->role_id);
DB::commit();
return response()->json(['message' => 'Successfully updated'], 200);
}catch(\Exception $e){
DB::rollBack();
return response()->json(['message' => $e->getMessage()],500);
}
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Http\Controllers;
use App\Models\Customer;
use Illuminate\Http\Request;
class CustomersController extends Controller
{
public function index()
{
return view('customers.index');
}
public function create()
{
return view('customers.create');
}
public function edit(string $id)
{
$data = Customer::findOrFail($id);
return view('customers.edit', compact('data'));
}
public function upload(){
return view('customers.upload');
}
}

View File

@@ -15,7 +15,8 @@ class BigDataController extends Controller
return view('dashboards.bigdata', compact('latest_created'));
}
public function pbg(){
return view('index');
public function pbg()
{
return view('dashboards.pbg');
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Http\Controllers\Dashboards;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class LackOfPotentialController extends Controller
{
public function lack_of_potential(){
return view('dashboards.lack_of_potential');
}
}

View File

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

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CustomersRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'nomor_pelanggan' => ['required', 'string'],
'kota_pelayanan' => ['required', 'string'],
'nama' => ['required', 'string'],
'alamat' => ['required', 'string'],
'latitude' => ['required', 'numeric', 'between:-90,90'],
'longitude' => ['required', 'numeric', 'between:-180,180'],
];
}
}

View File

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

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ExcelUploadRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
"file" => "required|file|mimes:xlsx,xls|max:102400"
];
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class MenuRequest extends FormRequest
{
@@ -21,12 +22,14 @@ 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'],
'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', 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'],
];
}
}

View File

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

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class SpatialPlanningsRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'name' => ['required','string','max:255'],
'kbli' => ['required','string','max:255'],
'kegiatan' => ['required','string'],
'luas' => ['required','numeric','regex:/^\d{1,16}(\.\d{1,2})?$/'],
'lokasi' => ['required','string'],
'nomor' => ['required','string','max:255',Rule::unique('spatial_plannings')->ignore($this->id)],
'sp_date' => ['required','date'],
];
}
}

View File

@@ -22,7 +22,7 @@ class UsersRequest extends FormRequest
*/
public function rules(): array
{
$userId = $this->route('user'); // Get user ID from route (used in update)
$userId = $this->route('users'); // Get user ID from route (used in update)
return [
'name' => ['required', 'string', 'max:255'],
@@ -31,7 +31,7 @@ class UsersRequest extends FormRequest
'string',
'email',
'max:255',
Rule::unique('users')->ignore($userId), // Ignore the user's own email when updating
Rule::unique('users')->ignore($userId)
],
'password' => [$this->isMethod('post') ? 'required' : 'nullable', 'confirmed', 'max:255'],
'firstname' => ['required', 'string', 'max:255'],

View File

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

View File

@@ -0,0 +1,19 @@
<?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

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

View File

@@ -0,0 +1,52 @@
<?php
namespace App\Imports;
use App\Models\Customer;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithLimit;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
class CustomersImport implements ToCollection, WithMultipleSheets
{
/**
* @param Collection $collection
*/
public function collection(Collection $collection)
{
$batchData = [];
foreach ($collection->skip(1) as $row) {
if (!isset($row[0]) || empty($row[0])) {
continue;
}
$latitude = filter_var($row[4], FILTER_VALIDATE_FLOAT) ? bcadd($row[4], '0', 18) : null;
$longitude = filter_var($row[5], FILTER_VALIDATE_FLOAT) ? bcadd($row[5], '0', 18) : null;
$batchData[] = [
'nomor_pelanggan' => $row[0],
'kota_pelayanan' => $row[1],
'nama' => $row[2],
'alamat' => $row[3],
'latitude' => $latitude,
'longitude' => $longitude,
];
}
if (!empty($batchData)) {
Customer::upsert($batchData, ['nomor_pelanggan'], ['kota_pelayanan', 'nama', 'alamat', 'latitude', 'longitude']);
}
}
public function sheets(): array {
return [
0 => $this
];
}
}

View File

@@ -60,4 +60,4 @@ class SpatialPlanningImport implements ToCollection
return;
}
}
}
}

20
app/Models/Customer.php Normal file
View File

@@ -0,0 +1,20 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Customer extends Model
{
protected $table = 'customers';
protected $fillable = [
'nomor_pelanggan',
'kota_pelayanan',
'nama',
'alamat',
'latitude',
'longitude',
];
}

View File

@@ -61,32 +61,37 @@ class ServiceSIMBG
}
}
public function syncIndexIntegration($uuid, $token)
public function syncIndexIntegration($uuids, $token)
{
try{
$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]);
if(empty($uuids)){
return false;
}
$integrations = [];
foreach($uuids as $uuid){
$url = "/api/pbg/v1/detail/" . $uuid . "/retribution/indeks-terintegrasi/";
$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],
[
$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,
'indeks_fungsi_bangunan' => $data['indeks_fungsi_bangunan'] ?? null,
'indeks_parameter_kompleksitas' => $data['indeks_parameter_kompleksitas'] ?? null,
'indeks_parameter_permanensi' => $data['indeks_parameter_permanensi'] ?? null,
@@ -94,8 +99,24 @@ 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){
@@ -190,7 +211,7 @@ class ServiceSIMBG
'created_at' => now(),
];
$this->syncIndexIntegration($item['uid'], $token);
// $this->syncIndexIntegration($item['uid'], $token);
$this->syncTaskDetailSubmit($item['uid'], $token);
@@ -215,8 +236,11 @@ 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"
@@ -311,5 +335,4 @@ class ServiceSIMBG
}
}
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class CustomCircle extends Component
{
/**
* Create a new component instance.
*/
public function __construct()
{
//
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.custom-circle');
}
}

View File

@@ -19,7 +19,6 @@
},
"require-dev": {
"fakerphp/faker": "^1.23",
"ibex/crud-generator": "^2.1",
"laravel/pail": "^1.1",
"laravel/pint": "^1.13",
"laravel/sail": "^1.26",

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('customers', function (Blueprint $table) {
$table->id();
$table->string('nomor_pelanggan')->unique();
$table->string('kota_pelayanan');
$table->string('nama');
$table->text('alamat');
$table->decimal('latitude', 22,18);
$table->decimal('longitude', 22,18);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('customers');
}
};

View File

@@ -109,6 +109,20 @@ class UsersRoleMenuSeeder extends Seeder
"parent_id" => $dashboard->id,
"sort_order" => 2,
],
[
"name" => "Dashboard Potensi",
"url" => "dashboard.lack_of_potential",
"icon" => null,
"parent_id" => $dashboard->id,
"sort_order" => 3,
],
[
"name" => "PETA",
"url" => "dashboard.maps",
"icon" => null,
"parent_id" => $dashboard->id,
"sort_order" => 4,
],
[
"name" => "Users",
"url" => "users.index",
@@ -179,6 +193,20 @@ class UsersRoleMenuSeeder extends Seeder
"parent_id" => $data->id,
"sort_order" => 5,
],
[
"name" => "Tata Ruang",
"url" => "spatial-plannings.index",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 6,
],
[
"name" => "PDAM",
"url" => "customers",
"icon" => null,
"parent_id" => $data->id,
"sort_order" => 7,
],
[
"name" => "Lap Pariwisata",
"url" => "tourisms.index",
@@ -205,6 +233,10 @@ class UsersRoleMenuSeeder extends Seeder
$pariwisata = Menu::where('name', 'Pariwisata')->first();
$laporan_pariwisata = Menu::where('name', 'Lap Pariwisata')->first();
$umkm = Menu::where('name', 'UMKM')->first();
$lack_of_potentials = Menu::where('name', 'Dashboard Potensi')->first();
$spatial_plannings = Menu::where('name', 'Tata Ruang')->first();
$pdam = Menu::where('name', 'PDAM')->first();
$peta = Menu::where('name', 'PETA')->first();
// Superadmin gets all menus
$superadmin->menus()->sync([
@@ -229,6 +261,10 @@ class UsersRoleMenuSeeder extends Seeder
$pariwisata->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$laporan_pariwisata->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$umkm->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$lack_of_potentials->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$spatial_plannings->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$pdam->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
$peta->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
]);
// Admin gets limited menus

View File

@@ -1,516 +0,0 @@
{
"__commonjsHelpers-C4iS2aBk.js": {
"file": "assets/_commonjsHelpers-C4iS2aBk.js",
"name": "_commonjsHelpers"
},
"_apexcharts.common-7mov3gaG.js": {
"file": "assets/apexcharts.common-7mov3gaG.js",
"name": "apexcharts.common",
"imports": [
"__commonjsHelpers-C4iS2aBk.js"
]
},
"_dropzone-B5tMhgFp.js": {
"file": "assets/dropzone-B5tMhgFp.js",
"name": "dropzone"
},
"_global-config-9uDKFQ8j.js": {
"file": "assets/global-config-9uDKFQ8j.js",
"name": "global-config"
},
"_gridjs.umd-BiCNXlqL.js": {
"file": "assets/gridjs.umd-BiCNXlqL.js",
"name": "gridjs.umd",
"imports": [
"__commonjsHelpers-C4iS2aBk.js"
]
},
"_table-generator-DPFVsCqk.js": {
"file": "assets/table-generator-DPFVsCqk.js",
"name": "table-generator",
"imports": [
"_gridjs.umd-BiCNXlqL.js"
]
},
"_world-BH8KG5u4.js": {
"file": "assets/world-BH8KG5u4.js",
"name": "world",
"imports": [
"__commonjsHelpers-C4iS2aBk.js"
]
},
"node_modules/flatpickr/dist/flatpickr.min.css": {
"file": "assets/flatpickr-CksuuEqD.css",
"src": "node_modules/flatpickr/dist/flatpickr.min.css",
"isEntry": true
},
"node_modules/flatpickr/dist/themes/dark.css": {
"file": "assets/dark-CLxH30By.css",
"src": "node_modules/flatpickr/dist/themes/dark.css",
"isEntry": true
},
"node_modules/gridjs/dist/theme/mermaid.css": {
"file": "assets/mermaid-B5wPN5RC.css",
"src": "node_modules/gridjs/dist/theme/mermaid.css",
"isEntry": true
},
"node_modules/gridjs/dist/theme/mermaid.min.css": {
"file": "assets/mermaid-1KsrsKla.css",
"src": "node_modules/gridjs/dist/theme/mermaid.min.css",
"isEntry": true
},
"node_modules/quill/dist/quill.bubble.css": {
"file": "assets/quill-BzaoboQ1.css",
"src": "node_modules/quill/dist/quill.bubble.css",
"isEntry": true
},
"node_modules/quill/dist/quill.snow.css": {
"file": "assets/quill-D-Ncpkvi.css",
"src": "node_modules/quill/dist/quill.snow.css",
"isEntry": true
},
"public/images/bg-dashboard.jpg": {
"file": "assets/bg-dashboard-CUwt8_jP.jpg",
"src": "public/images/bg-dashboard.jpg"
},
"resources/fonts/boxicons.eot": {
"file": "assets/boxicons-0t2gX1vj.eot",
"src": "resources/fonts/boxicons.eot"
},
"resources/fonts/boxicons.svg": {
"file": "assets/boxicons-KSR1BgPC.svg",
"src": "resources/fonts/boxicons.svg"
},
"resources/fonts/boxicons.ttf": {
"file": "assets/boxicons-BEZXjQG5.ttf",
"src": "resources/fonts/boxicons.ttf"
},
"resources/fonts/boxicons.woff": {
"file": "assets/boxicons-CEgI8ccS.woff",
"src": "resources/fonts/boxicons.woff"
},
"resources/fonts/boxicons.woff2": {
"file": "assets/boxicons-C7pETWQJ.woff2",
"src": "resources/fonts/boxicons.woff2"
},
"resources/js/app.js": {
"file": "assets/app-Wz_4hh3O.js",
"name": "app",
"src": "resources/js/app.js",
"isEntry": true,
"imports": [
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/business-industries/create.js": {
"file": "assets/create-CiRhiWZV.js",
"name": "create",
"src": "resources/js/business-industries/create.js",
"isEntry": true,
"imports": [
"_dropzone-B5tMhgFp.js",
"_global-config-9uDKFQ8j.js"
]
},
"resources/js/business-industries/index.js": {
"file": "assets/index-BIXijOG8.js",
"name": "index",
"src": "resources/js/business-industries/index.js",
"isEntry": true,
"imports": [
"_gridjs.umd-BiCNXlqL.js",
"_global-config-9uDKFQ8j.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/business-industries/update.js": {
"file": "assets/update-C8VOvIbF.js",
"name": "update",
"src": "resources/js/business-industries/update.js",
"isEntry": true
},
"resources/js/config.js": {
"file": "assets/config-DqV4EBmE.js",
"name": "config",
"src": "resources/js/config.js",
"isEntry": true
},
"resources/js/dashboards/bigdata.js": {
"file": "assets/bigdata-BGlke4DN.js",
"name": "bigdata",
"src": "resources/js/dashboards/bigdata.js",
"isEntry": true,
"imports": [
"_global-config-9uDKFQ8j.js"
],
"css": [
"assets/flatpickr-CksuuEqD.css"
]
},
"resources/js/data-settings/create.js": {
"file": "assets/create-C1IbeTHP.js",
"name": "create",
"src": "resources/js/data-settings/create.js",
"isEntry": true
},
"resources/js/data-settings/index.js": {
"file": "assets/index-C4raIbBK.js",
"name": "index",
"src": "resources/js/data-settings/index.js",
"isEntry": true,
"imports": [
"_gridjs.umd-BiCNXlqL.js",
"_global-config-9uDKFQ8j.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/data-settings/update.js": {
"file": "assets/update-nNw3P4hj.js",
"name": "update",
"src": "resources/js/data-settings/update.js",
"isEntry": true
},
"resources/js/data/advertisements/data-advertisements.js": {
"file": "assets/data-advertisements-ckr1EtLP.js",
"name": "data-advertisements",
"src": "resources/js/data/advertisements/data-advertisements.js",
"isEntry": true,
"imports": [
"_gridjs.umd-BiCNXlqL.js",
"_global-config-9uDKFQ8j.js",
"_table-generator-DPFVsCqk.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/data/advertisements/form-create-update.js": {
"file": "assets/form-create-update-CyN97GsU.js",
"name": "form-create-update",
"src": "resources/js/data/advertisements/form-create-update.js",
"isEntry": true,
"imports": [
"_global-config-9uDKFQ8j.js"
]
},
"resources/js/data/advertisements/form-upload.js": {
"file": "assets/form-upload-tA9zPESO.js",
"name": "form-upload",
"src": "resources/js/data/advertisements/form-upload.js",
"isEntry": true,
"imports": [
"_dropzone-B5tMhgFp.js",
"_global-config-9uDKFQ8j.js"
]
},
"resources/js/data/tourisms/data-tourisms.js": {
"file": "assets/data-tourisms-Db9aMSJn.js",
"name": "data-tourisms",
"src": "resources/js/data/tourisms/data-tourisms.js",
"isEntry": true,
"imports": [
"_gridjs.umd-BiCNXlqL.js",
"_global-config-9uDKFQ8j.js",
"_table-generator-DPFVsCqk.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/data/tourisms/form-create-update.js": {
"file": "assets/form-create-update-SviVezNW.js",
"name": "form-create-update",
"src": "resources/js/data/tourisms/form-create-update.js",
"isEntry": true,
"imports": [
"_global-config-9uDKFQ8j.js"
]
},
"resources/js/data/tourisms/form-upload.js": {
"file": "assets/form-upload-BtbLOLpA.js",
"name": "form-upload",
"src": "resources/js/data/tourisms/form-upload.js",
"isEntry": true,
"imports": [
"_dropzone-B5tMhgFp.js",
"_global-config-9uDKFQ8j.js"
]
},
"resources/js/data/umkm/data-umkm.js": {
"file": "assets/data-umkm-CLB33rMj.js",
"name": "data-umkm",
"src": "resources/js/data/umkm/data-umkm.js",
"isEntry": true,
"imports": [
"_gridjs.umd-BiCNXlqL.js",
"_global-config-9uDKFQ8j.js",
"_table-generator-DPFVsCqk.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/data/umkm/form-create-update.js": {
"file": "assets/form-create-update-BrB0xTMN.js",
"name": "form-create-update",
"src": "resources/js/data/umkm/form-create-update.js",
"isEntry": true,
"imports": [
"_global-config-9uDKFQ8j.js"
]
},
"resources/js/data/umkm/form-upload.js": {
"file": "assets/form-upload-BDyAWo4b.js",
"name": "form-upload",
"src": "resources/js/data/umkm/form-upload.js",
"isEntry": true,
"imports": [
"_dropzone-B5tMhgFp.js",
"_global-config-9uDKFQ8j.js"
]
},
"resources/js/master/users/create.js": {
"file": "assets/create-BfiYISiN.js",
"name": "create",
"src": "resources/js/master/users/create.js",
"isEntry": true
},
"resources/js/master/users/update.js": {
"file": "assets/update-DhoG4v8r.js",
"name": "update",
"src": "resources/js/master/users/update.js",
"isEntry": true
},
"resources/js/master/users/users.js": {
"file": "assets/users-jfWUOWyP.js",
"name": "users",
"src": "resources/js/master/users/users.js",
"isEntry": true,
"imports": [
"_gridjs.umd-BiCNXlqL.js",
"_global-config-9uDKFQ8j.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/menus/create.js": {
"file": "assets/create-ChUgh-yc.js",
"name": "create",
"src": "resources/js/menus/create.js",
"isEntry": true
},
"resources/js/menus/index.js": {
"file": "assets/index-C4xA1kYa.js",
"name": "index",
"src": "resources/js/menus/index.js",
"isEntry": true,
"imports": [
"_gridjs.umd-BiCNXlqL.js",
"_global-config-9uDKFQ8j.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/menus/update.js": {
"file": "assets/update-8JQOGES4.js",
"name": "update",
"src": "resources/js/menus/update.js",
"isEntry": true
},
"resources/js/pages/chart.js": {
"file": "assets/chart-DQBoD9wk.js",
"name": "chart",
"src": "resources/js/pages/chart.js",
"isEntry": true,
"imports": [
"_apexcharts.common-7mov3gaG.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/pages/dashboard.js": {
"file": "assets/dashboard-nkb3Omy9.js",
"name": "dashboard",
"src": "resources/js/pages/dashboard.js",
"isEntry": true,
"imports": [
"_apexcharts.common-7mov3gaG.js",
"_world-BH8KG5u4.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/pages/form-fileupload.js": {
"file": "assets/form-fileupload-DGbdX8GT.js",
"name": "form-fileupload",
"src": "resources/js/pages/form-fileupload.js",
"isEntry": true,
"imports": [
"_dropzone-B5tMhgFp.js"
]
},
"resources/js/pages/form-flatepicker.js": {
"file": "assets/form-flatepicker-ChSlk6xC.js",
"name": "form-flatepicker",
"src": "resources/js/pages/form-flatepicker.js",
"isEntry": true,
"imports": [
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/pages/form-quilljs.js": {
"file": "assets/form-quilljs-pSObT4Ti.js",
"name": "form-quilljs",
"src": "resources/js/pages/form-quilljs.js",
"isEntry": true,
"imports": [
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/pages/maps-canada.js": {
"file": "assets/maps-canada-Btz07hSk.js",
"name": "maps-canada",
"src": "resources/js/pages/maps-canada.js",
"isEntry": true
},
"resources/js/pages/maps-google.js": {
"file": "assets/maps-google-KamR_rNw.js",
"name": "maps-google",
"src": "resources/js/pages/maps-google.js",
"isEntry": true,
"imports": [
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/pages/maps-iraq.js": {
"file": "assets/maps-iraq-Blhf9V_8.js",
"name": "maps-iraq",
"src": "resources/js/pages/maps-iraq.js",
"isEntry": true
},
"resources/js/pages/maps-russia.js": {
"file": "assets/maps-russia-C3XucoMP.js",
"name": "maps-russia",
"src": "resources/js/pages/maps-russia.js",
"isEntry": true
},
"resources/js/pages/maps-spain.js": {
"file": "assets/maps-spain-CdBIHB66.js",
"name": "maps-spain",
"src": "resources/js/pages/maps-spain.js",
"isEntry": true
},
"resources/js/pages/maps-vector.js": {
"file": "assets/maps-vector-C2WpvMU7.js",
"name": "maps-vector",
"src": "resources/js/pages/maps-vector.js",
"isEntry": true,
"imports": [
"_world-BH8KG5u4.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/pages/table-gridjs.js": {
"file": "assets/table-gridjs-BQh80cFh.js",
"name": "table-gridjs",
"src": "resources/js/pages/table-gridjs.js",
"isEntry": true,
"imports": [
"_gridjs.umd-BiCNXlqL.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/pbg-task/index.js": {
"file": "assets/index-CqcfkvSL.js",
"name": "index",
"src": "resources/js/pbg-task/index.js",
"isEntry": true,
"imports": [
"_gridjs.umd-BiCNXlqL.js",
"_global-config-9uDKFQ8j.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/report/tourisms/index.js": {
"file": "assets/index-DlxOSPEG.js",
"name": "index",
"src": "resources/js/report/tourisms/index.js",
"isEntry": true,
"imports": [
"_gridjs.umd-BiCNXlqL.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/roles/create.js": {
"file": "assets/create-Dd-lHOwF.js",
"name": "create",
"src": "resources/js/roles/create.js",
"isEntry": true
},
"resources/js/roles/index.js": {
"file": "assets/index-C_kI_q7O.js",
"name": "index",
"src": "resources/js/roles/index.js",
"isEntry": true,
"imports": [
"_gridjs.umd-BiCNXlqL.js",
"_global-config-9uDKFQ8j.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/roles/role_menu.js": {
"file": "assets/role_menu-BuFAi1wM.js",
"name": "role_menu",
"src": "resources/js/roles/role_menu.js",
"isEntry": true
},
"resources/js/roles/update.js": {
"file": "assets/update-CapXnAP8.js",
"name": "update",
"src": "resources/js/roles/update.js",
"isEntry": true
},
"resources/js/settings/general/general-settings.js": {
"file": "assets/general-settings-BoJeYQk1.js",
"name": "general-settings",
"src": "resources/js/settings/general/general-settings.js",
"isEntry": true,
"imports": [
"_gridjs.umd-BiCNXlqL.js",
"_global-config-9uDKFQ8j.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/settings/syncronize/syncronize.js": {
"file": "assets/syncronize-DjtcngRb.js",
"name": "syncronize",
"src": "resources/js/settings/syncronize/syncronize.js",
"isEntry": true,
"imports": [
"_gridjs.umd-BiCNXlqL.js",
"_global-config-9uDKFQ8j.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/js/tables/common-table.js": {
"file": "assets/common-table-KF_NVAIE.js",
"name": "common-table",
"src": "resources/js/tables/common-table.js",
"isEntry": true,
"imports": [
"_gridjs.umd-BiCNXlqL.js",
"_global-config-9uDKFQ8j.js",
"__commonjsHelpers-C4iS2aBk.js"
]
},
"resources/scss/components/_circle.scss": {
"file": "assets/_circle-DgPqpfJw.css",
"src": "resources/scss/components/_circle.scss",
"isEntry": true
},
"resources/scss/dashboards/_bigdata.scss": {
"file": "assets/_bigdata-Syu0AGbZ.css",
"src": "resources/scss/dashboards/_bigdata.scss",
"isEntry": true
},
"resources/scss/icons.scss": {
"file": "assets/icons-CHxf0fE3.css",
"src": "resources/scss/icons.scss",
"isEntry": true
},
"resources/scss/style.scss": {
"file": "assets/style-CnBzxVPJ.css",
"src": "resources/scss/style.scss",
"isEntry": true
}
}

View File

@@ -2,6 +2,30 @@ 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() {
@@ -107,6 +131,7 @@ class FormValidation {
}
document.addEventListener("DOMContentLoaded", function (e) {
new Components().init(), new FormValidation().init();
// new InitDatePicker().init();
});
class ThemeLayout {
constructor() {

View File

@@ -2,58 +2,36 @@ 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.table = null; // Store Grid.js instance
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();
}
init() {
this.getFetchApiData();
initEvents() {
document.body.addEventListener("click", async (event) => {
const deleteButton = event.target.closest(
".btn-delete-business-industry"
);
if (deleteButton) {
event.preventDefault();
await this.handleDelete(deleteButton);
}
});
}
getFetchApiData() {
initTableBusinessIndustries() {
let tableContainer = document.getElementById(
"table-business-industries"
);
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;
}
// Create a new Grid.js instance only if it doesn't exist
this.table = new Grid({
columns: [
{ name: "ID", width: "80px", hidden: false },
@@ -71,27 +49,20 @@ class BusinessIndustries {
{ name: "Tahun Pajak", width: "120px" },
{ name: "Created", width: "180px" },
{
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>
`);
},
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>
`),
},
],
search: {
server: {
url: (prev, keyword) => `${prev}?search=${keyword}`,
},
},
pagination: {
limit: 15,
server: {
@@ -102,6 +73,11 @@ class BusinessIndustries {
},
},
sort: true,
search: {
server: {
url: (prev, keyword) => `${prev}?search=${keyword}`,
},
},
server: {
url: `${GlobalConfig.apiHost}/api/api-business-industries`,
headers: {
@@ -131,98 +107,26 @@ class BusinessIndustries {
total: (data) => data.total,
},
}).render(tableContainer);
document.addEventListener("click", this.handleDelete.bind(this));
}
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");
async handleDelete(deleteButton) {
const id = deleteButton.getAttribute("data-id");
if (!modalElement) {
console.error("Modal element not found!");
return;
}
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!",
});
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`,
if (result.isConfirmed) {
try {
let response = await fetch(
`${GlobalConfig.apiHost}/api/api-business-industries/${id}`,
{
method: "DELETE",
credentials: "include",
headers: {
Authorization: `Bearer ${document
@@ -230,31 +134,34 @@ class BusinessIndustries {
.getAttribute("content")}`,
"Content-Type": "application/json",
},
then: (data) =>
data.data.map((item) => [
item.id,
item.nama_kecamatan,
item.nama_kelurahan,
item.nop,
item.nama_wajib_pajak,
item.alamat_wajib_pajak,
item.alamat_objek_pajak,
item.luas_bumi,
item.luas_bangunan,
item.njop_bumi,
item.njop_bangunan,
item.ketetapan,
item.tahun_pajak,
item.created_at,
item.id, // ID for Actions column
]),
total: (data) => data.total,
},
})
.forceRender();
}
);
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();
}
}
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new BusinessIndustries().init();
new BusinessIndustries();
});

View File

@@ -0,0 +1,65 @@
class CreateCustomer {
constructor() {
this.initCreateCustomer();
}
initCreateCustomer() {
const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification);
document
.getElementById("btnCreateCustomer")
.addEventListener("click", async function () {
let submitButton = this;
let spinner = document.getElementById("spinner");
let form = document.getElementById("formCreateCustomer");
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 = "/data/customers";
}, 2000);
} else {
let error = await response.json();
document.getElementById("toast-message").innerText =
error.message;
toast.show();
console.error("Error:", error);
}
} catch (error) {
console.error("Request failed:", error);
document.getElementById("toast-message").innerText =
error.message;
toast.show();
}
});
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new CreateCustomer();
});

View File

@@ -0,0 +1,65 @@
class UpdateCustomer {
constructor() {
this.initUpdateCustomer();
}
initUpdateCustomer() {
const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification);
document
.getElementById("btnUpdateCustomer")
.addEventListener("click", async function () {
let submitButton = this;
let spinner = document.getElementById("spinner");
let form = document.getElementById("formUpdateCustomer");
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 = "/data/customers";
}, 2000);
} else {
let error = await response.json();
document.getElementById("toast-message").innerText =
error.message;
toast.show();
console.error("Error:", error);
}
} catch (error) {
console.error("Request failed:", error);
document.getElementById("toast-message").innerText =
error.message;
toast.show();
}
});
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new UpdateCustomer();
});

View File

@@ -0,0 +1,151 @@
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 Customers {
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.initTableCustomers();
this.initEvents();
}
initEvents() {
document.body.addEventListener("click", async (event) => {
const deleteButton = event.target.closest(".btn-delete-customers");
if (deleteButton) {
event.preventDefault();
await this.handleDelete(deleteButton);
}
});
}
initTableCustomers() {
let tableContainer = document.getElementById("table-customers");
// Create a new Grid.js instance only if it doesn't exist
this.table = new Grid({
columns: [
"ID",
"Nomor Pelanggan",
"Nama",
"Kota Pelayanan",
"Alamat",
"Latitude",
"Longitude",
{
name: "Action",
formatter: (cell) =>
gridjs.html(`
<div class="d-flex justify-content-center gap-2">
<a href="/data/customers/${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-customers d-inline-flex align-items-center justify-content-center">
<i class='bx bxs-trash' ></i>
</button>
</div>
`),
},
],
pagination: {
limit: 15,
server: {
url: (prev, page) =>
`${prev}${prev.includes("?") ? "&" : "?"}page=${
page + 1
}`,
},
},
sort: true,
search: {
server: {
url: (prev, keyword) => `${prev}?search=${keyword}`,
},
},
server: {
url: `${GlobalConfig.apiHost}/api/customers`,
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
"Content-Type": "application/json",
},
then: (data) =>
data.data.map((item) => [
item.id,
item.nomor_pelanggan,
item.nama,
item.kota_pelayanan,
item.alamat,
item.latitude,
item.longitude,
item.id,
]),
total: (data) => data.meta.total,
},
}).render(tableContainer);
}
async handleDelete(deleteButton) {
const id = deleteButton.getAttribute("data-id");
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 (result.isConfirmed) {
try {
let response = await fetch(
`${GlobalConfig.apiHost}/api/customers/${id}`,
{
method: "DELETE",
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();
}
}
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new Customers();
});

View File

@@ -0,0 +1,78 @@
import { Dropzone } from "dropzone";
Dropzone.autoDiscover = false;
class UploadCustomers {
constructor() {
this.spatialDropzone = null;
this.formElement = document.getElementById("formUploadCustomers");
this.uploadButton = document.getElementById("submit-upload");
this.spinner = document.getElementById("spinner");
if (!this.formElement) {
console.error("Element formUploadCustomers tidak ditemukan!");
}
}
init() {
this.initDropzone();
this.setupUploadButton();
}
initDropzone() {
const toastNotification = document.getElementById("toastNotification");
const toast = new bootstrap.Toast(toastNotification);
var previewTemplate,
dropzonePreviewNode = document.querySelector(
"#dropzone-preview-list"
);
(dropzonePreviewNode.id = ""),
dropzonePreviewNode &&
((previewTemplate = dropzonePreviewNode.parentNode.innerHTML),
dropzonePreviewNode.parentNode.removeChild(dropzonePreviewNode),
(this.spatialDropzone = new Dropzone(".dropzone", {
url: this.formElement.action,
method: "post",
acceptedFiles: ".xls,.xlsx",
previewTemplate: previewTemplate,
previewsContainer: "#dropzone-preview",
autoProcessQueue: false,
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
},
init: function () {
this.on("success", function (file, response) {
document.getElementById("toast-message").innerText =
response.message;
toast.show();
setTimeout(() => {
window.location.href = "/data/customers";
}, 2000);
});
this.on("error", function (file, errorMessage) {
document.getElementById("toast-message").innerText =
errorMessage.message;
toast.show();
this.uploadButton.disabled = false;
this.spinner.classList.add("d-none");
});
},
})));
}
setupUploadButton() {
this.uploadButton.addEventListener("click", (e) => {
if (this.spatialDropzone.files.length > 0) {
this.spatialDropzone.processQueue();
this.uploadButton.disabled = true;
this.spinner.classList.remove("d-none");
} else {
return;
}
});
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new UploadCustomers().init();
});

View File

@@ -1,165 +1,141 @@
import Big from "big.js";
import GlobalConfig, { addThousandSeparators } from "../global-config.js";
import flatpickr from "flatpickr";
import "flatpickr/dist/flatpickr.min.css";
import InitDatePicker from "../utils/InitDatePicker.js";
class BigData {
async init() {
try {
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);
new InitDatePicker(
"#datepicker-dashboard-bigdata",
this.handleChangeDate.bind(this)
).init();
// Load initial data
await this.updateData(this.filterYear);
this.updateData("latest");
} catch (error) {
console.error("Error initializing data:", error);
}
}
updateYear(value) {
let inputYear = parseInt(value, 10);
if (!isNaN(inputYear)) {
this.filterYear = inputYear;
this.updateData(this.filterYear);
} else {
console.error("Invalid year input");
}
handleChangeDate(filterDate) {
if (!filterDate) return;
this.updateData(filterDate);
}
async updateData(year) {
async updateData(filterDate) {
try {
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"
);
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"
// );
// 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
: 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();
@@ -177,6 +153,33 @@ 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(
@@ -370,53 +373,60 @@ class BigData {
.querySelectorAll(".document-total.chart-target-pad")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
this.bigTargetPAD.toString()
// this.bigTargetPAD.toString()
this.resumeBigData.target_pad.sum.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-target-pad")
.forEach((element) => {
element.innerText = `${100}%`;
element.innerText = `${this.resumeBigData.target_pad.percentage}%`;
});
}
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 = `${countAll}`;
element.innerText = `${this.resumeBigData.total_potensi.count}`;
});
document
.querySelectorAll(".document-total.chart-total-potensi")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
this.bigTotalPotensi.toString()
// this.bigTotalPotensi.toString()
this.resumeBigData.total_potensi.sum.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-total-potensi")
.forEach((element) => {
element.innerText = `${this.resultPercentage}%`;
// element.innerText = `${this.resultPercentage}%`;
element.innerText = `${this.resumeBigData.total_potensi.percentage}%`;
});
}
initChartVerificationDocuments() {
document
.querySelectorAll(".document-count.chart-berkas-terverifikasi")
.forEach((element) => {
element.innerText = `${this.dataVerification.count}`;
// element.innerText = `${this.dataVerification.count}`;
element.innerText = `${this.resumeBigData.verified_document.count}`;
});
document
.querySelectorAll(".document-total.chart-berkas-terverifikasi")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
this.bigTotalVerification.toString()
// this.bigTotalVerification.toString()
this.resumeBigData.verified_document.sum.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-berkas-terverifikasi")
.forEach((element) => {
element.innerText = `${this.percetageResultVerification}%`;
// element.innerText = `${this.percetageResultVerification}%`;
element.innerText = `${this.resumeBigData.verified_document.percentage}%`;
});
}
initChartNonVerificationDocuments() {
@@ -425,7 +435,8 @@ class BigData {
".document-count.chart-berkas-belum-terverifikasi"
)
.forEach((element) => {
element.innerText = `${this.dataNonVerification.count}`;
// element.innerText = `${this.dataNonVerification.count}`;
element.innerText = `${this.resumeBigData.non_verified_document.count}`;
});
document
.querySelectorAll(
@@ -433,7 +444,8 @@ class BigData {
)
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
this.bigTotalNonVerification.toString()
// this.bigTotalNonVerification.toString()
this.resumeBigData.non_verified_document.sum.toString()
)}`;
});
document
@@ -441,45 +453,52 @@ class BigData {
".small-percentage.chart-berkas-belum-terverifikasi"
)
.forEach((element) => {
element.innerText = `${this.percentageResultNonVerification}%`;
// element.innerText = `${this.percentageResultNonVerification}%`;
element.innerText = `${this.resumeBigData.non_verified_document.percentage}%`;
});
}
initChartUsaha() {
document
.querySelectorAll(".document-count.chart-business")
.forEach((element) => {
element.innerText = `${this.dataBusiness.count}`;
// element.innerText = `${this.dataBusiness.count}`;
element.innerText = `${this.resumeBigData.business_document.count}`;
});
document
.querySelectorAll(".document-total.chart-business")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
this.bigTotalBusiness.toString()
// this.bigTotalBusiness.toString()
this.resumeBigData.business_document.sum.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-business")
.forEach((element) => {
element.innerText = `${this.percentageResultBusiness}%`;
// element.innerText = `${this.percentageResultBusiness}%`;
element.innerText = `${this.resumeBigData.business_document.percentage}%`;
});
}
initChartNonUsaha() {
document
.querySelectorAll(".document-count.chart-non-business")
.forEach((element) => {
element.innerText = `${this.dataNonBusiness.count}`;
// element.innerText = `${this.dataNonBusiness.count}`;
element.innerText = `${this.resumeBigData.non_business_document.count}`;
});
document
.querySelectorAll(".document-total.chart-non-business")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
this.bigTotalNonBusiness.toString()
// this.bigTotalNonBusiness.toString()
this.resumeBigData.non_business_document.sum.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-non-business")
.forEach((element) => {
element.innerText = `${this.percentageResultNonBusiness}%`;
// element.innerText = `${this.percentageResultNonBusiness}%`;
element.innerText = `${this.resumeBigData.non_business_document.percentage}%`;
});
}
initChartKekuranganPotensi() {
@@ -492,70 +511,78 @@ class BigData {
.querySelectorAll(".document-total.chart-kekurangan-potensi")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
this.totalKekuranganPotensi.toString()
// this.totalKekuranganPotensi.toString()
this.resumeBigData.kekurangan_potensi.sum.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-kekurangan-potensi")
.forEach((element) => {
element.innerText = `${this.percentageKekuranganPotensi}%`;
// element.innerText = `${this.percentageKekuranganPotensi}%`;
element.innerText = `${this.resumeBigData.kekurangan_potensi.percentage}%`;
});
}
initChartRealisasiTerbitPBG() {
document
.querySelectorAll(".document-count.chart-realisasi-tebit-pbg")
.forEach((element) => {
element.innerText = `${this.dataCountRealisasiTerbit}`;
// element.innerText = `${this.dataCountRealisasiTerbit}`;
element.innerText = `${this.resumeBigData.realisasi_terbit.count}`;
});
document
.querySelectorAll(".document-total.chart-realisasi-tebit-pbg")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
this.dataSumRealisasiTerbit
// this.dataSumRealisasiTerbit
this.resumeBigData.realisasi_terbit.sum.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-realisasi-tebit-pbg")
.forEach((element) => {
element.innerText = `0.00%`;
element.innerText = `${this.resumeBigData.realisasi_terbit.percentage}%`;
});
}
initChartMenungguKlikDPMPTSP() {
document
.querySelectorAll(".document-count.chart-menunggu-klik-dpmptsp")
.forEach((element) => {
element.innerText = `${this.dataCountMenungguKlikDPMPTSP}`;
// element.innerText = `${this.dataCountMenungguKlikDPMPTSP}`;
element.innerText = `${this.resumeBigData.menunggu_klik_dpmptsp.count}`;
});
document
.querySelectorAll(".document-total.chart-menunggu-klik-dpmptsp")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
this.dataSumMenungguKlikDPMPTSP
// this.dataSumMenungguKlikDPMPTSP
this.resumeBigData.menunggu_klik_dpmptsp.sum.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-menunggu-klik-dpmptsp")
.forEach((element) => {
element.innerText = `0.00%`;
element.innerText = `${this.resumeBigData.menunggu_klik_dpmptsp.percentage}%`;
});
}
initChartProsesDinasTeknis() {
document
.querySelectorAll(".document-count.chart-proses-dinas-teknis")
.forEach((element) => {
element.innerText = `${this.dataCountProsesDinasTeknis}`;
// element.innerText = `${this.dataCountProsesDinasTeknis}`;
element.innerText = `${this.resumeBigData.proses_dinas_teknis.count}`;
});
document
.querySelectorAll(".document-total.chart-proses-dinas-teknis")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
this.dataSumProsesDinasTeknis
// this.dataSumProsesDinasTeknis
this.resumeBigData.proses_dinas_teknis.sum.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-proses-dinas-teknis")
.forEach((element) => {
element.innerText = `0.00%`;
element.innerText = `${this.resumeBigData.proses_dinas_teknis.percentage}%`;
});
}
initChartPotensiTataRuang() {
@@ -568,13 +595,15 @@ class BigData {
.querySelectorAll(".document-total.chart-potensi-tata-ruang")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
this.bigTotalTataRuang.toString()
// this.bigTotalTataRuang.toString()
this.resumeBigData.tata_ruang.sum.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-potensi-tata-ruang")
.forEach((element) => {
element.innerText = `${this.percentageResultTataRuang}%`;
// element.innerText = `${this.percentageResultTataRuang}%`;
element.innerText = `${this.resumeBigData.tata_ruang.percentage}%`;
});
}
}

View File

@@ -0,0 +1,172 @@
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.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.initChartKekuranganPotensi();
}
async getDataTotalPotensi(filterDate) {
try {
const response = await fetch(
`${GlobalConfig.apiHost}/api/bigdata-resume?filterByDate=${filterDate}`,
{
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 {
total: data.total_potensi.sum,
};
} catch (error) {
console.error("Error fetching chart data:", error);
return null;
}
}
async getDataSettings(string_key) {
try {
const response = await fetch(
`${GlobalConfig.apiHost}/api/data-settings?search=${string_key}`,
{
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.data[0].value;
} catch (error) {
console.error("Error fetching chart data:", error);
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")
.forEach((element) => {
element.innerText = ``;
});
document
.querySelectorAll(".document-total.chart-lack-of-potential")
.forEach((element) => {
element.innerText = `Rp.${addThousandSeparators(
this.bigTotalLackPotential.toString()
)}`;
});
document
.querySelectorAll(".small-percentage.chart-lack-of-potential")
.forEach((element) => {
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();
});
function resizeDashboard() {
let targetElement = document.getElementById("lack-of-potential-wrapper");
let dashboardElement = document.getElementById(
"lack-of-potential-fixed-container"
);
let targetWidth = targetElement.offsetWidth;
let dashboardWidth = 1400;
let scaleFactor = (targetWidth / dashboardWidth).toFixed(2);
// Prevent scaling beyond 1 (100%) to avoid overflow
scaleFactor = Math.min(scaleFactor, 1);
dashboardElement.style.transformOrigin = "left top";
dashboardElement.style.transition = "transform 0.2s ease-in-out";
dashboardElement.style.transform = `scale(${scaleFactor})`;
// Ensure horizontal scrolling is allowed if necessary
document.body.style.overflowX = "auto";
}
window.addEventListener("load", resizeDashboard);
window.addEventListener("resize", resizeDashboard);

View File

@@ -0,0 +1,470 @@
import Big from "big.js";
import GlobalConfig, { addThousandSeparators } from "../global-config.js";
import ApexCharts from "apexcharts";
import "gridjs/dist/gridjs.umd.js";
import GeneralTable from "../table-generator.js";
var chart;
document.addEventListener("DOMContentLoaded", async function () {
await initChart();
const yearPicker = document.getElementById("yearPicker");
async function updateDataByYear(selectedYear) {
// Target PAD Element
const targetPadElement = document.getElementById("target-pad");
if (!targetPadElement) return;
const targetPadValue = await getDataSettings("TARGET_PAD");
targetPadElement.textContent = formatCurrency(targetPadValue);
// Total Potensi Berkas
const totalPotensiBerkas = document.getElementById("total-potensi-berkas");
if (!totalPotensiBerkas) return;
const totalPotensiBerkasValue = await getDataTotalPotensi(selectedYear);
totalPotensiBerkas.textContent = formatCurrency(totalPotensiBerkasValue.totalData);
// Total Berkas Terverifikasi
const totalBerkasTerverifikasi = document.getElementById("total-berkas-terverifikasi");
if (!totalBerkasTerverifikasi) return;
const totalBerkasTerverifikasiValue = await getDataVerification(selectedYear);
totalBerkasTerverifikasi.textContent = formatCurrency(totalBerkasTerverifikasiValue.totalData);
// Total Kekurangan potensi
const totalKekuranganPotensi = document.getElementById("total-kekurangan-potensi");
if (!totalKekuranganPotensi) return;
const totalKekuranganPotensiValue = new Big(targetPadValue) - new Big(totalPotensiBerkasValue.totalData);
totalKekuranganPotensi.textContent = formatCurrency(totalKekuranganPotensiValue)
// Total Potensi PBG dari tata ruang
const totalPotensiPBGTataRuang = document.getElementById("total-potensi-pbd-tata-ruang");
if (!totalPotensiPBGTataRuang) return;
const totalPotensiPBGTataRuangValue = await getDataSettings("TATA_RUANG");
totalPotensiPBGTataRuang.textContent = formatCurrency(totalPotensiPBGTataRuangValue);
// Total Berkas Belum terverifikasi
const totalBerkasBelumTerverifikasi = document.getElementById("total-berkas-belum-terverifikasi");
if (!totalBerkasBelumTerverifikasi) return;
const totalBerkasBelumTerverifikasiValue = await getDataNonVerification(selectedYear);
const totalBerkasBelumTerverifikasiCount = totalBerkasBelumTerverifikasiValue.countData;
totalBerkasBelumTerverifikasi.textContent = formatCurrency(totalBerkasBelumTerverifikasiValue.totalData);
// Total Berkas Usaha
const totalBerkasUsahaValue = await getDataBusiness(selectedYear);
const totalBerkasUsahaCount = totalBerkasUsahaValue.countData;
const totalBerkasUsahaTotalData = totalBerkasUsahaValue.totalData;
// Total Berkas Non Usaha
const totalBerkasNonUsahaValue = await getDataNonBusiness(selectedYear);
const totalBerkasNonUsahaCount = totalBerkasNonUsahaValue.countData;
const totalBerkasNonUsahaTotalData = totalBerkasNonUsahaValue.totalData;
// Pie Chart Section
let persenUsaha = totalBerkasBelumTerverifikasiCount > 0
? ((totalBerkasUsahaCount / totalBerkasBelumTerverifikasiCount) * 100).toFixed(2)
: "0";
let persenNonUsaha = totalBerkasBelumTerverifikasiCount > 0
? ((totalBerkasNonUsahaCount / totalBerkasBelumTerverifikasiCount) * 100).toFixed(2)
: "0";
const dataSeriesPieChart = [Number(persenUsaha), Number(persenNonUsaha)]
const labelsPieChart = ["Berkas Usaha", "Berkas Non Usaha"];
document.querySelector("td[data-category='non-usaha']").textContent = formatCurrency(totalBerkasNonUsahaTotalData).toLocaleString();
document.querySelector("td[data-category='non-usaha-percentage']").textContent = persenNonUsaha + "%";
document.querySelector("td[data-category='usaha']").textContent = formatCurrency(totalBerkasUsahaTotalData).toLocaleString();
document.querySelector("td[data-category='usaha-percentage']").textContent = persenUsaha + "%";
updatePieChart(dataSeriesPieChart, labelsPieChart);
// Load all Tourism location
const allLocation = await getAllLocation();
console.log(allLocation);
// Filter hanya data yang memiliki angka valid
let validLocations = allLocation.dataLocation.filter(loc => {
return !isNaN(parseFloat(loc.longitude)) && !isNaN(parseFloat(loc.latitude));
});
// Ubah string ke float
validLocations = validLocations.map(loc => ({
name: loc.project_name,
longitude: parseFloat(loc.longitude),
latitude: parseFloat(loc.latitude)
}));
console.log(validLocations.name)
// Inisialisasi peta
var map = L.map('map').setView([-7.0230, 107.5275], 10);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; OpenStreetMap contributors'
}).addTo(map);
// Tambahkan marker ke peta
validLocations.forEach(function(loc) {
L.marker([loc.latitude, loc.longitude])
.addTo(map)
.bindPopup(`<b>${loc.name}</b>`) // Popup saat diklik
.bindTooltip(loc.name, { permanent: false, direction: "top" }); // Tooltip saat di-hover
});
// Realisasi terbit PBG
const totalRealisasiTerbitPBG = document.getElementById("realisasi-terbit-pbg");
if (!totalRealisasiTerbitPBG) return;
const totalRealisasiTerbitPBGValue = await getDataSettings("REALISASI_TERBIT_PBG_SUM");
totalRealisasiTerbitPBG.textContent = formatCurrency(totalRealisasiTerbitPBGValue);
// Menunggu Klik DPMPTSP
const totalMenungguKlikDpmptsp = document.getElementById("waiting-click-dpmptsp");
if (!totalMenungguKlikDpmptsp) return;
const totalMenungguKlikDpmptspValue = await getDataSettings("MENUNGGU_KLIK_DPMPTSP_SUM");
totalMenungguKlikDpmptsp.textContent = formatCurrency(totalMenungguKlikDpmptspValue);
// Proses Dinas Teknis
const totalProsesDinasTeknis = document.getElementById("processing-technical-services");
if (!totalProsesDinasTeknis) return;
const totalProsesDinasTeknisValue = await getDataSettings("PROSES_DINAS_TEKNIS_SUM");
totalProsesDinasTeknis.textContent = formatCurrency(totalProsesDinasTeknisValue);
// Load Tabel Baru di Update
const tableLastUpdated = new GeneralTable(
"pbg-filter-by-updated-at",
`${GlobalConfig.apiHost}/api/api-pbg-task?isLastUpdated=true`,
`${GlobalConfig.apiHost}`,
pbgTaskColumns
);
tableLastUpdated.processData = function (data) {
console.log("Response Data:", data);
return data.data.map((item) => {
return [
item.no,
item.name,
item.registration_number,
item.document_number,
item.address,
];
});
};
tableLastUpdated.init();
// Load Tabel Status SK Terbit
const tableSKPBGTerbit = new GeneralTable(
"pbg-filter-by-status",
`${GlobalConfig.apiHost}/api/api-pbg-task?isLastUpdated=false`,
`${GlobalConfig.apiHost}`,
pbgTaskColumns
);
tableSKPBGTerbit.processData = function (data) {
console.log("Response Data:", data);
return data.data.map((item) => {
return [
item.no,
item.name,
item.registration_number,
item.document_number,
item.address,
];
});
};
tableSKPBGTerbit.init();
document.querySelector("#pbg-filter-by-updated-at .gridjs-search").hidden = true;
document.querySelector("#pbg-filter-by-updated-at .gridjs-footer").hidden = true;
document.querySelector("#pbg-filter-by-status .gridjs-search").hidden = true;
document.querySelector("#pbg-filter-by-status .gridjs-footer").hidden = true;
}
await updateDataByYear(yearPicker.value);
yearPicker.addEventListener("change", async function () {
console.log("event change dropdown")
await updateDataByYear(yearPicker.value);
});
});
async function getDataSettings(string_key) {
try {
const response = await fetch(
`${GlobalConfig.apiHost}/api/api-data-settings?search=${string_key}`,
{
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.data?.[0]?.value ?? 0; // Pastikan tidak error jika data kosong
} catch (error) {
console.error("Error fetching data:", error);
return 0;
}
}
async function getDataTotalPotensi(year) {
try {
const response = await fetch(
`${GlobalConfig.apiHost}/api/all-task-documents?year=${year}`,
{
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 {
totalData: data.data.total,
};
} catch (error) {
console.error("Error fetching chart data:", error);
return null;
}
}
async function getDataVerification(year) {
try {
const response = await fetch(
`${GlobalConfig.apiHost}/api/verification-documents?year=${year}`,
{
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 {
totalData: data.data.total,
};
} catch (error) {
console.error("Error fetching chart data:", error);
return 0
}
}
async function getDataNonVerification(year) {
try {
const response = await fetch (
`${GlobalConfig.apiHost}/api/non-verification-documents?year=${year}`,
{
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 {
countData: data.data.count,
totalData: data.data.total,
}
} catch (error) {
console.error("Error fetching chart data:", error);
return 0;
}
}
async function getDataBusiness(year) {
try {
const response = await fetch(
`${GlobalConfig.apiHost}/api/business-documents?year=${year}`,
{
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 {
countData: data.data.count,
totalData: data.data.total,
};
} catch (error) {
console.error("Error fetching chart data:", error);
return 0;
}
}
async function getDataNonBusiness(year) {
try {
const response = await fetch(
`${GlobalConfig.apiHost}/api/non-business-documents?year=${year}`,
{
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 {
countData: data.data.count,
totalData: data.data.total
}
} catch (error) {
console.error("Error fetching chart data:", error);
return 0;
}
}
async function getAllLocation() {
try {
const response = await fetch(
`${GlobalConfig.apiHost}/api/get-all-location`,
{
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 {
dataLocation: data.data,
}
} catch (error) {
console.error("Error fetching chart data:", error);
return 0;
}
}
async function initChart() {
var options = {
chart: {
height: 180,
type: 'donut',
},
series: [0, 0], // Inisialisasi dengan nilai awal
labels: ["Berkas Usaha", "Berkas Non Usaha"],
legend: {
show: false
},
stroke: {
width: 0
},
plotOptions: {
pie: {
donut: {
size: '60%',
}
}
},
colors: ["#7e67fe", "#17c553"],
dataLabels: {
enabled: false
},
responsive: [{
breakpoint: 480,
options: {
chart: {
width: 200
}
}
}],
fill: {
type: 'gradient'
}
};
chart = new ApexCharts(document.querySelector("#conversions"), options);
chart.render();
}
async function updatePieChart(dataSeries, labels) {
if (!Array.isArray(dataSeries) || dataSeries.length === 0) {
console.error("Data series tidak valid:", dataSeries);
return;
}
// Perbarui data series chart
chart.updateSeries(dataSeries);
// Perbarui label jika diperlukan
if (Array.isArray(labels) && labels.length === dataSeries.length) {
chart.updateOptions({
labels: labels
});
}
}
// Fungsi untuk format angka ke Rupiah
function formatCurrency(number) {
return new Intl.NumberFormat("id-ID", {
style: "currency",
currency: "IDR",
minimumFractionDigits: 0
}).format(number);
}
const pbgTaskColumns = [
"No",
"Name",
"Nomor Registrasi",
"Nomor Dokumen",
"Alamat",
]

View File

@@ -24,10 +24,9 @@ document.addEventListener("DOMContentLoaded", function (e) {
method: "POST",
credentials: "include",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
"Content-Type": "application/json",
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
},
body: formData,
});
@@ -35,7 +34,7 @@ document.addEventListener("DOMContentLoaded", function (e) {
if (response.ok) {
let result = await response.json();
document.getElementById("toast-message").innerText =
result.message;
result.data.message;
toast.show();
setTimeout(() => {
window.location.href = "/data-settings";
@@ -46,6 +45,8 @@ 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,46 +2,34 @@ 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.table = null; // Store Grid.js instance
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();
}
init() {
this.getFetchApiData();
initEvents() {
document.body.addEventListener("click", async (event) => {
const deleteButton = event.target.closest(
".btn-delete-data-settings"
);
if (deleteButton) {
event.preventDefault();
await this.handleDelete(deleteButton);
}
});
}
getFetchApiData() {
initTableDataSettings() {
let tableContainer = document.getElementById("table-data-settings");
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;
}
// Create a new Grid.js instance only if it doesn't exist
this.table = new Grid({
columns: [
"ID",
@@ -65,11 +53,6 @@ class DataSettings {
},
},
],
search: {
server: {
url: (prev, keyword) => `${prev}?search=${keyword}`,
},
},
pagination: {
limit: 15,
server: {
@@ -80,8 +63,13 @@ class DataSettings {
},
},
sort: true,
search: {
server: {
url: (prev, keyword) => `${prev}?search=${keyword}`,
},
},
server: {
url: `${GlobalConfig.apiHost}/api/api-data-settings`,
url: `${GlobalConfig.apiHost}/api/data-settings`,
headers: {
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
@@ -99,94 +87,26 @@ class DataSettings {
total: (data) => data.meta.total,
},
}).render(tableContainer);
document.addEventListener("click", this.handleDelete.bind(this));
}
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");
async handleDelete(deleteButton) {
const id = deleteButton.getAttribute("data-id");
if (!modalElement) {
console.error("Modal element not found!");
return;
}
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!",
});
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`,
if (result.isConfirmed) {
try {
let response = await fetch(
`${GlobalConfig.apiHost}/api/data-settings/${id}`,
{
method: "DELETE",
credentials: "include",
headers: {
Authorization: `Bearer ${document
@@ -194,21 +114,34 @@ class DataSettings {
.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();
}
);
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();
}
}
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new DataSettings().init();
new DataSettings();
});

View File

@@ -24,16 +24,16 @@ document.addEventListener("DOMContentLoaded", function (e) {
let response = await fetch(form.action, {
method: "POST",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
},
body: formData,
});
if (response.ok) {
let result = await response.json();
toastMessage.innerText = result.message;
toastMessage.innerText = result.data.message;
toast.show();
setTimeout(() => {
window.location.href = "/data-settings";
@@ -43,6 +43,8 @@ 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

@@ -19,15 +19,24 @@ document.addEventListener("DOMContentLoaded", function (e) {
submitButton.disabled = true;
spinner.classList.remove("d-none");
let jsonData = {};
formData.forEach((value, key) => {
jsonData[key] = value;
});
console.log(jsonData);
try {
let response = await fetch(form.action, {
method: "POST",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
"Content-Type": "application/json",
Accept: "application/json",
Authorization: `Bearer ${document
.querySelector('meta[name="api-token"]')
.getAttribute("content")}`,
},
body: formData,
body: JSON.stringify(jsonData),
});
if (response.ok) {

View File

@@ -1,55 +1,67 @@
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");
class CreateMenu {
constructor() {
this.initCreateMenu();
}
if (!form) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
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");
// Disable button and show spinner
submitButton.disabled = true;
spinner.classList.remove("d-none");
if (!form) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
try {
let response = await fetch(form.action, {
method: "POST",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
},
body: formData,
});
// Disable button and show spinner
submitButton.disabled = true;
spinner.classList.remove("d-none");
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();
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();
console.error("Error:", error);
}
} catch (error) {
console.error("Request failed:", error);
document.getElementById("toast-message").innerText =
error.message;
toast.show();
}
});
});
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new CreateMenu();
});

View File

@@ -2,13 +2,27 @@ 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;
}
init() {
// 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);
}
});
}
initTableMenus() {
@@ -19,7 +33,7 @@ class Menus {
this.table
.updateConfig({
server: {
url: `${GlobalConfig.apiHost}/api/api-menus`,
url: `${GlobalConfig.apiHost}/api/menus`,
credentials: "include",
headers: {
Authorization: `Bearer ${document
@@ -60,7 +74,8 @@ 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>
@@ -83,7 +98,7 @@ class Menus {
},
},
server: {
url: `${GlobalConfig.apiHost}/api/api-menus`,
url: `${GlobalConfig.apiHost}/api/menus`,
credentials: "include",
headers: {
Authorization: `Bearer ${document
@@ -104,118 +119,63 @@ class Menus {
total: (data) => data.total,
},
}).render(tableContainer);
document.addEventListener("click", this.handleDelete.bind(this));
}
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");
async handleDelete(button) {
const id = button.getAttribute("data-id");
if (!modalElement) {
console.error("Modal element not found!");
return;
}
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!",
});
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}`, {
if (result.isConfirmed) {
try {
let response = await fetch(
`${GlobalConfig.apiHost}/api/menus/${id}`,
{
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",
},
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
}
);
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();
}
}
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new Menus().init();
new Menus();
});

View File

@@ -1,53 +1,67 @@
document.addEventListener("DOMContentLoaded", function (e) {
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;
class UpdateMenu {
constructor() {
this.initUpdateMenu();
}
if (!form) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
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");
// Disable button and show spinner
submitButton.disabled = true;
spinner.classList.remove("d-none");
if (!form) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
try {
let response = await fetch(form.action, {
method: "POST",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
},
body: formData,
// 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();
}
});
}
}
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();
}
});
document.addEventListener("DOMContentLoaded", function (e) {
new UpdateMenu();
});

View File

@@ -1,55 +1,67 @@
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");
class CreateRoles {
constructor() {
this.initCreateRole();
}
if (!form) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
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");
// Disable button and show spinner
submitButton.disabled = true;
spinner.classList.remove("d-none");
if (!form) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
try {
let response = await fetch(form.action, {
method: "POST",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
},
body: formData,
});
// Disable button and show spinner
submitButton.disabled = true;
spinner.classList.remove("d-none");
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();
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();
console.error("Error:", error);
}
} catch (error) {
console.error("Request failed:", error);
document.getElementById("toast-message").innerText =
error.message;
toast.show();
}
});
});
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new CreateRoles();
});

View File

@@ -2,46 +2,31 @@ 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.table = null; // Store Grid.js instance
}
this.toastMessage = document.getElementById("toast-message");
this.toastElement = document.getElementById("toastNotification");
this.toast = new bootstrap.Toast(this.toastElement);
this.table = null;
init() {
// Initialize functions
this.initTableRoles();
this.initEvents();
}
initEvents() {
document.body.addEventListener("click", async (event) => {
const deleteButton = event.target.closest(".btn-delete-role");
if (deleteButton) {
event.preventDefault();
await this.handleDelete(deleteButton);
}
});
}
initTableRoles() {
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: [
@@ -82,7 +67,7 @@ class Roles {
},
},
server: {
url: `${GlobalConfig.apiHost}/api/api-roles`,
url: `${GlobalConfig.apiHost}/api/roles`,
credentials: "include",
headers: {
Authorization: `Bearer ${document
@@ -100,116 +85,63 @@ class Roles {
total: (data) => data.total,
},
}).render(tableContainer);
document.addEventListener("click", this.handleDelete.bind(this));
}
handleDelete(event) {
if (event.target.classList.contains("btn-delete-role")) {
event.preventDefault();
async handleDelete(deleteButton) {
const id = deleteButton.getAttribute("data-id");
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;
}
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}`, {
if (result.isConfirmed) {
try {
let response = await fetch(
`${GlobalConfig.apiHost}/api/roles/${id}`,
{
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",
},
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
}
);
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();
}
}
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new Roles().init();
new Roles();
});

View File

@@ -1,53 +1,67 @@
document.addEventListener("DOMContentLoaded", function (e) {
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;
class UpdateRoles {
constructor() {
this.initUpdateRole();
}
if (!form) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
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");
// Disable button and show spinner
submitButton.disabled = true;
spinner.classList.remove("d-none");
if (!form) {
console.error("Form element not found!");
return;
}
// Get form data
let formData = new FormData(form);
try {
let response = await fetch(form.action, {
method: "POST",
headers: {
"X-CSRF-TOKEN": document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content"),
},
body: formData,
// 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();
}
});
}
}
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();
}
});
document.addEventListener("DOMContentLoaded", function (e) {
new UpdateRoles();
});

View File

@@ -0,0 +1,34 @@
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

@@ -1,15 +0,0 @@
<?php
namespace [% namespace %];
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
[% response_methods %]
}

View File

@@ -1 +0,0 @@
return new [% api_resource_class %]($[% model_name_singular_variable %], [% model_was_deleted %]);

View File

@@ -1,4 +0,0 @@
return $this->successResponse(
[% model_was_deleted %],
$this->transform($[% model_name_singular_variable %])
);

View File

@@ -1 +0,0 @@
return new [% api_resource_collection_class %]($[% model_name_plural_variable %], [% models_were_retrieved %]);

View File

@@ -1,26 +0,0 @@
$[% data_variable %] = $[% model_name_plural_variable %]->transform(function ($[% model_name_singular_variable %]) {
return $this->transform($[% model_name_singular_variable %]);
});
return $this->successResponse(
[% models_were_retrieved %],
$[% data_variable %],
[
'links' => [
'first' => $[% model_name_plural_variable %]->url(1),
'last' => $[% model_name_plural_variable %]->url($[% model_name_plural_variable %]->lastPage()),
'prev' => $[% model_name_plural_variable %]->previousPageUrl(),
'next' => $[% model_name_plural_variable %]->nextPageUrl(),
],
'meta' =>
[
'current_page' => $[% model_name_plural_variable %]->currentPage(),
'from' => $[% model_name_plural_variable %]->firstItem(),
'last_page' => $[% model_name_plural_variable %]->lastPage(),
'path' => $[% model_name_plural_variable %]->resolveCurrentPath(),
'per_page' => $[% model_name_plural_variable %]->perPage(),
'to' => $[% model_name_plural_variable %]->lastItem(),
'total' => $[% model_name_plural_variable %]->total(),
],
]
);

View File

@@ -1 +0,0 @@
return new [% api_resource_class %]($[% model_name_singular_variable %], [% model_was_retrieved %]);

View File

@@ -1,4 +0,0 @@
return $this->successResponse(
[% model_was_retrieved %],
$this->transform($[% model_name_singular_variable %])
);

View File

@@ -1 +0,0 @@
return new [% api_resource_class %]($[% model_name_singular_variable %], [% model_was_added %]);

View File

@@ -1,4 +0,0 @@
return $this->successResponse(
[% model_was_added %],
$this->transform($[% model_name_singular_variable %])
);

View File

@@ -1 +0,0 @@
return new [% api_resource_class %]($[% model_name_singular_variable %], [% model_was_updated %]);

View File

@@ -1,4 +0,0 @@
return $this->successResponse(
[% model_was_updated %],
$this->transform($[% model_name_singular_variable %])
);

View File

@@ -1,14 +0,0 @@
/**
* Get an error response
*
* @param mix $message
*
* @return Illuminate\Http\Response
*/
protected function errorResponse($message)
{
return response()->json([
'errors' => (array) $message,
'success' => false,
], 422);
}

View File

@@ -1,16 +0,0 @@
/**
* Gets a new validator instance with the defined rules.
*
* @param [% request_fullname %] $request
*
* @return Illuminate\Support\Facades\Validator
*/
protected function getValidator(Request $request)
{
$rules = [
[% validation_rules %]
];
[% file_validation_snippet %]
return Validator::make($request->all(), $rules);
}

View File

@@ -1,18 +0,0 @@
/**
* Get a success response
*
* @param mix $message
* @param mix $data
* @param array $meta
*
* @return Illuminate\Http\Response
*/
protected function successResponse($message, $data, array $meta = [])
{
return response()->json(
array_merge([
'data' => $data,
'message' => $message,
'success' => true,
], $meta), 200);
}

View File

@@ -1,13 +0,0 @@
/**
* Transform the giving [% model_name %] to public friendly array
*
* @param [% use_full_model_name %] $[% model_name_singular_variable %]
*
* @return array
*/
protected function [% transform_method_name %]([% model_name_class %] $[% model_name_singular_variable %])
{
return [
[% model_api_array %]
];
}

View File

@@ -1,5 +0,0 @@
$validator = $this->getValidator($request);
if ($validator->fails()) {
return $this->errorResponse($validator->errors()->all());
}

View File

@@ -1,104 +0,0 @@
<?php
namespace [% namespace %];
[% use_command_placeholder %]
use Exception;
class [% controller_name %] [% controller_extends %]
{
[% constructor %]
/**
* Display a listing of the assets.
*
* @return Illuminate\View\View
*/
public function index()
{
$[% model_name_plural_variable %] = [% model_name_class %]::[% with_relations_for_index %]paginate([% models_per_page %]);
[% index_return_success %]
}
/**
* Store a new [% model_name %] in the storage.
*
* @param [% request_fullname %] [% request_variable %]
*
* @return Illuminate\Http\Response
*/
public function store([% type_hinted_request_name %])
{
try {
[% validator_request %]
$[% data_variable %] = [% call_get_data %];
[% on_store_setter %]
$[% model_name_singular_variable %] = [% model_name_class %]::create($[% data_variable %]);
[% store_return_success %]
} catch (Exception $exception) {
return $this->errorResponse([% unexpected_error %]);
}
}
/**
* Display the specified [% model_name %].
*
* @param int $id
*
* @return Illuminate\Http\Response
*/
public function show($id)
{
$[% model_name_singular_variable %] = [% model_name_class %]::[% with_relations_for_show %]findOrFail($id);
[% show_return_success %]
}
/**
* Update the specified [% model_name %] in the storage.
*
* @param int $id
* @param [% request_fullname %] [% request_variable %]
*
* @return Illuminate\Http\Response
*/
public function update($id, [% type_hinted_request_name %])
{
try {
[% validator_request %]
$[% data_variable %] = [% call_get_data %];
[% on_update_setter %]
$[% model_name_singular_variable %] = [% model_name_class %]::findOrFail($id);
$[% model_name_singular_variable %]->update($[% data_variable %]);
[% update_return_success %]
} catch (Exception $exception) {
return $this->errorResponse([% unexpected_error %]);
}
}
/**
* Remove the specified [% model_name %] from the storage.
*
* @param int $id
*
* @return Illuminate\Http\Response
*/
public function destroy($id)
{
try {
$[% model_name_singular_variable %] = [% model_name_class %]::findOrFail($id);
$[% model_name_singular_variable %]->delete();
[% destroy_return_success %]
} catch (Exception $exception) {
return $this->errorResponse([% unexpected_error %]);
}
}
[% get_validator_method %]
[% get_data_method %]
[% upload_method %]
[% transform_method %]
[% response_methods %]
}

View File

@@ -1,21 +0,0 @@
<?php
namespace [% namespace %];
[% use_command_placeholder %]
class [% controller_name %] [% controller_extends %]
{
[% constructor %]
/**
* Display the documentation which corresponds to the giving version.
*
* @return Illuminate\View\View
*/
public function index($version)
{
$viewName = sprintf('[% view_access_fullname %]index', $this->getVersion($version));
return view($viewName);
}
}

View File

@@ -1,20 +0,0 @@
<?php
namespace [% namespace %];
[% use_command_placeholder %]
class [% controller_name %] [% controller_extends %]
{
[% constructor %]
/**
* Display the documentation's view.
*
* @return Illuminate\View\View
*/
public function index()
{
return view('[% view_access_fullname %]index');
}
}

View File

@@ -1 +0,0 @@
<span class="label label-danger" title="[% this_parameter_must_be_present_in_the_request %]">[% required_title %]</span>

View File

@@ -1,11 +0,0 @@
<tr>
<td>Authorization</td>
<td>[% string_title %]</td>
<td>
<span class="label label-primary" title="[% this_parameter_is_an_http_header %]">[% header_title %]</span>
</td>
<td>[% access_token_with_bearer %]</td>
@if(isset($showValidation) && $showValidation)
<td></td>
@endif
</tr>

View File

@@ -1,16 +0,0 @@
<h4 class="text-danger"><strong>401 - Unauthorized</strong></h4>
<p class="text-muted">[% the_user_does_not_have_permission_to_access_the_requested_resource %]</p>
<table class="table table-stripped">
<tbody>
<tr>
<td>success</td>
<td>[% boolean_title %]</td>
<td>[% indicate_whether_the_request_was_successful_or_not %]</td>
</tr>
<tr>
<td>error</td>
<td>[% array_of_strings %]</td>
<td>[% the_error_message %]</td>
</tr>
</tbody>
</table>

View File

@@ -1,16 +0,0 @@
<h4 class="text-danger"><strong>202 - Accepted</strong></h4>
<p class="text-muted">[% the_requested_model_does_not_exists %]</p>
<table class="table table-stripped">
<tbody>
<tr>
<td>success</td>
<td>[% boolean_title %]</td>
<td>[% indicate_whether_the_request_was_successful_or_not %]</td>
</tr>
<tr>
<td>error</td>
<td>[% array_of_strings %]</td>
<td>[% the_error_message %]</td>
</tr>
</tbody>
</table>

View File

@@ -1,16 +0,0 @@
<h4 class="text-danger"><strong>422 - Unprocessable Entity</strong></h4>
<p class="text-muted">[% the_request_failed_validation %]</p>
<table class="table table-stripped">
<tbody>
<tr>
<td>success</td>
<td>[% boolean_title %]</td>
<td>[% indicate_whether_the_request_was_successful_or_not %]</td>
</tr>
<tr>
<td>errors</td>
<td>[% array_of_strings %]</td>
<td>[% list_of_the_invalid_errors %]</td>
</tr>
</tbody>
</table>

View File

@@ -1,5 +0,0 @@
<tr>
<td>[% field_name %]</td>
<td>[% field_type_title %]</td>
<td>[% api_field_description %]</td>
</tr>

View File

@@ -1,12 +0,0 @@
<tr>
<td>[% field_name %]</td>
<td>[% field_type_title %]</td>
<td><span class="label label-default" title="[% this_parameter_is_part_of_the_body %]">[% body_title %]</span></td>
<td>[% api_field_description %]</td>
@if($showValidation)
<td>
[% validation_rule_required %]
<span>[% validation_rules %]</span>
</td>
@endif
</tr>

View File

@@ -1,37 +0,0 @@
<?php
$showValidation = (isset($withValidation) && $withValidation) ? true : false;
?>
<table class="table table-stripped">
<thead>
<tr>
<th>[% parameter_name_title %]</th>
<th>[% data_type_title %]</th>
<th>[% parameter_type_title %]</th>
<th>[% description_title %]</th>
@if($showValidation)
<th>[% validation_title %]</th>
@endif
</tr>
</thead>
<tbody>
[% include_parameter_for_authorized_request %]
@if(isset($withPathId) && $withPathId)
<tr>
<td>[% model_name %]</td>
<td>[% primary_key_type_title %]</td>
<td><span class="label label-info" title="[% this_parameter_is_part_of_the_path %]">[% path_title %]</span></td>
<td>[% the_id_of_the_model %]</td>
@if($showValidation)
<td>
[% validation_rule_required %]
</td>
@endif
</tr>
@endif
[% fields_list_for_body %]
</tbody>
</table>

View File

@@ -1,14 +0,0 @@
<table class="table table-stripped">
<thead>
<tr>
<th>[% parameter_name_title %]</th>
<th>[% data_type_title %]</th>
<th>[% parameter_type_title %]</th>
<th>[% description_title %]</th>
</tr>
</thead>
<tbody>
[% include_parameter_for_authorized_request %]
</tbody>
</table>

View File

@@ -1,5 +0,0 @@
<tr>
<td>[% field_name %]</td>
<td>[% field_type_title %]</td>
<td>[% api_field_description %]</td>
</tr>

View File

@@ -1,12 +0,0 @@
<table class="table table-stripped">
<thead>
<tr>
<th>[% name_title %]</th>
<th>[% type_title %]</th>
<th>[% description_title %]</th>
</tr>
</thead>
<tbody>
[% fields_list_for_body %]
</tbody>
</table>

View File

@@ -1,21 +0,0 @@
<h4 class="text-success"><strong>200 - Ok</strong></h4>
<p class="text-muted">[% request_was_successful %]</p>
<table class="table table-stripped">
<tbody>
<tr>
<td>success</td>
<td>[% boolean_title %]</td>
<td>[% indicate_whether_the_request_was_successful_or_not %]</td>
</tr>
<tr>
<td>message</td>
<td>[% string_title %]</td>
<td>[% the_success_message %]</td>
</tr>
<tr>
<td>data</td>
<td>[% array_title %]</td>
<td>[% the_key_is_the_model_property_and_the_value_is_the_model_value %]</td>
</tr>
</tbody>
</table>

View File

@@ -1,386 +0,0 @@
@extends('[% layout_name %]')
@section('content')
<h2>[% model_plural %]</h2>
[% general_description %]
<hr>
<h2>[% available_resources %]</h2>
<div class="card mb-3" id="index-documentation">
<div class="card-header text-bg-primary d-flex justify-content-between align-items-center p-3">
<div>
<span class="">GET</span>
<span><strong>/{{ Route::getRoutes()->getByName('[% index_route_name %]')->uri() }}</strong></span>
<p class="mb-0">[% index_route_description %]</p>
</div>
<div>
<button type="button" data-bs-toggle="collapse" data-bs-target="#index" aria-controls="index" class="btn btn-primary btn-sm" aria-expanded="false">
<span class="fa-solid fa-chevron-down"></span>
</button>
</div>
</div>
<div class="card-body collapse" id="index">
<h3><strong>[% request_title %]</strong></h3>
[% authorized_request_for_index %]
<hr>
<h3><strong>[% response_title %]</strong></h3>
<p>[% index_route_response_description %]</p>
<p></p>
<h4><strong class="text-success">200 - Ok</strong></h4>
<p class="text-muted">[% request_was_successful %]</p>
<table class="table table-stripped">
<tbody>
<tr>
<td>success</td>
<td>[% boolean_title %]</td>
<td>Was the request successful or not.</td>
</tr>
<tr>
<td>message</td>
<td>[% string_title %]</td>
<td>[% the_success_message %]</td>
</tr>
<tr>
<td>data</td>
<td>[% array_title %]</td>
<td>
[% the_key_is_the_model_property_and_the_value_is_the_model_value %]
</td>
</tr>
<tr>
<td>links</td>
<td>[% array_title %]</td>
<td>
<table class="table table-stripped">
<thead>
<tr>
<th class="col-md-2">[% key_title %]</th>
<th class="col-md-2">[% data_type_title %]</th>
<th class="col-md-8">[% description_title %]</th>
</tr>
</thead>
<tbody>
<tr>
<td>first</td>
<td>[% string_title %]</td>
<td>[% link_to_retrieve_first_page %]</td>
</tr>
<tr>
<td>last</td>
<td>[% string_title %]</td>
<td>[% link_to_retrieve_last_page %]</td>
</tr>
<tr>
<td>prev</td>
<td>[% string_title %]</td>
<td>[% link_to_retrieve_previous_page %]</td>
</tr>
<tr>
<td>next</td>
<td>[% string_title %]</td>
<td>[% link_to_retrieve_next_page %]</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>meta</td>
<td>[% array_title %]</td>
<td>
<table class="table table-stripped">
<thead>
<tr>
<th class="col-md-2">[% key_title %]</th>
<th class="col-md-2">[% data_type_title %]</th>
<th class="col-md-8">[% description_title %]</th>
</tr>
</thead>
<tbody>
<tr>
<td>current_page</td>
<td>[% integer_title %]</td>
<td>[% the_number_of_current_page %]</td>
</tr>
<tr>
<td>from</td>
<td>[% integer_title %]</td>
<td>[% the_index_of_the_first_retrieved_item %]</td>
</tr>
<tr>
<td>last_page</td>
<td>[% integer_title %]</td>
<td>[% the_number_of_the_last_page %]</td>
</tr>
<tr>
<td>Path</td>
<td>[% string_title %]</td>
<td>[% the_base_link_to_the_resource %]</td>
</tr>
<tr>
<td>per_page</td>
<td>[% integer_title %]</td>
<td>[% the_number_of_models_per_page %]</td>
</tr>
<tr>
<td>to</td>
<td>[% integer_title %]</td>
<td>[% the_index_of_the_last_retrieved_item %]</td>
</tr>
<tr>
<td>total</td>
<td>[% integer_title %]</td>
<td>[% the_total_of_available_pages %]</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
[% include_failed_authentication_for_authorized_request %]
</div>
</div>
<div class="card mb-3" id="store-documentation">
<div class="card-header text-bg-success d-flex justify-content-between align-items-center p-3">
<div>
<span>POST</span>
<span><strong>/{{ Route::getRoutes()->getByName('[% store_route_name %]')->uri() }}</strong></span>
<p class="mb-0">[% store_route_description %]</p>
</div>
<div>
<button type="button" data-bs-toggle="collapse" data-bs-target="#store" aria-controls="store" class="btn btn-success btn-sm" aria-expanded="false">
<span class="fa-solid fa-chevron-down"></span>
</button>
</div>
</div>
<div class="card-body collapse" id="store">
<h3><strong>[% request_title %]</strong></h3>
@include('[% path_to_view_home %]fields-list', [
'withValidation' => true
])
<hr>
<h3><strong>[% response_title %]</strong></h3>
<p>[% store_route_response_description %]</p>
<p></p>
@include('[% path_to_view_home %]retrieved')
@include('[% path_to_view_home %]failed-to-retrieve')
@include('[% path_to_view_home %]failed-validation')
[% include_failed_authentication_for_authorized_request %]
</div>
</div>
<div class="card mb-3" id="update-documentation">
<div class="card-header text-bg-warning d-flex justify-content-between align-items-center p-3">
<div>
<span class="">POST</span>
<span><strong>/{{ Route::getRoutes()->getByName('[% update_route_name %]')->uri() }}</strong></span>
<p class="mb-0">[% update_route_description %]</p>
</div>
<div>
<button type="button" data-bs-toggle="collapse" data-bs-target="#update" aria-controls="update" class="btn btn-warning btn-sm" aria-expanded="false">
<span class="fa-solid fa-chevron-down"></span>
</button>
</div>
</div>
<div class="card-collapse collapse" id="update">
<div class="card-body">
<h3><strong>[% request_title %]</strong></h3>
@include('[% path_to_view_home %]fields-list', [
'withValidation' => true,
'withPathId' => true,
])
<hr>
<h3><strong>[% response_title %]</strong></h3>
<p>[% update_route_response_description %]</p>
<p></p>
@include('[% path_to_view_home %]retrieved')
@include('[% path_to_view_home %]failed-to-retrieve')
@include('[% path_to_view_home %]failed-validation')
[% include_failed_authentication_for_authorized_request %]
</div>
</div>
</div>
<div class="card mb-3" id="show-documentation">
<div class="card-header text-bg-info d-flex justify-content-between align-items-center p-3">
<div>
<span class="">GET</span>
<span><strong>/{{ Route::getRoutes()->getByName('[% show_route_name %]')->uri() }}</strong></span>
<p class="mb-0">[% show_route_description %]</p>
</div>
<div>
<button type="button" data-bs-toggle="collapse" data-bs-target="#show" aria-controls="show" class="btn btn-info btn-sm" aria-expanded="false">
<span class="fa-solid fa-chevron-down"></span>
</button>
</div>
</div>
<div class="card-body collapse" id="show">
<h3><strong>[% request_title %]</strong></h3>
<table class="table table-stripped">
<thead>
<tr>
<th class="col-md-2">[% parameter_name_title %]</th>
<th class="col-md-2">[% data_type_title %]</th>
<th class="col-md-2">[% parameter_type_title %]</th>
<th class="col-md-6">[% description_title %]</th>
</tr>
</thead>
<tbody>
[% include_parameter_for_authorized_request %]
<tr>
<td>[% model_name %]</td>
<td>[% integer_title %]</td>
<td><span class="label label-info" title="[% this_parameter_is_part_of_the_path %]">[% path_title %]</span></td>
<td>[% the_id_of_model_to_retrieve %]</td>
</tr>
</tbody>
</table>
<hr>
<h3><strong>[% response_title %]</strong></h3>
<p>[% show_route_response_description %] </p>
<p></p>
@include('[% path_to_view_home %]retrieved')
@include('[% path_to_view_home %]failed-to-retrieve')
[% include_failed_authentication_for_authorized_request %]
</div>
</div>
<div class="card card-danger mb-3" id="destroy-documentation">
<div class="card-header text-bg-danger d-flex justify-content-between align-items-center p-3">
<div>
<span class="">DELETE</span>
<span><strong>/{{ Route::getRoutes()->getByName('[% destroy_route_name %]')->uri() }}</strong></span>
<p class="mb-0">[% destroy_route_description %]</p>
</div>
<div>
<button type="button" data-bs-toggle="collapse" data-bs-target="#destroy" aria-controls="destroy" class="btn btn-danger btn-sm" aria-expanded="false">
<span class="fa-solid fa-chevron-down"></span>
</button>
</div>
</div>
<div class="card-body collapse" id="destroy">
<h3><strong>[% request_title %]</strong></h3>
<table class="table table-stripped">
<thead>
<tr>
<th class="col-md-2">[% parameter_name_title %]</th>
<th class="col-md-2">[% data_type_title %]</th>
<th class="col-md-2">[% parameter_type_title %]</th>
<th class="col-md-6">[% description_title %]</th>
</tr>
</thead>
<tbody>
[% include_parameter_for_authorized_request %]
<tr>
<td>[% model_name %]</td>
<td>[% integer_title %]</td>
<td><span class="label label-info" title="[% this_parameter_is_part_of_the_path %]">[% path_title %]</span></td>
<td>[% the_id_of_model_to_delete %]</td>
</tr>
</tbody>
</table>
<hr>
<h3><strong>[% response_title %]</strong></h3>
<p>[% destroy_route_response_description %]</p>
<p></p>
@include('[% path_to_view_home %]retrieved')
@include('[% path_to_view_home %]failed-to-retrieve')
[% include_failed_authentication_for_authorized_request %]
</div>
</div>
<hr>
<h2>[% model_definition_title %]</h2>
<div class="card" id="[% model_name %]-model-documentation">
<div class="card-header text-bg-secondary d-flex justify-content-between align-items-center p-3">
<div>
<span class="">[% model_name_title %]</span>
</div>
<div>
<button type="button" data-bs-toggle="collapse" data-bs-target="#model-definitions" aria-controls="model-definitions" class="btn btn-secondary btn-sm" aria-expanded="false">
<span class="fa-solid fa-chevron-down"></span>
</button>
</div>
</div>
<div class="card-body collapse" id="model-definitions">
<table class="table table-stripped">
<thead>
<tr>
<th>[% field_name_title %]</th>
<th>[% field_type_title %]</th>
<th>[% description_title %]</th>
</tr>
</thead>
<tbody>
[% fields_list_for_body %]
</tbody>
</table>
</div>
</div>
@endsection

View File

@@ -1,2 +0,0 @@
Route::get('[% prefix %][% version %]', [[% controller_name %]::class, 'index'])
->name('[% index_route_name %]');

View File

@@ -1,2 +0,0 @@
Route::get('[% prefix %][% version %]', '[% controller_name %]@index')
->name('[% index_route_name %]');

View File

@@ -1,38 +0,0 @@
<?php
namespace [% namespace %];
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
/**
* Valid versions
*
* @var array
*/
private $versions = [
'[% api_version_number %]',
];
/**
* Get a valid version from the available list.
*
* @param string $version
*
* @return string
*/
protected function getVersion($version)
{
if (in_array($version, $this->versions)) {
return $version;
}
return end($this->versions);
}
}

View File

@@ -1,50 +0,0 @@
<?php
namespace [% namespace %];
use Illuminate\Http\Resources\Json\ResourceCollection;
use [% use_full_model_name %];
class [% api_resource_collection_class %] extends ResourceCollection
{
/**
* The response message
*
* @var mixed
*/
protected $message;
/**
* Create a new resource instance.
*
* @param mixed $resource
* @param mixed $message
*
* @return void
*/
public function __construct($resource, $message = null)
{
parent::__construct($resource);
$this->message = $message;
}
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
{
return [
'data' => $this->collection->transform(function ($[% model_name_singular_variable %]) {
return $this->transformModel($[% model_name_singular_variable %]);
}),
'message' => $this->message,
'success' => true,
];
}
[% transform_method %]
}

View File

@@ -1,59 +0,0 @@
<?php
namespace [% namespace %];
use Illuminate\Http\Resources\Json\Resource;
class [% api_resource_class %] extends Resource
{
/**
* The response message
*
* @var mixed
*/
protected $message;
/**
* Create a new resource instance.
*
* @param mixed $resource
* @param mixed $message
*
* @return void
*/
public function __construct($resource, $message = null)
{
parent::__construct($resource);
$this->message = $message;
}
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
*
* @return array
*/
public function toArray($request)
{
return [
[% model_api_array %]
];
}
/**
* Get any additional data that should be returned with the resource array.
*
* @param \Illuminate\Http\Request $request
*
* @return array
*/
public function with($request)
{
return [
'success' => true,
'message' => $this->message,
];
}
}

View File

@@ -1,10 +0,0 @@
Route::get('/', [[% controller_name %]::class, 'index'])
->name('[% index_route_name %]');
Route::get('/show/{[% model_name_singular_variable %]}',[[% controller_name %]::class, 'show'])
->name('[% show_route_name %]')[% route_id_clause %];
Route::post('/', [[% controller_name %]::class, 'store'])
->name('[% store_route_name %]');
Route::put('[% model_name_snake %]/{[% model_name_singular_variable %]}', [[% controller_name %]::class, 'update'])
->name('[% update_route_name %]')[% route_id_clause %];
Route::delete('/[% model_name_snake %]/{[% model_name_singular_variable %]}',[[% controller_name %]::class, 'destroy'])
->name('[% destroy_route_name %]')[% route_id_clause %];

View File

@@ -1,10 +0,0 @@
Route::get('/', '[% controller_name %]@index')
->name('[% index_route_name %]');
Route::get('/show/{[% model_name_singular_variable %]}','[% controller_name %]@show')
->name('[% show_route_name %]')[% route_id_clause %];
Route::post('/', '[% controller_name %]@store')
->name('[% store_route_name %]');
Route::put('[% model_name_snake %]/{[% model_name_singular_variable %]}', '[% controller_name %]@update')
->name('[% update_route_name %]')[% route_id_clause %];
Route::delete('/[% model_name_snake %]/{[% model_name_singular_variable %]}','[% controller_name %]@destroy')
->name('[% destroy_route_name %]')[% route_id_clause %];

View File

@@ -1,17 +0,0 @@
/**
* Validate the given request with the defined rules.
*
* @param [% request_fullname %] $request
*
* @return boolean
*/
protected function affirm(Request $request)
{
$rules = [
[% validation_rules %]
];
[% file_validation_snippet %]
return $this->validate($request, $rules);
}

View File

@@ -1,10 +0,0 @@
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
[% auth_middleware %]
}

View File

@@ -1,21 +0,0 @@
/**
* Get the request's data from the request.
*
* [% request_name_comment %]
* @return array
*/
[% visibility_level %] function getData([% type_hinted_request_name %])
{
$rules = [
[% validation_rules %]
];
[% file_validation_snippet %]
$data = [% request_variable %]->validate($rules);
[% file_snippet %]
[% boolean_snippet %]
[% string_to_null_snippet %]
return $data;
}

View File

@@ -1,15 +0,0 @@
/**
* Get the request's data from the request.
*
* [% request_name_comment %]
* @return array
*/
[% visibility_level %] function getData([% type_hinted_request_name %])
{
$data = [% request_variable %]->only([% fillable %]);
[% file_snippet %]
[% boolean_snippet %]
[% string_to_null_snippet %]
return $data;
}

View File

@@ -1,19 +0,0 @@
/**
* Moves the attached file to the server.
*
* @param \Symfony\Component\HttpFoundation\File\UploadedFile $file
*
* @return string
*/
protected function moveFile($file)
{
if (!$file->isValid()) {
return '';
}
$path = config('laravel-code-generator.files_upload_path', 'uploads');
$saved = $file->store('public/' . $path, config('filesystems.default'));
return substr($saved, 7);
}

View File

@@ -1,20 +0,0 @@
/**
* Moves the attached file to the server.
*
* @param \Symfony\Component\HttpFoundation\File\UploadedFile $file
*
* @return string
*/
protected function moveFile($file)
{
if (!$file->isValid()) {
return '';
}
$fileName = sprintf('%s.%s', uniqid(), $file->getClientOriginalExtension());
$destinationPath = config('laravel-code-generator.files_upload_path','uploads');
$path = $file->move($destinationPath, $fileName);
return $destinationPath . '/' . $fileName;
}

View File

@@ -1,126 +0,0 @@
<?php
namespace [% namespace %];
[% use_command_placeholder %]
use Exception;
class [% controller_name %] [% controller_extends %]
{
[% constructor %]
/**
* Display a listing of the [% model_name_plural %].
*
* @return \Illuminate\View\View
*/
public function index()
{
$[% model_name_plural_variable %] = [% model_name_class %]::[% with_relations_for_index %]paginate([% models_per_page %]);
return view('[% index_view_name %]'[% view_variables_for_index %]);
}
/**
* Show the form for creating a new [% model_name %].
*
* @return \Illuminate\View\View
*/
public function create()
{
[% relation_collections %]
return view('[% create_view_name %]'[% view_variables_for_create %]);
}
/**
* Store a new [% model_name %] in the storage.
*
* @param [% request_fullname %] [% request_variable %]
*
* @return \Illuminate\Http\RedirectResponse | \Illuminate\Routing\Redirector
*/
public function store([% type_hinted_request_name %])
{
[% call_affirm %]
$[% data_variable %] = [% call_get_data %];
[% on_store_setter %]
[% model_name_class %]::create($[% data_variable %]);
return redirect()->route('[% index_route_name %]')
->with('success_message', [% model_was_added %]);
}
/**
* Display the specified [% model_name %].
*
* @param int $id
*
* @return \Illuminate\View\View
*/
public function show($id)
{
$[% model_name_singular_variable %] = [% model_name_class %]::[% with_relations_for_show %]findOrFail($id);
return view('[% show_view_name %]'[% view_variables_for_show %]);
}
/**
* Show the form for editing the specified [% model_name %].
*
* @param int $id
*
* @return \Illuminate\View\View
*/
public function edit($id)
{
$[% model_name_singular_variable %] = [% model_name_class %]::findOrFail($id);
[% relation_collections %]
return view('[% edit_view_name %]'[% view_variables_for_edit %]);
}
/**
* Update the specified [% model_name %] in the storage.
*
* @param int $id
* @param [% request_fullname %] [% request_variable %]
*
* @return \Illuminate\Http\RedirectResponse | \Illuminate\Routing\Redirector
*/
public function update($id, [% type_hinted_request_name %])
{
[% call_affirm %]
$[% data_variable %] = [% call_get_data %];
[% on_update_setter %]
$[% model_name_singular_variable %] = [% model_name_class %]::findOrFail($id);
$[% model_name_singular_variable %]->update($[% data_variable %]);
return redirect()->route('[% index_route_name %]')
->with('success_message', [% model_was_updated %]);
}
/**
* Remove the specified [% model_name %] from the storage.
*
* @param int $id
*
* @return \Illuminate\Http\RedirectResponse | \Illuminate\Routing\Redirector
*/
public function destroy($id)
{
try {
$[% model_name_singular_variable %] = [% model_name_class %]::findOrFail($id);
$[% model_name_singular_variable %]->delete();
return redirect()->route('[% index_route_name %]')
->with('success_message', [% model_was_deleted %]);
} catch (Exception $exception) {
return back()->withInput()
->withErrors(['unexpected_error' => [% unexpected_error %]]);
}
}
[% affirm_method %]
[% get_data_method %]
[% upload_method %]
}

View File

@@ -1,46 +0,0 @@
@extends('[% layout_name %]')
@section('content')
<div class="card text-bg-theme">
<div class="card-header d-flex justify-content-between align-items-center p-3">
<h4 class="m-0">[% create_model %]</h4>
<div>
<a href="{{ route('[% index_route_name %]') }}" class="btn btn-primary" title="[% show_all_models %]">
<span class="fa-solid fa-table-list" aria-hidden="true"></span>
</a>
</div>
</div>
<div class="card-body">
@if ($errors->any())
<div class="alert alert-danger" role="alert">
<ul class="list-unstyled mb-0">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form method="POST" class="needs-validation" novalidate action="{{ route('[% store_route_name %]') }}" accept-charset="UTF-8" id="[% form_id %]" name="[% form_name %]" [% upload_files %]>
{{ csrf_field() }}
@include ('[% form_view_name %]', [
'[% model_name_singular_variable %]' => null,
])
<div class="col-lg-10 col-xl-9 offset-lg-2 offset-xl-3">
<input class="btn btn-primary" type="submit" value="[% add %]">
</div>
</form>
</div>
</div>
@endsection

View File

@@ -1,47 +0,0 @@
@extends('[% layout_name %]')
@section('content')
<div class="card text-bg-theme">
<div class="card-header d-flex justify-content-between align-items-center p-3">
<h4 class="m-0">{{ !empty([% model_header %]) ? [% model_header %] : '[% model_name_title %]' }}</h4>
<div>
<a href="{{ route('[% index_route_name %]') }}" class="btn btn-primary" title="[% show_all_models %]">
<span class="fa-solid fa-table-list" aria-hidden="true"></span>
</a>
<a href="{{ route('[% create_route_name %]') }}" class="btn btn-secondary" title="[% create_model %]">
<span class="fa-solid fa-plus" aria-hidden="true"></span>
</a>
</div>
</div>
<div class="card-body">
@if ($errors->any())
<div class="alert alert-danger" role="alert">
<ul class="list-unstyled mb-0">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form method="POST" class="needs-validation" novalidate action="{{ route('[% update_route_name %]', $[% model_name_singular_variable %]->[% primary_key %]) }}" id="[% form_id %]" name="[% form_name %]" accept-charset="UTF-8" [% upload_files %]>
{{ csrf_field() }}
<input name="_method" type="hidden" value="PUT">
@include ('[% form_view_name %]', [
'[% model_name_singular_variable %]' => $[% model_name_singular_variable %],
])
<div class="col-lg-10 col-xl-9 offset-lg-2 offset-xl-3">
<input class="btn btn-primary" type="submit" value="[% update %]">
</div>
</form>
</div>
</div>
@endsection

View File

@@ -1,14 +0,0 @@
<div class="mb-3">
<input class="form-control{{ $errors->has('[% field_name %]') ? ' is-invalid' : '' }}" type="file" name="[% field_name %]" id="[% field_name %]" class="[% css_class %]">
</div>
@if (isset($[% model_name_singular_variable %]->[% field_name %]) && !empty($[% model_name_singular_variable %]->[% field_name %]))
<div class="input-group mb-3">
<div class="form-check">
<input type="checkbox" name="custom_delete_[% field_name %]" id="custom_delete_[% field_name %]" class="form-check-input custom-delete-file" value="1" {{ old('custom_delete_[% field_name %]', '0') == '1' ? 'checked' : '' }}>
</div>
<label class="form-check-label" for="custom_delete_[% field_name %]"> Delete {{ [% field_value %] }}</label>
</div>
@endif

Some files were not shown because too many files have changed in this diff Show More