Compare commits

...

8 Commits

Author SHA1 Message Date
arifal
c4d865bf2b fix get menu id and height auto chart growth 2025-05-15 18:09:28 +07:00
arifal
a103b38265 create page growth report 2025-05-15 17:02:02 +07:00
arifal
9aa3d32b6e add link in potential dashboard 2025-05-15 14:18:27 +07:00
arifal
99e2c214b6 create redirect link for dashboard pimpinan 2025-05-14 20:56:36 +07:00
arifal
501a76bc81 partial update circle chart can click 2025-05-06 17:29:39 +07:00
arifal
460267992e handle null value on detail quick search 2025-05-06 15:32:03 +07:00
arifal
becc368069 last update feat quick search 2025-05-06 15:06:59 +07:00
arifal
2618ac06d0 partial update create page quick search 2025-05-05 18:36:56 +07:00
34 changed files with 1393 additions and 103 deletions

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Enums;
enum PbgTaskFilterData : string
{
case non_business = 'non-business';
case business = 'business';
case verified = 'verified';
case non_verified = 'non-verified';
case all = 'all';
public static function getAllOptions() : array {
return [
self::all->value => 'Potensi Berkas',
self::business->value => 'Usaha',
self::non_business->value => 'Bukan Usaha',
self::verified->value => 'Terverifikasi',
self::non_verified->value => 'Belum Terverifikasi',
];
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\BigdataResume;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class GrowthReportAPIController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
// Get current date
$today = Carbon::today();
// Define default range: 1 month back from today
$defaultStart = $today->copy()->subMonth();
$defaultEnd = $today;
// Use request values if provided, else use defaults
$startDate = $request->input('start_date', $defaultStart->toDateString());
$endDate = $request->input('end_date', $defaultEnd->toDateString());
// Optional year filter (used if specified)
$year = $request->input('year', now()->year);
$query = BigdataResume::selectRaw("
DATE(created_at) as date,
SUM(potention_sum) as potention_sum,
SUM(verified_sum) as verified_sum,
SUM(non_verified_sum) as non_verified_sum
")
->whereBetween('created_at', [$startDate, $endDate]);
$query->whereNotNull('year')
->where('year', '!=', 'all');
$data = $query->groupBy(DB::raw('DATE(created_at)'))
->orderBy(DB::raw('DATE(created_at)'))
->get()
->map(function ($item) {
$item->date = Carbon::parse($item->date)->format('d M Y');
return $item;
});
return response()->json($data);
}
/**
* 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

@@ -8,7 +8,7 @@ use App\Http\Resources\RequestAssignmentResouce;
use App\Models\PbgTask;
use App\Models\PbgTaskGoogleSheet;
use Barryvdh\DomPDF\Facade\Pdf;
use DB;
use Illuminate\Support\Facades\DB;
use Exception;
use Illuminate\Http\Request;
use Log;
@@ -21,18 +21,51 @@ class RequestAssignmentController extends Controller
*/
public function index(Request $request)
{
$query = PbgTask::with(['attachments' => function ($q) {
$q->whereIn('pbg_type', ['berita_acara', 'bukti_bayar']);
}])->orderBy('id', 'desc');
$query = PbgTask::with([
'attachments' => function ($q) {
$q->whereIn('pbg_type', ['berita_acara', 'bukti_bayar']);
},
'googleSheet'
])->orderBy('id', 'desc');
if ($request->has('filter') && !empty($request->get('filter'))) {
$filter = strtolower($request->get('filter'));
switch ($filter) {
case 'non-business':
$query->whereRaw("LOWER(function_type) != ?", ['sebagai tempat usaha'])->orWhereNull('function_type');
break;
case 'business':
$query->whereRaw("LOWER(function_type) = ?", ['sebagai tempat usaha']);
break;
case 'verified':
$query->whereHas('googleSheet', function ($q) {
$q->whereRaw("LOWER(status_verifikasi) = ?", ['selesai verifikasi']);
});
break;
case 'non-verified':
$query->where(function ($q) {
$q->whereDoesntHave('googleSheet')
->orWhereHas('googleSheet', function ($q2) {
$q2->whereRaw("LOWER(status_verifikasi) != ?", ['selesai verifikasi'])->orWhereNull('status_verifikasi');
});
});
break;
}
}
if ($request->has('search') && !empty($request->get("search"))) {
$query->where(function ($q) use ($request) {
$q->where('name', 'LIKE', '%' . $request->get('search') . '%')
->orWhere('registration_number', 'LIKE', '%' . $request->get('search') . '%')
->orWhere('document_number', 'LIKE', '%' . $request->get('search') . '%');
$search = $request->get('search');
$query->where(function ($q) use ($search) {
$q->where('name', 'LIKE', "%$search%")
->orWhere('registration_number', 'LIKE', "%$search%")
->orWhere('document_number', 'LIKE', "%$search%");
});
}
return RequestAssignmentResouce::collection($query->paginate());
}

View File

@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Dashboards;
use App\Http\Controllers\Controller;
use App\Models\ImportDatasource;
use App\Models\Menu;
use Illuminate\Http\Request;
class BigDataController extends Controller
@@ -12,7 +13,8 @@ class BigDataController extends Controller
$latest_import_datasource = ImportDatasource::latest()->first();
$latest_created = $latest_import_datasource ?
$latest_import_datasource->created_at->format("j F Y H:i:s") : null;
return view('dashboards.bigdata', compact('latest_created'));
$menus = Menu::all();
return view('dashboards.bigdata', compact('latest_created', 'menus'));
}
public function pbg()

View File

@@ -3,12 +3,14 @@
namespace App\Http\Controllers\Dashboards;
use App\Http\Controllers\Controller;
use App\Models\Menu;
use Illuminate\Http\Request;
class PotentialsController extends Controller
{
public function inside_system(){
return view('dashboards.potentials.inside_system');
$menus = Menu::all();
return view('dashboards.potentials.inside_system', compact('menus'));
}
public function outside_system(){
return view('dashboards.potentials.outside_system');

View File

@@ -0,0 +1,87 @@
<?php
namespace App\Http\Controllers;
use App\Enums\PbgTaskApplicationTypes;
use App\Enums\PbgTaskStatus;
use App\Http\Resources\TaskAssignmentsResource;
use App\Models\PbgTask;
use App\Models\TaskAssignment;
use Illuminate\Http\Request;
class QuickSearchController extends Controller
{
public function index(){
return view("quick-search.index");
}
public function search_result(Request $request){
$keyword = $request->get("keyword");
return view('quick-search.result', compact('keyword'));
}
public function quick_search_datatable(Request $request)
{
try {
$query = PbgTask::orderBy('id', 'desc');
if ($request->filled('search')) {
$search = $request->get('search');
$query->where(function ($q) use ($search) {
$q->where('name', 'LIKE', "%$search%")
->orWhere('registration_number', 'LIKE', "%$search%")
->orWhere('address', 'LIKE', "%$search%")
->orWhere('document_number', 'LIKE', "%$search%");
});
}
return response()->json($query->paginate());
} catch (\Throwable $e) {
\Log::error("Error fetching datatable data: " . $e->getMessage());
return response()->json([
'message' => 'Terjadi kesalahan saat mengambil data.',
'error' => $e->getMessage(),
], 500);
}
}
public function show($id)
{
try {
$data = PbgTask::with([
'pbg_task_retributions',
'pbg_task_index_integrations',
'pbg_task_retributions.pbg_task_prasarana'
])->findOrFail($id);
$statusOptions = PbgTaskStatus::getStatuses();
$applicationTypes = PbgTaskApplicationTypes::labels();
return view("quick-search.detail", compact("data", 'statusOptions', 'applicationTypes'));
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
\Log::warning("PbgTask with ID {$id} not found.");
return redirect()->route('quick-search.index')->with('error', 'Data tidak ditemukan.');
} catch (\Throwable $e) {
\Log::error("Error in QuickSearchController@show: " . $e->getMessage());
return response()->view('pages.404', [], 500); // Optional: create `resources/views/errors/500.blade.php`
}
}
public function task_assignments(Request $request, $uuid){
try{
$query = TaskAssignment::query()
->where('pbg_task_uid', $uuid)
->orderBy('id', 'desc');
if ($request->filled('search')) {
$query->where('name', 'like', "%{$request->get('search')}%")
->orWhere('email', 'like', "%{$request->get('search')}%");
}
return TaskAssignmentsResource::collection($query->paginate(config('app.paginate_per_page', 50)));
}catch(\Exception $exception){
return response()->json(['message' => $exception->getMessage()], 500);
}
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace App\Http\Controllers\Report;
use App\Http\Controllers\Controller;
use App\Models\Menu;
use Illuminate\Http\Request;
class GrowthReportsController extends Controller
{
public function index(){
return view('report.growth-report.index');
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers\RequestAssignment;
use App\Enums\PbgTaskApplicationTypes;
use App\Enums\PbgTaskFilterData;
use App\Http\Controllers\Controller;
use App\Models\PbgTask;
use Illuminate\Http\Request;
@@ -17,27 +18,21 @@ class PbgTaskController extends Controller
*/
public function index(Request $request)
{
$menuId = $request->query('menu_id');
$user = Auth::user();
$userId = $user->id;
$menuId = $request->query('menu_id') ?? $request->input('menu_id');
$filter = $request->query('filter');
// Ambil role_id yang dimiliki user
$roleIds = DB::table('user_role')
->where('user_id', $userId)
->pluck('role_id');
// Ambil data akses berdasarkan role_id dan menu_id
$roleAccess = DB::table('role_menu')
->whereIn('role_id', $roleIds)
->where('menu_id', $menuId)
->first();
// Pastikan roleAccess tidak null sebelum mengakses properti
$creator = $roleAccess->allow_create ?? 0;
$updater = $roleAccess->allow_update ?? 0;
$destroyer = $roleAccess->allow_destroy ?? 0;
return view('pbg_task.index', compact('creator', 'updater', 'destroyer'));
$permissions = $this->permissions[$menuId]?? []; // Avoid undefined index error
$creator = $permissions['allow_create'] ?? 0;
$updater = $permissions['allow_update'] ?? 0;
$destroyer = $permissions['allow_destroy'] ?? 0;
return view('pbg_task.index', [
'creator' => $creator,
'updater' => $updater,
'destroyer' => $destroyer,
'filter' => $filter,
'filterOptions' => PbgTaskFilterData::getAllOptions(),
]);
}
/**

View File

@@ -13,13 +13,15 @@ class Circle extends Component
public $document_type;
public $document_id;
public $visible_small_circle;
public function __construct($document_id = "",$document_title = "", $document_type = "", $document_color = "#020c5c", $visible_small_circle = true)
public $document_url;
public function __construct($document_id = "",$document_title = "", $document_type = "", $document_color = "#020c5c", $visible_small_circle = true, $document_url = "#")
{
$this->document_title = $document_title;
$this->document_color = $document_color;
$this->document_type = $document_type;
$this->document_id = $document_id;
$this->visible_small_circle = $visible_small_circle;
$this->document_url = $document_url;
}
/**

View File

@@ -208,23 +208,29 @@ class MenuSeeder extends Seeder
"icon" => null,
"sort_order" => 2,
],
[
"name" => "Lap Pertumbuhan",
"url" => "growths",
"icon" => null,
"sort_order" => 3,
],
[
"name" => "Rekap Pembayaran",
"url" => "payment-recaps",
"icon" => null,
"sort_order" => 3,
"sort_order" => 4,
],
[
"name" => "Lap Rekap Data Pembayaran",
"url" => "report-payment-recaps",
"icon" => null,
"sort_order" => 4,
"sort_order" => 5,
],
[
"name" => "Lap PBG (PTSP)",
"url" => "report-pbg-ptsp",
"icon" => null,
"sort_order" => 5,
"sort_order" => 6,
],
]
],

View File

@@ -25,7 +25,7 @@ class UsersRoleMenuSeeder extends Seeder
'Menu', 'Role', 'Setting Dashboard', 'PBG', 'Reklame', 'Usaha atau Industri', 'Pariwisata',
'Lap Pariwisata', 'UMKM', 'Dashboard Potensi', 'Tata Ruang', 'PDAM', 'PETA',
'Lap Pimpinan', 'Dalam Sistem', 'Luar Sistem', 'Google Sheets', 'TPA TPT',
'Approval Pejabat', 'Undangan', 'Rekap Pembayaran', 'Lap Rekap Data Pembayaran', 'Lap PBG (PTSP)'
'Approval Pejabat', 'Undangan', 'Rekap Pembayaran', 'Lap Rekap Data Pembayaran', 'Lap PBG (PTSP)', 'Lap Pertumbuhan'
])->get()->keyBy('name');
// Define access levels for each role
@@ -36,7 +36,7 @@ class UsersRoleMenuSeeder extends Seeder
'Menu', 'Role', 'Setting Dashboard', 'PBG', 'Reklame', 'Usaha atau Industri', 'Pariwisata',
'Lap Pariwisata', 'UMKM', 'Dashboard Potensi', 'Tata Ruang', 'PDAM', 'Dalam Sistem',
'Luar Sistem', 'Lap Pimpinan', 'Google Sheets', 'TPA TPT', 'Approval Pejabat',
'Undangan', 'Rekap Pembayaran', 'Lap Rekap Data Pembayaran', 'Lap PBG (PTSP)'
'Undangan', 'Rekap Pembayaran', 'Lap Rekap Data Pembayaran', 'Lap PBG (PTSP)', 'Lap Pertumbuhan'
],
'user' => ['Dashboard', 'Data', 'Laporan', 'Neng Bedas',
'Approval', 'Tools', 'Dashboard Pimpinan', 'Dashboard PBG', 'Users', 'Syncronize',

View File

@@ -168,6 +168,13 @@ document.addEventListener("DOMContentLoaded", async function (e) {
await new DashboardPotentialInsideSystem().init();
});
function handleCircleClick(element) {
const url = element.getAttribute("data-url") || "#";
if (url !== "#") {
window.location.href = url;
}
}
function resizeDashboard() {
let targetElement = document.getElementById("lack-of-potential-wrapper");
let dashboardElement = document.getElementById(

View File

@@ -34,11 +34,42 @@ class PbgTasks {
pbgType: "berita_acara",
bindFlag: "uploadHandlerBoundBeritaAcara",
});
this.initTableRequestAssignment();
this.handleFilterDatatable();
this.handleSendNotification();
}
initTableRequestAssignment() {
handleFilterDatatable() {
const form = document.getElementById("filter-form");
const filterSelect = document.getElementById("filter-select");
const urlParams = new URLSearchParams(window.location.search);
const initialFilter = urlParams.get("filter") || "";
this.initTableRequestAssignment(initialFilter); // Initial load with query param
form.addEventListener("submit", (e) => {
e.preventDefault();
const selectedFilter = filterSelect.value;
const params = new URLSearchParams(window.location.search);
params.set("filter", selectedFilter);
// Update the URL without reloading
window.history.replaceState(
{},
"",
`${location.pathname}?${params}`
);
// Call the method again with the selected filter
this.initTableRequestAssignment(selectedFilter);
});
}
initTableRequestAssignment(filterValue = "") {
const urlBase = `${GlobalConfig.apiHost}/api/request-assignments`;
// Ambil token
const token = document
.querySelector('meta[name="api-token"]')
@@ -124,7 +155,10 @@ class PbgTasks {
],
search: {
server: {
url: (prev, keyword) => `${prev}?search=${keyword}`,
url: (prev, keyword) =>
`${prev}${
prev.includes("?") ? "&" : "?"
}search=${keyword}`,
},
debounceTimeout: 1000,
},
@@ -139,7 +173,7 @@ class PbgTasks {
},
sort: true,
server: {
url: `${GlobalConfig.apiHost}/api/request-assignments`,
url: `${urlBase}?filter=${filterValue}`,
credentials: "include",
headers: {
Authorization: `Bearer ${token}`,

View File

@@ -0,0 +1,70 @@
import { Grid } from "gridjs";
class QuickSearchDetail {
init() {
this.initTablePbgTaskAssignments();
}
initTablePbgTaskAssignments() {
let tableContainer = document.getElementById(
"table-pbg-task-assignments"
);
let url_task_assignments = document.getElementById(
"url_task_assignments"
).value;
new Grid({
columns: [
"ID",
"Nama",
"Email",
"Nomor Telepon",
"Keahlian",
"Status",
],
search: {
server: {
url: (prev, keyword) => `${prev}?search=${keyword}`,
},
debounceTimeout: 1000,
},
pagination: {
limit: 15,
server: {
url: (prev, page) =>
`${prev}${prev.includes("?") ? "&" : "?"}page=${
page + 1
}`,
},
},
sort: true,
server: {
url: `${url_task_assignments}`,
then: (data) => {
return data.data.map((item) => {
const expertiseArray =
typeof item.expertise === "string"
? JSON.parse(item.expertise)
: item.expertise;
return [
item.id,
item.name,
item.email,
item.phone_number,
Array.isArray(expertiseArray)
? expertiseArray.map((e) => e.name).join(", ")
: "-",
item.status_name,
];
});
},
total: (data) => data.meta.total,
},
}).render(tableContainer);
}
}
document.addEventListener("DOMContentLoaded", function (e) {
new QuickSearchDetail().init();
});

View File

@@ -0,0 +1,21 @@
document.addEventListener("DOMContentLoaded", function () {
const searchBtn = document.getElementById("searchBtn");
const searchInput = document.getElementById("searchInput");
searchBtn.addEventListener("click", function () {
const keyword = searchInput.value.trim();
if (keyword !== "") {
// Redirect to the route with query parameter
window.location.href = `/search-result?keyword=${encodeURIComponent(
keyword
)}`;
}
});
// Optional: trigger search on Enter key
searchInput.addEventListener("keydown", function (e) {
if (e.key === "Enter") {
searchBtn.click();
}
});
});

View File

@@ -0,0 +1,135 @@
import { Grid, html } from "gridjs";
class QuickSearchResult {
constructor() {
this.table = null;
const baseInput = document.getElementById("base_url_datatable");
this.baseUrl = baseInput ? baseInput.value.split("?")[0] : "";
this.keywordInput = document.getElementById("search_input");
this.searchButton = document.getElementById("search_button");
this.datatableUrl = this.buildUrl(this.keywordInput.value);
}
init() {
this.bindSearchButton();
this.initDatatable();
}
bindSearchButton() {
const handleSearch = () => {
const newKeyword = this.keywordInput.value.trim();
if (newKeyword !== "") {
// 1. Update datatable URL and reload
this.datatableUrl = this.buildUrl(newKeyword);
this.initDatatable();
// 2. Update URL query string (without reloading the page)
const newUrl = `${
window.location.pathname
}?keyword=${encodeURIComponent(newKeyword)}`;
window.history.pushState({ path: newUrl }, "", newUrl);
// 3. Update visible keyword text in <em>{{ $keyword }}</em>>
const keywordDisplay = document.querySelector(".qs-header em");
if (keywordDisplay) {
keywordDisplay.textContent = newKeyword;
}
}
};
this.searchButton.addEventListener("click", handleSearch);
this.keywordInput.addEventListener("keydown", (event) => {
if (event.key === "Enter") {
event.preventDefault();
handleSearch();
}
});
}
buildUrl(keyword) {
const url = new URL(this.baseUrl, window.location.origin);
url.searchParams.set("search", keyword);
return url.toString();
}
initDatatable() {
const tableContainer = document.getElementById(
"datatable-quick-search-result"
);
const config = {
columns: [
"ID",
{ name: "Name" },
{ name: "Condition" },
"Registration Number",
"Document Number",
{ name: "Address" },
"Status",
"Function Type",
"Consultation Type",
{ name: "Due Date" },
{
name: "Action",
formatter: (cell) => {
return html(`
<a href="/quick-search/${cell.id}"
class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center"
style="white-space: nowrap; line-height: 1;">
<iconify-icon icon="mingcute:eye-2-fill" width="15" height="15" style="vertical-align: middle;"></iconify-icon>
</a>
`);
},
},
],
search: false,
pagination: {
limit: 15,
server: {
url: (prev, page) =>
`${prev}${prev.includes("?") ? "&" : "?"}page=${
page + 1
}`,
},
},
sort: true,
server: {
url: this.datatableUrl,
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,
item,
]),
total: (data) => data.total,
},
};
if (this.table) {
this.table
.updateConfig({
...config,
server: { ...config.server, url: this.datatableUrl },
})
.forceRender();
} else {
tableContainer.innerHTML = "";
this.table = new Grid(config).render(tableContainer);
}
}
}
document.addEventListener("DOMContentLoaded", function () {
const app = new QuickSearchResult();
app.init();
});

View File

@@ -0,0 +1,94 @@
import ApexCharts from "apexcharts";
class GrowthReport {
init() {
this.loadChart();
}
async loadChart() {
try {
const chartElement = document.getElementById("chart-growth-report");
const apiUrl = chartElement.dataset.url;
const token = document
.querySelector('meta[name="api-token"]')
.getAttribute("content");
const response = await fetch(apiUrl, {
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json",
},
});
const data = await response.json();
console.log("data", data);
const categories = data.map((item) => item.date);
const potentionSeries = {
name: "Potensi Berkas",
data: data.map((item) => item.potention_sum),
};
const verifiedSeries = {
name: "Terverifikasi",
data: data.map((item) => item.verified_sum),
};
const nonVerifiedSeries = {
name: "Belum Terverifikasi",
data: data.map((item) => item.non_verified_sum),
};
const options = {
chart: {
type: "bar",
height: "auto",
},
title: {
text: "Grafik Pertumbuhan",
},
dataLabels: {
enabled: false,
},
legend: {
show: true,
},
xaxis: {
categories: categories,
},
yaxis: {
title: {
text: "Total SUM Per Date",
},
labels: {
formatter: function (value) {
return "Rp. " + value.toLocaleString("id-ID");
},
},
},
noData: {
text: "Data tidak tersedia",
align: "center",
verticalAlign: "middle",
style: {
color: "#999",
fontSize: "16px",
},
},
series: [potentionSeries, verifiedSeries, nonVerifiedSeries],
};
const chart = new ApexCharts(chartElement, options);
chart.render();
} catch (error) {
console.error("Failed to load growth report data:", error);
}
}
}
document.addEventListener("DOMContentLoaded", function () {
new GrowthReport().init();
});

View File

@@ -0,0 +1,73 @@
.qs-detail-container {
color: #000; // black text
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
.card {
background-color: #fff;
.card-header {
background-color: #f5f5f5;
font-weight: bold;
color: #000;
}
.card-body {
dt {
font-weight: 600;
color: #000;
}
dd {
margin-bottom: 10px;
color: #000;
}
.nav-tabs {
border-bottom: 1px solid #000;
.nav-link {
color: #000;
border: 1px solid transparent;
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
font-weight: 500;
&.active {
background-color: #e0e0e0;
border-color: #000 #000 #fff;
}
&:hover {
color: #000;
}
}
}
.tab-content {
padding: 1rem;
}
.mb-3 {
dt {
font-weight: bold;
}
dd {
margin-left: 0;
}
}
.border {
border-color: #000 !important;
}
.shadow-sm {
box-shadow: none !important;
}
.rounded {
border-radius: 4px !important;
}
}
}
}

View File

@@ -0,0 +1,78 @@
.gsp-body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh; // ensures full vertical centering
background: #f0f2f5;
}
.gsp-icon {
width: 180px; // slightly smaller for better mobile view
height: auto;
margin-bottom: 15px;
}
.gsp-title {
font-size: 36px;
font-weight: 700;
color: #333;
}
.gsp-input {
width: 100%;
height: 44px;
font-size: 16px;
padding: 0 20px;
border-radius: 24px;
border: 1px solid #dfe1e5;
background-color: #fff;
box-shadow: none;
transition: box-shadow 0.2s ease-in-out, border-color 0.2s;
&:focus {
border-color: transparent;
box-shadow: 0 1px 6px rgba(32, 33, 36, 0.28);
outline: none;
}
}
.gsp-btn {
height: 44px;
padding: 0 24px;
font-size: 16px;
border: none;
border-radius: 24px;
background-color: #1a73e8;
color: white;
cursor: pointer;
transition: background-color 0.2s ease-in-out;
&:hover {
background-color: #1558d6;
}
}
@media (max-width: 576px) {
.gsp-input-wrapper {
flex-direction: column;
align-items: stretch;
}
.gsp-btn {
width: 100%;
padding: 0 20px;
}
.gsp-input {
padding: 0 20px;
font-size: 16px;
}
.gsp-title {
font-size: 28px;
}
.gsp-icon {
width: 140px;
}
}

View File

@@ -0,0 +1,130 @@
.qs-wrapper {
width: 100%;
margin: 0 auto;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
color: #2c3e50;
}
.qs-toolbar {
border-bottom: 1px solid #e0e0e0;
margin-bottom: 1.5rem;
}
.qs-search-form {
width: 100%;
.gsp-input {
width: 100%;
height: 44px;
font-size: 16px;
padding: 0 20px;
border-radius: 24px;
border: 1px solid #dfe1e5;
background-color: #fff;
box-shadow: none;
transition: box-shadow 0.2s ease-in-out, border-color 0.2s;
&:focus {
border-color: transparent;
box-shadow: 0 1px 6px rgba(32, 33, 36, 0.28);
outline: none;
}
}
.gsp-btn {
height: 44px;
padding: 0 24px;
font-size: 16px;
border: none;
border-radius: 24px;
background-color: #1a73e8;
color: white;
cursor: pointer;
transition: background-color 0.2s ease-in-out;
&:hover {
background-color: #1558d6;
}
}
}
.qs-header {
margin-bottom: 30px;
text-align: center;
h2 {
font-size: 24px;
font-weight: 600;
color: #1a237e;
em {
font-style: normal;
color: #0d47a1;
}
}
p {
font-size: 16px;
color: #555;
}
}
.qs-table-wrapper {
background-color: #fff;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
overflow-x: auto; // allow horizontal scroll on small screens
}
/* Grid.js overrides */
.qs-table-wrapper .gridjs {
font-size: 14px;
color: #333;
}
.qs-table-wrapper .gridjs-table {
width: 100%;
border-collapse: collapse;
}
.qs-table-wrapper .gridjs-th,
.qs-table-wrapper .gridjs-td {
padding: 12px 16px;
border: 1px solid #e0e0e0;
text-align: left;
vertical-align: middle;
}
.qs-table-wrapper .gridjs-th {
background-color: #f5f5f5;
font-weight: 600;
color: #1b1b1b;
}
.qs-table-wrapper .gridjs-tr:hover {
background-color: #f9f9f9;
}
.qs-table-wrapper .gridjs-pagination {
margin-top: 16px;
justify-content: center;
}
@media (max-width: 768px) {
.qs-header h2 {
font-size: 20px;
}
.qs-wrapper {
padding: 20px 10px;
}
.qs-table-wrapper {
padding: 15px;
}
.qs-table-wrapper .gridjs-th,
.qs-table-wrapper .gridjs-td {
padding: 10px 12px;
font-size: 13px;
}
}

View File

@@ -21,8 +21,8 @@ class="authentication-bg"
<img src="/images/dputr-kab-bandung.png" height="auto" width="100%" alt="logo light">
</a>
</div>
<h4 class="fw-bold text-dark mb-2">Welcome Back!</h4>
<p class="text-muted">Sign in to your account to continue</p>
<h4 class="fw-bold text-dark mb-2">Selamat Datang!</h4>
<p class="text-muted">Masuk kedalam akun untuk melihat lebih lanjut</p>
</div>
<form method="POST" action="{{ route('login') }}" class="mt-4">
@@ -35,7 +35,7 @@ class="authentication-bg"
@endif
<div class="mb-3">
<label for="email" class="form-label">Email Address</label>
<label for="email" class="form-label">Email </label>
<input type="email" class="form-control" id="email" name="email" placeholder="Enter your email">
</div>
<div class="mb-3">
@@ -45,6 +45,11 @@ class="authentication-bg"
<div class="d-grid">
<button class="btn btn-dark btn-lg fw-medium" type="submit">Sign In</button>
</div>
<div class="d-flex justify-content-start mt-3">
<a href="{{ route('search') }}" class="">
Pencarian cepat
</a>
</div>
</form>
</div>
</div>

View File

@@ -1,8 +1,11 @@
@props(['document_url' => '#'])
@section('css')
@vite(['resources/scss/components/_circle.scss'])
@endsection
<div class="circle-container" id="{{$document_id}}" style="--circle-color: {{$document_color}};{{$style}}">
<div class="circle-container" id="{{$document_id}}" style="--circle-color: {{$document_color}};{{$style}}" data-url="{{ $document_url }}"
onclick="handleCircleClick(this)">
<div class="circle-content">
<p class="document-title {{$document_id}}" >{{$document_title}}</p>
<p class="document-total {{$document_id}}" >Rp.0</p>
@@ -17,3 +20,12 @@
</div>
@endif
</div>
<script>
function handleCircleClick(element) {
const url = element.getAttribute('data-url') || '#';
if (url !== '#') {
window.location.href = url;
}
}
</script>

View File

@@ -1,11 +1,11 @@
@props(['title' => 'title component', 'visible_data' => false, 'data_count' => '', 'visible_data_type' => false,
'data_type' => '','style' => '', 'size' => '', 'line' => [], 'data_id' => ''])
'data_type' => '','style' => '', 'size' => '', 'data_id' => '', 'document_url' => '#'])
@section('css')
@vite(['resources/scss/components/_custom_circle.scss'])
@endsection
<div class="custom-circle-wrapper {{ $size }}" style="{{ $style }}">
<div class="custom-circle-wrapper {{ $size }}" style="{{ $style }}" data-url="{{ $document_url }}" onclick="handleCircleClick(this)">
<div class="custom-circle-content">
<p class="custom-circle-text">{{ $title }}</p>
@if ($visible_data === "true")
@@ -14,17 +14,5 @@
@if ($visible_data_type === "true")
<div class="custom-circle-data-type">{{ $data_type }}</div>
@endif
@if (!empty($lines))
<svg class="absolute w-full h-full" viewBox="0 0 100 100" preserveAspectRatio="none">
@foreach ($lines as $line)
<line
x1="{{ $line['x1'] }}" y1="{{ $line['y1'] }}"
x2="{{ $line['x2'] }}" y2="{{ $line['y2'] }}"
stroke="{{ $line['color'] ?? 'black' }}"
stroke-width="{{ $line['width'] ?? 2 }}"
/>
@endforeach
</svg>
@endif
</div>
</div>

View File

@@ -9,22 +9,6 @@
@include('layouts.partials/page-title', ['title' => 'Dashboards', 'subtitle' => 'Dashboard Pimpinan'])
<div id="dashboard-fixed-wrapper" class="row">
<!-- <div class="col-12">
<h2 class="mt-3 ms-2 text-danger">
<span class="float-end fs-6 me-3 text-black d-block d-sm-inline text-end">Terakhir di update - {{$latest_created}}</span>
ANALISA BIG DATA PROSES PBG <br>
MELALUI APLIKASI SIBEDAS PBG
</h2>
</div>
<div class="row d-flex justify-content-end">
<div class="col-12 col-sm-6 col-md-3">
<div class="d-flex flex-sm-nowrap flex-wrap justify-content-end">
<input type="text" class="form-control" style="max-width: 125px;" id="datepicker-dashboard-bigdata" placeholder="Filter Date" />
</div>
</div>
</div> -->
<div class="col-12">
<div class="d-flex justify-content-between align-items-center mt-3 ms-2">
<h2 class="text-danger m-0">
@@ -54,7 +38,8 @@
'document_type' => '',
'document_id' => 'chart-target-pad',
'visible_small_circle' => true,
'style' => 'left:200px;'
'style' => 'left:200px;',
'document_url' => route('data-settings.index', ['menu_id' => $menus->where('url','data-settings.index')->first()->id])
])
@endcomponent
@@ -72,7 +57,8 @@
'document_type' => 'Pemohon',
'document_id' => 'chart-total-potensi',
'visible_small_circle' => true,
'style' => 'left:400px;top:150px;'
'style' => 'left:400px;top:150px;',
'document_url' => route('pbg-task.index', ['menu_id' => $menus->where('url','pbg-task.index')->first()->id, 'filter' => 'all'])
])
@endcomponent
@@ -88,7 +74,8 @@
'document_type' => '',
'document_id' => 'chart-potensi-tata-ruang',
'visible_small_circle' => true,
'style' => 'left:600px;'
'style' => 'left:600px;',
'document_url' => route('web-spatial-plannings.index', ['menu_id' => $menus->where('url','web-spatial-plannings.index')->first()->id])
])
@endcomponent
@@ -101,7 +88,8 @@
'document_type' => 'Berkas',
'document_id' => 'chart-non-business',
'visible_small_circle' => true,
'style' => 'left:900px;top:150px;'
'style' => 'left:900px;top:150px;',
'document_url' => route('pbg-task.index', ['menu_id' => $menus->where('url','pbg-task.index')->first()->id, 'filter' => 'non-business'])
])
@endcomponent
@@ -111,7 +99,8 @@
'document_type' => 'Berkas',
'document_id' => 'chart-business',
'visible_small_circle' => true,
'style' => 'left:900px;top:400px;'
'style' => 'left:900px;top:400px;',
'document_url' => route('pbg-task.index', ['menu_id' => $menus->where('url','pbg-task.index')->first()->id, 'filter' => 'business'])
])
@endcomponent
@@ -121,7 +110,8 @@
'document_type' => 'Berkas',
'document_id' => 'chart-berkas-terverifikasi',
'visible_small_circle' => true,
'style' => 'top:300px;left:200px;'
'style' => 'top:300px;left:200px;',
'document_url' => route('pbg-task.index', ['menu_id' => $menus->where('url','pbg-task.index')->first()->id, 'filter' => 'verified'])
])
@endcomponent
@@ -137,7 +127,8 @@
'document_type' => 'Berkas',
'document_id' => 'chart-berkas-belum-terverifikasi',
'visible_small_circle' => true,
'style' => 'top:300px;left:600px;'
'style' => 'top:300px;left:600px;',
'document_url' => route('pbg-task.index', ['menu_id' => $menus->where('url','pbg-task.index')->first()->id, 'filter' => 'non-verified'])
])
@endcomponent
@@ -154,7 +145,8 @@
'document_type' => 'Berkas',
'document_id' => 'chart-realisasi-tebit-pbg',
'visible_small_circle' => true,
'style' => 'top:550px;left:100px;'
'style' => 'top:550px;left:100px;',
'document_url' => 'https://docs.google.com/spreadsheets/d/1QoXzuLdEX3MK70Yrfigz0Qj5rAt4T819jX85vubBNdY/edit?gid=1514195399#gid=1514195399'
])
@endcomponent
@@ -167,7 +159,8 @@
'document_type' => 'Berkas',
'document_id' => 'chart-menunggu-klik-dpmptsp',
'visible_small_circle' => true,
'style' => 'top:550px;left:400px'
'style' => 'top:550px;left:400px',
'document_url' => 'https://docs.google.com/spreadsheets/d/1QoXzuLdEX3MK70Yrfigz0Qj5rAt4T819jX85vubBNdY/edit?gid=1514195399#gid=1514195399'
])
@endcomponent
@@ -180,7 +173,8 @@
'document_type' => 'Berkas',
'document_id' => 'chart-proses-dinas-teknis',
'visible_small_circle' => true,
'style' => 'top:550px;left:700px'
'style' => 'top:550px;left:700px',
'document_url' => 'https://docs.google.com/spreadsheets/d/1QoXzuLdEX3MK70Yrfigz0Qj5rAt4T819jX85vubBNdY/edit?gid=1514195399#gid=1514195399'
])
@endcomponent
</div>

