bug fixes and refactoring

This commit is contained in:
Kwesi Banson Jnr 2026-06-23 09:32:42 +00:00
parent 91ad8c14a0
commit 970515be3c
29 changed files with 1056 additions and 287 deletions

View File

@ -2,7 +2,7 @@ APP_NAME=lupmisBackend
APP_ENV=local
APP_KEY=base64:pmEAeuW8clKrfKKjcMWylo68exoDO/Xr2hUhXvB7dS0=
APP_DEBUG=true
APP_URL=http:https://lupmis4luspa.org
#APP_URL=http:https://lupmis4luspa.org
LOG_CHANNEL=daily
LUPMISAPIKEY=1c46538c712e9b5b
@ -24,7 +24,7 @@ CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
SESSION_DOMAIN=.lupmis4luspa.org
#SESSION_DOMAIN=.housebanson.net
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null

View File

@ -6,6 +6,7 @@ use Session;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use App\Models;
class AdminController extends Controller
{
@ -252,13 +253,16 @@ class AdminController extends Controller
}
public function districtsettings(){
$data = [
'page_title' => "Page Under Development"
'page_title' => "District Settings"
];
return view('common.notready', $data);
return view('admin.district_settings', $data);
}
public function systempermissions(){
$user_group_matrix = Models\UserGroupMatrix::get();
// dd($user_group_matrix);
$data = [
'page_title' => "System Permissions"
"page_title" => "System Permissions",
"user_group_matrix" => $user_group_matrix
];
return view('admin.system-permissions', $data);
}

View File

@ -86,24 +86,66 @@ class PermitsController extends Controller
// dump($result);
$docs_url = "upload/get_all_files_per_application.php";
$doc_data = json_encode([
"application_id" => $result['data'][0]['applicant_id'],
"application_code" => $result['data'][0]['application_code'],
"api_token" => "1c46538c712e9b5b"
]);
/*
$documents_retval = ApiCalls::CurlPost($doc_data, $docs_url);
// dd($documents_retval);
dump($documents_retval);
$documents = json_decode($documents_retval, true);
dd($documents);
*/
$allowed_users_to_comment = ['PPD Head', 'Works Department Head', 'luspa-it-head'];
$data = [
'page_title' => 'Permits Details',
'permit_arr' => $result['data'][0],
'documents' => $documents['data'],
// 'documents' => ($documents['data']) ? $result['data'][0] : '',
'allowed_users_to_comment' => $allowed_users_to_comment
];
// return view('permits.show_20-06-2026-6-56pm', $data);
return view('permits.show', $data);
}
public function statusUpdate($id){
}
public function settingsStore(Request $request){
// 'https://api.lupmis4luspa.org/api/'
//email and sms settings
$url = "sms/insert_sms_settings.php";
$data = json_encode([
"districtid" => session('current_user.district_id'),
"sender_id"=> $request->sender_id,
"balance" => 0,
"status" => "active",
"api_key" => $request->api_key,
"remarks" => $request->remarks,
"api_token" => env('LUPMISAPIKEY')
]);
$result = ApiCalls::CurlPost($data, $url);
$result = json_decode($result, true);
$url = "sms/insert_sms_settings.php";
$data = json_encode([
"districtid" => session('current_user.district_id'),
"sender_id"=> $request->sender_id,
"mail_host" => $request->email_host,
"mail_from_address" => $request->mail_from_address,
"mail_from_encryption" => $request->mail_from_encryption,
"mail_from_name" => $request->mail_from_name,
"mail_port" => $request->mail_port,
"mail_host" => $request->email_host,
"mail_host" => $request->email_host,
"status" => "active",
"api_key" => $request->api_key,
"remarks" => $request->remarks,
"api_token" => env('LUPMISAPIKEY')
]);
$result = ApiCalls::CurlPost($data, $url);
$result = json_decode($result, true);
return redirect('/permits/districtsettings');
}
public function reports(){
$data = [

View File

@ -71,11 +71,11 @@ class UserloginController extends Controller
$request->session()->put('current_user.region_name', $region_name);
$request->session()->put('current_user.plainToken', $plainToken);
// dd($logged_in);
// $request->session()->put('current_user.permissions', $logged_in['permissions']);
Cookie::queue('sso_auth_token', $plainToken, 60, '/', '.lupmis4luspa.org');
\Log::info($logged_in['full_name']. ' Successfully logged in at : ' . date('Y-m-d H:i:s'));
return redirect(url('/admin/home'));
return redirect(url('/landing'));
}
public function handle_logout(Request $request) {
$user_id = session('current_user.id');

View File

@ -0,0 +1,17 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class UserGroupMatrix extends Model
{
protected $fillable = [
'name',
'permit_tools_backend',
'update_permits',
'drawing_tools',
'view_drawing_tools',
'admin_gui',
];
}

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('user_group_matrices', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->boolean('permit_tools_backend')->default(false);
$table->boolean('update_permits')->default(false);
$table->boolean('drawing_tools')->default(false);
$table->boolean('view_drawing_tools')->default(false);
$table->boolean('admin_gui')->default(false);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('user_group_matrices');
}
};

View File

@ -75,3 +75,6 @@ add_header Content-Security-Policy "frame-ancestors 'self' https://lupmis.houseb
"count": 1
}
php artisan make:model UserGroupMatrix -m

View File

@ -1,5 +1,5 @@
APP_NAME=lupmisBackend
APP_ENV=local
APP_ENV=production
APP_KEY=base64:pmEAeuW8clKrfKKjcMWylo68exoDO/Xr2hUhXvB7dS0=
APP_DEBUG=true
APP_URL=http:https://lupmis4luspa.org

View File

