Compare commits

..

7 Commits

Author SHA1 Message Date
arifal
d54edb7783 update 2025-06-02 2025-02-06 04:55:30 +07:00
arifal
4eac6ab83d Merge remote-tracking branch 'origin/dev' into feat/data-settings 2025-02-05 13:40:13 +07:00
arifal
604e0d8479 partial updates create service google sheet 2025-02-05 13:38:21 +07:00
Firman Herdiansyah
99e99fa2e6 Update Dashboard Layout 2025-02-05 13:36:33 +07:00
arifal
ff324014f6 partial update create crud pbg 2025-02-05 02:40:14 +07:00
arifal
7d06e12de8 create crud data settings 2025-02-04 21:49:10 +07:00
Firman Herdiansyah
f38d518f96 Init Dev 2025-02-04 19:53:59 +07:00
142 changed files with 5972 additions and 1011 deletions

View File

@@ -65,6 +65,5 @@ AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
SIMBG_HOST="xxxxxx"
SIMBG_EMAIL="xxxxxx"
SIMBG_PASSWORD="xxxxx"
API_KEY_GOOGLE="xxxxx"
SPREAD_SHEET_ID="xxxxx"

View File

@@ -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'

View File

@@ -0,0 +1,104 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\DataSettingRequest;
use App\Http\Resources\DataSettingResource;
use App\Models\DataSetting;
use App\Traits\GlobalApiResponse;
use Exception;
use Illuminate\Http\Request;
class DataSettingController extends Controller
{
use GlobalApiResponse;
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
try {
$query = DataSetting::query()->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());
}
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Services\GoogleSheetService;
use Illuminate\Http\Request;
class GoogleSheetController extends Controller
{
protected $googleSheetService;
public function __construct(GoogleSheetService $googleSheetService){
$this->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)
{
//
}
}

View File

@@ -0,0 +1,291 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\PbgTaskMultiStepRequest;
use App\Models\PbgTask;
use App\Models\PbgTaskGoogleSheet;
use App\Services\GoogleSheetService;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class PbgTaskController extends Controller
{
protected $googleSheetService;
public function __construct(GoogleSheetService $googleSheetService){
$this->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;
}
}
}

View File

@@ -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());
}

View File

@@ -0,0 +1,120 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\DataSettingRequest;
use App\Models\DataSetting;
use Exception;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request;
class DataSettingController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
return view("data-settings.index");
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
return view("data-settings.create");
}
/**
* Store a newly created resource in storage.
*/
public function store(DataSettingRequest $request)
{
try{
DB::beginTransaction();
DataSetting::create($request->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);
}
}
}

View File

@@ -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");
}
/**

View File

@@ -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);
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class DataSettingRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
$id = $this->route('data_setting');
return [
"key" => "required|unique:data_settings,key," . $id,
"value" => "required",
"type" => "nullable",
];
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class PbgTaskMultiStepRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules()
{
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.",
];
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class DataSettingResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
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(),
];
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class DataSetting extends Model
{
protected $table = "data_settings";
protected $fillable = [
"key",
"value",
"type"
];
}

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class PbgTaskGoogleSheet extends Model
{
protected $table = "pbg_task_google_sheet";
protected $fillable = [
'jenis_konsultasi',
'no_registrasi',
'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',
];
}

View File

@@ -26,7 +26,7 @@ class ServiceClient
);
}
public function makeRequest($url, $method = 'GET', $body = null, $headers = [], $timeout = 300){
public function makeRequest($url, $method = 'GET', $body = null, $headers = [], $timeout = 14400){
try {
$headers = array_merge($this->headers, $headers);

View File

@@ -58,6 +58,8 @@ class ServiceSIMBG
];
$res = $clientHelper->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]);

View File

@@ -0,0 +1,131 @@
<?php
namespace App\Services;
use Google_Client;
use Google_Service_Sheets;
class GoogleSheetService
{
/**
* Create a new class instance.
*/
protected $client;
protected $service;
protected $spreadsheetID;
public function __construct()
{
$this->client = new Google_Client();
$this->client->setApplicationName("Sibedas Google Sheets API");
$this->client->setScopes([Google_Service_Sheets::SPREADSHEETS_READONLY]);
$this->client->setAuthConfig(storage_path("app/teak-banner-450003-s8-ea05661d9db0.json"));
$this->client->setAccessType("offline");
$this->service = new Google_Service_Sheets($this->client);
$this->spreadsheetID = env("SPREAD_SHEET_ID");
$this->service_sheets = new Google_Service_Sheets($this->client);
}
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;
}
}

View File

@@ -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",
@@ -69,5 +70,11 @@
}
},
"minimum-stability": "stable",
"prefer-stable": true
"prefer-stable": true,
"repositories": {
"grocery-crud": {
"type": "composer",
"url": "https://composer.grocerycrud.com/"
}
}
}