View File

@@ -21,11 +21,20 @@
<div class="wrapper">
<div id="lack-of-potential-fixed-container" class="" style="width:1400px;height:770px;position:relative;margin:auto;z-index:1;">
<div style="position: absolute; top: 200px; left: 50px;">
<x-custom-circle title="Restoran" size="small" style="background-color: #0e4753;" visible_data="true" data_id="restoran-count" data_count="0" />
<x-custom-circle title="Restoran" size="small" style="background-color: #0e4753;"
visible_data="true" data_id="restoran-count" data_count="0"
document_url="{{ route('web-spatial-plannings.index', ['menu_id' => $menus->where('url','web-spatial-plannings.index')->first()->id]) }}"
/>
<div class="square dia-top-left-bottom-right" style="top:30px;left:50px;width:150px;height:120px;"></div>
<x-custom-circle title="PBB Bangunan" visible_data="true" data_id="pbb-bangunan-count" data_count="0" size="small" style="background-color: #0e4753;" />
<x-custom-circle title="PBB Bangunan" visible_data="true" data_id="pbb-bangunan-count"
data_count="0" size="small" style="background-color: #0e4753;"
document_url="{{ route('web-spatial-plannings.index', ['menu_id' => $menus->where('url','web-spatial-plannings.index')->first()->id]) }}"
/>
<div class="square" style="width:150px;height:2px;background-color:black;left:50px;top:150px;"></div>
<x-custom-circle title="Reklame" visible_data="true" data_id="reklame-count" data_count="0" size="small" style="background-color: #0e4753;" />
<x-custom-circle title="Reklame" visible_data="true" data_id="reklame-count"
data_count="0" size="small" style="background-color: #0e4753;"
document_url="{{ route('web-advertisements.index', ['menu_id' => $menus->where('url','web-advertisements.index')->first()->id]) }}"
/>
<div class="square dia-top-right-bottom-left" style="top:140px;left:50px;width:150px;height:120px;"></div>
</div>
@@ -33,30 +42,39 @@
<div class="square dia-top-right-bottom-left" style="top:-100px;left:30px;width:150px;height:120px;"></div>
<div class="square dia-top-left-bottom-right" style="top:-100px;left:120px;width:120px;height:120px;"></div>
<x-custom-circle title="BAPENDA" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="PDAM" visible_data="true" data_id="pdam-count" data_count="0" visible_data_type="true" data_type="Pelanggan" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="KECAMATAN" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="PDAM" visible_data="true" data_id="pdam-count"
visible_data_type="true" data_type="Pelanggan"
size="small" style="float:left;background-color: #234f6c;position: absolute;margin-left: 99px;"
document_url="{{ route('customers', ['menu_id' => $menus->where('url','customers')->first()->id]) }}"
/>
<x-custom-circle title="KECAMATAN" size="small" style="float:left;background-color: #234f6c;position: absolute;margin-left: 198px;" />
</div>
<div style="position: absolute; top: 0px; left: 270px;">
<div style="position: absolute; top: 0px; left: 270px;">
<div class="square" style="width:5px;height:600px;background-color:black;left:70px;top:50px;"></div>
<div class="square dia-top-left-bottom-right" style="top:350px;left:-50px;width:120px;height:120px;"></div>
<div class="square dia-top-right-bottom-left" style="top:350px;left:70px;width:120px;height:120px;"></div>
<x-custom-circle title="Rumah Tinggal" size="small" style="background-color: #234f6c;margin:auto;" />
<x-custom-circle title="Non Usaha" size="large" style="background-color: #3a968b;margin-top:20px;" />
<x-custom-circle title="USAHA" size="large" style="background-color: #627c8b;margin-top:150px;" />
<x-custom-circle title="USAHA" size="large" style="background-color: #627c8b;margin-top:150px;position: absolute;" />
</div>
<div style="position: absolute; top: 650px; left: 110px;">
<div style="position: absolute; top: 650px; left: 110px;">
<div class="square dia-top-right-bottom-left" style="top:-110px;left:40px;width:200px;height:120px;"></div>
<div class="square dia-top-right-bottom-left" style="top:-110px;left:90px;width:150px;height:170px;"></div>
<div class="square dia-top-left-bottom-right" style="top:-110px;left:230px;width:150px;height:170px;"></div>
<div class="square dia-top-left-bottom-right" style="top:-110px;left:260px;width:200px;height:180px;"></div>
<x-custom-circle title="Villa" size="small" style="float:left;background-color: #234f6c;" visible_data="true" data_id="villa-count" data_count="0" />
<x-custom-circle title="Villa" size="small" style="float:left;background-color: #234f6c;"
visible_data="true" data_id="villa-count" data_count="0"
document_url="{{ route('web-tourisms.index', ['menu_id' => $menus->where('url','web-tourisms.index')->first()->id]) }}"
/>
<x-custom-circle title="Pabrik" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="Jalan Protocol" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="Ruko" size="small" style="float:left;background-color: #234f6c;" />
<x-custom-circle title="Pariwisata" size="small" style="float:left;background-color: #234f6c; margin-right: 20px;" visible_data="true" data_id="pariwisata-count" data_count="0" />
<x-custom-circle title="Pariwisata" size="small" style="float:left;background-color: #234f6c; margin-right: 20px;"
visible_data="true" data_id="pariwisata-count" data_count="0"
document_url="{{ route('web-tourisms.index', ['menu_id' => $menus->where('url','web-tourisms.index')->first()->id]) }}"
/>
<div class="square" style="width:150px;height:2px;background-color:black;left:350px;top:50px;"></div>
<x-custom-circle title="DISBUDPAR" size="small" style="background-color: #3a968b;" />
</div>
@@ -75,7 +93,10 @@
'style' => 'margin-left:180px;top:-20px;'
])
@endcomponent
<x-custom-circle title="Tata Ruang" size="large" style="background-color: #da6635;float:left;margin-left:250px;" visible_data="true" data_id="tata-ruang-count" data_count="0" />
<x-custom-circle title="Tata Ruang" size="large" style="background-color: #da6635;float:left;margin-left:250px;"
visible_data="true" data_id="tata-ruang-count" data_count="0"
document_url="{{ route('web-spatial-plannings.index', ['menu_id' => $menus->where('url','web-spatial-plannings.index')->first()->id]) }}"
/>
</div>
<div style="position: absolute; top: 310px; left: 1150px;">
@@ -102,7 +123,10 @@
<div style="position: absolute; top: 50px; left: 1100px;">
<x-custom-circle title="Non Usaha" size="large" style="background-color: #3a968b;margin-top:20px;" />
<x-custom-circle title="USAHA" size="large" style="background-color: #627c8b;margin-top:260px;" visible_data="true" data_id="tata-ruang-usaha-count" data_count="0" />
<x-custom-circle title="USAHA" size="large" style="background-color: #627c8b;margin-top:260px;"
visible_data="true" data_id="tata-ruang-usaha-count" data_count="0"
document_url="{!! route('pbg-task.index', ['filter' => 'business', 'menu_id' => $menus->where('url','pbg-task.index')->first()->id]) !!}"
/>
</div>
</div>
</div>