@ -0,0 +1,46 @@
/* --- Page Loader Styles --- */
.page-loader-overlay {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: #ffffff;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.5s ease, visibility 0.5s ease;
/* Optional: If that faint pattern in your screenshot is a background image, uncomment and add it here: */
/* background-image: url('../images/faint-watermark-pattern.png'); */
/* background-size: cover; */
/* background-position: center; */
}
.loader-content {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.loader-logo {
max-width: 250px; /* Adjust this width to match the scale of your actual logo image */
height: auto;
}
/* Thicker, slightly larger spinner to match your design */
.loader-spinner {
width: 3rem;
height: 3rem;
border-width: 0.3em;
/* If your primary blue isn't exactly matching the logo, force the hex color here: */
/* color: #0d6efd !important; */
}
/* Class applied by JavaScript to trigger the fade-out animation */
.page-loader-overlay.fade-out {
opacity: 0;
visibility: hidden;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@ -207,8 +207,10 @@ document.addEventListener("DOMContentLoaded", function () {
card.addEventListener("click", function () {
const title = card.querySelector(".card-title").textContent;
console.log(title);
// let cleaned = title.replace(/\s+/g, '');
// title = title.trim();
if (title === 'Permissions') {
if (title === 'User Group Matrix') {
window.location.href = "/admin/permissions";
}
else if(title === 'Fee Fixing'){

View File

@ -1,16 +1,19 @@
$(document).ready(function(){
console.log('inside comments');
const baseUrl = base_url + "/permits/getcomments";
fetchPermitApplicationComments();
// CREATE
$(".submitPermitCommentBtn").click(function (e) {
e.preventDefault();
// let formData = $(this).serialize();
var currentStatus = $('permitCurrentStatus').val();
var commentBody = $('.commentBody').val();
var applicationCode = $('.applicationCode').val();
const formData = new FormData();
formData.append('comment_body', commentBody);
formData.append('application_code', applicationCode);
formData.append('application_current_status', currentStatus);
$.ajax({
url: base_url + "/permits/addcomment",
@ -42,9 +45,11 @@ $(document).ready(function(){
// READ (fetch all)
function fetchPermitApplicationComments() {
var applicationCode = $('.applicationCode').val();
var currentStatus = $('permitCurrentStatus').val();
const formData = new FormData();
formData.append('application_code', applicationCode);
formData.append('application_current_status', currentStatus);
$.ajax({
url: baseUrl,

View File

@ -58,12 +58,12 @@
</div>
<!-- Team Settings Card -->
<div class="col-12 col-md-6 col-lg-4">
<div class="col-12 col-md-6 col-lg-4 userGroupMatrix">
<div class="settings-card">
<div class="card-icon mb-3">
<i class="fas fa-users"></i>
</div>
<h3 class="card-title mb-2">Permissions</h3>
<h3 class="card-title mb-2">User Group Matrix</h3>
<p class="card-description mb-0">View user groups and permissions</p>
</div>
</div>

View File

@ -0,0 +1,119 @@
@extends('layouts.master')
@section('page-title')
Permits | {{ $page_title }}
@endsection
@section('page-css')
@endsection
@section('page-content')
@include('layouts.partials.navbar')
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="mb-4">
<h1 class="h3 mb-1">District Settings</h1>
<p class="text-muted">Update these settings as needed</p>
</div>
<form action="permit/districtsettings" method="POST">
@csrf <div class="card shadow-sm mb-4">
<div class="card-header bg-white py-3">
<h5 class="card-title mb-0 text-dark">
<i class="bi bi-building me-2 text-secondary"></i>Assembly Profile
</h5>
</div>
<div class="card-body">
<div class="row mb-3 g-3">
<div class="col-md-6">
<label for="regionName" class="form-label fw-bold">Region Name</label>
<input type="text" class="form-control" id="regionName" name="region_name" value="" placeholder="e.g. Western Region" required>
</div>
<div class="col-md-6">
<label for="districtName" class="form-label fw-bold">District Name</label>
<input type="text" class="form-control" id="districtName" name="district_name" value="" placeholder="e.g. Sekondi-Takoradi Metropolitan Assembly" required>
</div>
</div>
<div class="row mb-3 g-3">
<div class="col-md-6">
<label for="assemblyType" class="form-label fw-bold">Assembly Type</label>
<select class="form-select" id="assemblyType" name="assembly_type" required>
<option value="" selected disabled>Select assembly type...</option>
<option value="metropolitan">Metropolitan</option>
<option value="municipal">Municipal</option>
<option value="district">District</option>
</select>
</div>
<div class="col-md-6">
<label for="abbreviation" class="form-label fw-bold">Abbreviation</label>
<input type="text" class="form-control" id="abbreviation" name="abbreviation" value="" placeholder="e.g. STMA" required>
</div>
</div>
<div class="row mb-3 g-3">
<div class="col-md-6">
<label for="contactPhone" class="form-label fw-bold">Contact Phone Number</label>
<input type="tel" class="form-control" id="contactPhone" name="contact_phone" value="" placeholder="e.g. 0554116836" required>
</div>
<div class="col-md-6">
<label for="contactEmail" class="form-label fw-bold">Contact Email</label>
<input type="email" class="form-control" id="contactEmail" name="contact_email" value="" placeholder="e.g. info@stma.gov.gh" required>
</div>
</div>
</div>
</div>
<div class="card shadow-sm mb-4">
<div class="card-header bg-white py-3">
<h5 class="card-title mb-0 text-primary">
<i class="bi bi-envelope-fill me-2"></i>Email Notifications
</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="outgoingEmail" class="form-label fw-bold">Outgoing Email Address</label>
<input type="email" class="form-control" id="outgoingEmail" name="outgoing_email" value="" placeholder="e.g. ppd@stma.gov.gh" required>
</div>
<div class="mb-3">
<label for="displayName" class="form-label fw-bold">Display Name</label>
<input type="text" class="form-control" id="displayName" name="display_name" value="" placeholder="e.g. Physical Planning Department" required>
</div>
</div>
</div>
<div class="card shadow-sm mb-4">
<div class="card-header bg-white py-3">
<h5 class="card-title mb-0 text-success">
<i class="bi bi-chat-left-text-fill me-2"></i>SMS Notifications
</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="senderName" class="form-label fw-bold">Sender Name</label>
<input type="text" class="form-control" id="senderName" name="sms_sender_name" placeholder="e.g. STMA" value="" required>
</div>
</div>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end mb-5">
<button type="button" class="btn btn-outline-secondary px-4">Cancel</button>
<button type="submit" class="btn btn-primary px-4">Save Changes</button>
</div>
</form>
</div>
</div>
</div>
@endsection
@section('page-js')
<script type="text/javascript">
$(document).ready(function(){
// Form validation or dynamic selection logic can go here
});
</script>
@endsection

View File

@ -87,8 +87,8 @@
</ul>
</div>
<button id="bulkMoveBtn" class="btn btn-primary" disabled data-bs-toggle="modal" data-bs-target="#moveModal">Move</button>
<button id="bulkDeactivate" class="btn btn-outline-danger" disabled>Suspend</button>
<!-- <button id="bulkMoveBtn" class="btn btn-primary" disabled data-bs-toggle="modal" data-bs-target="#moveModal">Move</button> -->
<button id="bulkDeactivate" class="btn btn-outline-danger" disabled>Disable</button>
</div>
</div>
</div>
@ -134,7 +134,7 @@
<td class="align-middle">{{ $user['allowed_apps'] }}</td>
<td class="align-middle">
<div class="row-actions d-flex gap-2">
<button class="btn btn-sm btn-outline-secondary viewBtn" data-id="{{ $user['user_id'] }}"><i class="bi bi-eye"></i> View</button>
<!-- <button class="btn btn-sm btn-outline-secondary viewBtn" data-id="{{ $user['user_id'] }}"><i class="bi bi-eye"></i> View</button> -->
<button class="btn btn-sm btn-primary editUserBtn" data-id="{{ $user['user_id'] }}" data-bs-toggle="modal" data-bs-target="#editUserModal"><i class="bi bi-pen"></i> Edit</button>
</div>
</td>
@ -192,7 +192,7 @@
<td class="align-middle">{{ $user['allowed_apps'] }}</td>
<td class="align-middle">
<div class="row-actions d-flex gap-2">
<button class="btn btn-sm btn-outline-secondary viewBtn" data-id="{{ $user['user_id'] }}"><i class="bi-eye"></i> View</button>
<!-- <button class="btn btn-sm btn-outline-secondary viewBtn" data-id="{{ $user['user_id'] }}"><i class="bi-eye"></i> View</button> -->
<button class="btn btn-sm btn-primary editUserBtn" data-id="{{ $user['user_id'] }}" data-bs-toggle="modal" data-bs-target="#editUserModal"><i class="bi-pen"></i> Edit</button>
</div>
</td>
@ -249,7 +249,7 @@
<td class="align-middle">{{ $user['allowed_apps'] }}</td>
<td class="align-middle">
<div class="row-actions d-flex gap-2">
<button class="btn btn-sm btn-outline-secondary viewBtn" data-id="{{ $user['user_id'] }}"><i class="bi bi-eye"></i> View</button>
<!-- <button class="btn btn-sm btn-outline-secondary viewBtn" data-id="{{ $user['user_id'] }}"><i class="bi bi-eye"></i> View</button> -->
<button class="btn btn-sm btn-primary editUserBtn" data-id="{{ $user['user_id'] }}" data-bs-toggle="modal" data-bs-target="#editUserModal"><i class="bi bi-eye"></i> Edit</button>
</div>
</td>

View File

@ -25,72 +25,30 @@
<th class="text-center">Permit Backend</th>
<th class="text-center">Update Permits</th>
<th class="text-center">Drawing Tools</th>
<th class="text-center">View Tools</th>
<th class="text-center">View Drawing Tools</th>
<th class="text-center pe-4">Admin GUI</th>
</tr>
</thead>
<tbody>
<tr class="table-secondary"><td colspan="6" class="ps-4 fw-bold small">National & Regional Authorities</td></tr>
<tr>
<td class="ps-4 fw-bold">LUSPA National</td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-danger"><i class="bi bi-x-circle"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
</tr>
<tr>
<td class="ps-4 fw-bold">LUSPA Regional</td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-danger"><i class="bi bi-x-circle"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
</tr>
@foreach($user_group_matrix as $row)
<?php //dump($row);
$permit_tools_backend_fill = ($row->permit_tools_backend == true) ? "bi-check-circle-fill" : "bi-x-circle";
$update_permits_fill = ($row->update_permits == true) ? "bi-check-circle-fill" : "bi-x-circle";
$drawing_tools_fill = ($row->drawing_tools == true) ? "bi-check-circle-fill" : "bi-x-circle";
$view_drawing_tools_fill = ($row->view_drawing_tools == true) ? "bi-check-circle-fill" : "bi-x-circle";
$admin_gui_fill = ($row->admin_gui == true) ? "bi-check-circle-fill" : "bi-x-circle";
<tr class="table-secondary"><td colspan="6" class="ps-4 fw-bold small">District Technical Departments</td></tr>
<tr>
<td class="ps-4 fw-bold">Head of Physical Planning</td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
</tr>
<tr>
<td class="ps-4 fw-bold">District MIS</td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-danger"><i class="bi bi-x-circle"></i></td>
<td class="text-center text-danger"><i class="bi bi-x-circle"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
</tr>
<tr class="table-secondary"><td colspan="6" class="ps-4 fw-bold small">District Administration & Stakeholders</td></tr>
?>
<tr>
<td class="ps-4 fw-bold">District Chief Executive</td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-danger"><i class="bi bi-x-circle"></i></td>
<td class="text-center text-danger"><i class="bi bi-x-circle"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-danger"><i class="bi bi-x-circle"></i></td>
</tr>
<tr>
<td class="ps-4 fw-bold">Traditional Council Rep</td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-danger"><i class="bi bi-x-circle"></i></td>
<td class="text-center text-danger"><i class="bi bi-x-circle"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-danger"><i class="bi bi-x-circle"></i></td>
</tr>
<tr>
<td class="ps-4 fw-bold">Development Planning Officer</td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-danger"><i class="bi bi-x-circle"></i></td>
<td class="text-center text-danger"><i class="bi bi-check-circle-circle"></i></td>
<td class="text-center text-success"><i class="bi bi-check-circle-fill"></i></td>
<td class="text-center text-danger"><i class="bi bi-x-circle"></i></td>
<td class="ps-4 fw-bold">{{ $row->name }}</td>
<td class="text-center text-<?php echo ($row->permit_tools_backend == true)? 'success':'danger'; ?>"><i class="bi {{ $permit_tools_backend_fill }}"></i></td>
<td class="text-center text-<?php echo ($row->update_permits == true)? 'success':'danger'; ?>"><i class="bi {{ $update_permits_fill }}"></i></td>
<td class="text-center text-<?php echo ($row->drawing_tools == true)? 'success':'danger'; ?>"><i class="bi {{ $drawing_tools_fill }}"></i></td>
<td class="text-center text-<?php echo ($row->view_drawing_tools == true)? 'success':'danger'; ?>"><i class="bi {{ $view_drawing_tools_fill }}"></i></td>
<td class="text-center text-<?php echo ($row->admin_gui == true)? 'success':'danger'; ?>"><i class="bi {{ $admin_gui_fill }}"></i></td>
</tr>
@endforeach
</tbody>
</table>
</div>
@ -105,7 +63,4 @@
@section('page-js')
<script src="{{ url('public/assets/libs/select2/dist/js/select2.full.min.js') }}" type="text/javascript" ></script>
<script src="{{ url('public/assets/js/params.js') }}" type="text/javascript" ></script>
@endsection

View File

@ -24,17 +24,27 @@
<link rel="stylesheet" href="{{ url('public/assets/libs/fontawesome-free-7.1.0-web/css/all.min.css') }}" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.min.css">
<link rel="stylesheet" href="{{ url('public/assets/libs/jquery-confirm/jquery-confirm.min.css') }}" type="text/css">
<link rel="stylesheet" href="{{ url('public/assets/css/page_loader.css') }}" rel="stylesheet">
@yield('page-css')
<script type="text/javascript">
var base_url = "{!! url('/') !!}";
</script>
</head>
@include('admin.partials.profile')
<!-- <body class="bg-gradient-primary"> -->
<body class="bg-light">
<nav class="navbar navbar-expand-lg navbar-dark bg-primary shadow-sm">
@include('admin.partials.profile')
<div id="page-loader" class="page-loader-overlay">
<div class="loader-content">
<img src="{{ url('public/assets/images/lupmis_logo.png') }}" alt="LUPMIS Logo" class="loader-logo mb-4">
<div class="spinner-border text-primary loader-spinner" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary shadow-sm" style="z-index: 2000;">
<div class="container">
<a class="navbar-brand" href="/landing">LUPMIS4LUSPA</a>
<div class="ms-auto">
@ -63,7 +73,23 @@
<script src="{{ url('public/assets/libs/fontawesome-free-7.1.0-web/js/all.min.js') }}"></script>
<script src="{{ url('public/assets/libs/jquery-confirm/jquery-confirm.min.js') }}"></script>
<script src="{{ url('public/assets/js/all_pages.js') }}"></script>
<script>
// Wait for the complete page to load
window.addEventListener('load', function() {
const loader = document.getElementById('page-loader');
if (loader) {
// 1. Trigger the CSS fade-out transition
loader.classList.add('fade-out');
// 2. Completely remove it from the DOM after the fade finishes (500ms)
// This prevents it from blocking clicks on the page underneath it
setTimeout(() => {
loader.style.display = 'none';
}, 500);
}
});
</script>
@yield('page-js')
</body>

View File

@ -1,10 +1,28 @@
<nav class="navbar navbar-expand-lg">
<div class="container">
<div class="navbar-nav me-auto">
<a class="nav-link text-muted" href="{{ url('/permits/home') }}">Home</a>
<a class="nav-link text-muted" href="{{ url('/permits/home') }}">Permits Home</a>
<a class="nav-link text-muted" href="{{ url('/permits/districtsettings') }}">District Settings</a>
<!-- <a class="nav-link text-muted" href="{{ url('/permits/luspaparams') }}">LUSPA Parameters</a> -->
<a class="nav-link text-muted" href="{{ url('/permits/reports') }}">Reports</a>
</div>
<div class="fw-semibold fs-5">
<?php
$district_name = '';
if (session('current_user.user_type') == 'district_user') {
echo "Current District :";
$district_name = session('current_user.district_name');
}
elseif (session('current_user.user_type') == 'regional_luspa') {
echo "Current User : ";
$district_name = 'Regional LUSPA';
}
elseif (session('current_user.user_type') == 'national_luspa') {
echo "Current User : ";
$district_name = 'National LUSPA';
}
?>
{{ $district_name }}
</div>
</div>
</nav>

View File

@ -16,8 +16,7 @@
<p class="text-muted">Update these settings as needed</p>
</div>
<form>
<!-- EMAIL SETTINGS CARD -->
<form action="permit/districtsettings" method="POST" >
<div class="card shadow-sm mb-4">
<div class="card-header bg-white py-3">
<h5 class="card-title mb-0 text-primary">
@ -35,12 +34,8 @@
</div>
<hr class="my-4">
</div>
</div>
<!-- SMS SETTINGS CARD -->
<div class="card shadow-sm mb-4">
<div class="card-header bg-white py-3">
<h5 class="card-title mb-0 text-success">
@ -54,14 +49,9 @@
<input type="text" class="form-control" id="senderName" placeholder="e.g. STMA" value="">
</div>
</div>
<hr class="my-4">
</div>
</div>
<!-- SAVE / ACTIONS (Using Bootstrap 5 responsive block strategy) -->
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button type="button" class="btn btn-outline-secondary px-4">Cancel</button>
<button type="submit" class="btn btn-primary px-4">Save Changes</button>

View File

@ -50,9 +50,6 @@
</div>
</div>
</div>
</div>
</div>

View File

@ -11,10 +11,10 @@
<h6 class="text-primary fw-bold border-bottom pb-2 mb-3">1. Project Information</h6>
<div class="row g-3 mb-4">
<div class="col-md-6">
<label class="form-label text-muted small mb-1">Applicant Name</label> <input type="text" class="form-control form-control-sm" value="Jedidiah Madjanor">
<label class="form-label text-muted small mb-1">Applicant Name</label> <input type="text" class="form-control form-control-sm" value="{{ $permit_arr['applicant_name'] }}">
</div>
<div class="col-md-6">
<label class="form-label text-muted small mb-1">Site Location</label> <input type="text" class="form-control form-control-sm" value="2nd 3rdlink Fertilizer Road, Accra">
<label class="form-label text-muted small mb-1">Site Location</label> <input type="text" class="form-control form-control-sm" value="{{ $permit_arr['address'] }}">
</div>
<div class="col-md-4">
<label class="form-label text-muted small mb-1">Plot/House Number (Ghana Post GPS)</label> <input type="text" class="form-control form-control-sm">
@ -28,14 +28,14 @@
</div>
<h6 class="text-primary fw-bold border-bottom pb-2 mb-3">2. Site Identification & Boundaries</h6>
<div class="row g-3 mb-4">
<div class="row g-3 mb-6">
<div class="col-md-4">
<label class="form-label text-muted small mb-1">Boundary Verification (Clear/Match Plan?)</label> <select class="form-select form-select-sm"><option>Yes</option><option>No</option></select>
</div>
<div class="col-md-4">
<!-- <div class="col-md-4">
<label class="form-label text-muted small mb-1">Beacon Check (Fixed and visible?)</label> <select class="form-select form-select-sm"><option>Yes</option><option>No</option></select>
</div>
<div class="col-md-4">
</div> -->
<div class="col-md-6">
<label class="form-label text-muted small mb-1">Land Ownership Document Verified?</label> <select class="form-select form-select-sm"><option>Yes</option><option>No</option></select>
</div>
</div>

View File

@ -0,0 +1,439 @@
@extends('layouts.master')
@section('page-title')
Permits | {{ $page_title }}
@endsection
@section('page-css')
<link rel="stylesheet" type="text/css" href="{{ url('public/assets/css/permit_show.css') }}">
<style>
/* TIMELINE & STEPPER CSS */
/* Vertical Stepper Line */
.planning-stepper { position: relative; padding-left: 1.25rem; }
.planning-stepper::before { content: ''; position: absolute; top: 6px; bottom: 0; left: 4px; width: 2px; background-color: #e9ecef; z-index: 0; }
.stepper-item { position: relative; padding-bottom: 1.75rem; }
.stepper-item:last-child { padding-bottom: 0; }
.stepper-dot { position: absolute; left: -1.25rem; top: 0.25rem; width: 10px; height: 10px; border-radius: 50%; z-index: 1; background-color: #dee2e6; }
.stepper-dot.completed { background-color: #20c997; }
.stepper-dot.active { background-color: #fd7e14; box-shadow: 0 0 0 5px rgba(253, 126, 20, 0.15); }
.stepper-dot.pending { background-color: #e2e8f0; }
.stepper-item.pending .step-title, .stepper-item.pending .step-desc { opacity: 0.6; }
/* Offcanvas Timeline CSS */
.timeline { position: relative; padding-left: 2rem; margin-top: 1rem; }
.timeline::before { content: ''; position: absolute; top: 0; bottom: 0; left: 0.85rem; width: 2px; background-color: #dee2e6; z-index: 0; }
.timeline-item { position: relative; margin-bottom: 1.5rem; }
.timeline-icon { position: absolute; top: 0; left: -2rem; width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 1rem; z-index: 1; }
.timeline-content { margin-left: 0.5rem; background-color: #fff; transition: all 0.2s ease; }
.timeline-content:hover { box-shadow: 0 .5rem 1rem rgba(0,0,0,.08)!important; }
</style>
@endsection
@section('page-content')
@include('permits.partials.pdf-modal')
@include('layouts.partials.permits-navbar')
@include('permits.partials.site-inspection')
<div class="container py-4">
<div class="row g-4">
<div class="col-lg-7 col-md-12">
<div class="d-flex align-items-center mb-4 mt-2 gap-3">
<h1 class="display-6 fw-bold text-dark mb-0">{{ $permit_arr['application_code'] }}</h1>
<span class="badge bg-warning text-dark fs-5 shadow-sm align-middle">{{ $permit_arr['status'] }}</span>
</div>
<div class="map-container mb-4 border border-light-subtle shadow-sm rounded overflow-hidden" style="height: 450px; background-color: #f8f9fc;">
<iframe id="permit-map"
src="https://pwa.lupmis4luspa.org/embed.php?mode=permit&application_code={{ urlencode($permit_arr['application_code']) }}{{ !empty($permit_arr['lon']) ? '&lon='.urlencode($permit_arr['lon']).'&lat='.urlencode($permit_arr['lat']) : '' }}{{ !empty($permit_arr['upn']) ? '&upn='.urlencode($permit_arr['upn']) : '' }}"
style="width:100%;height:500px;border:0;border-radius:8px;"
allow="geolocation; clipboard-write"
referrerpolicy="strict-origin-when-cross-origin"
loading="lazy"
title="Permit location map">
</iframe>
<!-- <div class="map-container mb-4 border border-light-subtle shadow-sm rounded p-5 text-center" style="background-color: #f8f9fc;">
<i class="bi bi-map text-secondary" style="font-size: 3rem;"></i>
<h5 class="mt-3 text-dark">Map View Available</h5>
<p class="text-muted">For security reasons, the interactive map must be opened in a secure window.</p>
<a href="https://pwa.lupmis4luspa.org/embed.php?mode=permit&application_code={{ urlencode($permit_arr['application_code']) }}..." target="_blank" class="btn btn-primary mt-2">
<i class="bi bi-box-arrow-up-right me-1"></i> Open Spatial Map
</a>
</div> -->
</div>
<div class="card border border-light-subtle shadow-sm mb-4">
<div class="card-body p-4">
<div class="d-flex align-items-center border-bottom pb-3 mb-4">
<i class="bi bi-person text-primary fs-5 me-2"></i>
<h6 class="fw-bold mb-0 text-dark" style="font-size: 1.1rem;">Applicant & Property Details</h6>
</div>
<div class="row gy-4">
<div class="col-12">
<div class="text-uppercase text-secondary fw-semibold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">Applicant Name:</div>
<div class="fw-bold text-dark fs-5">{{ $permit_arr['applicant_name'] }}</div>
</div>
<div class="col-md-6">
<div class="text-uppercase text-secondary fw-semibold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">Nationality:</div>
<div class="text-dark fw-medium">{{ $permit_arr['nationality'] }}</div>
</div>
<div class="col-md-6">
<div class="text-uppercase text-secondary fw-semibold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">Email Address:</div>
<div><a href="mailto:jmadjanor6@gmail.com" class="text-decoration-none text-primary">{{ $permit_arr['email'] }}</a></div>
</div>
<div class="col-md-6">
<div class="text-uppercase text-secondary fw-semibold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">Telephone Number:</div>
<div class="text-dark">{{ $permit_arr['phone'] }}</div>
</div>
<div class="col-md-6">
<div class="text-uppercase text-secondary fw-semibold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">Project Location:</div>
<div class="text-dark fw-bold">{{ $permit_arr['project_location'] }}</div>
</div>
<div class="col-12">
<div class="text-uppercase text-secondary fw-semibold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">Mailing Address:</div>
<div class="text-dark">{{ $permit_arr['address'] }}</div>
</div>
<div class="col-md-6">
<div class="text-uppercase text-secondary fw-semibold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">Permit Type Requested</div>
<div class="text-dark fw-bold">{{ $permit_arr['permit_type'] }}</div>
</div>
<div class="col-md-6">
<div class="text-uppercase text-secondary fw-semibold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">Purpose</div>
<div class="fw-bold" style="color: #e67e22;">{{ $permit_arr['land_request_use'] }}</div>
</div>
<div class="col-12 mt-2">
<div class="border border-dark-subtle rounded p-3">
<div class="text-uppercase text-secondary fw-semibold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">Project Scope:</div>
<div class="text-dark fst-italic" style="font-size: 0.95rem;">{{ $permit_arr['project_description'] }}</div>
</div>
</div>
</div>
</div>
</div>
<div class="card border border-light-subtle shadow-sm mb-4" style="background-color: #f8f9fc;">
<div class="card-body p-4">
<h6 class="fw-bold text-uppercase text-secondary mb-4" style="letter-spacing: 0.5px; font-size: 0.85rem;">
Actual Project Location & Cadastral Registration
</h6>
<div class="row g-3 mb-4">
<div class="col-md-4">
<label class="form-label fw-bold text-secondary small mb-1">
Coordinates <br class="d-none d-md-block"> (Latitude, Longitude) <span class="text-danger">*</span>
</label>
<div class="input-group shadow-sm">
<span class="input-group-text bg-white border-end-0 text-muted font-monospace small pe-1">GPS:</span>
<input type="text" class="form-control border-start-0 ps-1 font-monospace" placeholder="e.g., 5.66240, -0.18055" value="">
</div>
</div>
<div class="col-md-4">
<label class="form-label fw-bold text-secondary small mb-1">
<br class="d-none d-md-block">UPN (Unique Parcel Number)
</label>
<input type="text" class="form-control shadow-sm" value="">
</div>
<div class="col-md-4">
<label class="form-label fw-bold text-secondary small mb-1">
Permit <br class="d-none d-md-block">Fee (GH₵) <span class="text-danger">*</span>
</label>
<input type="number" class="form-control shadow-sm fw-bold" value="">
</div>
</div>
<div class="d-flex flex-wrap gap-2">
<button type="button" class="btn fw-bold px-4 text-dark shadow-sm" style="background-color: #ffb400; border-color: #ffb400;">
Check Zone Compliance
</button>
<button type="button" class="btn btn-primary fw-bold px-4 shadow-sm">
<i class="bi bi-map me-1"></i> Save Physical Location
</button>
</div>
</div>
</div>
<div class="card border border-light-subtle shadow-sm mb-4">
<div class="card-body p-4">
<div class="d-flex align-items-center border-bottom pb-3 mb-4">
<i class="bi bi-file-earmark-text text-primary fs-5 me-2"></i>
<h6 class="fw-bold mb-0 text-dark" style="font-size: 1.1rem;">Uploaded Documents</h6>
</div>
<div class="d-flex flex-column gap-3">
<div class="border border-light-subtle rounded p-3 d-flex align-items-center justify-content-between bg-light shadow-sm transition-all">
<div class="d-flex align-items-center text-truncate pe-3">
<i class="bi bi-file-earmark text-primary fs-4 me-3"></i>
<div class="text-truncate">
<div class="text-dark fw-medium" style="font-size: 0.95rem;">Site Plan Drawing</div>
<div class="text-secondary font-monospace text-uppercase" style="font-size: 0.75rem; letter-spacing: 0.5px;">site_plan.pdf</div>
</div>
</div>
<a href="#" class="text-decoration-none fw-semibold text-nowrap" style="font-size: 0.85rem;">
Open File <i class="bi bi-arrow-up-right ms-1"></i>
</a>
</div>
<!-- <div class="border border-light-subtle rounded p-3 d-flex align-items-center justify-content-between bg-light shadow-sm transition-all">
<div class="d-flex align-items-center text-truncate pe-3">
<i class="bi bi-file-earmark text-primary fs-4 me-3"></i>
<div class="text-truncate">
<div class="text-dark fw-medium" style="font-size: 0.95rem;">Block Plan Drawing</div>
<div class="text-secondary font-monospace text-uppercase" style="font-size: 0.75rem; letter-spacing: 0.5px;">LUSPA_TAIFA_BLOCK2_A.jpg</div>
</div>
</div>
<a href="#" class="text-decoration-none fw-semibold text-nowrap" style="font-size: 0.85rem;">
Open File <i class="bi bi-arrow-up-right ms-1"></i>
</a>
</div> -->
<div class="border border-light-subtle rounded p-3 d-flex align-items-center justify-content-between bg-light shadow-sm transition-all">
<div class="d-flex align-items-center text-truncate pe-3">
<i class="bi bi-file-earmark text-primary fs-4 me-3"></i>
<div class="text-truncate">
<div class="text-dark fw-medium" style="font-size: 0.95rem;">Architectural Drawings</div>
<div class="text-secondary font-monospace text-uppercase" style="font-size: 0.75rem; letter-spacing: 0.5px;">architectural.pdf</div>
</div>
</div>
<a href="#" class="text-decoration-none fw-semibold text-nowrap" style="font-size: 0.85rem;">
Open File <i class="bi bi-arrow-up-right ms-1"></i>
</a>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-5 col-md-12">
<div class="sticky-top" style="top: 1.5rem; ">
<div class="card border border-light-subtle shadow-sm mb-4">
<div class="card-body p-4">
<div class="d-flex justify-content-between align-items-start border-bottom pb-3 mb-4">
<div class="d-flex align-items-center">
<i class="bi bi-clock text-primary fs-5 me-2"></i>
<h6 class="fw-bold mb-0 text-dark" style="font-size: 1.1rem;">Processing & Duration</h6>
</div>
<div class="text-end">
<div class="text-uppercase text-secondary fw-semibold mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">Remaining Days</div>
<span class="badge text-dark fs-6 px-3 py-1" style="background-color: #fce4b4;">N/A</span>
</div>
</div>
<div class="overflow-auto pe-2" style="max-height: 450px;">
<div class="planning-stepper">
<div class="stepper-item">
<div class="stepper-dot completed"></div>
<div class="text-uppercase text-secondary fw-semibold mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">28th Feb 2026, 11:59 PM LUPMIS ENGINE</div>
<h6 class="fw-bold mb-1 text-dark">Submission Received</h6>
<p class="mb-2 small text-secondary">Application successfully uploaded to on the Portal by applicant.</p>
<span class="badge bg-light text-secondary border fw-medium px-2 py-1">Verified by: Applicant Portal</span>
</div>
<div class="stepper-item">
<div class="stepper-dot active"></div>
<div class="text-uppercase text-secondary fw-semibold mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">PENDING PROCESS SCHEDULE LUPMIS ENGINE</div>
<h6 class="fw-bold mb-1" style="color: #e67e22;">Applicant to Review</h6>
<p class="mb-2 small text-secondary">Applicant asked to review attached documenets.</p>
<span class="badge bg-light text-secondary border fw-medium px-2 py-1">Updated by: Luke Eshun</span>
</div>
<!-- <div class="stepper-item pending">
<div class="stepper-dot pending"></div>
<div class="text-uppercase text-secondary fw-semibold mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">PENDING PROCESS SCHEDULE LUPMIS ENGINE</div>
<h6 class="fw-bold mb-1 step-title text-secondary">Spatial GIS Alignment</h6>
<p class="mb-2 small text-secondary step-desc">Verification of parcel boundaries against Taifa master plan & greenbelt buffers.</p>
</div> -->
</div>
</div>
</div>
</div>
<div class="remarks-section card border border-light-subtle shadow-sm mb-4">
<div class="card-body p-4">
<div class="d-flex align-items-center border-bottom pb-3 mb-4">
<i class="fa-solid fa-comments text-primary fs-5 me-2"></i>
<h6 class="fw-bold mb-0 text-dark" style="font-size: 1.1rem;">Status & Comments</h6>
</div>
<div class="mb-4">
<button class="btn btn-outline-secondary w-100 fw-bold" type="button" data-bs-toggle="offcanvas" data-bs-target="#historyOffcanvas" aria-controls="historyOffcanvas">
<i class="bi bi-clock-history me-1"></i> View Full History & Comments
</button>
</div>
<div class="mb-4">
<label for="permitCurrentStatus" class="form-label fw-bold text-secondary small mb-2" style="letter-spacing: 0.5px;">
<i class="fa-solid fa-temperature-three-quarters text-primary me-1"></i> Status Update
</label>
<select class="form-select shadow-sm" id="permitCurrentStatus">
<option value="" selected disabled>Select status ...</option>
<option value="status_zero">Applicant to Review</option>
<option value="status_one">Application Received</option>
<option value="status_two" disabled>Application Accepted</option>
<option value="status_three" disabled>Permit Pending TSC Review</option>
</select>
</div>
<div class="mb-4">
<textarea class="form-control shadow-sm commentBody" rows="4" name="comment_body" placeholder="Enter new comment here"></textarea>
<input type="hidden" class="applicationCode" name="application_code" value="{{ $permit_arr['application_code'] }}">
</div>
<button class="btn btn-primary w-100 fw-bold shadow-sm submitPermitCommentBtn" type="button">
<i class="fa-solid fa-paper-plane me-1"></i> Submit
</button>
</div>
</div>
</div> </div> </div>
</div>
<div class="offcanvas offcanvas-end shadow-lg" tabindex="-1" id="historyOffcanvas" aria-labelledby="historyOffcanvasLabel" style="width: 450px;">
<div class="offcanvas-header border-bottom bg-light sticky-top z-3">
<h5 class="offcanvas-title fw-bold" id="historyOffcanvasLabel">Application History</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<div class="timeline" id="historyTimeline">
<div class="text-center text-muted mt-5">
<i class="bi bi-arrow-clockwise fs-1"></i>
<p class="mt-2">Loading application history...</p>
</div>
</div>
</div>
</div>
@endsection
@section('page-scripts')
<script>
$(document).ready(function(){
const MAP_ORIGIN = 'https://pwa.lupmis4luspa.org';
const iframe = document.getElementById('permit-map');
const upnInput = document.getElementById('permitUPN');
const locInput = document.getElementById('permitLocation');
window.addEventListener('message', function (event) {
if (event.origin !== MAP_ORIGIN) return;
const msg = event.data;
if (!msg || typeof msg !== 'object') return;
switch (msg.type) {
case 'ready':
@if(!empty($permit_arr['upn']))
iframe.contentWindow.postMessage(
{ type: 'set:selected', upn: @json($permit_arr['upn']) },
MAP_ORIGIN);
@endif
break;
case 'parcel:select':
upnInput.value = msg.upn || '';
locInput.value = (msg.lon != null && msg.lat != null)
? msg.lat.toFixed(6) + ', ' + msg.lon.toFixed(6)
: '';
upnInput.dataset.parcelId = msg.parcel_id || '';
upnInput.dataset.zoneCode = msg.zone_code || '';
break;
case 'parcel:cleared':
upnInput.value = '';
locInput.value = '';
delete upnInput.dataset.parcelId;
delete upnInput.dataset.zoneCode;
break;
case 'error':
console.warn('[permit-map]', msg.code, msg.message);
break;
}
$('#checkComplianceBtn').on('click', function (e) {
e.preventDefault();
const payload = {
application_code: @json($permit_arr['application_code']),
upn: upnInput.value,
parcel_id: upnInput.dataset.parcelId || null,
coordinates: locInput.value,
zone_code: upnInput.dataset.zoneCode || null,
};
$.ajax({ url: '{{ route("permits.checkCompliance") }}',
method: 'POST', data: payload })
.done(function (res) { /* render compliance result */ });
});
});
document.addEventListener('DOMContentLoaded', function() {
// === PDF GENERATION LOGIC ===
window.generateReportPDF = function() {
console.log("1. Button clicked. Starting PDF process...");
if (typeof html2pdf === 'undefined') {
alert("ERROR: The html2pdf library is not loaded.");
return;
}
const element = document.getElementById('report-pdf-content');
if (!element) {
alert("ERROR: Could not find the div with id='report-pdf-content'.");
return;
}
try {
// Lock in the form values AND remove problem images
const inputs = element.querySelectorAll('input, textarea, select');
inputs.forEach(input => {
if (input.tagName === 'TEXTAREA') {
input.innerHTML = input.value;
} else if (input.tagName === 'SELECT') {
// Lock the selected value
const selectedOption = input.options[input.selectedIndex];
if (selectedOption) selectedOption.setAttribute('selected', 'selected');
// THE FIX: Remove the SVG background arrow that crashes html2canvas
input.style.backgroundImage = 'none';
input.style.appearance = 'none'; // Removes native browser arrows
} else {
input.setAttribute('value', input.value);
}
});
console.log("3. Form data locked and SVGs removed. Generating file...");
const opt = {
margin: 0.5,
filename: 'Site_Inspection_Report.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: {
scale: 2,
useCORS: true,
logging: false,
scrollY: 0,
windowY: 0
},
jsPDF: { unit: 'in', format: 'a4', orientation: 'portrait' },
pagebreak: {
mode: 'css',
avoid: ['.row', 'h6']
}
};
// Generate PDF
html2pdf().set(opt).from(element).save().then(() => {
console.log("Success: PDF downloaded.");
// THE RESTORE: Put the arrows back on the screen after download finishes
inputs.forEach(input => {
if (input.tagName === 'SELECT') {
input.style.backgroundImage = '';
input.style.appearance = '';
}
});
}).catch(err => {
console.error("PDF Generation Error:", err);
alert("Failed to build the PDF. Check the browser console.");
});
} catch (error) {
console.error("Critical Execution Error:", error);
alert("A javascript error occurred: " + error.message);
}
}
});
});
</script>
@endsection

View File

@ -53,14 +53,6 @@
loading="lazy"
title="Permit location map">
</iframe>
<!-- <div class="map-container mb-4 border border-light-subtle shadow-sm rounded p-5 text-center" style="background-color: #f8f9fc;">
<i class="bi bi-map text-secondary" style="font-size: 3rem;"></i>
<h5 class="mt-3 text-dark">Map View Available</h5>
<p class="text-muted">For security reasons, the interactive map must be opened in a secure window.</p>
<a href="https://pwa.lupmis4luspa.org/embed.php?mode=permit&application_code={{ urlencode($permit_arr['application_code']) }}..." target="_blank" class="btn btn-primary mt-2">
<i class="bi bi-box-arrow-up-right me-1"></i> Open Spatial Map
</a>
</div> -->
</div>
<div class="card border border-light-subtle shadow-sm mb-4">
@ -118,7 +110,7 @@
Actual Project Location & Cadastral Registration
</h6>
<div class="row g-3 mb-4">
<div class="col-md-4">
<div class="col-md-6">
<label class="form-label fw-bold text-secondary small mb-1">
Coordinates <br class="d-none d-md-block"> (Latitude, Longitude) <span class="text-danger">*</span>
</label>
@ -127,13 +119,46 @@
<input type="text" class="form-control border-start-0 ps-1 font-monospace" placeholder="e.g., 5.66240, -0.18055" value="">
</div>
</div>
<div class="col-md-4">
<div class="col-md-6">
<label class="form-label fw-bold text-secondary small mb-1">
<br class="d-none d-md-block">UPN (Unique Parcel Number)
</label>
<input type="text" class="form-control shadow-sm" value="">
</div>
<div class="col-md-4">
</div>
<div class="d-flex flex-wrap gap-2">
<button type="button" class="btn fw-bold px-4 text-dark shadow-sm" style="background-color: #ffb400; border-color: #ffb400;">
Check Zone Compliance
</button>
<button type="button" class="btn btn-primary fw-bold px-4 shadow-sm">
<i class="bi bi-map me-1"></i> Save Physical Location
</button>
</div>
</div>
</div>
<div class="card border border-light-subtle shadow-sm mb-4">
<div class="card-body p-4">
<h6 class="fw-bold text-uppercase text-secondary mb-4" style="letter-spacing: 0.5px; font-size: 0.85rem;">
Site Inspection
</h6>
<div class="col-md-12">
<div class="d-flex gap-1">
<!-- <button class="btn btn-primary flex-fill"><i class="fa-solid fa-paper-plane"></i> Submit</button> -->
<button type="button" class="btn btn-outline-primary flex-fill" data-bs-toggle="modal" data-bs-target="#inspectionReportModal">
<i class="bi bi-file-earmark-text"></i> Site Inspection Report
</button>
</div>
</div>
</div>
</div>
<div class="card border border-light-subtle shadow-sm mb-4">
<div class="card-body p-4">
<h6 class="fw-bold text-uppercase text-secondary mb-4" style="letter-spacing: 0.5px; font-size: 0.85rem;">
Permit Fees
</h6>
<div class="row g-3 mb-4">
<div class="col-md-6">
<label class="form-label fw-bold text-secondary small mb-1">
Permit Municipal <br class="d-none d-md-block">Review Fee (GH₵) <span class="text-danger">*</span>
</label>
@ -141,11 +166,8 @@
</div>
</div>
<div class="d-flex flex-wrap gap-2">
<button type="button" class="btn fw-bold px-4 text-dark shadow-sm" style="background-color: #ffb400; border-color: #ffb400;">
Check Spatial Buffers
</button>
<button type="button" class="btn btn-primary fw-bold px-4 shadow-sm">
<i class="bi bi-map me-1"></i> Save Geospatial Bounds
<button type="button" class="btn btn-success fw-bold px-4 shadow-sm">
Submit Fee
</button>
</div>
</div>
@ -163,19 +185,7 @@
<i class="bi bi-file-earmark text-primary fs-4 me-3"></i>
<div class="text-truncate">
<div class="text-dark fw-medium" style="font-size: 0.95rem;">Site Plan Drawing</div>
<div class="text-secondary font-monospace text-uppercase" style="font-size: 0.75rem; letter-spacing: 0.5px;">LUSPA_TAIFA_SP3_DRAFT.jpg</div>
</div>
</div>
<a href="#" class="text-decoration-none fw-semibold text-nowrap" style="font-size: 0.85rem;">
Open File <i class="bi bi-arrow-up-right ms-1"></i>
</a>
</div>
<div class="border border-light-subtle rounded p-3 d-flex align-items-center justify-content-between bg-light shadow-sm transition-all">
<div class="d-flex align-items-center text-truncate pe-3">
<i class="bi bi-file-earmark text-primary fs-4 me-3"></i>
<div class="text-truncate">
<div class="text-dark fw-medium" style="font-size: 0.95rem;">Block Plan Drawing</div>
<div class="text-secondary font-monospace text-uppercase" style="font-size: 0.75rem; letter-spacing: 0.5px;">LUSPA_TAIFA_BLOCK2_A.jpg</div>
<div class="text-secondary font-monospace text-uppercase" style="font-size: 0.75rem; letter-spacing: 0.5px;">site_plan.pdf</div>
</div>
</div>
<a href="#" class="text-decoration-none fw-semibold text-nowrap" style="font-size: 0.85rem;">
@ -187,7 +197,7 @@
<i class="bi bi-file-earmark text-primary fs-4 me-3"></i>
<div class="text-truncate">
<div class="text-dark fw-medium" style="font-size: 0.95rem;">Architectural Drawings</div>
<div class="text-secondary font-monospace text-uppercase" style="font-size: 0.75rem; letter-spacing: 0.5px;">TAIFA_RESID_ELEVATION.jpg</div>
<div class="text-secondary font-monospace text-uppercase" style="font-size: 0.75rem; letter-spacing: 0.5px;">architectural.pdf</div>
</div>
</div>
<a href="#" class="text-decoration-none fw-semibold text-nowrap" style="font-size: 0.85rem;">
@ -201,7 +211,7 @@
</div>
<div class="col-lg-5 col-md-12">
<div class="sticky-top" style="top: 1.5rem; z-index: 1020;">
<div class="sticky-top" style="top: 1.5rem; ">
<div class="card border border-light-subtle shadow-sm mb-4">
<div class="card-body p-4">
@ -231,12 +241,6 @@
<p class="mb-2 small text-secondary">Applicant asked to review attached documenets.</p>
<span class="badge bg-light text-secondary border fw-medium px-2 py-1">Updated by: Luke Eshun</span>
</div>
<!-- <div class="stepper-item pending">
<div class="stepper-dot pending"></div>
<div class="text-uppercase text-secondary fw-semibold mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">PENDING PROCESS SCHEDULE LUPMIS ENGINE</div>
<h6 class="fw-bold mb-1 step-title text-secondary">Spatial GIS Alignment</h6>
<p class="mb-2 small text-secondary step-desc">Verification of parcel boundaries against Taifa master plan & greenbelt buffers.</p>
</div> -->
</div>
</div>
</div>
@ -257,12 +261,17 @@
<label for="permitCurrentStatus" class="form-label fw-bold text-secondary small mb-2" style="letter-spacing: 0.5px;">
<i class="fa-solid fa-temperature-three-quarters text-primary me-1"></i> Status Update
</label>
<select class="form-select shadow-sm" id="permitCurrentStatus">
<select class="form-select shadow-sm" id="permitCurrentStatus" name="application_status">
<option value="" selected disabled>Select status ...</option>
<option value="status_zero">Applicant to Review</option>
<option value="status_one">Application Received</option>
<option value="status_two" disabled>Application Accepted</option>
<option value="status_three" disabled>Permit Pending TSC Review</option>
<option value="status_four" disabled>Permit Pending SPC Decision</option>
<option value="status_five" disabled>Permit Approved (In Principle)</option>
<option value="status_six" disabled>Permit Approved</option>
<option value="status_seven" disabled>Permit Refused</option>
<option value="status_eight" disabled>Permit Deferred</option>
</select>
</div>
<div class="mb-4">
@ -278,9 +287,9 @@
</div> </div> </div>
</div>
<div class="offcanvas offcanvas-end shadow-lg" tabindex="-1" id="historyOffcanvas" aria-labelledby="historyOffcanvasLabel" style="width: 450px;">
<!-- <div class="offcanvas offcanvas-end shadow-lg" tabindex="-1" id="historyOffcanvas" aria-labelledby="historyOffcanvasLabel" style="width: 450px;">
<div class="offcanvas-header border-bottom bg-light sticky-top z-3">
<h5 class="offcanvas-title fw-bold" id="historyOffcanvasLabel">Application History</h5>
<h5 class="offcanvas-title fw-bold" id="historyOffcanvasLabel">Comments History</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
@ -291,71 +300,17 @@
</div>
</div>
</div>
</div>
</div> -->
@include('permits.partials.comments-timeline')
@endsection
@section('page-scripts')
<script>
$(document).ready(function(){
@section('page-js')
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
<script src="{{ url('public/assets/js/permit_comments.js') }}" type="text/javascript" ></script>
<script type="text/javascript">
const MAP_ORIGIN = 'https://pwa.lupmis4luspa.org';
const iframe = document.getElementById('permit-map');
const upnInput = document.getElementById('permitUPN');
const locInput = document.getElementById('permitLocation');
window.addEventListener('message', function (event) {
if (event.origin !== MAP_ORIGIN) return;
const msg = event.data;
if (!msg || typeof msg !== 'object') return;
switch (msg.type) {
case 'ready':
@if(!empty($permit_arr['upn']))
iframe.contentWindow.postMessage(
{ type: 'set:selected', upn: @json($permit_arr['upn']) },
MAP_ORIGIN);
@endif
break;
case 'parcel:select':
upnInput.value = msg.upn || '';
locInput.value = (msg.lon != null && msg.lat != null)
? msg.lat.toFixed(6) + ', ' + msg.lon.toFixed(6)
: '';
upnInput.dataset.parcelId = msg.parcel_id || '';
upnInput.dataset.zoneCode = msg.zone_code || '';
break;
case 'parcel:cleared':
upnInput.value = '';
locInput.value = '';
delete upnInput.dataset.parcelId;
delete upnInput.dataset.zoneCode;
break;
case 'error':
console.warn('[permit-map]', msg.code, msg.message);
break;
}
$('#checkComplianceBtn').on('click', function (e) {
e.preventDefault();
const payload = {
application_code: @json($permit_arr['application_code']),
upn: upnInput.value,
parcel_id: upnInput.dataset.parcelId || null,
coordinates: locInput.value,
zone_code: upnInput.dataset.zoneCode || null,
};
$.ajax({ url: '{{ route("permits.checkCompliance") }}',
method: 'POST', data: payload })
.done(function (res) { /* render compliance result */ });
});
});
document.addEventListener('DOMContentLoaded', function() {
// === PDF GENERATION LOGIC ===
window.generateReportPDF = function() {
window.generateReportPDF = function() {
console.log("1. Button clicked. Starting PDF process...");
if (typeof html2pdf === 'undefined') {
@ -370,19 +325,15 @@ document.addEventListener('DOMContentLoaded', function() {
}
try {
// Lock in the form values AND remove problem images
const inputs = element.querySelectorAll('input, textarea, select');
inputs.forEach(input => {
if (input.tagName === 'TEXTAREA') {
input.innerHTML = input.value;
} else if (input.tagName === 'SELECT') {
// Lock the selected value
const selectedOption = input.options[input.selectedIndex];
if (selectedOption) selectedOption.setAttribute('selected', 'selected');
// THE FIX: Remove the SVG background arrow that crashes html2canvas
input.style.backgroundImage = 'none';
input.style.appearance = 'none'; // Removes native browser arrows
input.style.appearance = 'none';
} else {
input.setAttribute('value', input.value);
}
@ -401,18 +352,14 @@ document.addEventListener('DOMContentLoaded', function() {
windowY: 0
},
jsPDF: { unit: 'in', format: 'a4', orientation: 'portrait' },
pagebreak: {
mode: 'css',
avoid: ['.row', 'h6']
}
};
// Generate PDF
html2pdf().set(opt).from(element).save().then(() => {
console.log("Success: PDF downloaded.");
// THE RESTORE: Put the arrows back on the screen after download finishes
inputs.forEach(input => {
if (input.tagName === 'SELECT') {
input.style.backgroundImage = '';
@ -428,8 +375,130 @@ document.addEventListener('DOMContentLoaded', function() {
console.error("Critical Execution Error:", error);
alert("A javascript error occurred: " + error.message);
}
};
$(document).ready(function(){
var pdfModal = document.getElementById('pdfModal');
if(pdfModal) {
pdfModal.addEventListener('show.bs.modal', function (event) {
var button = event.relatedTarget;
var pdfUrl = button.getAttribute('data-pdf-url');
var pdfIframe = document.getElementById('pdfIframe');
if(pdfIframe) pdfIframe.src = pdfUrl;
});
pdfModal.addEventListener('hidden.bs.modal', function () {
var pdfIframe = document.getElementById('pdfIframe');
if(pdfIframe) pdfIframe.src = '';
});
}
const MAP_ORIGIN = 'https://pwa.lupmis4luspa.org';
const iframe = document.getElementById('permit-map');
const upnInput = document.getElementById('permitUPN');
const locInput = document.getElementById('permitLocation');
window.addEventListener('message', function (event) {
if (event.origin !== MAP_ORIGIN) return;
const msg = event.data;
if (!msg || typeof msg !== 'object') return;
switch (msg.type) {
case 'ready':
@if(!empty($permit_arr['upn']))
if(iframe) {
iframe.contentWindow.postMessage(
{ type: 'set:selected', upn: @json($permit_arr['upn']) },
MAP_ORIGIN);
}
@endif
break;
case 'parcel:select':
if(upnInput) upnInput.value = msg.upn || '';
if(locInput) {
locInput.value = (msg.lon != null && msg.lat != null)
? msg.lat.toFixed(6) + ', ' + msg.lon.toFixed(6)
: '';
}
if(upnInput) {
upnInput.dataset.parcelId = msg.parcel_id || '';
upnInput.dataset.zoneCode = msg.zone_code || '';
}
break;
case 'parcel:cleared':
if(upnInput) {
upnInput.value = '';
delete upnInput.dataset.parcelId;
delete upnInput.dataset.zoneCode;
}
if(locInput) locInput.value = '';
break;
case 'error':
console.warn('[permit-map]', msg.code, msg.message);
break;
}
});
$('#checkComplianceBtn').on('click', function (e) {
e.preventDefault();
const payload = {
application_code: @json($permit_arr['application_code']),
upn: upnInput ? upnInput.value : '',
parcel_id: upnInput ? (upnInput.dataset.parcelId || null) : null,
coordinates: locInput ? locInput.value : '',
zone_code: upnInput ? (upnInput.dataset.zoneCode || null) : null,
};
$.ajax({
url: '{{ route("permits.checkCompliance") }}',
method: 'POST',
data: payload
}).done(function (res) {
/* render compliance result */
});
});
// --- Download Button Listener ---
const downloadBtn = document.getElementById('downloadPdfBtn');
if(downloadBtn) {
downloadBtn.addEventListener('click', function() {
const element = document.getElementById('report-pdf-content');
if(!element) return;
const inputs = element.querySelectorAll('input, textarea, select');
inputs.forEach(input => {
if (input.tagName === 'TEXTAREA') {
input.innerHTML = input.value;
} else if (input.tagName === 'SELECT') {
const selectedOption = input.options[input.selectedIndex];
if (selectedOption) selectedOption.setAttribute('selected', 'selected');
} else {
input.setAttribute('value', input.value);
}
});
const originalText = downloadBtn.innerHTML;
downloadBtn.innerHTML = '<i class="bi bi-hourglass-split"></i> Generating...';
downloadBtn.disabled = true;
const opt = {
margin: 0.5,
filename: 'Site_Inspection_Report.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2, useCORS: true, logging: false },
jsPDF: { unit: 'in', format: 'a4', orientation: 'portrait' }
};
html2pdf().set(opt).from(element).save().then(() => {
downloadBtn.innerHTML = originalText;
downloadBtn.disabled = false;
});
});
}
});
});
</script>
@ -437,3 +506,6 @@ document.addEventListener('DOMContentLoaded', function() {

View File

@ -47,7 +47,7 @@
<div class="row g-3 mb-4">
<div class="col-md-4">
<div class="col-md-6">
<label class="form-label fw-bold text-secondary small mb-1">
Coordinates <br class="d-none d-md-block"> (Latitude, Longitude) <span class="text-danger">*</span>
</label>
@ -57,19 +57,19 @@
</div>
</div>
<div class="col-md-4">
<div class="col-md-6">
<label class="form-label fw-bold text-secondary small mb-1">
<br class="d-none d-md-block">UPN (Unique Parcel Number)
</label>
<input type="text" class="form-control shadow-sm" value="">
</div>
<div class="col-md-4">
<!-- <div class="col-md-4">
<label class="form-label fw-bold text-secondary small mb-1">
Permit <br class="d-none d-md-block"> Fee (GH₵) <span class="text-danger"></span>
</label>
<input type="number" class="form-control shadow-sm fw-bold" value="">
</div>
</div> -->
</div>
@ -220,7 +220,7 @@
<div class="d-flex align-items-center border-bottom pb-3 mb-4">
<i class="bi bi-file-earmark-text text-primary fs-5 me-2"></i>
<h6 class="fw-bold mb-0 text-dark" style="font-size: 1.1rem;">Attached CAD Drawings & Documents</h6>
<h6 class="fw-bold mb-0 text-dark" style="font-size: 1.1rem;">Attached Documents</h6>
</div>
<div class="d-flex flex-column gap-3">
@ -229,18 +229,18 @@
<div class="d-flex align-items-center text-truncate pe-3">
<i class="bi bi-file-earmark text-primary fs-4 me-3"></i>
<div class="text-truncate">
<div class="text-dark fw-medium" style="font-size: 0.95rem;">Site Plan Drawing</div>
<div class="text-dark fw-medium" style="font-size: 0.95rem;">Site Plan</div>
<div class="text-secondary font-monospace text-uppercase" style="font-size: 0.75rem; letter-spacing: 0.5px;">
LUSPA_TAIFA_SP3_DRAFT.jpg
site_plan.jpg
</div>
</div>
</div>
<a href="#" class="text-decoration-none fw-semibold text-nowrap" style="font-size: 0.85rem;">
Inspect CAD <i class="bi bi-arrow-up-right ms-1"></i>
Open File <i class="bi bi-arrow-up-right ms-1"></i>
</a>
</div>
<div class="border border-light-subtle rounded p-3 d-flex align-items-center justify-content-between bg-light shadow-sm transition-all">
<!-- <div class="border border-light-subtle rounded p-3 d-flex align-items-center justify-content-between bg-light shadow-sm transition-all">
<div class="d-flex align-items-center text-truncate pe-3">
<i class="bi bi-file-earmark text-primary fs-4 me-3"></i>
<div class="text-truncate">
@ -252,7 +252,7 @@
</div>
<a href="#" class="text-decoration-none fw-semibold text-nowrap" style="font-size: 0.85rem;">Inspect CAD <i class="bi bi-arrow-up-right ms-1"></i>
</a>
</div>
</div> -->
<div class="border border-light-subtle rounded p-3 d-flex align-items-center justify-content-between bg-light shadow-sm transition-all">
<div class="d-flex align-items-center text-truncate pe-3">
@ -260,12 +260,12 @@
<div class="text-truncate">
<div class="text-dark fw-medium" style="font-size: 0.95rem;">Architectural Drawings</div>
<div class="text-secondary font-monospace text-uppercase" style="font-size: 0.75rem; letter-spacing: 0.5px;">
TAIFA_RESID_ELEVATION.jpg
architectural.jpg
</div>
</div>
</div>
<a href="#" class="text-decoration-none fw-semibold text-nowrap" style="font-size: 0.85rem;">
Inspect CAD <i class="bi bi-arrow-up-right ms-1"></i>
Open File <i class="bi bi-arrow-up-right ms-1"></i>
</a>
</div>

View File

@ -99,6 +99,7 @@ Route::middleware([CheckBackendSession::class])->group(function () {
Route::get('/permits/reports', [App\Http\Controllers\PermitsController::class, 'reports']);
Route::post('/permits/checkcompliance', [App\Http\Controllers\PermitsController::class, 'checkCompliance'])->name('permits.checkCompliance');
Route::get('/permits/districtsettings', [App\Http\Controllers\PermitsController::class, 'settings']);
Route::post('/permits/districtsettings', [App\Http\Controllers\PermitsController::class, 'settingsStore']);
Route::get('/permits/viewapplication/{id}', [App\Http\Controllers\PermitsController::class, 'show']);