diff --git a/.env.example b/.env.example index b4fad41..3ef4203 100755 --- a/.env.example +++ b/.env.example @@ -65,6 +65,5 @@ AWS_USE_PATH_STYLE_ENDPOINT=false VITE_APP_NAME="${APP_NAME}" -SIMBG_HOST="xxxxxx" -SIMBG_EMAIL="xxxxxx" -SIMBG_PASSWORD="xxxxx" \ No newline at end of file +API_KEY_GOOGLE="xxxxx" +SPREAD_SHEET_ID="xxxxx" \ No newline at end of file diff --git a/app/Http/Controllers/Api/DashboardController.php b/app/Http/Controllers/Api/DashboardController.php index 2abb2ad..394aded 100644 --- a/app/Http/Controllers/Api/DashboardController.php +++ b/app/Http/Controllers/Api/DashboardController.php @@ -12,42 +12,47 @@ class DashboardController extends Controller use GlobalApiResponse; public function businnessDocument(Request $request){ - $businessData = DB::table('pbg_task') - ->leftJoin('pbg_task_retributions', 'pbg_task.uuid', '=', 'pbg_task_retributions.pbg_task_uid') - ->select( - DB::raw('COUNT(DISTINCT pbg_task.id) as task_count'), - DB::raw('SUM(pbg_task_retributions.nilai_retribusi_bangunan) as total_retribution') - ) + $query = DB::table('pbg_task AS pt') + ->leftJoin('pbg_task_google_sheet AS ptgs', 'pt.registration_number', '=', 'ptgs.no_registrasi') + ->leftJoin('pbg_task_retributions AS ptr', 'pt.uuid', '=', 'ptr.pbg_task_uid') // Join ke pbg_task_retributions ->where(function ($query) { - $query->where("pbg_task.function_type", "LIKE", "sebagai tempat usaha%"); + $query->whereRaw('LOWER(TRIM(ptgs.status_verifikasi)) != ?', [strtolower(trim('Selesai Verifikasi'))]) + ->orWhereNull('ptgs.status_verifikasi'); }) + ->where(function ($query) { + $query->whereRaw('LOWER(TRIM(pt.function_type)) = ?', [strtolower(trim('Sebagai Tempat Usaha'))]); + }) + ->selectRaw('COUNT(pt.id) AS total_data, + SUM(ptr.nilai_retribusi_bangunan) AS total_retribution') // Menambahkan SUM dari pbg_task_retributions ->first(); - $taskCount = $businessData->task_count; - $taskTotal = $businessData->total_retribution; + $taskCount = $query->total_data; + $taskTotal = $query->total_retribution ?? 0; $result = [ "count" => $taskCount, - "series" => [$taskCount], "total" => $taskTotal ]; return $this->resSuccess($result); } public function nonBusinnessDocument(Request $request){ - $businessData = DB::table('pbg_task') - ->leftJoin('pbg_task_retributions', 'pbg_task.uuid', '=', 'pbg_task_retributions.pbg_task_uid') - ->select( - DB::raw('COUNT(DISTINCT pbg_task.id) as task_count'), - DB::raw('SUM(pbg_task_retributions.nilai_retribusi_bangunan) as total_retribution') - ) + + $query = DB::table('pbg_task AS pt') + ->leftJoin('pbg_task_google_sheet AS ptgs', 'pt.registration_number', '=', 'ptgs.no_registrasi') + ->leftJoin('pbg_task_retributions AS ptr', 'pt.uuid', '=', 'ptr.pbg_task_uid') // Join ke pbg_task_retributions ->where(function ($query) { - $query->where("pbg_task.function_type", "NOT LIKE", "sebagai tempat usaha%") - ->orWhereNull("pbg_task.function_type"); + $query->whereRaw('LOWER(TRIM(ptgs.status_verifikasi)) != ?', [strtolower(trim('Selesai Verifikasi'))]) + ->orWhereNull('ptgs.status_verifikasi'); // Include NULL values }) + ->where(function ($query) { + $query->whereRaw('LOWER(TRIM(pt.function_type)) != ?', [strtolower(trim('Sebagai Tempat Usaha'))]) + ->orWhereNull('pt.function_type'); // Include NULL values + }) + ->selectRaw('COUNT(pt.id) AS total_data, + SUM(ptr.nilai_retribusi_bangunan) AS total_retribution') // Menambahkan SUM dari pbg_task_retributions ->first(); - $taskCount = $businessData->task_count; - $taskTotal = $businessData->total_retribution; + $taskCount = $query->total_data; + $taskTotal = $query->total_retribution ?? 0; $result = [ "count" => $taskCount, - "series" => [$taskCount], "total" => $taskTotal ]; return $this->resSuccess($result); @@ -64,12 +69,54 @@ class DashboardController extends Controller $taskTotal = $query->total_retribution; $result = [ "count" => $taskCount, - "series" => [$taskCount], "total" => $taskTotal ]; return $this->resSuccess($result); } + public function verificationDocuments(){ + $query = DB::table('pbg_task AS pt') + ->leftJoin('pbg_task_google_sheet AS ptgs', 'pt.registration_number', '=', 'ptgs.no_registrasi') + ->leftJoin('pbg_task_retributions AS ptr', 'pt.uuid', '=', 'ptr.pbg_task_uid') // Menambahkan join ke pbg_task_retributions + ->whereRaw('LOWER(TRIM(ptgs.status_verifikasi)) = ?', [strtolower(trim('Selesai Verifikasi'))]) + ->selectRaw('COUNT(pt.id) AS total_data, + SUM(ptr.nilai_retribusi_bangunan) AS total_retribution') + ->first(); + + $taskCount = $query->total_data; + $taskTotal = $query->total_retribution; + + $result = [ + "count"=> $taskCount, + "total"=> $taskTotal + ]; + + return $this->resSuccess($result); + } + + public function nonVerificationDocuments(){ + $query = DB::table('pbg_task AS pt') + ->leftJoin('pbg_task_google_sheet AS ptgs', 'pt.registration_number', '=', 'ptgs.no_registrasi') + ->leftJoin('pbg_task_retributions AS ptr', 'pt.uuid', '=', 'ptr.pbg_task_uid') // Join tabel pbg_task_retributions + ->where(function ($query) { + $query->whereRaw('LOWER(TRIM(ptgs.status_verifikasi)) != ?', [strtolower(trim('Selesai Verifikasi'))]) + ->orWhereNull('ptgs.status_verifikasi'); // Include NULL values + }) + ->selectRaw('COUNT(pt.id) AS total_data, + SUM(ptr.nilai_retribusi_bangunan) AS total_retribution') // Menambahkan SUM dari pbg_task_retributions + ->first(); + + $taskCount = $query->total_data; + $taskTotal = $query->total_retribution ?? 0; + + $result = [ + "count"=> $taskCount, + "total"=> $taskTotal + ]; + + return $this->resSuccess($result); + } + public function pbgTaskDocuments(Request $request){ $request->validate([ 'status' => 'required|string' diff --git a/app/Http/Controllers/Api/DataSettingController.php b/app/Http/Controllers/Api/DataSettingController.php new file mode 100644 index 0000000..ac5d1d4 --- /dev/null +++ b/app/Http/Controllers/Api/DataSettingController.php @@ -0,0 +1,104 @@ +orderBy('id', 'desc'); + if ($request->has("search") && !empty($request->get("search"))) { + $query = $query->where("key", $request->get("search")); + } + + return DataSettingResource::collection($query->paginate()); + } catch (Exception $e) { + return $this->resError($e->getMessage(), $e->getTrace()); + } + } + + /** + * Store a newly created resource in storage. + */ + public function store(DataSettingRequest $request) + { + try { + $data = DataSetting::create($request->validated()); + $result = [ + "success" => true, + "message" => "Data Setting created successfully", + "data" => new DataSettingResource($data) + ]; + return $this->resSuccess($result); + } catch (Exception $e) { + return $this->resError($e->getMessage(), $e); + } + } + + /** + * Display the specified resource. + */ + public function show(string $id) + { + try { + $setting = DataSetting::findOrFail($id); + $result = [ + "setting" => true, + "message" => "Data setting successfully", + "data" => new DataSettingResource($setting) + ]; + return $this->resSuccess($result); + } catch (Exception $e) { + return $this->resError($e->getMessage()); + } + } + + /** + * Update the specified resource in storage. + */ + public function update(DataSettingRequest $request, string $id) + { + try { + $data = DataSetting::findOrFail($id); + $data->update($request->validated()); + $result = [ + "success" => true, + "message" => "Data Setting updated successfully" + ]; + return $this->resSuccess($result); + } catch (Exception $e) { + return $this->resError($e->getMessage()); + } + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(string $id) + { + try { + $setting = DataSetting::findOrFail($id); + $setting->delete(); + $result = [ + "success" => true, + "message" => "Data Setting deleted successfully" + ]; + return $this->resSuccess($result); + } catch (Exception $e) { + return $this->resError($e->getMessage()); + } + } +} diff --git a/app/Http/Controllers/Api/GoogleSheetController.php b/app/Http/Controllers/Api/GoogleSheetController.php new file mode 100644 index 0000000..7cad121 --- /dev/null +++ b/app/Http/Controllers/Api/GoogleSheetController.php @@ -0,0 +1,61 @@ +googleSheetService = $googleSheetService; + } + /** + * Display a listing of the resource. + */ + public function index() + { + $dataCollection = $this->googleSheetService->getSheetDataCollection(); + $result = [ + "last_row" => $this->googleSheetService->getLastRowByColumn("C"), + "last_column" => $this->googleSheetService->getLastColumn(), + "header" => $this->googleSheetService->getHeader(), + "data_collection" => $dataCollection + ]; + return response()->json($result); + } + + /** + * 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) + { + // + } +} diff --git a/app/Http/Controllers/Api/PbgTaskController.php b/app/Http/Controllers/Api/PbgTaskController.php new file mode 100644 index 0000000..0f7eb68 --- /dev/null +++ b/app/Http/Controllers/Api/PbgTaskController.php @@ -0,0 +1,291 @@ +googleSheetService = $googleSheetService; + } + public function index() + { + // + } + + /** + * Store a newly created resource in storage. + */ + public function store(PbgTaskMultiStepRequest $request) + { + try { + $data = PbgTask::create([ + "uuid" => $request->input("step1Form.uuid"), + "name" => $request->input("step1Form.name"), + "owner_name" => $request->input("step1Form.owner_name"), + "application_type" => $request->input("step1Form.application_type"), + "application_type_name" => $request->input("step1Form.application_type_name"), + "condition" => $request->input("step1Form.condition"), + "registration_number" => $request->input("step1Form.registration_number"), + "document_number" => $request->input("step1Form.document_number"), + "address" => $request->input("step1Form.address"), + "status" => $request->input("step1Form.status"), + "status_name" => $request->input("step1Form.status_name"), + "slf_status" => $request->input("step1Form.slf_status"), + "slf_status_name" => $request->input("step1Form.slf_status_name"), + "function_type" => $request->input("step1Form.function_type"), + "consultation_type" => $request->input("step1Form.consultation_type"), + "due_date" => $request->input("step1Form.due_date"), + "land_certificate_phase" => $request->input("step1Form.land_certificate_phase"), + "task_created_at" => $request->input("step1Form.task_created_at"), + ]); + + return response()->json([ + "success" => true, + "message" => "Step 1 berhasil disimpan!", + "data" => $data + ], 201); + } catch (\Exception $e) { + return response()->json([ + "success" => false, + "message" => "Gagal menyimpan data", + "error" => $e->getMessage() + ], 500); + } + } + + /** + * 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) + { + // + } + + protected function validatePbgTask(Request $request){ + return $request->validate([ + "uuid" => $request->input("step1Form.uuid"), + ]); + } + + public function syncPbgFromGoogleSheet(){ + try{ + $totalRowCount = $this->googleSheetService->getLastRowByColumn("C"); + $sheetData = $this->googleSheetService->getSheetDataCollection($totalRowCount); + $mapToUpsert = []; + $count = 0; + foreach($sheetData as $data){ + $mapToUpsert[] = + [ + 'no_registrasi' => $data['no__registrasi'] ?? null, + 'jenis_konsultasi' => $data['jenis_konsultasi'] ?? null, + 'fungsi_bg' => $data['fungsi_bg'] ?? null, + 'tgl_permohonan' => $this->convertToDate($data['tgl_permohonan']), + 'status_verifikasi' => $data['status_verifikasi'] ?? null, + 'status_permohonan' => $this->convertToDate($data['status_permohonan']), + 'alamat_pemilik' => $data['alamat_pemilik'] ?? null, + 'no_hp' => $data['no__hp'] ?? null, + 'email' => $data['e_mail'] ?? null, + 'tanggal_catatan' => $this->convertToDate($data['tanggal_catatan']), + 'catatan_kekurangan_dokumen' => $data['catatan_kekurangan_dokumen'] ?? null, + 'gambar' => $data['gambar'] ?? null, + 'krk_kkpr' => $data['krk_kkpr'] ?? null, + 'no_krk' => $data['no__krk'] ?? null, + 'lh' => $data['lh'] ?? null, + 'ska' => $data['ska'] ?? null, + 'keterangan' => $data['keterangan'] ?? null, + 'helpdesk' => $data['helpdesk'] ?? null, + 'pj' => $data['pj'] ?? null, + 'kepemilikan' => $data['kepemilikan'] ?? null, + 'potensi_taru' => $data['potensi_taru'] ?? null, + 'validasi_dinas' => $data['validasi_dinas'] ?? null, + 'kategori_retribusi' => $data['kategori_retribusi'] ?? null, + 'no_urut_ba_tpt' => $data['no__urut_ba_tpt__2024_0001_'] ?? null, + 'tanggal_ba_tpt' => $this->convertToDate($data['tanggal_ba_tpt']), + 'no_urut_ba_tpa' => $data['no__urut_ba_tpa'] ?? null, + 'tanggal_ba_tpa' => $this->convertToDate($data['tanggal_ba_tpa']), + 'no_urut_skrd' => $data['no__urut_skrd__2024_0001_'] ?? null, + 'tanggal_skrd' => $this->convertToDate($data['tanggal_skrd']), + 'ptsp' => $data['ptsp'] ?? null, + 'selesai_terbit' => $data['selesai_terbit'] ?? null, + 'tanggal_pembayaran' => $this->convertToDate($data['tanggal_pembayaran__yyyy_mm_dd_']), + 'format_sts' => $data['format_sts'] ?? null, + 'tahun_terbit' => (int) $data['tahun_terbit'] ?? null, + 'tahun_berjalan' => (int) $data['tahun_berjalan'] ?? null, + 'kelurahan' => $data['kelurahan'] ?? null, + 'kecamatan' => $data['kecamatan'] ?? null, + 'lb' => $this->convertToDecimal($data['lb']) ?? null, + 'tb' => $this->convertToDecimal($data['tb']) ?? null, + 'jlb' => (int) $data['jlb'] ?? null, + 'unit' => (int) $data['unit'] ?? null, + 'usulan_retribusi' => (int) $data['usulan_retribusi'] ?? null, + 'nilai_retribusi_keseluruhan_simbg' => $this->convertToDecimal($data['nilai_retribusi_keseluruhan__simbg_']) ?? null, + 'nilai_retribusi_keseluruhan_pad' => $this->convertToDecimal($data['nilai_retribusi_keseluruhan__pad_']) ?? null, + 'denda' => $this->convertToDecimal($data['denda']) ?? null, + 'latitude' => $data['latitude'] ?? null, + 'longitude' => $data['longitude'] ?? null, + 'nik_nib' => $data['nik_nib'] ?? null, + 'dok_tanah' => $data['dok__tanah'] ?? null, + 'temuan' => $data['temuan'] ?? null, + ]; + } + + DB::beginTransaction(); + + $batchSize = 1000; + $chunks = array_chunk($mapToUpsert, $batchSize); + + foreach($chunks as $chunk){ + PbgTaskGoogleSheet::upsert($chunk, ["no_registrasi"],[ + 'jenis_konsultasi', + 'nama_pemilik', + 'lokasi_bg', + 'fungsi_bg', + 'nama_bangunan', + 'tgl_permohonan', + 'status_verifikasi', + 'status_permohonan', + 'alamat_pemilik', + 'no_hp', + 'email', + 'tanggal_catatan', + 'catatan_kekurangan_dokumen', + 'gambar', + 'krk_kkpr', + 'no_krk', + 'lh', + 'ska', + 'keterangan', + 'helpdesk', + 'pj', + 'kepemilikan', + 'potensi_taru', + 'validasi_dinas', + 'kategori_retribusi', + 'no_urut_ba_tpt', + 'tanggal_ba_tpt', + 'no_urut_ba_tpa', + 'tanggal_ba_tpa', + 'no_urut_skrd', + 'tanggal_skrd', + 'ptsp', + 'selesai_terbit', + 'tanggal_pembayaran', + 'format_sts', + 'tahun_terbit', + 'tahun_berjalan', + 'kelurahan', + 'kecamatan', + 'lb', + 'tb', + 'jlb', + 'unit', + 'usulan_retribusi', + 'nilai_retribusi_keseluruhan_simbg', + 'nilai_retribusi_keseluruhan_pad', + 'denda', + 'latitude', + 'longitude', + 'nik_nib', + 'dok_tanah', + 'temuan', + ]); + } + + DB::commit(); + + return response()->json([ + "success" => true, + "message" => "Data berhasil disimpan ke database" + ], 200); + }catch(\Exception $ex){ + DB::rollBack(); + return response()->json([ + "success" => false, + "message" => "Gagal menyimpan data", + "error" => $ex->getMessage() + ], 500); + } + } + + protected function convertToDecimal(?string $value): ?float + { + if (empty($value)) { + return null; // Return null if the input is empty + } + + // Remove all non-numeric characters except comma and dot + $value = preg_replace('/[^0-9,\.]/', '', $value); + + // If the number contains both dot (.) and comma (,) + if (strpos($value, '.') !== false && strpos($value, ',') !== false) { + $value = str_replace('.', '', $value); // Remove thousands separator + $value = str_replace(',', '.', $value); // Convert decimal separator to dot + } + // If only a dot is present (assumed as thousands separator) + elseif (strpos($value, '.') !== false) { + $value = str_replace('.', '', $value); // Remove all dots (treat as thousands separators) + } + // If only a comma is present (assumed as decimal separator) + elseif (strpos($value, ',') !== false) { + $value = str_replace(',', '.', $value); // Convert comma to dot (decimal separator) + } + + // Ensure the value is numeric before returning + return is_numeric($value) ? (float) number_format((float) $value, 2, '.', '') : null; + } + + protected function convertToInteger($value) { + // Check if the value is an empty string, and return null if true + if (trim($value) === "") { + return null; + } + + // Otherwise, cast to integer + return (int) $value; + } + + protected function convertToDate($dateString) + { + try { + // Check if the string is empty + if (empty($dateString)) { + return null; + } + + // Try to parse the date string + $date = Carbon::parse($dateString); + + // Return the Carbon instance + return $date->format('Y-m-d'); + } catch (\Exception $e) { + // Return null if an error occurs during parsing + return null; + } + } +} diff --git a/app/Http/Controllers/Api/RequestAssignmentController.php b/app/Http/Controllers/Api/RequestAssignmentController.php index 10d4319..56605f5 100644 --- a/app/Http/Controllers/Api/RequestAssignmentController.php +++ b/app/Http/Controllers/Api/RequestAssignmentController.php @@ -14,9 +14,10 @@ class RequestAssignmentController extends Controller */ public function index(Request $request) { - $query = PbgTask::query(); + $query = PbgTask::query()->orderBy('id', 'desc'); if($request->has('search') && !empty($request->get("search"))){ - $query->where('name', 'LIKE', '%'.$request->get('search').'%'); + $query->where('name', 'LIKE', '%'.$request->get('search').'%') + ->orWhere('registration_number', 'LIKE', '%'.$request->get('search').'%'); } return RequestAssignmentResouce::collection($query->paginate()); } diff --git a/app/Http/Controllers/DataSettingController.php b/app/Http/Controllers/DataSettingController.php new file mode 100644 index 0000000..872f87d --- /dev/null +++ b/app/Http/Controllers/DataSettingController.php @@ -0,0 +1,120 @@ +validated()); + DB::commit(); + return redirect()->route("data-settings.index")->with("success","Successfully created"); + }catch(Exception $ex){ + DB::rollBack(); + return redirect()->back() + ->withInput() + ->with('error', 'Something went wrong while saving data. ' . $ex->getMessage()); + } + } + + /** + * Display the specified resource. + */ + public function show(DataSetting $dataSetting) + { + // + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(string $id) + { + try{ + $data = DataSetting::findOrFail($id); + if(empty($data)){ + return redirect()->route('data-settings.index')->with('error', 'Invalid id'); + } + return view("data-settings.edit", compact("data")); + }catch(Exception $ex){ + return redirect()->route("data-settings.index")->with("error", "Invalid id"); + } + } + + /** + * Update the specified resource in storage. + */ + public function update(DataSettingRequest $request,string $id) + { + try{ + DB::beginTransaction(); + $data = DataSetting::findOrFail($id); + $data->update($request->validated()); + DB::commit(); + return redirect()->route("data-settings.index")->with("success","Successfully updated"); + }catch(Exception $ex){ + DB::rollBack(); + return redirect()->back() + ->withInput() + ->with('error', 'Something went wrong while saving data. ' . $ex->getMessage()); + } + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(string $id) + { + try{ + DB::beginTransaction(); + DataSetting::findOrFail($id)->delete(); + DB::commit(); + return response()->json(['success' => true, 'message' => 'Item deleted successfully.']); + }catch(Exception $e){ + DB::rollBack(); + Log::error($e->getMessage()); + return response()->json(['success' => false, 'message' => 'Failed to delete item.'], 500); + } + } + + public function getValueSetting(Request $request){ + try{ + $data = DataSetting::where('key', $request->key_name)->first(); + return response()->json([ + 'success' => true, + 'message' => "Successfully retrieved data", + "data"=> $data + ]); + }catch(Exception $e){ + return response()->json(['success' => false, 'message' => $e->getMessage()], 500); + } + } +} diff --git a/app/Http/Controllers/RequestAssignment/PbgTaskController.php b/app/Http/Controllers/RequestAssignment/PbgTaskController.php index 395ca33..d2e0cdf 100644 --- a/app/Http/Controllers/RequestAssignment/PbgTaskController.php +++ b/app/Http/Controllers/RequestAssignment/PbgTaskController.php @@ -12,7 +12,7 @@ class PbgTaskController extends Controller */ public function index() { - return view('request-assignment.index'); + return view('pbg_task.index'); } /** @@ -20,7 +20,7 @@ class PbgTaskController extends Controller */ public function create() { - // + return view("pbg_task.create"); } /** @@ -28,7 +28,7 @@ class PbgTaskController extends Controller */ public function store(Request $request) { - // + } /** @@ -36,7 +36,7 @@ class PbgTaskController extends Controller */ public function show(string $id) { - // + return view("pbg_task.show"); } /** @@ -44,7 +44,7 @@ class PbgTaskController extends Controller */ public function edit(string $id) { - // + return view("pbg_task.edit"); } /** diff --git a/app/Http/Controllers/RoutingController.php b/app/Http/Controllers/RoutingController.php index 6392e29..2bb3b5f 100755 --- a/app/Http/Controllers/RoutingController.php +++ b/app/Http/Controllers/RoutingController.php @@ -15,30 +15,4 @@ class RoutingController extends Controller return redirect('auth.signin'); } } - - /** - * Display a view based on first route param - * - * @return \Illuminate\Http\Response - */ - public function root(Request $request, $first) - { - return view($first); - } - - /** - * second level route - */ - public function secondLevel(Request $request, $first, $second) - { - return view($first . '.' . $second); - } - - /** - * third level route - */ - public function thirdLevel(Request $request, $first, $second, $third) - { - return view($first . '.' . $second . '.' . $third); - } } diff --git a/app/Http/Requests/DataSettingRequest.php b/app/Http/Requests/DataSettingRequest.php new file mode 100644 index 0000000..2305e39 --- /dev/null +++ b/app/Http/Requests/DataSettingRequest.php @@ -0,0 +1,31 @@ +|string> + */ + public function rules(): array + { + $id = $this->route('data_setting'); + return [ + "key" => "required|unique:data_settings,key," . $id, + "value" => "required", + "type" => "nullable", + ]; + } +} diff --git a/app/Http/Requests/PbgTaskMultiStepRequest.php b/app/Http/Requests/PbgTaskMultiStepRequest.php new file mode 100644 index 0000000..e76af85 --- /dev/null +++ b/app/Http/Requests/PbgTaskMultiStepRequest.php @@ -0,0 +1,62 @@ +|string> + */ + public function rules() + { + return [ + // rules step 1 + "step1Form.uuid" => "required", + "step1Form.name" => "nullable|string|max:255", + "step1Form.owner_name" => "nullable|string|max:255", + "step1Form.application_type" => "nullable|string|max:255", + "step1Form.application_type_name" => "nullable|string|max:255", + "step1Form.condition" => "nullable|string|max:255", + "step1Form.registration_number" => "nullable|string|max:255", + "step1Form.document_number" => "nullable|string|max:255", + "step1Form.address" => "nullable|string|max:255", + "step1Form.status" => "nullable|integer", + "step1Form.status_name" => "nullable|string|max:255", + "step1Form.slf_status" => "nullable|string|max:255", + "step1Form.slf_status_name" => "nullable|string|max:255", + "step1Form.function_type" => "nullable|string|max:255", + "step1Form.consultation_type" => "nullable|string|max:255", + "step1Form.due_date" => "nullable|date", + "step1Form.land_certificate_phase" => "nullable|boolean", + "step1Form.task_created_at" => "nullable|date", + ]; + } + + public function messages() + { + return [ + // message step 1 + "step1Form.uuid.required" => "UUID wajib diisi.", + "step1Form.uuid.uuid" => "Format UUID tidak valid.", + "step1Form.name.max" => "Nama tidak boleh lebih dari 255 karakter.", + "step1Form.owner_name.max" => "Nama pemilik tidak boleh lebih dari 255 karakter.", + "step1Form.registration_number.max" => "Nomor registrasi tidak boleh lebih dari 255 karakter.", + "step1Form.document_number.max" => "Nomor dokumen tidak boleh lebih dari 255 karakter.", + "step1Form.status.integer" => "Status harus berupa angka.", + "step1Form.due_date.date" => "Tanggal jatuh tempo tidak valid.", + "step1Form.land_certificate_phase.boolean" => "Fase sertifikat tanah harus berupa true/false.", + ]; + } +} diff --git a/app/Http/Resources/DataSettingResource.php b/app/Http/Resources/DataSettingResource.php new file mode 100644 index 0000000..3cc1d14 --- /dev/null +++ b/app/Http/Resources/DataSettingResource.php @@ -0,0 +1,26 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'id' => $this->id, + 'key' => $this->key, + 'value' => $this->value, + 'type' => $this->type, + 'created_at' => $this->created_at->toDateTimeString(), + 'updated_at' => $this->updated_at->toDateTimeString(), + ]; + } +} diff --git a/app/Models/DataSetting.php b/app/Models/DataSetting.php new file mode 100644 index 0000000..8ac2f87 --- /dev/null +++ b/app/Models/DataSetting.php @@ -0,0 +1,15 @@ +get($url, $headers); + + Log::info("response index integration", ['res' => $res]); if (empty($res->original['success']) || !$res->original['success']) { // Log error @@ -128,9 +130,10 @@ class ServiceSIMBG $savedCount = $failedCount = 0; - for ($currentPage = 1; $currentPage <= $totalPage; $currentPage++) { + for ($currentPage = 50; $currentPage <= $totalPage; $currentPage++) { $pageUrl = "/api/pbg/v1/list/?page={$currentPage}&size={$this->fetch_per_page}&sort=ASC"; $getToken = $this->getToken(); + Log::info("response index integration", ['currentPage' => $currentPage]); if (empty($getToken->original['data']['token']['access'])) { $importDatasource->update([ 'status' => ImportDatasourceStatus::Failed->value, @@ -227,6 +230,8 @@ class ServiceSIMBG $res = $clientHelper->get($url, $headers); + Log::info("response task detail submit", ['res' => $res]); + if (empty($res->original['success']) || !$res->original['success']) { // Log error Log::error("API response indicates failure", ['url' => $url, 'uuid' => $uuid]); diff --git a/app/Services/GoogleSheetService.php b/app/Services/GoogleSheetService.php new file mode 100644 index 0000000..8118347 --- /dev/null +++ b/app/Services/GoogleSheetService.php @@ -0,0 +1,131 @@ +client = new Google_Client(); + $this->client->setApplicationName("Sibedas Google Sheets API"); + $this->client->setScopes([Google_Service_Sheets::SPREADSHEETS_READONLY]); + $this->client->setAuthConfig(storage_path("app/teak-banner-450003-s8-ea05661d9db0.json")); + $this->client->setAccessType("offline"); + + $this->service = new Google_Service_Sheets($this->client); + $this->spreadsheetID = env("SPREAD_SHEET_ID"); + + $this->service_sheets = new Google_Service_Sheets($this->client); + } + + public function getSheetData($range){ + $response = $this->service->spreadsheets_values->get($this->spreadsheetID, $range); + return $response->getValues(); + } + + public function getLastRowByColumn($column = "A") + { + // Ambil spreadsheet + $spreadsheet = $this->service->spreadsheets->get($this->spreadsheetID); + $sheets = $spreadsheet->getSheets(); + + if (!empty($sheets)) { + // Ambil nama sheet pertama dengan benar + $firstSheetTitle = $sheets[0]->getProperties()->getTitle(); + + // ✅ Format range harus benar! + $range = "{$firstSheetTitle}!{$column}:{$column}"; + + // Ambil data dari kolom yang diminta + $response = $this->service->spreadsheets_values->get($this->spreadsheetID, $range); + $values = $response->getValues(); + + // Cek nilai terakhir yang tidak kosong + $lastRow = 0; + if (!empty($values)) { + foreach ($values as $index => $row) { + if (!empty($row[0])) { // Jika ada data, update lastRow + $lastRow = $index + 1; + } + } + } + + return $lastRow; + } + + return 0; + } + public function getHeader() + { + $spreadsheet = $this->service->spreadsheets->get($this->spreadsheetID); + $sheets = $spreadsheet->getSheets(); + + // Ambil nama sheet pertama + $firstSheetTitle = $sheets[0]->getProperties()->getTitle(); + + // Ambil data dari baris pertama (header) + $range = "{$firstSheetTitle}!1:1"; + $response = $this->service->spreadsheets_values->get($this->spreadsheetID, $range); + $values = $response->getValues(); + + // Kembalikan header (baris pertama) + return !empty($values) ? $values[0] : []; + } + + public function getLastColumn() + { + $spreadsheet = $this->service->spreadsheets->get($this->spreadsheetID); + $sheets = $spreadsheet->getSheets(); + + // Ambil nama sheet pertama + $firstSheetTitle = $sheets[0]->getProperties()->getTitle(); + + // Ambil baris pertama untuk mendapatkan jumlah kolom yang terisi + $range = "{$firstSheetTitle}!1:1"; + $response = $this->service->spreadsheets_values->get($this->spreadsheetID, $range); + $values = $response->getValues(); + + // Hitung jumlah kolom yang memiliki nilai + return !empty($values) ? count(array_filter($values[0], fn($value) => $value !== "")) : 0; + } + + public function getSheetDataCollection($totalRow = 10){ + $spreadsheet = $this->service->spreadsheets->get($this->spreadsheetID); + $sheets = $spreadsheet->getSheets(); + $firstSheetTitle = $sheets[0]->getProperties()->getTitle(); + + $header = $this->getHeader(); + $header = array_map(function($columnHeader) { + // Trim spaces first, then replace non-alphanumeric characters with underscores + $columnHeader = trim($columnHeader); + return strtolower(preg_replace('/[^A-Za-z0-9_]/', '_', $columnHeader)); + }, $header); + $range = "{$firstSheetTitle}!2:{$totalRow}"; + + $response = $this->service->spreadsheets_values->get($this->spreadsheetID, $range); + $values = $response->getValues(); + + $mappedData = []; + if (!empty($values)) { + foreach ($values as $row) { + $rowData = []; + foreach ($header as $index => $columnHeader) { + // Map header to the corresponding value from the row + $rowData[$columnHeader] = isset($row[$index]) ? $row[$index] : null; + } + $mappedData[] = $rowData; + } + } + + return $mappedData; + } +} diff --git a/composer.json b/composer.json index e2276de..1c44a58 100755 --- a/composer.json +++ b/composer.json @@ -7,6 +7,7 @@ "license": "MIT", "require": { "php": "^8.2", + "google/apiclient": "^2.12", "guzzlehttp/guzzle": "^7.9", "laravel/framework": "^11.31", "laravel/sanctum": "^4.0", diff --git a/composer.lock b/composer.lock index 3dd62c7..f1e8843 100755 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7bb7c3b4b4eb50972252c4683f797104", + "content-hash": "3fea2988b5efebfd50ec7c29aeae3830", "packages": [ { "name": "brick/math", @@ -510,6 +510,69 @@ ], "time": "2024-12-27T00:36:43+00:00" }, + { + "name": "firebase/php-jwt", + "version": "v6.11.0", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "8f718f4dfc9c5d5f0c994cdfd103921b43592712" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/8f718f4dfc9c5d5f0c994cdfd103921b43592712", + "reference": "8f718f4dfc9c5d5f0c994cdfd103921b43592712", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.4", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "psr/cache": "^2.0||^3.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-sodium": "Support EdDSA (Ed25519) signatures", + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/firebase/php-jwt/issues", + "source": "https://github.com/firebase/php-jwt/tree/v6.11.0" + }, + "time": "2025-01-23T05:11:06+00:00" + }, { "name": "fruitcake/php-cors", "version": "v1.3.0", @@ -581,6 +644,180 @@ ], "time": "2023-10-12T05:21:21+00:00" }, + { + "name": "google/apiclient", + "version": "v2.18.2", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-api-php-client.git", + "reference": "d8d201ba8a189a3cd7fb34e4da569f2ed440eee7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/d8d201ba8a189a3cd7fb34e4da569f2ed440eee7", + "reference": "d8d201ba8a189a3cd7fb34e4da569f2ed440eee7", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "^6.0", + "google/apiclient-services": "~0.350", + "google/auth": "^1.37", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.6", + "monolog/monolog": "^2.9||^3.0", + "php": "^8.0", + "phpseclib/phpseclib": "^3.0.36" + }, + "require-dev": { + "cache/filesystem-adapter": "^1.1", + "composer/composer": "^1.10.23", + "phpcompatibility/php-compatibility": "^9.2", + "phpspec/prophecy-phpunit": "^2.1", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.8", + "symfony/css-selector": "~2.1", + "symfony/dom-crawler": "~2.1" + }, + "suggest": { + "cache/filesystem-adapter": "For caching certs and tokens (using Google\\Client::setCache)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "files": [ + "src/aliases.php" + ], + "psr-4": { + "Google\\": "src/" + }, + "classmap": [ + "src/aliases.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "support": { + "issues": "https://github.com/googleapis/google-api-php-client/issues", + "source": "https://github.com/googleapis/google-api-php-client/tree/v2.18.2" + }, + "time": "2024-12-16T22:52:40+00:00" + }, + { + "name": "google/apiclient-services", + "version": "v0.393.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-api-php-client-services.git", + "reference": "ed24c09584df8ef0cdcfb9d4305abf66fc17e609" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/ed24c09584df8ef0cdcfb9d4305abf66fc17e609", + "reference": "ed24c09584df8ef0cdcfb9d4305abf66fc17e609", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6" + }, + "type": "library", + "autoload": { + "files": [ + "autoload.php" + ], + "psr-4": { + "Google\\Service\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "support": { + "issues": "https://github.com/googleapis/google-api-php-client-services/issues", + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.393.0" + }, + "time": "2025-02-03T00:54:21+00:00" + }, + { + "name": "google/auth", + "version": "v1.45.3", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-auth-library-php.git", + "reference": "000d9439f430c6e56cba105c5ab750f5f7d69ea8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/000d9439f430c6e56cba105c5ab750f5f7d69ea8", + "reference": "000d9439f430c6e56cba105c5ab750f5f7d69ea8", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "^6.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.4.5", + "php": "^8.0", + "psr/cache": "^2.0||^3.0", + "psr/http-message": "^1.1||^2.0", + "psr/log": "^3.0" + }, + "require-dev": { + "guzzlehttp/promises": "^2.0", + "kelvinmo/simplejwt": "0.7.1", + "phpseclib/phpseclib": "^3.0.35", + "phpspec/prophecy-phpunit": "^2.1", + "phpunit/phpunit": "^9.6", + "sebastian/comparator": ">=1.2.3", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^6.0||^7.0", + "webmozart/assert": "^1.11" + }, + "suggest": { + "phpseclib/phpseclib": "May be used in place of OpenSSL for signing strings or for token management. Please require version ^2." + }, + "type": "library", + "autoload": { + "psr-4": { + "Google\\Auth\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google Auth Library for PHP", + "homepage": "https://github.com/google/google-auth-library-php", + "keywords": [ + "Authentication", + "google", + "oauth2" + ], + "support": { + "docs": "https://googleapis.github.io/google-auth-library-php/main/", + "issues": "https://github.com/googleapis/google-auth-library-php/issues", + "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.45.3" + }, + "time": "2025-01-29T18:17:08+00:00" + }, { "name": "graham-campbell/result-type", "version": "v1.1.3", @@ -2572,6 +2809,123 @@ ], "time": "2024-11-21T10:39:51+00:00" }, + { + "name": "paragonie/constant_time_encoding", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512", + "shasum": "" + }, + "require": { + "php": "^8" + }, + "require-dev": { + "phpunit/phpunit": "^9", + "vimeo/psalm": "^4|^5" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2024-05-08T12:36:18+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" + }, { "name": "phpoption/phpoption", "version": "1.9.3", @@ -2647,6 +3001,165 @@ ], "time": "2024-07-20T21:41:07+00:00" }, + { + "name": "phpseclib/phpseclib", + "version": "3.0.43", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "709ec107af3cb2f385b9617be72af8cf62441d02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/709ec107af3cb2f385b9617be72af8cf62441d02", + "reference": "709ec107af3cb2f385b9617be72af8cf62441d02", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "^1|^2|^3", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": ">=5.6.1" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "suggest": { + "ext-dom": "Install the DOM extension to load XML formatted public keys.", + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib3\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "support": { + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.43" + }, + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "time": "2024-12-14T21:12:59+00:00" + }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, { "name": "psr/clock", "version": "1.0.0", diff --git a/database/migrations/2025_02_04_133926_create_data_settings_table.php b/database/migrations/2025_02_04_133926_create_data_settings_table.php new file mode 100644 index 0000000..b4ee77e --- /dev/null +++ b/database/migrations/2025_02_04_133926_create_data_settings_table.php @@ -0,0 +1,30 @@ +id(); + $table->string('key')->unique(); + $table->string('value'); + $table->string('type')->nullable()->default('integer'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('data_settings'); + } +}; diff --git a/database/migrations/2025_02_05_162953_create_pbg_task_google_sheet.php b/database/migrations/2025_02_05_162953_create_pbg_task_google_sheet.php new file mode 100644 index 0000000..07fb562 --- /dev/null +++ b/database/migrations/2025_02_05_162953_create_pbg_task_google_sheet.php @@ -0,0 +1,80 @@ +id(); + $table->string('jenis_konsultasi')->nullable(); + $table->string('no_registrasi')->nullable()->unique(); + $table->string('nama_pemilik')->nullable(); + $table->text('lokasi_bg')->nullable(); + $table->string('fungsi_bg')->nullable(); + $table->string('nama_bangunan')->nullable(); + $table->date('tgl_permohonan')->nullable(); + $table->string('status_verifikasi')->nullable(); + $table->string('status_permohonan')->nullable(); + $table->text('alamat_pemilik')->nullable(); + $table->string('no_hp')->nullable(); + $table->string('email')->nullable(); + $table->date('tanggal_catatan')->nullable(); + $table->text('catatan_kekurangan_dokumen')->nullable(); + $table->string('gambar')->nullable(); + $table->string('krk_kkpr')->nullable(); + $table->string('no_krk')->nullable(); + $table->string('lh')->nullable(); + $table->string('ska')->nullable(); + $table->text('keterangan')->nullable(); + $table->string('helpdesk')->nullable(); + $table->string('pj')->nullable(); + $table->string('kepemilikan')->nullable(); + $table->string('potensi_taru')->nullable(); + $table->string('validasi_dinas')->nullable(); + $table->string('kategori_retribusi')->nullable(); + $table->string('no_urut_ba_tpt')->nullable(); + $table->date('tanggal_ba_tpt')->nullable(); + $table->string('no_urut_ba_tpa')->nullable(); + $table->date('tanggal_ba_tpa')->nullable(); + $table->string('no_urut_skrd')->nullable(); + $table->date('tanggal_skrd')->nullable(); + $table->string('ptsp')->nullable(); + $table->string('selesai_terbit')->nullable(); + $table->date('tanggal_pembayaran')->nullable(); + $table->string('format_sts')->nullable(); + $table->integer('tahun_terbit')->nullable(); + $table->integer('tahun_berjalan')->nullable(); + $table->string('kelurahan')->nullable(); + $table->string('kecamatan')->nullable(); + $table->decimal('lb', 20,2)->nullable(); + $table->decimal('tb', 20, 2)->nullable(); + $table->integer('jlb')->nullable(); + $table->integer('unit')->nullable(); + $table->integer('usulan_retribusi')->nullable(); + $table->decimal('nilai_retribusi_keseluruhan_simbg', 20, 2)->nullable(); + $table->decimal('nilai_retribusi_keseluruhan_pad', 20, 2)->nullable(); + $table->decimal('denda', 20, 2)->nullable(); + $table->string('latitude')->nullable(); + $table->string('longitude')->nullable(); + $table->string('nik_nib')->nullable(); + $table->string('dok_tanah')->nullable(); + $table->text('temuan')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('pbg_task_google_sheet'); + } +}; diff --git a/database/migrations/2025_02_05_164238_modify_uuid_in_pbg_task.php b/database/migrations/2025_02_05_164238_modify_uuid_in_pbg_task.php new file mode 100644 index 0000000..7af5337 --- /dev/null +++ b/database/migrations/2025_02_05_164238_modify_uuid_in_pbg_task.php @@ -0,0 +1,28 @@ +string('uuid')->nullable()->unique()->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('pbg_task', function (Blueprint $table) { + $table->string('uuid')->nullable()->change(); + }); + } +}; diff --git a/database/migrations/2025_02_05_184032_modify_pbg_task_uid_in_pbg_task_index_integrations.php b/database/migrations/2025_02_05_184032_modify_pbg_task_uid_in_pbg_task_index_integrations.php new file mode 100644 index 0000000..296fef9 --- /dev/null +++ b/database/migrations/2025_02_05_184032_modify_pbg_task_uid_in_pbg_task_index_integrations.php @@ -0,0 +1,28 @@ +string('pbg_task_uid')->unique()->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('pbg_task_index_integrations', function (Blueprint $table) { + $table->string('pbg_task_uid')->unique()->change(); + }); + } +}; diff --git a/database/migrations/2025_02_05_185048_modify_detail_id_in_pbg_task_retributions.php b/database/migrations/2025_02_05_185048_modify_detail_id_in_pbg_task_retributions.php new file mode 100644 index 0000000..8d9c311 --- /dev/null +++ b/database/migrations/2025_02_05_185048_modify_detail_id_in_pbg_task_retributions.php @@ -0,0 +1,28 @@ +string('detail_id')->unique()->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('pbg_task_retributions', function (Blueprint $table) { + $table->string('detail_id')->unique()->change(); + }); + } +}; diff --git a/database/seeders/DataSettingSeeder.php b/database/seeders/DataSettingSeeder.php new file mode 100644 index 0000000..2303d5b --- /dev/null +++ b/database/seeders/DataSettingSeeder.php @@ -0,0 +1,35 @@ + "TARGET_PAD", + "value" => "33.200.000.000", + "type" => "integer" + ] + ]; + + foreach ($data_settings as $setting) { + DataSetting::updateOrCreate([ + "key" => $setting["key"], + ],[ + "value" => $setting["value"], + "type" => $setting["type"], + "created_at" => now(), + "updated_at" => now(), + ]); + } + } +} diff --git a/package-lock.json b/package-lock.json index 6861a22..96e09d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,7 @@ "": { "dependencies": { "apexcharts": "^3.44.2", + "big.js": "^6.2.2", "bootstrap": "^5.3.3", "countup.js": "^2.3.2", "dropzone": "^5.9.0", @@ -477,6 +478,19 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/big.js": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz", + "integrity": "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", diff --git a/package.json b/package.json index 69ca869..23afe1f 100755 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "apexcharts": "^3.44.2", + "big.js": "^6.2.2", "bootstrap": "^5.3.3", "countup.js": "^2.3.2", "dropzone": "^5.9.0", diff --git a/public/index.php b/public/index.php index 947d989..ee72fab 100755 --- a/public/index.php +++ b/public/index.php @@ -4,6 +4,8 @@ use Illuminate\Http\Request; define('LARAVEL_START', microtime(true)); +ini_set('max_execution_time',14400); + // Determine if the application is in maintenance mode... if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) { require $maintenance; diff --git a/resources/js/dashboards/bigdata.js b/resources/js/dashboards/bigdata.js index 8bb04c5..c50eacf 100644 --- a/resources/js/dashboards/bigdata.js +++ b/resources/js/dashboards/bigdata.js @@ -1,13 +1,83 @@ -import ApexCharts from "apexcharts"; - +import Big from "big.js"; import GlobalConfig, { addThousandSeparators } from "../global-config.js"; class BigData { async init() { - try{ - this.resultDataTotal = await this.getTotalAllTask(); + try { + this.totalTargetPAD = await this.getTargetPAD(); + this.resultDataTotal = await this.getDataTotalPotensi(); + this.dataVerification = await this.getDataVerfication(); + this.dataNonVerification = await this.getDataNonVerfication(); + this.dataBusiness = await this.getDataBusiness(); + this.dataNonBusiness = await this.getDataNonBusiness(); - if (!this.resultDataTotal) { + // 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; + } + } + + // kekurangan potensi + this.totalKekuranganPotensi = new Big( + this.totalTargetPAD - this.bigTotalPotensi + ); + this.percentageKekuranganPotensi = + this.totalKekuranganPotensi <= 0 || this.totalTargetPAD <= 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 + .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); + + // business documents + this.bigTotalBusiness = new Big(this.dataBusiness.total); + this.percentageResultBusiness = + this.bigTotalNonVerification <= 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 + ? 0 + : this.bigTotalNonBusiness + .div(this.bigTotalNonVerification) + .times(100) + .toFixed(2); + + if (!this.totalTargetPAD) { console.error("Failed to load chart data"); return; } @@ -15,455 +85,469 @@ class BigData { this.initChartTargetPAD(); this.initChartUsaha(); this.initChartNonUsaha(); - this.initChartStatus1(); - this.initChartStatus2(); - this.initChartStatus3(); - this.initChartStatus4(); - this.initChartStatus5(); - this.initChartStatus6(); - this.initChartStatus7(); - this.initChartStatus20(); - this.initChartStatus24(); - }catch(e){ + this.initChartTotalPotensi(); + this.initChartVerificationDocuments(); + this.initChartNonVerificationDocuments(); + this.initChartKekuranganPotensi(); + this.initChartRealisasiTerbitPBG(); + this.initChartMenungguKlikDPMPTSP(); + this.initChartProsesDinasTeknis(); + this.initChartPotensiTataRuang(); + } catch (e) { console.error(e); } } - async getTotalAllTask() { + async getDataTotalPotensi() { try { - const response = await fetch(`${GlobalConfig.apiHost}/api/all-task-documents`, { - credentials: "include", - headers: { - Authorization: `Bearer ${document.querySelector("meta[name='api-token']").content}`, - "Content-Type": "application/json", - }, - }); - + const response = await fetch( + `${GlobalConfig.apiHost}/api/all-task-documents`, + { + 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 { seriesData: data.data.series, countData: data.data.count, - totalData: data.data.total + totalData: data.data.total, }; - } catch (error) { console.error("Error fetching chart data:", error); - return null; // Mengembalikan null jika terjadi error + return null; + } + } + + async getTargetPAD() { + try { + const response = await fetch( + `${GlobalConfig.apiHost}/api/api-data-settings?search=target_pad`, + { + 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 null; + } + } + + async getDataVerfication() { + try { + const response = await fetch( + `${GlobalConfig.apiHost}/api/verification-documents`, + { + 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 { + count: data.data.count, + total: data.data.total, + }; + } catch (error) { + console.error("Error fetching chart data:", error); + return null; + } + } + + async getDataNonVerfication() { + try { + const response = await fetch( + `${GlobalConfig.apiHost}/api/non-verification-documents`, + { + 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 { + count: data.data.count, + total: data.data.total, + }; + } catch (error) { + console.error("Error fetching chart data:", error); + return null; + } + } + + async getDataBusiness() { + try { + const response = await fetch( + `${GlobalConfig.apiHost}/api/business-documents`, + { + 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 { + count: data.data.count, + total: data.data.total, + }; + } catch (error) { + console.error("Error fetching chart data:", error); + return null; + } + } + + async getDataNonBusiness() { + try { + const response = await fetch( + `${GlobalConfig.apiHost}/api/non-business-documents`, + { + 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 { + count: data.data.count, + total: data.data.total, + }; + } catch (error) { + console.error("Error fetching chart data:", error); + return null; } } initChartTargetPAD() { - const total = this.resultDataTotal.totalData; - const count = this.resultDataTotal.countData; - document.querySelectorAll('.document-count.chart-all-task').forEach((element) => { - element.innerText = `${count}`; - }); - document.querySelectorAll('.document-total.chart-all-task').forEach((element) => { - element.innerText = `Rp.${addThousandSeparators(total)}`; - }); - document.querySelectorAll('.small-percentage.chart-all-task').forEach((element) => { - element.innerText = `${100}%`; - }); + let totalPad = 0; + fetch( + `${GlobalConfig.apiHost}/api/api-data-settings?search=target_pad`, + { + credentials: "include", + headers: { + Authorization: `Bearer ${ + document.querySelector("meta[name='api-token']").content + }`, + "Content-Type": "application/json", + }, + } + ) + .then((response) => { + if (!response.ok) { + throw new Error("Network response was not ok"); + } + return response.json(); + }) + .then((data) => { + totalPad = data.data[0].value; + document + .querySelectorAll(".document-count.chart-target-pad") + .forEach((element) => { + element.innerText = ``; + }); + document + .querySelectorAll(".document-total.chart-target-pad") + .forEach((element) => { + element.innerText = `Rp.${addThousandSeparators( + totalPad + )}`; + }); + document + .querySelectorAll(".small-percentage.chart-target-pad") + .forEach((element) => { + element.innerText = `${100}%`; + }); + }) + .catch((error) => { + console.error("Error fetching target_pad:", error); + }); + } + initChartTotalPotensi() { + const countAll = this.resultDataTotal.countData ?? 0; + + document + .querySelectorAll(".document-count.chart-total-potensi") + .forEach((element) => { + element.innerText = `${countAll}`; + }); + document + .querySelectorAll(".document-total.chart-total-potensi") + .forEach((element) => { + element.innerText = `Rp.${addThousandSeparators( + this.bigTotalPotensi.toString() + )}`; + }); + document + .querySelectorAll(".small-percentage.chart-total-potensi") + .forEach((element) => { + element.innerText = `${this.resultPercentage}%`; + }); + } + initChartVerificationDocuments() { + document + .querySelectorAll(".document-count.chart-berkas-terverifikasi") + .forEach((element) => { + element.innerText = `${this.dataVerification.count}`; + }); + document + .querySelectorAll(".document-total.chart-berkas-terverifikasi") + .forEach((element) => { + element.innerText = `Rp.${addThousandSeparators( + this.bigTotalVerification.toString() + )}`; + }); + document + .querySelectorAll(".small-percentage.chart-berkas-terverifikasi") + .forEach((element) => { + element.innerText = `${this.percetageResultVerification}%`; + }); + } + initChartNonVerificationDocuments() { + document + .querySelectorAll( + ".document-count.chart-berkas-belum-terverifikasi" + ) + .forEach((element) => { + element.innerText = `${this.dataNonVerification.count}`; + }); + document + .querySelectorAll( + ".document-total.chart-berkas-belum-terverifikasi" + ) + .forEach((element) => { + element.innerText = `Rp.${addThousandSeparators( + this.bigTotalNonVerification.toString() + )}`; + }); + document + .querySelectorAll( + ".small-percentage.chart-berkas-belum-terverifikasi" + ) + .forEach((element) => { + element.innerText = `${this.percentageResultNonVerification}%`; + }); } initChartUsaha() { - fetch(`${GlobalConfig.apiHost}/api/business-documents`,{ - credentials: "include", - headers: { - Authorization: `Bearer ${document.querySelector("meta[name='api-token']").content}`, - "Content-Type": "application/json", - }, - }) - .then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then((data) => { - // Pastikan this.resultDataTotal sudah ada - if (!this.resultDataTotal) { - console.error("Error: resultDataTotal is undefined"); - return; - } - - const totalAll = this.resultDataTotal.totalData ?? 0; - const countAll = this.resultDataTotal.countData ?? 0; - const countUsaha = data?.data?.count ?? 0; - const totalUsaha = data?.data?.total ?? 0; - - // Perbaikan perhitungan persentase - let resultPercentage = 0; - if (countUsaha > 0) { - resultPercentage = (countUsaha / countAll) * 100; - if (resultPercentage > 100) { - resultPercentage = 100; // Batasi maksimum 100% - } - } - document.querySelectorAll('.document-count.chart-business').forEach((element) => { - element.innerText = `${countUsaha}`; + document + .querySelectorAll(".document-count.chart-business") + .forEach((element) => { + element.innerText = `${this.dataBusiness.count}`; }); - document.querySelectorAll('.document-total.chart-business').forEach((element) => { - element.innerText = `Rp.${addThousandSeparators(totalUsaha)}`; + document + .querySelectorAll(".document-total.chart-business") + .forEach((element) => { + element.innerText = `Rp.${addThousandSeparators( + this.bigTotalBusiness.toString() + )}`; }); - document.querySelectorAll('.small-percentage.chart-business').forEach((element) => { - element.innerText = `${resultPercentage.toFixed(2)}%`; + document + .querySelectorAll(".small-percentage.chart-business") + .forEach((element) => { + element.innerText = `${this.percentageResultBusiness}%`; }); - }) - .catch((error) => { - console.error("error fetching chart dara : ", error); - }); } initChartNonUsaha() { - fetch(`${GlobalConfig.apiHost}/api/non-business-documents`, { - credentials: "include", - headers: { - Authorization: `Bearer ${document.querySelector("meta[name='api-token']").content}`, - "Content-Type": "application/json", - }, - }) - .then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then((data) => { - // Pastikan this.resultDataTotal sudah ada - if (!this.resultDataTotal) { - console.error("Error: resultDataTotal is undefined"); - return; - } - - const totalAll = this.resultDataTotal.totalData ?? 0; - const countAll = this.resultDataTotal.countData ?? 0; - const countUsaha = data?.data?.count ?? 0; - const totalUsaha = data?.data?.total ?? 0; - - // Perbaikan perhitungan persentase - let resultPercentage = 0; - if (countUsaha > 0) { - resultPercentage = (countUsaha / countAll) * 100; - if (resultPercentage > 100) { - resultPercentage = 100; // Batasi maksimum 100% - } - } - document.querySelectorAll('.document-count.chart-non-business').forEach((element) => { - element.innerText = `${data.data.count}`; + document + .querySelectorAll(".document-count.chart-non-business") + .forEach((element) => { + element.innerText = `${this.dataNonBusiness.count}`; }); - document.querySelectorAll('.document-total.chart-non-business').forEach((element) => { - element.innerText = `Rp.${addThousandSeparators(data.data.total)}`; + document + .querySelectorAll(".document-total.chart-non-business") + .forEach((element) => { + element.innerText = `Rp.${addThousandSeparators( + this.bigTotalNonBusiness.toString() + )}`; }); - document.querySelectorAll('.small-percentage.chart-non-business').forEach((element) => { - element.innerText = `${resultPercentage.toFixed(2)}%`; + document + .querySelectorAll(".small-percentage.chart-non-business") + .forEach((element) => { + element.innerText = `${this.percentageResultNonBusiness}%`; }); - }) - .catch((error) => { - console.error("error fetching chart dara : ", error); - }); } - initChartStatus1(){ - fetch(`${GlobalConfig.apiHost}/api/pbg-task-documents?status=1`, { - credentials: "include", - headers: { - Authorization: `Bearer ${document.querySelector("meta[name='api-token']").content}`, - "Content-Type": "application/json", - } - }) - .then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then((data) => { - const seriesData = data.data.series; - // document.getElementById( - // "countStatus1" - // ).innerText = `${data.data.count} Berkas`; - // document.getElementById( - // "totalStatus1" - // ).innerText = `Rp.${addThousandSeparators(data.data.total)}`; - }) - .catch((error) => { - console.error("error fetching chart dara : ", error); - }); + initChartKekuranganPotensi() { + document + .querySelectorAll(".document-count.chart-kekurangan-potensi") + .forEach((element) => { + element.innerText = ``; + }); + document + .querySelectorAll(".document-total.chart-kekurangan-potensi") + .forEach((element) => { + element.innerText = `Rp.${addThousandSeparators( + this.totalKekuranganPotensi.toString() + )}`; + }); + document + .querySelectorAll(".small-percentage.chart-kekurangan-potensi") + .forEach((element) => { + element.innerText = `${this.percentageKekuranganPotensi}%`; + }); } - initChartStatus2(){ - fetch(`${GlobalConfig.apiHost}/api/pbg-task-documents?status=2`, { - credentials: "include", - headers: { - Authorization: `Bearer ${document.querySelector("meta[name='api-token']").content}`, - "Content-Type": "application/json", - } - }) - .then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then((data) => { - const seriesData = data.data.series; - // document.getElementById( - // "countStatus2" - // ).innerText = `${data.data.count} Berkas`; - // document.getElementById( - // "totalStatus2" - // ).innerText = `Rp.${addThousandSeparators(data.data.total)}`; - }) - .catch((error) => { - console.error("error fetching chart dara : ", error); - }); + initChartRealisasiTerbitPBG() { + document + .querySelectorAll(".document-count.chart-realisasi-tebit-pbg") + .forEach((element) => { + element.innerText = `0`; + }); + document + .querySelectorAll(".document-total.chart-realisasi-tebit-pbg") + .forEach((element) => { + element.innerText = `Rp.${addThousandSeparators("0.00")}`; + }); + document + .querySelectorAll(".small-percentage.chart-realisasi-tebit-pbg") + .forEach((element) => { + element.innerText = `0.00%`; + }); } - initChartStatus3(){ - fetch(`${GlobalConfig.apiHost}/api/pbg-task-documents?status=3`, { - credentials: "include", - headers: { - Authorization: `Bearer ${document.querySelector("meta[name='api-token']").content}`, - "Content-Type": "application/json", - } - }) - .then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then((data) => { - const seriesData = data.data.series; - // document.getElementById( - // "countStatus3" - // ).innerText = `${data.data.count} Berkas`; - // document.getElementById( - // "totalStatus3" - // ).innerText = `Rp.${addThousandSeparators(data.data.total)}`; - }) - .catch((error) => { - console.error("error fetching chart dara : ", error); - }); + initChartMenungguKlikDPMPTSP() { + document + .querySelectorAll(".document-count.chart-menunggu-klik-dpmptsp") + .forEach((element) => { + element.innerText = `${0}`; + }); + document + .querySelectorAll(".document-total.chart-menunggu-klik-dpmptsp") + .forEach((element) => { + element.innerText = `Rp.${addThousandSeparators("0.00")}`; + }); + document + .querySelectorAll(".small-percentage.chart-menunggu-klik-dpmptsp") + .forEach((element) => { + element.innerText = `0.00%`; + }); } - initChartStatus4(){ - fetch(`${GlobalConfig.apiHost}/api/pbg-task-documents?status=4`, { - credentials: "include", - headers: { - Authorization: `Bearer ${document.querySelector("meta[name='api-token']").content}`, - "Content-Type": "application/json", - } - }) - .then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then((data) => { - const seriesData = data.data.series; - // document.getElementById( - // "countStatus4" - // ).innerText = `${data.data.count} Berkas`; - // document.getElementById( - // "totalStatus4" - // ).innerText = `Rp.${addThousandSeparators(data.data.total)}`; - }) - .catch((error) => { - console.error("error fetching chart dara : ", error); - }); + initChartProsesDinasTeknis() { + document + .querySelectorAll(".document-count.chart-proses-dinas-teknis") + .forEach((element) => { + element.innerText = `${0}`; + }); + document + .querySelectorAll(".document-total.chart-proses-dinas-teknis") + .forEach((element) => { + element.innerText = `Rp.${addThousandSeparators("0.00")}`; + }); + document + .querySelectorAll(".small-percentage.chart-proses-dinas-teknis") + .forEach((element) => { + element.innerText = `0.00%`; + }); } - initChartStatus5(){ - fetch(`${GlobalConfig.apiHost}/api/pbg-task-documents?status=5`, { - credentials: "include", - headers: { - Authorization: `Bearer ${document.querySelector("meta[name='api-token']").content}`, - "Content-Type": "application/json", - } - }) - .then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then((data) => { - const seriesData = data.data.series; - // document.getElementById( - // "countStatus5" - // ).innerText = `${data.data.count} Berkas`; - // document.getElementById( - // "totalStatus5" - // ).innerText = `Rp.${addThousandSeparators(data.data.total)}`; - }) - .catch((error) => { - console.error("error fetching chart dara : ", error); - }); - } - initChartStatus6(){ - fetch(`${GlobalConfig.apiHost}/api/pbg-task-documents?status=6`, { - credentials: "include", - headers: { - Authorization: `Bearer ${document.querySelector("meta[name='api-token']").content}`, - "Content-Type": "application/json", - } - }) - .then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then((data) => { - const seriesData = data.data.series; - // document.getElementById( - // "countStatus6" - // ).innerText = `${data.data.count} Berkas`; - // document.getElementById( - // "totalStatus6" - // ).innerText = `Rp.${addThousandSeparators(data.data.total)}`; - }) - .catch((error) => { - console.error("error fetching chart dara : ", error); - }); - } - initChartStatus7(){ - fetch(`${GlobalConfig.apiHost}/api/pbg-task-documents?status=7`, { - credentials: "include", - headers: { - Authorization: `Bearer ${document.querySelector("meta[name='api-token']").content}`, - "Content-Type": "application/json", - } - }) - .then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then((data) => { - const seriesData = data.data.series; - // document.getElementById( - // "countStatus7" - // ).innerText = `${data.data.count} Berkas`; - // document.getElementById( - // "totalStatus7" - // ).innerText = `Rp.${addThousandSeparators(data.data.total)}`; - }) - .catch((error) => { - console.error("error fetching chart dara : ", error); - }); - } - initChartStatus20(){ - fetch(`${GlobalConfig.apiHost}/api/pbg-task-documents?status=20`, { - credentials: "include", - headers: { - Authorization: `Bearer ${document.querySelector("meta[name='api-token']").content}`, - "Content-Type": "application/json", - } - }) - .then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then((data) => { - const seriesData = data.data.series; - // document.getElementById( - // "countStatus20" - // ).innerText = `${data.data.count} Berkas`; - // document.getElementById( - // "totalStatus20" - // ).innerText = `Rp.${addThousandSeparators(data.data.total)}`; - }) - .catch((error) => { - console.error("error fetching chart dara : ", error); - }); - } - initChartStatus24(){ - fetch(`${GlobalConfig.apiHost}/api/pbg-task-documents?status=24`, { - credentials: "include", - headers: { - Authorization: `Bearer ${document.querySelector("meta[name='api-token']").content}`, - "Content-Type": "application/json", - } - }) - .then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then((data) => { - const seriesData = data.data.series; - // document.getElementById( - // "countStatus24" - // ).innerText = `${data.data.count} Berkas`; - // document.getElementById( - // "totalStatus24" - // ).innerText = `Rp.${addThousandSeparators(data.data.total)}`; - }) - .catch((error) => { - console.error("error fetching chart dara : ", error); - }); - } - -} - -class ArrowConnectorCircles { - init(){ - // Memanggil fungsi saat halaman dimuat dan ketika layar diubah ukurannya - document.addEventListener("resize", this.updateLine()); - document.addEventListener("load", this.updateLine()); - } - - updateLine() { - const circle1 = document.getElementById("chart-all-task-1").getBoundingClientRect(); - const circle2 = document.getElementById("chart-all-task-2").getBoundingClientRect(); - const line = document.getElementById("connector-line"); - - console.log(circle1); - console.log(circle2); - - line.setAttribute("x1", circle1.left + circle1.width / 2); - line.setAttribute("y1", circle1.top + circle1.height / 2); - line.setAttribute("x2", circle2.left + circle2.width / 2); - line.setAttribute("y2", circle2.top + circle2.height / 2); + initChartPotensiTataRuang() { + document + .querySelectorAll(".document-count.chart-potensi-tata-ruang") + .forEach((element) => { + element.innerText = `${0}`; + }); + document + .querySelectorAll(".document-total.chart-potensi-tata-ruang") + .forEach((element) => { + element.innerText = `Rp.${addThousandSeparators("0.00")}`; + }); + document + .querySelectorAll(".small-percentage.chart-potensi-tata-ruang") + .forEach((element) => { + element.innerText = `0.00%`; + }); } } document.addEventListener("DOMContentLoaded", async function (e) { await new BigData().init(); - // new ArrowConnectorCircles().init(); }); -function resizeDashboard(){ - //Target Width - let targetElement = document.getElementById("dashboard-fixed-wrapper"); - let targetWidth = targetElement.offsetWidth; - //console.log("TARGET ",targetWidth); +function resizeDashboard() { + //Target Width + let targetElement = document.getElementById("dashboard-fixed-wrapper"); + let targetWidth = targetElement.offsetWidth; + //console.log("TARGET ",targetWidth); - //Real Object Width - let dashboardElement = document.getElementById("dashboard-fixed-container"); - let dashboardWidth = 1110; //dashboardElement.offsetWidth; - //console.log("CURRENT ",dashboardWidth); + //Real Object Width + let dashboardElement = document.getElementById("dashboard-fixed-container"); + let dashboardWidth = 1110; //dashboardElement.offsetWidth; + //console.log("CURRENT ",dashboardWidth); - if(targetWidth> dashboardWidth){ - targetWidth = dashboardWidth; - } - - dashboardElement.style.transformOrigin = "left top"; - dashboardElement.style.transition = "transform 0.2s ease-in-out"; - dashboardElement.style.transform = "scale(" + (targetWidth/dashboardWidth).toFixed(2) + ")"; - //console.log("SCALE ", (targetWidth/dashboardWidth).toFixed(2)); + if (targetWidth > dashboardWidth) { + targetWidth = dashboardWidth; } + dashboardElement.style.transformOrigin = "left top"; + dashboardElement.style.transition = "transform 0.2s ease-in-out"; + dashboardElement.style.transform = + "scale(" + (targetWidth / dashboardWidth).toFixed(2) + ")"; + //console.log("SCALE ", (targetWidth/dashboardWidth).toFixed(2)); +} + window.addEventListener("load", function () { resizeDashboard(); }); window.addEventListener("resize", function () { resizeDashboard(); - -}); \ No newline at end of file +}); diff --git a/resources/js/data-settings/index.js b/resources/js/data-settings/index.js new file mode 100644 index 0000000..2e9f2a4 --- /dev/null +++ b/resources/js/data-settings/index.js @@ -0,0 +1,107 @@ +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"; + +class DataSettings { + init() { + this.getFetchApiData(); + } + + getFetchApiData() { + const table = new Grid({ + columns: [ + "ID", + "Key", + "Value", + "Created", + { + name: "Actions", + width: "120px", + formatter: function (cell) { + console.log("cell data", cell); + return gridjs.html(` +
+ Update + +
+ `); + }, + }, + ], + search: { + server: { + url: (prev, keyword) => `${prev}?search=${keyword}`, + }, + }, + pagination: { + limit: 15, + server: { + url: (prev, page) => + `${prev}${prev.includes("?") ? "&" : "?"}page=${ + page + 1 + }`, + }, + }, + sort: true, + server: { + url: `${GlobalConfig.apiHost}/api/api-data-settings`, + 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, + }, + }); + table.render(document.getElementById("table-data-settings")); + + document.addEventListener("click", this.handleDelete); + } + handleDelete(event) { + if (event.target.classList.contains("btn-delete-data-settings")) { + event.preventDefault(); + const id = event.target.getAttribute("data-id"); + + if (confirm("Are you sure you want to delete this item?")) { + fetch(`/data-settings/${id}`, { + method: "DELETE", + headers: { + "X-CSRF-TOKEN": document + .querySelector('meta[name="csrf-token"]') + .getAttribute("content"), + "Content-Type": "application/json", + }, + }) + .then((response) => { + if (response.ok) { + alert("Item deleted successfully!"); + window.location.reload(); + } else { + return response.json().then((error) => { + throw new Error( + error.message || "Failed to delete item." + ); + }); + } + }) + .catch((error) => { + console.error("Error deleting item:", error); + alert("Something went wrong. Please try again."); + }); + } + } + } +} +document.addEventListener("DOMContentLoaded", function (e) { + new DataSettings().init(); +}); diff --git a/resources/js/global-config.js b/resources/js/global-config.js index 701c698..331ebb9 100644 --- a/resources/js/global-config.js +++ b/resources/js/global-config.js @@ -1,12 +1,28 @@ const GlobalConfig = { - apiHost: 'http://localhost:8000' + apiHost: "http://localhost:8000", }; export default GlobalConfig; -export function addThousandSeparators(number, fractionDigits = 2) { - return new Intl.NumberFormat('en-US', { - minimumFractionDigits: fractionDigits, - maximumFractionDigits: fractionDigits, - }).format(number); -} \ No newline at end of file +export function addThousandSeparators(value, fractionDigits = 2) { + if (!value) return null; // Handle empty or null values + + // Remove any non-numeric characters except commas and dots + value = value.replace(/[^0-9,.]/g, ""); + + // If the value contains multiple dots, assume dots are thousand separators + if ((value.match(/\./g) || []).length > 1) { + value = value.replace(/\./g, ""); + } + + // Convert to a proper decimal number + let number = parseFloat(value.replace(",", ".")); + + if (isNaN(number)) return null; // Return null if conversion fails + + // Format the number with thousand separators + return new Intl.NumberFormat("en-US", { + minimumFractionDigits: fractionDigits, + maximumFractionDigits: fractionDigits, + }).format(number); +} diff --git a/resources/js/pbg-task/create.js b/resources/js/pbg-task/create.js new file mode 100644 index 0000000..ff984d4 --- /dev/null +++ b/resources/js/pbg-task/create.js @@ -0,0 +1,132 @@ +import GlobalConfig from "../global-config.js"; + +class MultiFormCreatePBG { + constructor() { + this.currentStep = 1; + this.totalSteps = 4; + this.formData = {}; // Menyimpan data dari semua langkah + } + + init() { + document + .getElementById("nextStep") + .addEventListener("click", () => this.nextStep()); + + document + .getElementById("prevStep") + .addEventListener("click", () => this.prevStep()); + } + + nextStep() { + if (!this.validateStep()) return; + + this.saveStepData(); + + if (this.currentStep < this.totalSteps) { + document + .getElementById(`step${this.currentStep}`) + .classList.add("d-none"); + + this.currentStep++; + document + .getElementById(`step${this.currentStep}`) + .classList.remove("d-none"); + + document.getElementById( + "stepTitle" + ).innerText = `Step ${this.currentStep}`; + document.getElementById("prevStep").disabled = false; + document.getElementById("nextStep").innerText = + this.currentStep === this.totalSteps ? "Submit" : "Next →"; + } else { + this.submitForm(); // Submit ke API jika sudah step terakhir + } + } + + prevStep() { + if (this.currentStep > 1) { + document + .getElementById(`step${this.currentStep}`) + .classList.add("d-none"); + + this.currentStep--; + document + .getElementById(`step${this.currentStep}`) + .classList.remove("d-none"); + + document.getElementById( + "stepTitle" + ).innerText = `Step ${this.currentStep}`; + document.getElementById("prevStep").disabled = + this.currentStep === 1; + document.getElementById("nextStep").innerText = "Next →"; + } + } + + saveStepData() { + const stepForm = document.querySelector(`#step${this.currentStep}Form`); + const formDataObj = new FormData(stepForm); + + if (!this.formData) { + this.formData = {}; + } + + const stepKey = `step${this.currentStep}Form`; + this.formData[stepKey] = {}; + + for (const [key, value] of formDataObj.entries()) { + this.formData[stepKey][key] = value; + } + + console.log("form data", this.formData); + } + + validateStep() { + const stepForm = document.querySelector(`#step${this.currentStep}Form`); + const inputs = stepForm.querySelectorAll( + "input[required], select[required]" + ); + let isValid = true; + + inputs.forEach((input) => { + if (!input.value) { + input.classList.add("is-invalid"); + isValid = false; + } else { + input.classList.remove("is-invalid"); + } + }); + + return isValid; + } + + async submitForm() { + try { + const response = await fetch( + `${GlobalConfig.apiHost}/api/api-pbg-task`, + { + method: "POST", + headers: { + Authorization: `Bearer ${ + document.querySelector("meta[name='api-token']") + .content + }`, + "Content-Type": "application/json", + }, + body: JSON.stringify(this.formData), + } + ); + + const result = await response.json(); + alert(result.message); + window.location.href = "/pbg-task"; + } catch (error) { + console.error("Error submitting form:", error); + alert("Terjadi kesalahan saat mengirim data."); + } + } +} + +document.addEventListener("DOMContentLoaded", function () { + new MultiFormCreatePBG().init(); +}); diff --git a/resources/js/pbg-task/index.js b/resources/js/pbg-task/index.js new file mode 100644 index 0000000..56dc6d5 --- /dev/null +++ b/resources/js/pbg-task/index.js @@ -0,0 +1,69 @@ +import { Grid } from "gridjs/dist/gridjs.umd.js"; +import "gridjs/dist/gridjs.umd.js"; +import GlobalConfig from "../global-config"; + +class PbgTasks { + init() { + this.initTableRequestAssignment(); + } + + initTableRequestAssignment() { + new Grid({ + columns: [ + "ID", + { name: "Name", width: "15%" }, + { name: "Condition", width: "7%" }, + "Registration Number", + "Document Number", + { name: "Address", width: "30%" }, + "Status", + "Function Type", + "Consultation Type", + { name: "Due Date", width: "7%" }, + ], + search: { + server: { + url: (prev, keyword) => `${prev}?search=${keyword}`, + }, + }, + pagination: { + limit: 15, + server: { + url: (prev, page) => + `${prev}${prev.includes("?") ? "&" : "?"}page=${ + page + 1 + }`, + }, + }, + sort: true, + server: { + url: `${GlobalConfig.apiHost}/api/request-assignments`, + 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.condition, + item.registration_number, + item.document_number, + item.address, + item.status_name, + item.function_type, + item.consultation_type, + item.due_date, + ]), + total: (data) => data.meta.total, + }, + }).render(document.getElementById("table-pbg-tasks")); + } +} + +document.addEventListener("DOMContentLoaded", function (e) { + new PbgTasks().init(); +}); diff --git a/resources/js/settings/syncronize/syncronize.js b/resources/js/settings/syncronize/syncronize.js index a09b5d1..6430ed3 100644 --- a/resources/js/settings/syncronize/syncronize.js +++ b/resources/js/settings/syncronize/syncronize.js @@ -7,6 +7,7 @@ class SyncronizeTask { init() { this.initTableImportDatasources(); this.handleSubmitSync(); + this.handleSubmitSnycGoogleSheet(); } initTableImportDatasources() { new Grid({ @@ -48,68 +49,112 @@ class SyncronizeTask { } handleSubmitSync() { const button = document.getElementById("btn-sync-submit"); - + // Check if the button should be enabled or disabled based on the status - fetch(`${GlobalConfig.apiHost}/api/import-datasource/check-datasource`, { - method: "GET", - headers: { - Authorization: `Bearer ${document - .querySelector('meta[name="api-token"]') - .getAttribute("content")}`, - "Content-Type": "application/json", + fetch( + `${GlobalConfig.apiHost}/api/import-datasource/check-datasource`, + { + method: "GET", + headers: { + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, + "Content-Type": "application/json", + }, } - }) - .then(response => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then(data => { - console.log("data check button sync", data.can_execute); - button.disabled = !data.can_execute; - - // If the button is enabled, add click event to trigger sync - if (!button.disabled) { - button.addEventListener("click", function(e) { - button.disabled = true; // Disable button to prevent multiple clicks - button.textContent = "Syncing..."; // Change button text to show syncing - - // Trigger the scraping API call - fetch(`${GlobalConfig.apiHost}/api/scraping`, { - method: "GET", - headers: { - Authorization: `Bearer ${document - .querySelector('meta[name="api-token"]') - .getAttribute("content")}`, - "Content-Type": "application/json", - } - }) - .then(response => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then(data => { - console.log("data sync button", data); - alert("Synchronization executed successfully"); - window.location.reload(); - }) - .catch(err => { - console.error("Fetch error:", err); - alert("An error occurred during synchronization"); - }) - .finally(() => { - button.disabled = false; // Re-enable the button after the request is complete - button.textContent = "Sync Data"; // Reset button text + ) + .then((response) => { + if (!response.ok) { + throw new Error("Network response was not ok"); + } + return response.json(); + }) + .then((data) => { + console.log("data check button sync", data.can_execute); + button.disabled = !data.can_execute; + + // If the button is enabled, add click event to trigger sync + if (!button.disabled) { + button.addEventListener("click", function (e) { + button.disabled = true; // Disable button to prevent multiple clicks + button.textContent = "Syncing..."; // Change button text to show syncing + + // Trigger the scraping API call + fetch(`${GlobalConfig.apiHost}/api/scraping`, { + method: "GET", + headers: { + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, + "Content-Type": "application/json", + }, + }) + .then((response) => { + if (!response.ok) { + throw new Error( + "Network response was not ok" + ); + } + return response.json(); + }) + .then((data) => { + console.log("data sync button", data); + alert("Synchronization executed successfully"); + window.location.reload(); + }) + .catch((err) => { + console.error("Fetch error:", err); + alert( + "An error occurred during synchronization" + ); + }) + .finally(() => { + button.disabled = false; // Re-enable the button after the request is complete + button.textContent = "Sync Data"; // Reset button text + }); }); + } + }) + .catch((err) => { + console.error("Fetch error:", err); + alert("An error occurred while checking the datasource"); + }); + } + handleSubmitSnycGoogleSheet() { + const button = document.getElementById("btn-sync-submit-google-sheet"); + button.addEventListener("click", function (e) { + button.disabled = true; // Disable button to prevent multiple clicks + button.textContent = "Syncing..."; // Change button text to show syncing + + // Trigger the scraping API call + fetch(`${GlobalConfig.apiHost}/api/sync-pbg-task-google-sheet`, { + method: "GET", + headers: { + Authorization: `Bearer ${document + .querySelector('meta[name="api-token"]') + .getAttribute("content")}`, + "Content-Type": "application/json", + }, + }) + .then((response) => { + if (!response.ok) { + throw new Error("Network response was not ok"); + } + return response.json(); + }) + .then((data) => { + console.log("data sync button", data); + alert("Synchronization executed successfully"); + window.location.reload(); + }) + .catch((err) => { + console.error("Fetch error:", err); + alert("An error occurred during synchronization"); + }) + .finally(() => { + button.disabled = false; // Re-enable the button after the request is complete + button.textContent = "Sync Google Sheet"; // Reset button text }); - } - }) - .catch(err => { - console.error("Fetch error:", err); - alert("An error occurred while checking the datasource"); }); } } diff --git a/resources/scss/components/_circle.scss b/resources/scss/components/_circle.scss index e7e840e..f3bcf1a 100644 --- a/resources/scss/components/_circle.scss +++ b/resources/scss/components/_circle.scss @@ -1,110 +1,97 @@ :root { - --circle-color: #c97a04; /* Default warna lingkaran */ + --circle-color: #c97a04; /* Default warna lingkaran */ } .circle-container { - width: 200px; /* Ukuran lingkaran */ - height: 200px; - display: flex; - align-items: center; - justify-content: center; - background-color: var(--circle-color);; /* Warna lingkaran utama */ - border-radius: 50%; /* Membuat lingkaran */ - border: 6px solid white; /* Border putih */ - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Efek bayangan */ - position: absolute; - - .circle-content { - width: 180px; /* Ukuran lingkaran dalam */ - height: 180px; - background-color: var(--circle-color); /* Warna lingkaran dalam */ - border-radius: 50%; + width: 200px; /* Ukuran lingkaran */ + height: 200px; display: flex; - flex-direction: column; align-items: center; justify-content: center; - text-align: center; - color: white; /* Warna teks */ - border: 4px solid white; /* Border lingkaran dalam */ - padding: 10px; - box-sizing: border-box; - } - - .circle-content .document-title { - font-size: 14px; - font-weight: bold; - margin: 0 5px; - line-height: 1.5; - } - - .circle-content .document-total { - font-size: 14px; - font-weight: bold; - color: #000000; /* Warna biru gelap untuk total */ - background-color: white; /* Background putih untuk total */ - padding: 0 7px; - border-radius: 10px; - margin: 0; - } - - .circle-content .document-count { - font-size: 24px; - font-weight: bold; - margin: 0; - } - - .circle-content .document-type { - font-size: 14px; - margin: 0; - } - - .small-circle-container { - position: absolute; - bottom: 0; - right: 0; - width: 50px; /* Ukuran lingkaran kecil */ - height: 50px; - background-color: #2d4f90; /* Warna lingkaran kecil */ + background-color: var(--circle-color); /* Warna lingkaran utama */ border-radius: 50%; /* Membuat lingkaran */ - // border: 4px solid white; /* Border putih */ - display: flex; - align-items: center; - justify-content: center; + border: 6px solid white; /* Border putih */ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Efek bayangan */ + position: absolute; - .small-circle-content{ - width: 45px; - height: 45px; - background-color: #2d4f90; /* Warna lingkaran kecil */ - border-radius: 50%; /* Membuat lingkaran */ - border: 2px solid white; /* Border putih */ - display: flex; - align-items: center; - justify-content: center; - - .small-percentage { - font-size: 10px; - font-weight: bold; + .circle-content { + width: 180px; /* Ukuran lingkaran dalam */ + height: 180px; + background-color: var(--circle-color); /* Warna lingkaran dalam */ + border-radius: 50%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; color: white; /* Warna teks */ - margin: 0; - } + border: 4px solid white; /* Border lingkaran dalam */ + padding: 10px; + box-sizing: border-box; } - } + .circle-content .document-title { + font-size: 14px; + font-weight: bold; + margin: 0 5px; + line-height: 1.5; + } + + .circle-content .document-total { + font-size: 14px; + font-weight: bold; + color: #000000; /* Warna biru gelap untuk total */ + background-color: white; /* Background putih untuk total */ + padding: 0 7px; + border-radius: 10px; + margin: 0; + } + + .circle-content .document-count { + font-size: 24px; + font-weight: bold; + margin: 0; + } + + .circle-content .document-type { + font-size: 14px; + margin: 0; + } + + .small-circle-container { + position: absolute; + bottom: 0; + right: 0; + width: 50px; /* Ukuran lingkaran kecil */ + height: 50px; + background-color: #2d4f90; /* Warna lingkaran kecil */ + border-radius: 50%; /* Membuat lingkaran */ + // border: 4px solid white; /* Border putih */ + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Efek bayangan */ + + .small-circle-content { + width: 45px; + height: 45px; + background-color: #2d4f90; /* Warna lingkaran kecil */ + border-radius: 50%; /* Membuat lingkaran */ + border: 2px solid white; /* Border putih */ + display: flex; + align-items: center; + justify-content: center; + + .small-percentage { + font-size: 10px; + font-weight: bold; + color: white; /* Warna teks */ + margin: 0; + } + } + } } - - -.arrow-container { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - pointer-events: none; /* Agar SVG tidak menghalangi interaksi */ -} - - // .circle-container { // width: 20vw; /* Responsif menggunakan unit viewport */ // height: 20vw; /* Pastikan tinggi sama dengan lebar */ diff --git a/resources/views/dashboards/bigdata.blade.php b/resources/views/dashboards/bigdata.blade.php index 4df9d9e..29f648a 100644 --- a/resources/views/dashboards/bigdata.blade.php +++ b/resources/views/dashboards/bigdata.blade.php @@ -59,8 +59,8 @@ @component('components.circle', [ 'document_title' => 'Kekurangan Potensi', 'document_color' => '#911701', - 'document_type' => 'Pemohon', - 'document_id' => 'chart-all-task', + 'document_type' => '', + 'document_id' => 'chart-kekurangan-potensi', 'visible_small_circle' => true, 'style' => 'top:150px;' ]) @@ -69,8 +69,8 @@ @component('components.circle', [ 'document_title' => 'Target PAD 2024', 'document_color' => '#020e42', - 'document_type' => 'Pemohon', - 'document_id' => 'chart-all-task', + 'document_type' => '', + 'document_id' => 'chart-target-pad', 'visible_small_circle' => true, 'style' => 'left:200px;' ]) @@ -88,7 +88,7 @@ 'document_title' => 'Total Potensi Berkas', 'document_color' => '#02acfa', 'document_type' => 'Pemohon', - 'document_id' => 'chart-all-task', + 'document_id' => 'chart-total-potensi', 'visible_small_circle' => true, 'style' => 'left:400px;top:150px;' ]) @@ -103,8 +103,8 @@ @component('components.circle', [ 'document_title' => 'Perkiraan Potensi PBG Dari Tata Ruang', 'document_color' => '#bf04bc', - 'document_type' => 'Pemohon', - 'document_id' => 'chart-all-task', + 'document_type' => 'Berkas', + 'document_id' => 'chart-potensi-tata-ruang', 'visible_small_circle' => true, 'style' => 'left:600px;' ]) @@ -137,7 +137,7 @@ 'document_title' => 'Berkas Terverifikasi', 'document_color' => '#0561f5', 'document_type' => 'Berkas', - 'document_id' => 'chart-business', + 'document_id' => 'chart-berkas-terverifikasi', 'visible_small_circle' => true, 'style' => 'top:300px;left:200px;' ]) @@ -153,7 +153,7 @@ 'document_title' => 'Berkas Belum Terverifikasi', 'document_color' => '#b973ff', 'document_type' => 'Berkas', - 'document_id' => 'chart-business', + 'document_id' => 'chart-berkas-belum-terverifikasi', 'visible_small_circle' => true, 'style' => 'top:300px;left:600px;' ]) @@ -170,7 +170,7 @@ 'document_title' => 'Realisasi Terbit PBG', 'document_color' => '#09ab5a', 'document_type' => 'Berkas', - 'document_id' => 'chart-business', + 'document_id' => 'chart-realisasi-tebit-pbg', 'visible_small_circle' => true, 'style' => 'top:550px;left:100px;' ]) @@ -183,7 +183,7 @@ 'document_title' => 'Menunggu Klik DPMPTSP', 'document_color' => '#0294ad', 'document_type' => 'Berkas', - 'document_id' => 'chart-business', + 'document_id' => 'chart-menunggu-klik-dpmptsp', 'visible_small_circle' => true, 'style' => 'top:550px;left:400px' ]) @@ -196,57 +196,12 @@ 'document_title' => 'Berproses Di Dinas Teknis', 'document_color' => '#422519', 'document_type' => 'Berkas', - 'document_id' => 'chart-business', + 'document_id' => 'chart-proses-dinas-teknis', 'visible_small_circle' => true, 'style' => 'top:550px;left:700px' ]) @endcomponent -
- - - -
-
- -
-
- - - -
-
- - - -
-
- - - - - - - -
-
- -
@endsection diff --git a/resources/views/data-settings/create.blade.php b/resources/views/data-settings/create.blade.php new file mode 100644 index 0000000..e6d22da --- /dev/null +++ b/resources/views/data-settings/create.blade.php @@ -0,0 +1,50 @@ +@extends('layouts.vertical', ['subtitle' => 'Create']) + +@section('content') + +@include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard']) + +
+ @if (session('error')) +
+ {{ session('error') }} +
+ @endif + + @if ($errors->any()) +
+ +
+ @endif +
+
+
+
+ @csrf +
+ + +
+
+ + +
+
+ + +
+ +
+
+
+
+
+ +@endsection + +@section('scripts') +@endsection \ No newline at end of file diff --git a/resources/views/data-settings/edit.blade.php b/resources/views/data-settings/edit.blade.php new file mode 100644 index 0000000..58a8c42 --- /dev/null +++ b/resources/views/data-settings/edit.blade.php @@ -0,0 +1,51 @@ +@extends('layouts.vertical', ['subtitle' => 'Create']) + +@section('content') + +@include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard']) + +
+ @if (session('error')) +
+ {{ session('error') }} +
+ @endif + + @if ($errors->any()) +
+ +
+ @endif +
+
+
+
+ @csrf + @method('PUT') +
+ + +
+
+ + +
+
+ + +
+ +
+
+
+
+
+ +@endsection + +@section('scripts') +@endsection \ No newline at end of file diff --git a/resources/views/data-settings/index.blade.php b/resources/views/data-settings/index.blade.php new file mode 100644 index 0000000..16bfd11 --- /dev/null +++ b/resources/views/data-settings/index.blade.php @@ -0,0 +1,24 @@ +@extends('layouts.vertical', ['subtitle' => 'Data Settings']) + +@section('css') +@vite(['node_modules/gridjs/dist/theme/mermaid.min.css']) +@endsection + +@section('content') + +@include('layouts.partials/page-title', ['title' => 'Data Settings', 'subtitle' => 'Setting Dashboard']) + +
+
+ Create +
+
+
+
+
+ +@endsection + +@section('scripts') +@vite(['resources/js/data-settings/index.js']) +@endsection \ No newline at end of file diff --git a/resources/views/layouts/partials/sidebar.blade.php b/resources/views/layouts/partials/sidebar.blade.php index 5f66da9..329763e 100644 --- a/resources/views/layouts/partials/sidebar.blade.php +++ b/resources/views/layouts/partials/sidebar.blade.php @@ -30,6 +30,7 @@