View File

@@ -27,7 +27,8 @@
'document_type' => 'Berkas',
'document_id' => 'outside-system-non-business',
'visible_small_circle' => true,
'style' => 'top:10px;'
'style' => 'top:10px;',
'document_url' => route('pbg-task.index', ['menu_id' => 13, 'filter' => 'non-business'])
])
@endcomponent
<div class="square dia-top-right-bottom-left" style="top:10px;left:180px;width:230px;height:120px;"></div>
@@ -37,7 +38,8 @@
'document_type' => 'Berkas',
'document_id' => 'outside-system-business',
'visible_small_circle' => true,
'style' => 'top:300px;'
'style' => 'top:300px;',
'document_url' => route('pbg-task.index', ['menu_id' => 13, 'filter' => 'business'])
])
@endcomponent
<div class="square dia-top-right-bottom-left" style="top:320px;left:170px;width:200px;height:100px;"></div>

View File

@@ -42,9 +42,29 @@
<a href="{{ route('pbg-task.create')}}" class="btn btn-success btn-sm d-block d-sm-inline w-auto">Create</a>
@endif
</div>
<form id="filter-form">
<div class="row pb-3">
<div class="col-md-4">
<select name="filter" id="filter-select" class="form-select">
@foreach ($filterOptions as $key => $label)
<option value="{{ $key }}" {{ request('filter') == $key ? 'selected' : '' }}>
{{ $label }}
</option>
@endforeach
</select>
<input name="menu_id" value="13" type="hidden" />
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100">Apply</button>
</div>
</div>
</form>
<!-- Table or Data Display Area -->
<div id="table-pbg-tasks"
data-updater="{{ $updater }}"
data-destroyer="{{ $destroyer }}">
data-updater="{{ $updater }}"
data-destroyer="{{ $destroyer }}">
</div>
</div>
</div>