1361
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| CodeGenerator config overrides
|--------------------------------------------------------------------------
|
| It is a good idea to separate your configuration form the code-generator's
| own configuration. This way you won't lose any settings/preference
| you have when upgrading to a new version of the package.
|
| Additionally, you will always know any the configuration difference between
| the default config than your own.
|
| To override the setting that is found in the 'config/default.php' file, you'll
| need to create identical key here with a different value
|
| IMPORTANT: When overriding an option that is an array, the configurations
| are merged together using php's array_merge() function. This means that
| any option that you list here will take presence during a conflict in keys.
|
| EXAMPLE: The following addition to this file, will add another entry in
| the common_definitions collection
|
| 'common_definitions' =>
| [
| [
| 'match' => '*_at',
| 'set' => [
| 'css-class' => 'datetime-picker',
| ],
| ],
| ],
|
*/
/*
|--------------------------------------------------------------------------
| The default path of where the uploaded files live.
|--------------------------------------------------------------------------
|
| You can use Laravel Storage filesystem. By default, the code-generator
| uses the default file system.
| For more info about Laravel's file system visit
| https://laravel.com/docs/5.5/filesystem
|
*/
'files_upload_path' => 'uploads',
];

View File

@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('data_settings', function (Blueprint $table) {
$table->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');
}
};

View File

@@ -0,0 +1,80 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('pbg_task_google_sheet', function (Blueprint $table) {
$table->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');
}
};

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('pbg_task', function (Blueprint $table) {
$table->string('uuid')->nullable()->unique()->change();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('pbg_task', function (Blueprint $table) {
$table->string('uuid')->nullable()->change();
});
}
};

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('pbg_task_index_integrations', function (Blueprint $table) {
$table->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();
});
}
};

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('pbg_task_retributions', function (Blueprint $table) {
$table->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();
});
}
};

View File

@@ -0,0 +1,35 @@
<?php
namespace Database\Seeders;
use App\Models\DataSetting;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DataSettingSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$data_settings = [
[
"key" => "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(),
]);
}
}
}

16
package-lock.json generated
View File

@@ -1,11 +1,12 @@
{
"name": "Darkone-Laravel",
"name": "sibedas-pbg-web",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"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",

View File

@@ -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",

View File

@@ -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;

View File

@@ -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,424 +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);
//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));
}
window.addEventListener("load", function () {
resizeDashboard();
});
window.addEventListener("resize", function () {
resizeDashboard();
});

View File

@@ -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(`
<div class="d-flex justify-items-end gap-10">
<a href="/data-settings/${cell}/edit" class="btn btn-yellow me-2">Update</a>
<button class="btn btn-red btn-delete btn-delete-data-settings" data-id="${cell}">Delete</button>
</div>
`);
},
},
],
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();
});

View File

@@ -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);
}
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);
}

View File

@@ -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();
});

View File

@@ -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();
});

View File

@@ -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");
});
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1 @@
{!! $errors->first('[% field_name %]', '<div class="invalid-feedback">:message</div>') !!}

View File

@@ -0,0 +1 @@
<input class="form-control{{ $errors->has('[% field_name %]') ? ' is-invalid' : '' }}[% css_class %]" name="[% field_name %]" type="[% field_type %]" id="[% field_name %]" value="[% field_value %]"[% min_length %][% max_length %][% min_value %][% max_value %][% required_field %][% placeholder %][% step %]>

View File

@@ -0,0 +1,8 @@
<div class="mb-3 row">
[% field_label %]
<div class="col-lg-10 col-xl-9">
[% field_input %]
[% field_validation_helper %]
</div>
</div>

View File

@@ -0,0 +1 @@
<label for="[% field_name %]" class="col-form-label text-lg-end col-lg-2 col-xl-3">[% field_title %]</label>

View File

@@ -0,0 +1,8 @@
<select class="form-select{{ $errors->has('[% field_name %]') ? ' is-invalid' : '' }}[% css_class %]" id="[% field_name %]" name="[% field_name %]">
[% placeholder %]
@foreach (range(1, 12) as $value)
<option value="{{ $value }}"[% selected_value %]>
{{ date('F', mktime(0, 0, 0, $value, 1)) }}
</option>
@endforeach
</select>

View File

@@ -0,0 +1 @@
<div class="col-form-label text-lg-end col-lg-2 col-xl-3"></div>

View File

@@ -0,0 +1 @@
<input class="form-control{{ $errors->has('[% field_name %]') ? ' is-invalid' : '' }}[% css_class %]" name="[% field_name %]" type="password" id="[% field_name %]" value="[% field_value %]"[% min_length %][% max_length %][% min_value %][% max_value %][% required_field %][% placeholder %]>

View File