View File

@@ -0,0 +1,229 @@
@extends('layouts.base', ['subtitle' => 'Quick Search'])
@section('css')
@vite(['resources/scss/pages/quick-search/detail.scss'])
@vite(['node_modules/gridjs/dist/theme/mermaid.min.css'])
@endsection
@section('content')
<div class="container qs-detail-container pt-3">
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Detail Informasi Permohonan PBG</h5>
<a href="javascript:history.back()" class="btn btn-primary">Back</a>
</div>
<div class="card-body">
<div class="row gy-3 gx-4">
<div class="col-md-6">
<dl class="row mb-0">
<dt class="col-sm-5">Nama Pemohon</dt>
<dd class="col-sm-7">{{ $data->name ?? '-' }}</dd>
<dt class="col-sm-5">Nama Pemilik</dt>
<dd class="col-sm-7">{{ $data->owner_name ?? '-' }}</dd>
<dt class="col-sm-5">Jenis Permohonan</dt>
<dd class="col-sm-7">{{ isset($data->application_type) ? $applicationTypes[$data->application_type] : '-' }}</dd>
<dt class="col-sm-5">Kondisi</dt>
<dd class="col-sm-7">{{ $data->condition ?? '-' }}</dd>
<dt class="col-sm-5">Nomor Registrasi</dt>
<dd class="col-sm-7">{{ $data->registration_number ?? '-'}}</dd>
<dt class="col-sm-5">Nomor Dokumen</dt>
<dd class="col-sm-7">{{ $data->document_number ?? '-' }}</dd>
<dt class="col-sm-5">Status</dt>
<dd class="col-sm-7">{{ isset($data->status) ? $statusOptions[$data->status] : '-' }}</dd>
</dl>
</div>
<div class="col-md-6">
<dl class="row mb-0">
<dt class="col-sm-5">Alamat</dt>
<dd class="col-sm-7">{{ $data->address ?? '-' }}</dd>
<dt class="col-sm-5">Status SLF</dt>
<dd class="col-sm-7">{{ $data->slf_status_name ?? '-' }}</dd>
<dt class="col-sm-5">Fungsi Bangunan</dt>
<dd class="col-sm-7">{{ $data->function_type ?? '-' }}</dd>
<dt class="col-sm-5">Jenis Konsultasi</dt>
<dd class="col-sm-7">{{ $data->consultation_type ?? '-' }}</dd>
<dt class="col-sm-5">Jatuh Tempo</dt>
<dd class="col-sm-7">{{$data->due_date ? \Carbon\Carbon::parse($data->due_date)->format('d M Y') : '-' }}</dd>
<dt class="col-sm-5">Tanggal Dibuat</dt>
<dd class="col-sm-7">{{ \Carbon\Carbon::parse($data->task_created_at)->format('d M Y H:i') }}</dd>
</dl>
</div>
</div>
</div>
</div>
</div>
<div class="col-12">
<div class="card">
<div class="card-header">
<ul class="nav nav-tabs nav-justified">
<li class="nav-item">
<a href="#pbgTaskRetributions" data-bs-toggle="tab" aria-expanded="false"
class="nav-link active">
<span class="d-sm-block">PBG Task Retributions</span>
</a>
</li>
<li class="nav-item">
<a href="#pbgTaskIntegration" data-bs-toggle="tab" aria-expanded="false" class="nav-link">
<span class="d-sm-block">PBG Task Index Integrations</span>
</a>
</li>
<li class="nav-item">
<a href="#pbgTaskPrasarana" data-bs-toggle="tab" aria-expanded="false" class="nav-link">
<span class="d-sm-block">PBG Task Prasarana</span>
</a>
</li>
<li class="nav-item">
<a href="#pbgTaskAssignments" data-bs-toggle="tab" aria-expanded="false" class="nav-link">
<span class="d-sm-block">Penugasan</span>
</a>
</li>
</ul>
</div>
<div class="card-body">
<div class="tab-content">
<div class="tab-pane active" id="pbgTaskRetributions">
@if ($data->pbg_task_retributions)
<div class="row">
<div class="col-md-6">
<dl class="row mb-0">
<dt class="col-sm-4">Luas Bangunan</dt>
<dd class="col-sm-8">{{$data->pbg_task_retributions->luas_bangunan ?? '-'}}</dd>
<dt class="col-sm-4">Indeks Lokalitas</dt>
<dd class="col-sm-8">{{$data->pbg_task_retributions->indeks_lokalitas ?? '-'}}</dd>
<dt class="col-sm-4">Wilayah SHST</dt>
<dd class="col-sm-8">{{$data->pbg_task_retributions->wilayah_shst ?? '-'}}</dd>
<dt class="col-sm-4">Nama Kegiatan</dt>
<dd class="col-sm-8">{{$data->pbg_task_retributions->kegiatan_name ?? '-'}}</dd>
<dt class="col-sm-4">Nilai SHST</dt>
<dd class="col-sm-8">{{$data->pbg_task_retributions->nilai_shst ?? '-'}}</dd>
<dt class="col-sm-4">Indeks Integrasi</dt>
<dd class="col-sm-8">{{$data->pbg_task_retributions->indeks_terintegrasi ?? '-'}}</dd>
<dt class="col-sm-4">Indeks Bg Terbangun</dt>
<dd class="col-sm-8">{{$data->pbg_task_retributions->indeks_bg_terbangun ?? '-'}}</dd>
</dl>
</div>
<div class="col-md-6">
<dl class="row mb-0">
<dt class="col-sm-4">Nilai Retribusi Bangunan</dt>
<dd class="col-sm-8">{{$data->pbg_task_retributions->nilai_retribusi_bangunan ?? '-'}}</dd>
<dt class="col-sm-4">Nilai Prasarana</dt>
<dd class="col-sm-8">{{$data->pbg_task_retributions->nilai_prasarana ?? '-'}}</dd>
<dt class="col-sm-4">PBG Dokumen</dt>
<dd class="col-sm-8">{{$data->pbg_task_retributions->pbg_document ?? '-'}}</dd>
<dt class="col-sm-4">Underpayment</dt>
<dd class="col-sm-8">{{$data->pbg_task_retributions->underpayment ?? '-'}}</dd>
<dt class="col-sm-4">SKRD Amount</dt>
<dd class="col-sm-8">{{$data->pbg_task_retributions->skrd_amount ?? '-'}}</dd>
</dl>
</div>
</div>
@else
<div class="alert alert-secondary" role="alert">
Data Not Available
</div>
@endif
</div>
<div class="tab-pane" id="pbgTaskIntegration">
@if ($data->pbg_task_index_integrations)
<dl class="row">
<dt class="col-sm-4">Indeks Fungsi Bangunan</dt>
<dd class="col-sm-8">{{$data->pbg_task_index_integrations->indeks_fungsi_bangunan ?? '-'}}</dd>
<dt class="col-sm-4">Indeks Parameter Kompleksitas</dt>
<dd class="col-sm-8">{{$data->pbg_task_index_integrations->indeks_parameter_kompleksitas ?? '-'}}</dd>
<dt class="col-sm-4">Indeks Parameter Permanensi</dt>
<dd class="col-sm-8">{{$data->pbg_task_index_integrations->indeks_parameter_permanensi ?? '-'}}</dd>
<dt class="col-sm-4">Indeks Parameter Ketinggian</dt>
<dd class="col-sm-8">{{$data->pbg_task_index_integrations->indeks_parameter_ketinggian ?? '-'}}</dd>
<dt class="col-sm-4">Faktor Kepemilikan</dt>
<dd class="col-sm-8">{{$data->pbg_task_index_integrations->faktor_kepemilikan ?? '-'}}</dd>
<dt class="col-sm-4">Indeks Terintegrasi</dt>
<dd class="col-sm-8">{{$data->pbg_task_index_integrations->indeks_terintegrasi ?? '-'}}</dd>
<dt class="col-sm-4">Total</dt>
<dd class="col-sm-8">{{$data->pbg_task_index_integrations->total ?? '-'}}</dd>
</dl>
@else
<div class="alert alert-secondary" role="alert">
Data Not Available
</div>
@endif
</div>
<div class="tab-pane" id="pbgTaskPrasarana">
<div class="row d-flex flex-warp gap-3 justify-content-center">
@if ($data->pbg_task_retributions && $data->pbg_task_retributions->pbg_task_prasarana)
@foreach ($data->pbg_task_retributions->pbg_task_prasarana as $prasarana)
<div class="border p-3 rounded shadow-sm col-md-4">
<dl class="row">
<dt class="col-sm-4">Prasarana Type</dt>
<dd class="col-sm-8">{{$prasarana->prasarana_type ?? '-'}}</dd>
<dt class="col-sm-4">Building Type</dt>
<dd class="col-sm-8">{{$prasarana->building_type ?? '-'}}</dd>
<dt class="col-sm-4">Total</dt>
<dd class="col-sm-8">{{$prasarana->total ?? '-'}}</dd>
<dt class="col-sm-4">Quantity</dt>
<dd class="col-sm-8">{{$prasarana->quantity ?? '-'}}</dd>
<dt class="col-sm-4">Unit</dt>
<dd class="col-sm-8">{{$prasarana->unit ?? '-'}}</dd>
<dt class="col-sm-4">Index Prasarana</dt>
<dd class="col-sm-8">{{$prasarana->index_prasarana ?? '-'}}</dd>
<dt class="col-sm-4">Created At</dt>
<dd class="col-sm-8">{{$prasarana->created_at ? \Carbon\Carbon::parse($prasarana->created_at)->format('d M Y') : '-'}}</dd>
</dl>
</div>
@endforeach
@else
<div class="alert alert-secondary" role="alert">
Data Not Available
</div>
@endif
</div>
</div>
<div class="tab-pane" id="pbgTaskAssignments">
<input type="hidden" id="url_task_assignments" value="{{ route('api.quick-search-task-assignments', ['uuid' => $data->uuid]) }}" />
<div id="table-pbg-task-assignments"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@section('scripts')
@vite(['resources/js/quick-search/detail.js'])
@endsection

View File

@@ -0,0 +1,35 @@
@extends('layouts.base', ['subtitle' => 'Quick Search'])
@section('css')
@vite(['resources/scss/pages/quick-search/index.scss'])
@endsection
@section('body-attribuet')
class="gsp-body"
@endsection
@section('content')
<div class="position-absolute top-0 end-0 p-3">
<a href="{{ route('login') }}" class="btn btn-md btn-secondary">
Login
</a>
</div>
<div class="container min-vh-100 d-flex justify-content-center align-items-center gsp-body">
<div class="w-100" style="max-width: 700px;">
<div class="text-center mb-4">
<img src="{{ asset('images/simbg-dputr.png') }}" alt="PBG Icon" class="img-fluid gsp-icon mb-3">
<h1 class="gsp-title">SIBEDAS PBG</h1>
</div>
<div class="d-flex flex-column flex-sm-row align-items-stretch gap-2">
<div class="flex-fill">
<input type="text" class="gsp-input" id="searchInput" placeholder="Cari..." autocomplete="off" />
</div>
<button class="gsp-btn" id="searchBtn">Cari</button>
</div>
</div>
</div>
@endsection
@section('scripts')
@vite(['resources/js/quick-search/index.js'])
@endsection

View File

@@ -0,0 +1,44 @@
@extends('layouts.base', ['subtitle' => 'Quick Search'])
@section('css')
@vite(['resources/scss/pages/quick-search/result.scss'])
@vite(['node_modules/gridjs/dist/theme/mermaid.min.css'])
@endsection
@section('content')
<input type="hidden" value="{{ route('quick-search-datatable', ['search' => $keyword]) }}" id="base_url_datatable" />
<div class="container qs-wrapper">
<div class="qs-toolbar d-flex justify-content-between align-items-center pt-4 pb-4">
<!-- Back Button -->
<a href="{{ route('search') }}" class="btn btn-light border me-3">
Kembali
</a>
<!-- Search Area (no form action) -->
<div class="qs-search-form d-flex align-items-center">
<input
type="text"
id="search_input"
class="gsp-input me-2"
value="{{ $keyword }}"
placeholder="Cari data..."
required
/>
<button type="button" id="search_button" class="gsp-btn">Cari</button>
</div>
</div>
<div class="qs-header mb-3">
<h2>Hasil Pencarian: <em>{{ $keyword }}</em></h2>
<p>Berikut adalah data hasil pencarian berdasarkan kata kunci yang Anda masukkan.</p>
</div>
<div class="qs-table-wrapper">
<div class="p-3" id="datatable-quick-search-result"></div>
</div>
</div>
@endsection
@section('scripts')
@vite(['resources/js/quick-search/result.js'])
@endsection