@@ -0,0 +1,6 @@
<div class="form-check [% field_type %]">
<input id="[% item_id %]" class="form-check-input[% required_class %][% css_class %]" name="[% field_name %]" type="[% field_type %]" value="[% option_value %]"[% required_field %][% checked_item %]>
<label class="form-check-label" for="[% item_id %]">
[% item_title %]
</label>
</div>

View File

@@ -0,0 +1,6 @@
<div class="form-check form-check-inline[% field_type %]">
<input id="[% item_id %]" class="form-check-input[% required_class %][% css_class %]" name="[% field_name %]" type="[% field_type %]" value="[% option_value %]"[% required_field %][% checked_item %]>
<label class="form-check-label" for="[% item_id %]">
[% item_title %]
</label>
</div>

View File

@@ -0,0 +1,35 @@
<?php
namespace [% class_namespace %];
use Illuminate\Foundation\Http\FormRequest;
[% use_command_placeholder %]
class [% form_request_class %] extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return [% autherized_boolean %];
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
$rules = [
[% validation_rules %]
];
[% file_validation_snippet %]
return $rules;
}
[% get_data_method %]
[% upload_method %]
}

View File

@@ -0,0 +1,9 @@
<select class="form-select{{ $errors->has('[% field_name %]') ? ' is-invalid' : '' }}[% css_class %]" id="[% field_name %]" name="[% field_name %]"[% field_multiple %][% required_field %]>
[% placeholder %]
@foreach ([% field_items %] as $key => [% field_item %])
<option value="{{ $key }}"[% selected_value %]>
{{ [% field_item %] }}
</option>
@endforeach
</select>

View File

@@ -0,0 +1,9 @@
<select class="form-select{{ $errors->has('[% field_name %]') ? ' is-invalid' : '' }}[% css_class %]" id="[% field_name %]" name="[% field_name %]">
[% placeholder %]
@foreach (range([% min_value %], [% max_value %]) as $value)
<option value="{{ $value }}"[% selected_value %]>
{{ $value }}
</option>
@endforeach
</select>

View File

@@ -0,0 +1 @@
<textarea class="form-control{{ $errors->has('[% field_name %]') ? ' is-invalid' : '' }}[% css_class %]" name="[% field_name %]" id="[% field_name %]"[% min_length %][% max_length %][% min_value %][% max_value %][% required_field %][% placeholder %]>[% field_value %]</textarea>

View File

@@ -0,0 +1 @@
[% form_fields_html %]

View File

@@ -0,0 +1,78 @@
@extends('[% layout_name %]')
@section('content')
@if(Session::has('success_message'))
<div class="alert alert-success alert-dismissible" role="alert">
{!! session('success_message') !!}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
<div class="card text-bg-theme">
<div class="card-header d-flex justify-content-between align-items-center p-3">
<h4 class="m-0">[% model_name_plural_title %]</h4>
<div>
<a href="{{ route('[% create_route_name %]') }}" class="btn btn-secondary" title="[% create_model %]">
<span class="fa-solid fa-plus" aria-hidden="true"></span>
</a>
</div>
</div>
@if(count($[% model_name_plural_variable %]) == 0)
<div class="card-body text-center">
<h4>[% no_models_available %]</h4>
</div>
@else
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-striped ">
<thead>
<tr>
[% header_cells %]
<th></th>
</tr>
</thead>
<tbody>
@foreach($[% model_name_plural_variable %] as $[% model_name_singular_variable %])
<tr>
[% body_cells %]
<td class="text-end">
<form method="POST" action="{!! route('[% destroy_route_name %]', $[% model_name_singular_variable %]->[% primary_key %]) !!}" accept-charset="UTF-8">
<input name="_method" value="DELETE" type="hidden">
{{ csrf_field() }}
<div class="btn-group btn-group-sm" role="group">
<a href="{{ route('[% show_route_name %]', $[% model_name_singular_variable %]->[% primary_key %] ) }}" class="btn btn-info" title="[% show_model %]">
<span class="fa-solid fa-arrow-up-right-from-square" aria-hidden="true"></span>
</a>
<a href="{{ route('[% edit_route_name %]', $[% model_name_singular_variable %]->[% primary_key %] ) }}" class="btn btn-primary" title="[% edit_model %]">
<span class="fa-regular fa-pen-to-square" aria-hidden="true"></span>
</a>
<button type="submit" class="btn btn-danger" title="[% delete_model %]" onclick="return confirm(&quot;[% confirm_delete %]&quot;)">
<span class="fa-regular fa-trash-can" aria-hidden="true"></span>
</button>
</div>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
{!! $[% model_name_plural_variable %]->links('[% pagination_view_name %]') !!}
</div>
@endif
</div>
@endsection

View File

@@ -0,0 +1 @@
<td class="align-middle">{{ [% field_value %] }}</td>

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