View File

@@ -0,0 +1,21 @@
@extends('layouts.vertical', ['subtitle' => 'Laporan Pertumbuhan'])
@section('css')
@endsection
@section('content')
@include('layouts.partials/page-title', ['title' => 'Laporan', 'subtitle' => 'Laporan Pertumbuhan'])
<div class="card">
<div class="card-body">
<div class="row">
<div id="chart-growth-report" data-url="{{ route('api.growth') }}"></div>
</div>
</div>
</div>
@endsection
@section('scripts')
@vite(['resources/js/report/growth-report/index.js'])
@endsection

View File

@@ -7,6 +7,7 @@ use App\Http\Controllers\Api\DashboardController;
use App\Http\Controllers\Api\DataSettingController;
use App\Http\Controllers\Api\GlobalSettingsController;
use App\Http\Controllers\Api\GoogleSheetController;
use App\Http\Controllers\Api\GrowthReportAPIController;
use App\Http\Controllers\Api\ImportDatasourceController;
use App\Http\Controllers\Api\LackOfPotentialController;
use App\Http\Controllers\Api\MenusController;
@@ -187,4 +188,8 @@ Route::group(['middleware' => 'auth:sanctum'], function (){
Route::post('/pbg-task-attachment/{pbg_task_id}', 'store')->name('api.pbg-task.upload');
Route::get('/pbg-task-attachment/{attachment_id}/download', 'download')->name('api.pbg-task.download');
});
Route::controller(GrowthReportAPIController::class)->group(function(){
Route::get('/growth','index')->name('api.growth');
});
});

View File

@@ -15,6 +15,8 @@ use App\Http\Controllers\Master\UsersController;
use App\Http\Controllers\MenusController;
use App\Http\Controllers\PaymentRecapsController;
use App\Http\Controllers\PbgTaskAttachmentsController;
use App\Http\Controllers\QuickSearchController;
use App\Http\Controllers\Report\GrowthReportsController;
use App\Http\Controllers\ReportPaymentRecapsController;
use App\Http\Controllers\ReportPbgPTSPController;
use App\Http\Controllers\RequestAssignment\PbgTaskController;
@@ -34,6 +36,12 @@ use Illuminate\Support\Facades\Route;
require __DIR__ . '/auth.php';
Route::get('/search', [QuickSearchController::class, 'index'])->name('search');
Route::get('/search-result', [QuickSearchController::class, 'search_result'])->name('search-result');
Route::get('/quick-search-datatable', [QuickSearchController::class, 'quick_search_datatable'])->name('quick-search-datatable');
Route::get('/quick-search/{id}', [QuickSearchController::class, 'show'])->name('quick-search.detail');
Route::get('/quick-search/{uuid}/task-assignments', [QuickSearchController::class, 'task_assignments'])->name('api.quick-search-task-assignments');
// auth
Route::group(['middleware' => 'auth'], function(){
@@ -156,6 +164,10 @@ Route::group(['middleware' => 'auth'], function(){
Route::controller(ReportPbgPTSPController::class)->group(function (){
Route::get('/report-pbg-ptsp', 'index')->name('report-pbg-ptsp');
});
Route::controller(GrowthReportsController::class)->group(function (){
Route::get('/growths','index')->name('growths');
});
});
// approval

View File

@@ -20,6 +20,9 @@ export default defineConfig({
"resources/scss/components/_custom_circle.scss",
"resources/scss/dashboards/potentials/_inside_system.scss",
"resources/scss/dashboards/potentials/_outside_system.scss",
"resources/scss/pages/quick-search/detail.scss",
"resources/scss/pages/quick-search/index.scss",
"resources/scss/pages/quick-search/result.scss",
"node_modules/quill/dist/quill.snow.css",
"node_modules/quill/dist/quill.bubble.css",
@@ -109,6 +112,12 @@ export default defineConfig({
"resources/js/pbg-task/create.js",
// google-sheets
"resources/js/data/google-sheet/index.js",
// quick-search
"resources/js/quick-search/index.js",
"resources/js/quick-search/result.js",
"resources/js/quick-search/detail.js",
// growth-report
"resources/js/report/growth-report/index.js",
// dummy
"resources/js/approval/index.js",
"resources/js/invitations/index.js",