Bug fixes in User Mgt and Permit
This commit is contained in:
parent
6ee90a93e6
commit
066b9fd2d8
52
info.md
Normal file
52
info.md
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Tit Bits
|
||||||
|
## API Base URL
|
||||||
|
- https://api.lupmis4luspa.org/
|
||||||
|
|
||||||
|
|
||||||
|
````
|
||||||
|
- g!_ArOqhC$Gs9-u2
|
||||||
|
````
|
||||||
|
|
||||||
|
## API Testing Tool
|
||||||
|
- https://restful-api.dev/
|
||||||
|
|
||||||
|
git remote add https://gitea.lupmis4luspa.org/kwesigitea/main-backend.git
|
||||||
|
|
||||||
|
title - add N/A
|
||||||
|
|
||||||
|
from the server 29-10-2025
|
||||||
|
services:
|
||||||
|
l4lauthentication-docker:
|
||||||
|
container_name: l4lauthentication
|
||||||
|
build: .
|
||||||
|
volumes:
|
||||||
|
- ./php_code:/var/www/html
|
||||||
|
#ports:
|
||||||
|
#- 8831:80
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- nginx_proxy_manager_default
|
||||||
|
networks:
|
||||||
|
nginx_proxy_manager_default:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
curl -X 'POST' \
|
||||||
|
'https://api.lupmis4luspa.org/api/user_mgt/get_district_by_region_id.php' \
|
||||||
|
-H 'accept: application/json' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{
|
||||||
|
"region_id": "3",
|
||||||
|
"api_token": "1c46538c712e9b5b"
|
||||||
|
}'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
permit application comments
|
||||||
|
id, user_id, application_code, comment_body, created_at, updated_at
|
||||||
|
|
||||||
|
php artisan make:model PermitApplicationComments -m
|
||||||
|
|
||||||
|
|
||||||
BIN
lupmis.sqlite
Normal file
BIN
lupmis.sqlite
Normal file
Binary file not shown.
@ -4,7 +4,7 @@ namespace App\Http\Controllers\Admin;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Models\User; // adjust if you have a custom model
|
use App\Models\User;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
@ -13,6 +13,7 @@ class UserController extends Controller
|
|||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
|
dd(session('current_user'));
|
||||||
return view('admin.users'); // Blade file below
|
return view('admin.users'); // Blade file below
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,4 +103,5 @@ class UserController extends Controller
|
|||||||
$user->delete();
|
$user->delete();
|
||||||
return response()->json(['deleted'=>true]);
|
return response()->json(['deleted'=>true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,11 +7,15 @@ use Illuminate\Http\Request;
|
|||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use App\Models;
|
use App\Models;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
|
||||||
class AdminController extends Controller
|
class AdminController extends Controller
|
||||||
{
|
{
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
|
//dd(session('current_user')); //"ua_position" => "district-ppd-head" "user_type" => "district_user"
|
||||||
|
|
||||||
if (session('current_user.user_type') == 'district_user') {
|
if (session('current_user.user_type') == 'district_user') {
|
||||||
$users_url = "user_mgt/get_all_users_by_district.php";
|
$users_url = "user_mgt/get_all_users_by_district.php";
|
||||||
$data = ['district_id' => session('current_user.district_id'), 'api_token' => env('LUPMISAPIKEY')];
|
$data = ['district_id' => session('current_user.district_id'), 'api_token' => env('LUPMISAPIKEY')];
|
||||||
@ -20,19 +24,47 @@ class AdminController extends Controller
|
|||||||
$users_url = "user_mgt/get_all_users_by_district.php";
|
$users_url = "user_mgt/get_all_users_by_district.php";
|
||||||
$data = ['region_id' => session('region_id'), 'api_token' => env('LUPMISAPIKEY')];
|
$data = ['region_id' => session('region_id'), 'api_token' => env('LUPMISAPIKEY')];
|
||||||
}
|
}
|
||||||
|
elseif(session('current_user.user_type') == 'national_luspa'){
|
||||||
|
$users_url = "user_mgt/get_all_users.php";
|
||||||
|
$data = ['api_token' => env('LUPMISAPIKEY')];
|
||||||
|
}
|
||||||
else{
|
else{
|
||||||
$users_url = "user_mgt/get_all_users.php";
|
$users_url = "user_mgt/get_all_users.php";
|
||||||
$data = ['api_token' => env('LUPMISAPIKEY') ];
|
$data = ['api_token' => env('LUPMISAPIKEY') ];
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = ApiCalls::CurlPost(json_encode($data), $users_url);
|
$result = ApiCalls::CurlPost(json_encode($data), $users_url);
|
||||||
|
/*
|
||||||
$users_arr = json_decode($result, true);
|
$users_arr = json_decode($result, true);
|
||||||
|
dump($users_arr);
|
||||||
if ($users_arr == null || $users_arr['success'] == false) {
|
if ($users_arr == null || $users_arr['success'] == false || $users_arr['status'] == 'error') {
|
||||||
\Log::info(session('current_user.username') . " tried accessing Admin/home and got empty or no success users_arr");
|
Log::info(session('current_user.username') . " tried accessing Admin/home and got empty or no success users_arr");
|
||||||
return redirect()->back()->withErrors('Your request cannot be handled at this time. Try again later');
|
return redirect()->back()->withErrors('Your request cannot be handled at this time. Try again later');
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
try {
|
||||||
|
$usersArr = json_decode($result, true, 512, JSON_THROW_ON_ERROR);
|
||||||
|
}
|
||||||
|
catch (\JsonException $e) {
|
||||||
|
Log::warning('Admin/home API returned invalid JSON', [
|
||||||
|
'user' => session('current_user.username'),
|
||||||
|
'json_error' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect()->back()
|
||||||
|
->withErrors(['api' => 'Your request cannot be handled at this time. Try again later.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($usersArr) || ($usersArr['success'] ?? null) === false || strtolower((string) ($usersArr['status'] ?? '')) === 'error') {
|
||||||
|
Log::warning('Admin/home API returned an unsuccessful response', [
|
||||||
|
'user' => session('current_user.username'),
|
||||||
|
'success' => $usersArr['success'] ?? 'missing',
|
||||||
|
'status' => $usersArr['status'] ?? 'missing',
|
||||||
|
]);
|
||||||
|
return redirect()->back()
|
||||||
|
->withErrors(['api' => 'Your request cannot be handled at this time. Try again later.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$regions_url = "user_mgt/get_all_regions.php";
|
$regions_url = "user_mgt/get_all_regions.php";
|
||||||
@ -40,7 +72,7 @@ class AdminController extends Controller
|
|||||||
$result = ApiCalls::CurlPost(json_encode($data), $regions_url);
|
$result = ApiCalls::CurlPost(json_encode($data), $regions_url);
|
||||||
$regions_arr = json_decode($result, true);
|
$regions_arr = json_decode($result, true);
|
||||||
if ($regions_arr == null || $regions_arr['success'] == false) {
|
if ($regions_arr == null || $regions_arr['success'] == false) {
|
||||||
\Log::info(session('current_user.username') . " tried accessing Admin/home and got empty or no success region");
|
Log::info(session('current_user.username') . " tried accessing Admin/home and got empty or no success region");
|
||||||
return redirect()->back()->withErrors('Your request cannot be handled at this time. Try again later');
|
return redirect()->back()->withErrors('Your request cannot be handled at this time. Try again later');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,15 +130,7 @@ class AdminController extends Controller
|
|||||||
$paginatedDistrict = $this->paginateCollection($districtUsers, 10, 'district_page');
|
$paginatedDistrict = $this->paginateCollection($districtUsers, 10, 'district_page');
|
||||||
$paginatedRegional = $this->paginateCollection($regionalUsers, 10, 'regional_page');
|
$paginatedRegional = $this->paginateCollection($regionalUsers, 10, 'regional_page');
|
||||||
$paginatedNational = $this->paginateCollection($nationalUsers, 10, 'national_page');
|
$paginatedNational = $this->paginateCollection($nationalUsers, 10, 'national_page');
|
||||||
// dd($paginatedRegional);
|
|
||||||
// return view('admin.home_cats', [
|
|
||||||
// 'page_title' => 'User Management',
|
|
||||||
// 'nationalUsers' => $nationalUsers,
|
|
||||||
// 'regionalUsers' => $regionalUsers,
|
|
||||||
// 'districtUsers' => $districtUsers,
|
|
||||||
// 'totalUsers' => $users->count()
|
|
||||||
// ]);
|
|
||||||
// dd($regionalUsers->count());
|
|
||||||
return view('admin.home_cats', [
|
return view('admin.home_cats', [
|
||||||
'page_title' => 'User Admin',
|
'page_title' => 'User Admin',
|
||||||
'regions_arr' => $regions_arr['data'],
|
'regions_arr' => $regions_arr['data'],
|
||||||
@ -194,37 +218,7 @@ class AdminController extends Controller
|
|||||||
// return view('admin.home', $data);
|
// return view('admin.home', $data);
|
||||||
|
|
||||||
}
|
}
|
||||||
public function indexOld(){
|
|
||||||
$users_url = "user_mgt/get_all_users.php";
|
|
||||||
$data = ['api_token' => env('LUPMISAPIKEY')];
|
|
||||||
$result = ApiCalls::CurlPost(json_encode($data), $users_url);
|
|
||||||
$users_arr = json_decode($result, true);
|
|
||||||
if ($users_arr['success'] == false) {
|
|
||||||
return redirect->back();
|
|
||||||
}
|
|
||||||
|
|
||||||
$regions_url = "user_mgt/get_all_regions.php";
|
|
||||||
$data = ['api_token' => env('LUPMISAPIKEY')];
|
|
||||||
$result = ApiCalls::CurlPost(json_encode($data), $regions_url);
|
|
||||||
$regions_arr = json_decode($result, true);
|
|
||||||
if ($regions_arr['success'] == false) {
|
|
||||||
return redirect->back();
|
|
||||||
}
|
|
||||||
|
|
||||||
$user_type_arr = [
|
|
||||||
'district_user' => 'District User',
|
|
||||||
'regional_user' => 'Regional User',
|
|
||||||
'national_user' => 'National User'
|
|
||||||
];
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'page_title' => 'User Admin',
|
|
||||||
'users_arr' => $users_arr['data'],
|
|
||||||
'regions_arr' => $regions_arr['data'],
|
|
||||||
'user_type_arr' => $user_type_arr
|
|
||||||
];
|
|
||||||
return view('admin.home', $data);
|
|
||||||
}
|
|
||||||
public function districtparams(){
|
public function districtparams(){
|
||||||
/*
|
/*
|
||||||
$url = "user_mgt/get_district_parameters.php";
|
$url = "user_mgt/get_district_parameters.php";
|
||||||
|
|||||||
@ -6,35 +6,86 @@ use Session;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Storage;
|
use Storage;
|
||||||
use Response;
|
use Response;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
class PermitsController extends Controller
|
class PermitsController extends Controller
|
||||||
{
|
{
|
||||||
public function index(){
|
public function indexOld(){
|
||||||
// dd(session('current_user.district_id'));
|
|
||||||
$url = "permit/get_applications_by_district.php";
|
$url = "permit/get_applications_by_district.php";
|
||||||
$data = json_encode([
|
$data = json_encode([
|
||||||
'district_id' => session('current_user.district_id'),
|
'district_id' => session('current_user.district_id'),
|
||||||
'api_token' => env('LUPMISAPIKEY')
|
'api_token' => env('LUPMISAPIKEY')
|
||||||
]);
|
]);
|
||||||
$result = ApiCalls::CurlPost($data, $url);
|
$result = ApiCalls::CurlPost($data, $url);
|
||||||
// dd($result);
|
|
||||||
|
|
||||||
|
|
||||||
// { "id":163,"applicant_id":376,"client_generated_id":"7d707dc2-938f-47e7-8979-2def086d4a8d","application_code":"REQ-20260310-2ZK4","permit_type":"Development Permit","permit_form_type":"structural_alteration","project_description":"jkhghhjghjgh","project_location":"mbvmbnv","project_region_id":10,"project_district_id":122,"estimated_cost":0.00,"status":"submitted","property_size":null,"expected_completion_date":null,"is_paid":null,"submitted_at":"2026-03-10T09:18:04.224672","updated_at":"2026-03-10T09:18:04.224672"},
|
|
||||||
// {"id":313,"applicant_id":482,"client_generated_id":"34ceb996-c809-4dbe-ba27-df1527e75538","application_code":"REQ-20260312-22AL","permit_type":"Development Permit","permit_form_type":"erection_of_building","project_description":"Two floor residence","project_location":"Butumagyabu","project_region_id":10,"project_district_id":122,"estimated_cost":0.00,"status":"submitted","property_size":null,"expected_completion_date":null,"is_paid":null,"submitted_at":"2026-03-12T13:14:04.420739","updated_at":"2026-03-12T13:14:04.420739"}]}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$result = json_decode($result, true);
|
$result = json_decode($result, true);
|
||||||
// dd(is_array($result['data']));
|
dd($result);
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'page_title' => 'Permits Dashboard',
|
'page_title' => 'Permits Dashboard',
|
||||||
'permits_arr' => $result
|
'permits_arr' => $result
|
||||||
];
|
];
|
||||||
return view('permits.dashboard', $data);
|
return view('permits.dashboard', $data);
|
||||||
}
|
}
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$url = "permit/get_applications_by_district.php";
|
||||||
|
$data = json_encode([
|
||||||
|
'district_id' => session('current_user.district_id'),
|
||||||
|
'api_token' => env('LUPMISAPIKEY')
|
||||||
|
]);
|
||||||
|
$result = ApiCalls::CurlPost($data, $url);
|
||||||
|
$response = json_decode($result, true);
|
||||||
|
// dd($response);
|
||||||
|
$permits = collect($response['data'] ?? []);
|
||||||
|
|
||||||
|
|
||||||
|
$summaries = [
|
||||||
|
'total' => $permits->count(),
|
||||||
|
'submitted' => $permits->filter(fn($p) => strtolower($p['status'] ?? '') === 'submitted')->count(),
|
||||||
|
'development' => $permits->filter(fn($p) => str_contains(strtolower($p['permit_type'] ?? ''), 'development'))->count(),
|
||||||
|
'planning' => $permits->filter(fn($p) => str_contains(strtolower($p['permit_type'] ?? ''), 'planning'))->count(),
|
||||||
|
];
|
||||||
|
if ($request->has('search') && $request->search != '') {
|
||||||
|
$search = strtolower($request->search);
|
||||||
|
$permits = $permits->filter(function($p) use ($search) {
|
||||||
|
$code = strtolower($p['application_code'] ?? '');
|
||||||
|
$location = strtolower($p['project_location'] ?? '');
|
||||||
|
$type = strtolower($p['permit_type'] ?? '');
|
||||||
|
$form_type = strtolower($p['permit_form_type'] ?? '');
|
||||||
|
|
||||||
|
return str_contains($code, $search) ||
|
||||||
|
str_contains($location, $search) ||
|
||||||
|
str_contains($form_type, $search) ||
|
||||||
|
str_contains($type, $search);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$paginatedPermits = $this->paginateCollection($permits, 15, 'page');
|
||||||
|
|
||||||
|
return view('permits.dashboard', [
|
||||||
|
'page_title' => 'Permits Management',
|
||||||
|
'permits' => $paginatedPermits,
|
||||||
|
'summaries' => $summaries
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
private function paginateCollection(Collection $items, $perPage = 15, $pageName = 'page')
|
||||||
|
{
|
||||||
|
$page = LengthAwarePaginator::resolveCurrentPage($pageName);
|
||||||
|
$currentPageItems = $items->slice(($page - 1) * $perPage, $perPage)->values();
|
||||||
|
|
||||||
|
$paginator = new LengthAwarePaginator(
|
||||||
|
$currentPageItems,
|
||||||
|
$items->count(),
|
||||||
|
$perPage,
|
||||||
|
$page,
|
||||||
|
[
|
||||||
|
'path' => LengthAwarePaginator::resolveCurrentPath(),
|
||||||
|
'pageName' => $pageName,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return $paginator->withQueryString();
|
||||||
|
}
|
||||||
public function settings(){
|
public function settings(){
|
||||||
//pull email address, sms configs,
|
//pull email address, sms configs,
|
||||||
/*
|
/*
|
||||||
@ -74,6 +125,7 @@ class PermitsController extends Controller
|
|||||||
return view('permits.index', $data);
|
return view('permits.index', $data);
|
||||||
}
|
}
|
||||||
public function show($id){
|
public function show($id){
|
||||||
|
// dd($id);
|
||||||
// dump(session('current_user'));
|
// dump(session('current_user'));
|
||||||
$url = "permit/get_applications_with_applicant_by_application_code.php";
|
$url = "permit/get_applications_with_applicant_by_application_code.php";
|
||||||
|
|
||||||
|
|||||||
@ -50,8 +50,9 @@ class UsersController extends Controller
|
|||||||
//send reset link email
|
//send reset link email
|
||||||
//baduhupir@mailinator.com
|
//baduhupir@mailinator.com
|
||||||
$reset_link = env('APP_URL') . "/reset-auth/" . $user_id;
|
$reset_link = env('APP_URL') . "/reset-auth/" . $user_id;
|
||||||
|
if(env('APP_ENV') == 'production'){
|
||||||
Mail::to($recipientEmail)->send(new PasswordResetMail($fullname, $reset_link));
|
Mail::to($recipientEmail)->send(new PasswordResetMail($fullname, $reset_link));
|
||||||
|
}
|
||||||
return redirect(url('reset-notice')); //get
|
return redirect(url('reset-notice')); //get
|
||||||
// return redirect(url('new-password-form'));
|
// return redirect(url('new-password-form'));
|
||||||
|
|
||||||
@ -72,16 +73,6 @@ class UsersController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function handle_reset(Request $request){
|
public function handle_reset(Request $request){
|
||||||
// code...show_new_passform
|
|
||||||
// dd('foo bar handle reset');
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
"username": "string",
|
|
||||||
"pass": "string",
|
|
||||||
"user_id": "string",
|
|
||||||
"api_token": "string"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
$url = "user_mgt/update_usr_user.php";
|
$url = "user_mgt/update_usr_user.php";
|
||||||
$user_data = [
|
$user_data = [
|
||||||
|
|
||||||
@ -167,7 +158,6 @@ class UsersController extends Controller
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function store(Request $request){
|
public function store(Request $request){
|
||||||
$url = "user_mgt/add_usr_user.php";
|
$url = "user_mgt/add_usr_user.php";
|
||||||
|
|
||||||
@ -175,7 +165,7 @@ class UsersController extends Controller
|
|||||||
'full_name' => 'required|string|max:255',
|
'full_name' => 'required|string|max:255',
|
||||||
'username' => 'required|string|max:255|unique:users,username',
|
'username' => 'required|string|max:255|unique:users,username',
|
||||||
'ua_position' => 'required|string',
|
'ua_position' => 'required|string',
|
||||||
'allowed_apps'=> 'required|array',
|
// 'allowed_apps'=> 'required|array',
|
||||||
'user_status' => 'required|string',
|
'user_status' => 'required|string',
|
||||||
'gender' => 'required|in:male,female',
|
'gender' => 'required|in:male,female',
|
||||||
'district_id' => [
|
'district_id' => [
|
||||||
@ -198,7 +188,7 @@ class UsersController extends Controller
|
|||||||
'username.required' => 'A username is required.',
|
'username.required' => 'A username is required.',
|
||||||
'username.unique' => 'This username is already taken.',
|
'username.unique' => 'This username is already taken.',
|
||||||
'ua_position.required' => 'Position is mandatory.',
|
'ua_position.required' => 'Position is mandatory.',
|
||||||
'allowed_apps.required'=> 'Select at least one application.',
|
// 'allowed_apps.required'=> 'Select at least one application.',
|
||||||
'gender.required' => 'Gender is required.',
|
'gender.required' => 'Gender is required.',
|
||||||
'district_id.required' => 'District must be selected.',
|
'district_id.required' => 'District must be selected.',
|
||||||
'region_id.required' => 'Region is required',
|
'region_id.required' => 'Region is required',
|
||||||
@ -210,15 +200,29 @@ class UsersController extends Controller
|
|||||||
'phone.required' => 'Phone number is required.',
|
'phone.required' => 'Phone number is required.',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Generate random password
|
// dd($request->ua_position);
|
||||||
$password = Str::random(10);
|
$password = Str::random(10);
|
||||||
|
$user_group_matrix = Config('usergroupmatrix');
|
||||||
|
//$allowed_apps_all = $user_group_matrix[ucwords($request->ua_position)];
|
||||||
|
$allowed_apps_all = collect($user_group_matrix)
|
||||||
|
->filter(
|
||||||
|
fn (array $user_group_matrix, string $groupName) =>
|
||||||
|
str_contains(strtolower($groupName), strtolower($request->ua_position))
|
||||||
|
)->all();
|
||||||
|
|
||||||
|
$allowed_apps = collect($allowed_apps_all)
|
||||||
|
->filter(fn ($allowed) => $allowed === true)
|
||||||
|
->keys()
|
||||||
|
->values()
|
||||||
|
->all();
|
||||||
|
|
||||||
$data = json_encode([
|
$data = json_encode([
|
||||||
'full_name' => $request['full_name'],
|
'full_name' => $request['full_name'],
|
||||||
'username' => $request['username'],
|
'username' => $request['username'],
|
||||||
'ua_position' => $request['ua_position'],
|
'ua_position' => $request['ua_position'],
|
||||||
'email' => $request['email'],
|
'email' => $request['email'],
|
||||||
'title' => $request['title'],
|
'title' => $request['title'],
|
||||||
'allowed_apps' => implode(", ", $request['allowed_apps']),
|
'allowed_apps' => implode(", ", $allowed_apps),
|
||||||
'is_password_changed' => false,
|
'is_password_changed' => false,
|
||||||
'password_hint' => 'none',
|
'password_hint' => 'none',
|
||||||
'phone' => str_replace('+', '',$request['phone']),
|
'phone' => str_replace('+', '',$request['phone']),
|
||||||
@ -230,7 +234,33 @@ class UsersController extends Controller
|
|||||||
'district_id' => $request['district_id'],
|
'district_id' => $request['district_id'],
|
||||||
'api_token' => env('LUPMISAPIKEY'),
|
'api_token' => env('LUPMISAPIKEY'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
// dd($data);
|
// dd($data);
|
||||||
|
//todo determine the allowed_apps user
|
||||||
|
//user_type and ua_position
|
||||||
|
if ($request->user_type == 'district_user') {
|
||||||
|
// code...
|
||||||
|
}
|
||||||
|
elseif ($request->user_type == 'regional_luspa') {
|
||||||
|
// code...
|
||||||
|
}
|
||||||
|
elseif ($request->user_type == 'national_luspa') {
|
||||||
|
// code...
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
'permit_tools_backend',
|
||||||
|
'update_permits',
|
||||||
|
'drawing_tools',
|
||||||
|
'view_drawing_tools',
|
||||||
|
'admin_gui',
|
||||||
|
|
||||||
|
*/
|
||||||
|
// "drawing-tools"
|
||||||
|
// "permit-tools"
|
||||||
|
// "admin-gui"
|
||||||
|
// ""
|
||||||
|
|
||||||
$result = ApiCalls::CurlPost($data, $url);
|
$result = ApiCalls::CurlPost($data, $url);
|
||||||
$result = json_decode($result, true);
|
$result = json_decode($result, true);
|
||||||
|
|
||||||
@ -239,9 +269,9 @@ class UsersController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
\Log::info("Your Password is $password");
|
\Log::info("Your Password is $password");
|
||||||
|
if(env('APP_ENV') == 'production'){
|
||||||
Mail::to($request->email)->send(new UserAccountsMail($password, $request->username));
|
Mail::to($request->email)->send(new UserAccountsMail($password, $request->username));
|
||||||
|
}
|
||||||
$sms_message = "Hello {$request->full_name}, your LUPMIS account has been successfully created\n";
|
$sms_message = "Hello {$request->full_name}, your LUPMIS account has been successfully created\n";
|
||||||
$sms_message .= "Username: {$request->username}\n";
|
$sms_message .= "Username: {$request->username}\n";
|
||||||
$sms_message .= "Password: $password\n";
|
$sms_message .= "Password: $password\n";
|
||||||
@ -251,9 +281,10 @@ class UsersController extends Controller
|
|||||||
'recipient' => $request['phone'],
|
'recipient' => $request['phone'],
|
||||||
'message' => $sms_message
|
'message' => $sms_message
|
||||||
];
|
];
|
||||||
|
if(env('APP_ENV') == 'production'){
|
||||||
$sms = new SmsLibrary;
|
$sms = new SmsLibrary;
|
||||||
$retval = $sms->SendMnotitySms($sms_data);
|
$retval = $sms->SendMnotitySms($sms_data);
|
||||||
|
}
|
||||||
\Log::info("SMS Body : $sms_message");
|
\Log::info("SMS Body : $sms_message");
|
||||||
|
|
||||||
if ($request->expectsJson()) {
|
if ($request->expectsJson()) {
|
||||||
@ -269,10 +300,10 @@ class UsersController extends Controller
|
|||||||
'full_name' => 'required|string|max:255',
|
'full_name' => 'required|string|max:255',
|
||||||
'username' => 'required|string|max:20|',
|
'username' => 'required|string|max:20|',
|
||||||
'ua_position' => 'required|string',
|
'ua_position' => 'required|string',
|
||||||
'allowed_apps'=> 'required|array',
|
// 'allowed_apps'=> 'required|array',
|
||||||
'user_status' => 'required|string',
|
'user_status' => 'required|string',
|
||||||
'district_id' => 'required|integer',
|
'district_id' => 'required|integer',
|
||||||
'region_id' => 'required|integer',
|
'region_id' => 'sometimes|integer',
|
||||||
'gender' => 'required|in:male,female',
|
'gender' => 'required|in:male,female',
|
||||||
/*
|
/*
|
||||||
'district_id' => [
|
'district_id' => [
|
||||||
@ -295,7 +326,7 @@ class UsersController extends Controller
|
|||||||
'full_name.required' => 'Please provide the full name.',
|
'full_name.required' => 'Please provide the full name.',
|
||||||
'username.required' => 'A username is required.',
|
'username.required' => 'A username is required.',
|
||||||
'ua_position.required' => 'Position is mandatory.',
|
'ua_position.required' => 'Position is mandatory.',
|
||||||
'allowed_apps.required'=> 'Select at least one application.',
|
// 'allowed_apps.required'=> 'Select at least one application.',
|
||||||
'gender.required' => 'Gender is required.',
|
'gender.required' => 'Gender is required.',
|
||||||
'district_id.required' => 'District must be selected.',
|
'district_id.required' => 'District must be selected.',
|
||||||
'region_id.required' => 'Region is required',
|
'region_id.required' => 'Region is required',
|
||||||
@ -307,6 +338,20 @@ class UsersController extends Controller
|
|||||||
'phone.required' => 'Phone number is required.',
|
'phone.required' => 'Phone number is required.',
|
||||||
]);
|
]);
|
||||||
$is_disabled = ($request->user_status == 'active') ? 'false' : 'true';
|
$is_disabled = ($request->user_status == 'active') ? 'false' : 'true';
|
||||||
|
$user_group_matrix = Config('usergroupmatrix');
|
||||||
|
//$allowed_apps_all = $user_group_matrix[ucwords($request->ua_position)];
|
||||||
|
$allowed_apps_all = collect($user_group_matrix)
|
||||||
|
->filter(
|
||||||
|
fn (array $user_group_matrix, string $groupName) =>
|
||||||
|
str_contains(strtolower($groupName), strtolower($request->ua_position))
|
||||||
|
)->all();
|
||||||
|
|
||||||
|
$allowed_apps = collect($allowed_apps_all)
|
||||||
|
->filter(fn ($allowed) => $allowed === true)
|
||||||
|
->keys()
|
||||||
|
->values()
|
||||||
|
->all();
|
||||||
|
|
||||||
$userData = [
|
$userData = [
|
||||||
'user_id' => $request->user_id,
|
'user_id' => $request->user_id,
|
||||||
'full_name' => $request->full_name,
|
'full_name' => $request->full_name,
|
||||||
@ -314,8 +359,8 @@ class UsersController extends Controller
|
|||||||
'ua_position' => $request->ua_position,
|
'ua_position' => $request->ua_position,
|
||||||
'email' => $request->email,
|
'email' => $request->email,
|
||||||
'title' => $request->title,
|
'title' => $request->title,
|
||||||
|
// 'allowed_apps' => implode(", ", $request->allowed_apps),
|
||||||
'allowed_apps' => implode(", ", $request->allowed_apps),
|
'allowed_apps' => implode(", ", $allowed_apps),
|
||||||
'phone' => str_replace('+', '', $request->phone),
|
'phone' => str_replace('+', '', $request->phone),
|
||||||
|
|
||||||
'gender' => $request->gender,
|
'gender' => $request->gender,
|
||||||
@ -379,4 +424,29 @@ class UsersController extends Controller
|
|||||||
return response()->json($result);
|
return response()->json($result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public function getPositionsMap()
|
||||||
|
{
|
||||||
|
$district_groups = array_keys(Config('usergroupmatrix'));
|
||||||
|
$map = [
|
||||||
|
'district_user' => $district_groups,
|
||||||
|
/*
|
||||||
|
'district_user' => [
|
||||||
|
"PPD Head", "Works Head", "MIS", "PPD Staff", "Works Staff",
|
||||||
|
"Devt Planning Officer", "MCE", "DCE", "Urban Roads Department Head",
|
||||||
|
"District Fire Officer", "District Disaster Prevention Department",
|
||||||
|
"Head of District Health Department", "Representative of the Lands Commission",
|
||||||
|
"Representative of the Environmental Protection Agency", "Rep from Traditional Council",
|
||||||
|
"Chairman of the Works Sub Committee", "Chairman of Development Sub Planning Committee",
|
||||||
|
"Nominated Elected Assembly Memebers"
|
||||||
|
],
|
||||||
|
*/
|
||||||
|
'national_luspa' => ["Director", "IT Head", "Staff"],
|
||||||
|
'regional_luspa' => ["Director", "Staff"]
|
||||||
|
];
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'data' => $map
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ namespace App\Http\Controllers;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Utilities\ApiCalls;
|
use App\Utilities\ApiCalls;
|
||||||
use App\Utilities\SmsLibrary;
|
use App\Utilities\SmsLibrary;
|
||||||
|
use App\Services\MicrosoftMailService;
|
||||||
|
|
||||||
class UtilityController extends Controller
|
class UtilityController extends Controller
|
||||||
{
|
{
|
||||||
@ -23,4 +24,15 @@ class UtilityController extends Controller
|
|||||||
|
|
||||||
\Log::info("SMS API Response : $sms_result");
|
\Log::info("SMS API Response : $sms_result");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testMSEmail(MicrosoftMailService $mailService)
|
||||||
|
{
|
||||||
|
$mailService->sendEmail(
|
||||||
|
'kwesilabs@outlook.com',
|
||||||
|
'Test from LUPMIS',
|
||||||
|
'<h1>Hello!</h1><p>This is sent via Microsoft Graph API.</p>'
|
||||||
|
);
|
||||||
|
|
||||||
|
return 'Email sent!';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,4 +47,23 @@ class User extends Authenticatable
|
|||||||
'password' => 'hashed',
|
'password' => 'hashed',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
$matrix = [
|
||||||
|
'LUSPA National' => ['permit backend', 'drawing tools', 'view drawing tools', 'admin gui'],
|
||||||
|
'District Chief Executive' => ['permit backend', 'view drawing tools'],
|
||||||
|
'District Coordinating Director' => ['view drawing tools'],
|
||||||
|
'Head of Physical Planning Department' => ['permit backend', 'update permits', 'drawing tools', 'view drawing tools', 'admin gui'],
|
||||||
|
];
|
||||||
|
|
||||||
|
Gate::before(function (User $user, string $ability) use ($matrix) {
|
||||||
|
$role = $user->role;
|
||||||
|
|
||||||
|
if (isset($matrix[$role]) && in_array($ability, $matrix[$role])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|||||||
65
php_code/app/Services/MicrosoftMailService.php
Normal file
65
php_code/app/Services/MicrosoftMailService.php
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class MicrosoftMailService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Authenticates with Microsoft and returns the access token.
|
||||||
|
*/
|
||||||
|
private function getAccessToken()
|
||||||
|
{
|
||||||
|
$tenantId = env('MS_GRAPH_TENANT_ID');
|
||||||
|
$clientId = env('MS_GRAPH_CLIENT_ID');
|
||||||
|
$clientSecret = env('MS_GRAPH_CLIENT_SECRET');
|
||||||
|
$response = Http::asForm()->post("https://login.microsoftonline.com/{$tenantId}/oauth2/v2.0/token", [
|
||||||
|
'client_id' => $clientId,
|
||||||
|
'client_secret' => $clientSecret,
|
||||||
|
'scope' => 'https://graph.microsoft.com/.default',
|
||||||
|
'grant_type' => 'client_credentials',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($response->failed()) {
|
||||||
|
throw new Exception('Failed to get Microsoft Graph token: ' . $response->body());
|
||||||
|
}
|
||||||
|
// dd($response);
|
||||||
|
return $response->json('access_token');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an email using the Microsoft Graph API.
|
||||||
|
*/
|
||||||
|
public function sendEmail($toEmail, $subject, $body)
|
||||||
|
{
|
||||||
|
$accessToken = $this->getAccessToken();
|
||||||
|
$sender = env('MS_GRAPH_SENDER_EMAIL');
|
||||||
|
|
||||||
|
$response = Http::withToken($accessToken)
|
||||||
|
->post("https://graph.microsoft.com/v1.0/users/{$sender}/sendMail", [
|
||||||
|
'message' => [
|
||||||
|
'subject' => $subject,
|
||||||
|
'body' => [
|
||||||
|
'contentType' => 'HTML', // Or 'Text'
|
||||||
|
'content' => $body
|
||||||
|
],
|
||||||
|
'toRecipients' => [
|
||||||
|
[
|
||||||
|
'emailAddress' => [
|
||||||
|
'address' => $toEmail
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'saveToSentItems' => 'true'
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($response->failed()) {
|
||||||
|
throw new Exception('Failed to send email: ' . $response->body());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
326
php_code/config/usergroupmatrix.php
Normal file
326
php_code/config/usergroupmatrix.php
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'luspa_national' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'luspa_regional' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'district_chief_executive' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'district_coordinating_director' => [
|
||||||
|
'permit_backend' => false,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'district_mis' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'head_of_physical_planning_department' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => true,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'physical_planning_department_staff' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'development_planning_officer' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'head_of_works_department' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'works_department_staff' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'head_of_the_roads_unit_or_urban_roads_department' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'district_fire_officer' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'district_disaster_prevention_department' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'head_of_district_health_department' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'representative_of_the_lands_commission' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'representative_of_the_environmental_protection_agency' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'rep_from_traditional_council' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'chairman_of_the_works_sub_committee' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'chairman_of_development_sub_planning_committee' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'nominated_elected_assembly_members' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/*return [
|
||||||
|
'LUSPA National' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'LUSPA Regional' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'District Chief Executive' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'District Coordinating Director' => [
|
||||||
|
'permit_backend' => false,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'District MIS' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'Head of Physical Planning Department' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => true,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => true,
|
||||||
|
],
|
||||||
|
'Physical Planning Department Staff' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
'Development Planning Officer' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'Head of Works Department' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
'Works Department Staff' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'Head of the Roads Unit or Urban Roads Department' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'District Fire Officer' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => true,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'District Disaster Prevention Department' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'Head of District Health Department' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'Representative of the Lands Commission' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'Representative of the Environmental Protection Agency' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'Rep from Traditional Council' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'Chairman of the Works Sub Committee' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
'Chairman of Development Sub Planning Committee' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
'Nominated Elected Assembly Members' => [
|
||||||
|
'permit_backend' => true,
|
||||||
|
'update_permits' => false,
|
||||||
|
'drawing_tools' => false,
|
||||||
|
'view_drawing_tools' => true,
|
||||||
|
'admin_gui' => false,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
||||||
@ -1,9 +1,9 @@
|
|||||||
# Acounts
|
# Acounts
|
||||||
- assiamah/win
|
- assiamah/win
|
||||||
- kwesilupmis/7aa0478bce/virgin200
|
- kwesilupmis/7aa0478bce/virgin200
|
||||||
- kwesibanson/virgin200
|
- kwesibanson/virgin200 : district user
|
||||||
|
|
||||||
Username: saxiquzipa/lwCDfAMaBy </li>
|
Username: saxiquzipa/lwCDfAMaBy </li> : national_luspa
|
||||||
|
|
||||||
|
|
||||||
composer create-project laravel/laravel:^11.0 my-laravel-11-project
|
composer create-project laravel/laravel:^11.0 my-laravel-11-project
|
||||||
@ -11,6 +11,10 @@ chmod -R 0777 storage/
|
|||||||
chmod -R 0777 bootstrap/
|
chmod -R 0777 bootstrap/
|
||||||
|
|
||||||
|
|
||||||
|
https://lupmis4luspa.org/landing
|
||||||
|
https://lupmis4luspa.org/landing
|
||||||
|
afuaabasa / 2jcukPZGiCsf
|
||||||
|
|
||||||
|
|
||||||
<li>Username: kwesilupmis</li>
|
<li>Username: kwesilupmis</li>
|
||||||
<li>Password: 7aa0478bce </li>
|
<li>Password: 7aa0478bce </li>
|
||||||
@ -35,28 +39,19 @@ add measurements to the backend for works department
|
|||||||
|
|
||||||
216.55.185.131
|
216.55.185.131
|
||||||
|
|
||||||
ua_id": 10,
|
## Microsoft Email
|
||||||
"user_id": "34ba702b-18f8-4d85-948d-8c55e8500f32",
|
|
||||||
"username": "hyhix",
|
|
||||||
"title": "Mr",
|
|
||||||
"full_name": "Myles Benton",
|
|
||||||
"ua_position": "district-works-head",
|
|
||||||
"email": "baduhupir@mailinator.com",
|
|
||||||
"phone": "233244678092",
|
|
||||||
"gender": "male",
|
|
||||||
"is_disabled": "true",
|
|
||||||
"is_logged_in": null,
|
|
||||||
"is_password_changed": "false",
|
|
||||||
"password_hint": "none",
|
|
||||||
"created_by_id": null,
|
|
||||||
"created_date": "2025-09-08T20:06:11.290737",
|
|
||||||
"updated_by_id": null,
|
|
||||||
"updated_date": "2025-09-08T20:06:11.290737",
|
|
||||||
"allowed_apps": "permit-tools",
|
|
||||||
"region_id": 3,
|
|
||||||
"district_id": 180,
|
|
||||||
"user_type": "District User"
|
|
||||||
|
|
||||||
|
Application (client) ID:
|
||||||
|
8e31f6b1-4a4f-4bb6-9019-aaf64e66143f
|
||||||
|
|
||||||
|
Directory (tenant) ID:
|
||||||
|
afab14ca-ab60-42a6-8a29-ff101424f318
|
||||||
|
|
||||||
|
Secret ID:
|
||||||
|
bd797934-94be-4506-977c-cd65042c9667
|
||||||
|
|
||||||
|
Secret Value:
|
||||||
|
Obk8Q~6pnUQEIn3b9xBe~havTyRgn7u5~mZ7Ecan
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -7,27 +7,25 @@ $(document).ready(function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// --- PHONE INPUT LOGIC ---
|
||||||
const phoneInstances = {};
|
const phoneInstances = {};
|
||||||
|
|
||||||
function initPhoneInput(selector) {
|
function initPhoneInput(selector) {
|
||||||
const input = document.querySelector(selector);
|
const input = document.querySelector(selector);
|
||||||
if (!input) return null;
|
if (!input) return null;
|
||||||
|
|
||||||
// If it was already initialized, don't do it again
|
|
||||||
if (phoneInstances[selector]) return phoneInstances[selector];
|
if (phoneInstances[selector]) return phoneInstances[selector];
|
||||||
|
|
||||||
phoneInstances[selector] = window.intlTelInput(input, {
|
phoneInstances[selector] = window.intlTelInput(input, {
|
||||||
initialCountry: "gh",
|
initialCountry: "gh",
|
||||||
onlyCountries: ["gh"],
|
onlyCountries: ["gh"],
|
||||||
nationalMode: true, // ALLOW users to type 024... natively
|
nationalMode: true,
|
||||||
autoPlaceholder: "polite",
|
autoPlaceholder: "polite",
|
||||||
utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/js/utils.js"
|
utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/js/utils.js"
|
||||||
});
|
});
|
||||||
|
|
||||||
// Auto-format on blur using the plugin's built-in engine
|
|
||||||
input.addEventListener("blur", function () {
|
input.addEventListener("blur", function () {
|
||||||
if (phoneInstances[selector].isValidNumber()) {
|
if (phoneInstances[selector].isValidNumber()) {
|
||||||
// Reformats to local standard (e.g., 024 123 4567) for UI
|
|
||||||
phoneInstances[selector].setNumber(phoneInstances[selector].getNumber());
|
phoneInstances[selector].setNumber(phoneInstances[selector].getNumber());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -35,10 +33,10 @@ $(document).ready(function () {
|
|||||||
return phoneInstances[selector];
|
return phoneInstances[selector];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize inputs when their respective modals open
|
|
||||||
$('#editUserModal').on('shown.bs.modal', () => initPhoneInput("#editPhone"));
|
$('#editUserModal').on('shown.bs.modal', () => initPhoneInput("#editPhone"));
|
||||||
$('#addUserModal').on('shown.bs.modal', () => initPhoneInput("#addUserphone"));
|
$('#addUserModal').on('shown.bs.modal', () => initPhoneInput("#addUserphone"));
|
||||||
|
|
||||||
|
// --- SELECT2 LOGIC ---
|
||||||
$('#editAllowedApps, #inputPermissions').select2({
|
$('#editAllowedApps, #inputPermissions').select2({
|
||||||
dropdownParent: $('#editUserModal'),
|
dropdownParent: $('#editUserModal'),
|
||||||
placeholder: "Select options, multiple allowed"
|
placeholder: "Select options, multiple allowed"
|
||||||
@ -49,46 +47,74 @@ $(document).ready(function () {
|
|||||||
placeholder: "Select options, multiple allowed"
|
placeholder: "Select options, multiple allowed"
|
||||||
});
|
});
|
||||||
|
|
||||||
const optionsMap = {
|
|
||||||
district_user: [
|
// --- DYNAMIC POSITIONS MAP LOGIC ---
|
||||||
"PPD Head", "Works Head", "MIS", "PPD Staff", "Works Staff",
|
let optionsMap = {}; // Start empty
|
||||||
"Devt Planning Officer", "MCE", "DCE", "Urban Roads Department Head",
|
|
||||||
"District Fire Officer", "District Disaster Prevention Department",
|
|
||||||
"Head of District Health Department", "Representative of the Lands Commission",
|
|
||||||
"Representative of the Environmental Protection Agency", "Rep from Traditional Council",
|
|
||||||
"Chairman of the Works Sub Committee", "Chairman of Development Sub Planning Committee",
|
|
||||||
"Nominated Elected Assembly Memebers"
|
|
||||||
],
|
|
||||||
national_luspa: ["Director", "IT Head", "Staff"],
|
|
||||||
regional_luspa: ["Director", "Staff"]
|
|
||||||
};
|
|
||||||
|
|
||||||
function populatePositions(userType, targetDropdown) {
|
function populatePositions(userType, targetDropdown) {
|
||||||
targetDropdown.empty().append('<option value="">-- Select an option --</option>');
|
targetDropdown.empty().append('<option value="">-- Select an option --</option>');
|
||||||
if (optionsMap[userType]) {
|
if (optionsMap[userType]) {
|
||||||
$.each(optionsMap[userType], function(index, value) {
|
$.each(optionsMap[userType], function(index, value) {
|
||||||
targetDropdown.append($("<option></option>").attr("value", value.toLowerCase()).text(value));
|
targetDropdown.append($("<option></option>").attr("value", value.toLowerCase()).text(toTitleCase(value)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function toSentenceCase(value) {
|
||||||
|
value = value
|
||||||
|
.replace(/_+/g, ' ')
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.trim()
|
||||||
|
.toLowerCase();
|
||||||
|
|
||||||
|
return value
|
||||||
|
? value.charAt(0).toUpperCase() + value.slice(1)
|
||||||
|
: '';
|
||||||
|
}
|
||||||
|
function toTitleCase(value) {
|
||||||
|
return value
|
||||||
|
.replace(/_+/g, ' ')
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.trim()
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/\b\w/g, char => char.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Fetch the map from the backend on load
|
||||||
|
$.ajax({
|
||||||
|
url: base_url + '/users/positions-map',
|
||||||
|
type: 'GET',
|
||||||
|
success: function(response) {
|
||||||
|
let mapData = response.data || response;
|
||||||
|
if (mapData && Object.keys(mapData).length > 0) {
|
||||||
|
optionsMap = mapData;
|
||||||
|
// Populate if a radio is already checked
|
||||||
let initialUserType = $("input[name='user_type']:checked").val();
|
let initialUserType = $("input[name='user_type']:checked").val();
|
||||||
if(initialUserType) populatePositions(initialUserType, $("#uaPostionAdd"));
|
if(initialUserType) {
|
||||||
|
populatePositions(initialUserType, $("#uaPostionAdd"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn("The map data is empty or formatted incorrectly.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
console.error("Failed to load positions map:", error);
|
||||||
|
console.log(xhr.responseText); // Shows PHP errors if the route crashed
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Handle Radio Changes
|
|
||||||
$("input[name='user_type']").change(function() {
|
$("input[name='user_type']").change(function() {
|
||||||
let userType = $(this).val();
|
let userType = $(this).val();
|
||||||
|
|
||||||
let isDistrict = (userType === 'district_user');
|
let isDistrict = (userType === 'district_user');
|
||||||
let isRegional = (userType === 'regional_luspa');
|
let isRegional = (userType === 'regional_luspa');
|
||||||
|
|
||||||
//$('#regionID, #editRegionID').prop('disabled', !isDistrict && !isRegional);
|
|
||||||
//$('#districtID, #editdistrictID').prop('disabled', !isDistrict);
|
|
||||||
|
|
||||||
populatePositions(userType, $("#uaPostionAdd"));
|
populatePositions(userType, $("#uaPostionAdd"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// --- DEPENDENT DROPDOWNS ---
|
||||||
$('.regionIDD').change(function() {
|
$('.regionIDD').change(function() {
|
||||||
let region_id = $(this).val();
|
let region_id = $(this).val();
|
||||||
let $districtSelect = $('.districtIDD');
|
let $districtSelect = $('.districtIDD');
|
||||||
@ -111,6 +137,7 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// --- EDIT USER LOGIC ---
|
||||||
let lastTrigger = null;
|
let lastTrigger = null;
|
||||||
|
|
||||||
$(document).on('click', '.editUserBtn', function(evnt) {
|
$(document).on('click', '.editUserBtn', function(evnt) {
|
||||||
@ -120,7 +147,6 @@ $(document).ready(function () {
|
|||||||
const row = $(this).closest('.user-row');
|
const row = $(this).closest('.user-row');
|
||||||
let selectedUserId = row.data('id');
|
let selectedUserId = row.data('id');
|
||||||
|
|
||||||
// Ensure phone instance exists before trying to set data into it
|
|
||||||
let phoneIti = initPhoneInput("#editPhone");
|
let phoneIti = initPhoneInput("#editPhone");
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@ -143,12 +169,12 @@ $(document).ready(function () {
|
|||||||
$('#editUsername').val(user.username);
|
$('#editUsername').val(user.username);
|
||||||
$('#editGender').val(user.gender);
|
$('#editGender').val(user.gender);
|
||||||
$('#editTitle').val(user.title);
|
$('#editTitle').val(user.title);
|
||||||
$('#editUaPostion').val(user.ua_position);
|
|
||||||
$('#editRegionID').val(user.region_id);
|
$('#editRegionID').val(user.region_id);
|
||||||
$('#editDistrictId').val(user.district_id);
|
$('#editDistrictId').val(user.district_id);
|
||||||
$("input[name='user_id']").val(user.user_id);
|
$("input[name='user_id']").val(user.user_id);
|
||||||
|
|
||||||
$('#editAllowedApps').val(allowedAppsArray).trigger('change');
|
$('#editAllowedApps').val(allowedAppsArray).trigger('change');
|
||||||
|
|
||||||
if (user.user_type === 'district_user') {
|
if (user.user_type === 'district_user') {
|
||||||
$('#editUserTypeDistrict').prop('checked', true);
|
$('#editUserTypeDistrict').prop('checked', true);
|
||||||
}
|
}
|
||||||
@ -159,12 +185,17 @@ $(document).ready(function () {
|
|||||||
$('#editUserTypeLuspaNational').prop('checked', true);
|
$('#editUserTypeLuspaNational').prop('checked', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Populate positions based on the loaded user_type
|
||||||
|
if(user.user_type) {
|
||||||
|
populatePositions(user.user_type, $("#editUaPostion"));
|
||||||
|
}
|
||||||
|
$('#editUaPostion').val(user.ua_position);
|
||||||
|
|
||||||
if (phoneIti && user.phone) {
|
if (phoneIti && user.phone) {
|
||||||
phoneIti.setNumber(user.phone);
|
phoneIti.setNumber(user.phone);
|
||||||
} else {
|
} else {
|
||||||
$('#editPhone').val(user.phone);
|
$('#editPhone').val(user.phone);
|
||||||
}
|
}
|
||||||
// $('#editUserModal').modal('show')
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function(xhr, status, error) {
|
error: function(xhr, status, error) {
|
||||||
@ -179,6 +210,7 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// --- FORM SUBMISSION LOGIC ---
|
||||||
function handleFormSubmission(formElement, url, successMessage, phoneInstanceSelector) {
|
function handleFormSubmission(formElement, url, successMessage, phoneInstanceSelector) {
|
||||||
const $form = $(formElement);
|
const $form = $(formElement);
|
||||||
const isEdit = formElement.id === 'editUserForm';
|
const isEdit = formElement.id === 'editUserForm';
|
||||||
@ -194,17 +226,14 @@ $(document).ready(function () {
|
|||||||
const formData = new FormData(formElement);
|
const formData = new FormData(formElement);
|
||||||
let errors = [];
|
let errors = [];
|
||||||
|
|
||||||
// Validate Phone cleanly
|
|
||||||
if (itiInstance) {
|
if (itiInstance) {
|
||||||
if (!itiInstance.isValidNumber()) {
|
if (!itiInstance.isValidNumber()) {
|
||||||
errors.push("01|Please enter a valid Ghana phone number.");
|
errors.push("01|Please enter a valid Ghana phone number.");
|
||||||
} else {
|
} else {
|
||||||
// Get the clean E.164 database format (e.g. +233241234567)
|
|
||||||
formData.set("phone", itiInstance.getNumber());
|
formData.set("phone", itiInstance.getNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate standard fields
|
|
||||||
const fullName = $form.find('input[name="full_name"], [id*="FullName"], [id*="Fullname"]').val().trim();
|
const fullName = $form.find('input[name="full_name"], [id*="FullName"], [id*="Fullname"]').val().trim();
|
||||||
const username = $form.find('input[name="username"], [id*="Username"]').val().trim();
|
const username = $form.find('input[name="username"], [id*="Username"]').val().trim();
|
||||||
const email = $form.find('input[type="email"], [id*="Email"]').val().trim();
|
const email = $form.find('input[type="email"], [id*="Email"]').val().trim();
|
||||||
@ -260,7 +289,6 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$("#editUserForm").on("submit", function (evt) {
|
$("#editUserForm").on("submit", function (evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
handleFormSubmission(this, base_url + '/userupdate', "User details successfully updated!", "#editPhone");
|
handleFormSubmission(this, base_url + '/userupdate', "User details successfully updated!", "#editPhone");
|
||||||
|
|||||||
30
php_code/public/assets/js/permits_index.js
Normal file
30
php_code/public/assets/js/permits_index.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
$(document).ready(function() {
|
||||||
|
let searchTimer;
|
||||||
|
|
||||||
|
$('#permitSearch').on('keyup', function() {
|
||||||
|
clearTimeout(searchTimer);
|
||||||
|
let query = $(this).val();
|
||||||
|
|
||||||
|
$('#permitBody').css('opacity', '0.5');
|
||||||
|
|
||||||
|
searchTimer = setTimeout(function() {
|
||||||
|
$.ajax({
|
||||||
|
url: window.location.pathname,
|
||||||
|
type: "GET",
|
||||||
|
data: { search: query },
|
||||||
|
success: function(response) {
|
||||||
|
let html = $(response);
|
||||||
|
|
||||||
|
$('#permitBody').html(html.find('#permitBody').html());
|
||||||
|
|
||||||
|
$('#permit-pagination').html(html.find('#permit-pagination').html());
|
||||||
|
$('#permitBody').css('opacity', '1');
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
console.error("Live search failed");
|
||||||
|
$('#permitBody').css('opacity', '1');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 500); // 500ms delay
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -3,7 +3,7 @@
|
|||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="addUserModalLabel">New User Form</h5>
|
<h5 class="modal-title" id="addUserModalLabel">New User Form 001</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
@ -75,12 +75,7 @@
|
|||||||
<label for="uaPostionAdd" class="form-label">Position</label>
|
<label for="uaPostionAdd" class="form-label">Position</label>
|
||||||
<select id="uaPostionAdd" name="ua_position" class="form-select" required>
|
<select id="uaPostionAdd" name="ua_position" class="form-select" required>
|
||||||
<option selected disabled>Choose...</option>
|
<option selected disabled>Choose...</option>
|
||||||
<option value="district-mis">District MIS</option>
|
|
||||||
<option value="district-ppd-head">PPD Head</option>
|
|
||||||
<option value="luspa-it-head">IT(LUSPA)</option>
|
|
||||||
<option value="district-ppd-staff">PPD Staff</option>
|
|
||||||
<option value="district-works-head">Works Department Head</option>
|
|
||||||
<option value="district-works-staff">Works Department Staff</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@if (session('current_user.user_type') == 'district_user' )
|
@if (session('current_user.user_type') == 'district_user' )
|
||||||
@ -120,14 +115,14 @@
|
|||||||
<option value="inactive">Inactive</option>
|
<option value="inactive">Inactive</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-12">
|
<!-- <div class="col-md-12">
|
||||||
<label for="allowedApps" class="form-label">Allowed Apps*</label>
|
<label for="allowedApps" class="form-label">Allowed Apps*</label>
|
||||||
<select id="allowedApps" name="allowed_apps[]"class="form-select" multiple required style="width:100%">
|
<select id="allowedApps" name="allowed_apps[]"class="form-select" multiple required style="width:100%">
|
||||||
<option value="drawing-tools">Drawing Tools</option>
|
<option value="drawing-tools">Drawing Tools</option>
|
||||||
<option value="permit-tools">Permit Tools</option>
|
<option value="permit-tools">Permit Tools</option>
|
||||||
<option value="admin-gui">Admin GUI</option>
|
<option value="admin-gui">Admin GUI</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div> -->
|
||||||
<div class="col-md-12" style="padding-top: 10px;">
|
<div class="col-md-12" style="padding-top: 10px;">
|
||||||
<div class="d-grid gap-2">
|
<div class="d-grid gap-2">
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
@csrf
|
@csrf
|
||||||
<input type="hidden" name="user_id" value="">
|
<input type="hidden" name="user_id" value="">
|
||||||
<input type="hidden" name="district_id" value="{{ session('current_user.district_id') }}">
|
<input type="hidden" name="district_id" value="{{ session('current_user.district_id') }}">
|
||||||
|
<input type="hidden" name="region_id" value="{{ session('current_user.region_id') }}">
|
||||||
<!-- <input type="hidden" name="user_type" value="district_user"> -->
|
<!-- <input type="hidden" name="user_type" value="district_user"> -->
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
@if (session('current_user.user_type') == 'district_user')
|
@if (session('current_user.user_type') == 'district_user')
|
||||||
@ -136,15 +137,14 @@
|
|||||||
<option value="inactive">Inactive</option>
|
<option value="inactive">Inactive</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<!-- <div class="col-md-4">
|
||||||
<label for="editAllowedApps" class="form-label">Allowed Apps *</label>
|
<label for="editAllowedApps" class="form-label">Allowed Apps *</label>
|
||||||
<select id="editAllowedApps" name="allowed_apps[]" class="form-select" multiple required style="width:100%">
|
<select id="editAllowedApps" name="allowed_apps[]" class="form-select" multiple required style="width:100%">
|
||||||
<!-- <option selected >Choose...</option> -->
|
|
||||||
<option value="drawing-tools">Drawing Tools</option>
|
<option value="drawing-tools">Drawing Tools</option>
|
||||||
<option value="permit-tools">Permit Tools</option>
|
<option value="permit-tools">Permit Tools</option>
|
||||||
<option value="admin-gui">Admin GUI</option>
|
<option value="admin-gui">Admin GUI</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
@if(env('APP_ENV') == 'local')
|
@if(env('APP_ENV') == 'local')
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
<nav class="navbar navbar-expand-lg">
|
<nav class="navbar navbar-expand-lg">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="navbar-nav me-auto">
|
<div class="navbar-nav me-auto">
|
||||||
<a class="nav-link text-muted" href="{{ url('/admin/home') }}">Home</a>
|
<a class="nav-link text-muted <?php echo ($page_title == 'User Admin') ? 'active' : ''; ?>" href="{{ url('/admin/home') }}">Admin Home</a>
|
||||||
<a class="nav-link text-muted" href="{{ url('/admin/districtparams') }}">District Parameters</a>
|
<a class="nav-link text-muted <?php echo ($page_title == 'District Parameters') ? 'active' : ''; ?>" href="{{ url('/admin/districtparams') }}">District Parameters</a>
|
||||||
<!-- <a class="nav-link text-muted" href="{{ url('/admin/luspaparams') }}">LUSPA Parameters</a> -->
|
<a class="nav-link text-muted <?php echo ($page_title == 'Reports') ? 'active' : ''; ?>" href="{{ url('/admin/reports') }}">Reports</a>
|
||||||
<a class="nav-link text-muted" href="{{ url('/admin/luspaparams') }}">Reports</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@ -1,109 +1,135 @@
|
|||||||
@extends('layouts.master')
|
@extends('layouts.master')
|
||||||
|
|
||||||
@section('page-title')
|
@section('page-title')
|
||||||
Permits | {{ $page_title }}
|
Admin | {{ $page_title }}
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('page-css')
|
@section('page-css')
|
||||||
<link rel="stylesheet" href="{{ url('public/assets/css/dashboard.css') }}">
|
<style>
|
||||||
|
.summary-card { border-left: 4px solid; border-radius: 0.5rem; }
|
||||||
|
.card-total { border-left-color: #6c757d; }
|
||||||
|
.card-submitted { border-left-color: #f6a623; }
|
||||||
|
.card-dev { border-left-color: #1f6feb; }
|
||||||
|
.card-plan { border-left-color: #17a2b8; }
|
||||||
|
.badge-submitted { background-color: #f6a623; color: #fff; }
|
||||||
|
.badge-approved { background-color: #28a745; color: #fff; }
|
||||||
|
</style>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('page-content')
|
@section('page-content')
|
||||||
@include('layouts.partials.permits-navbar')
|
<div class="container py-4">
|
||||||
<div class="container mt-4">
|
<div class="d-flex align-items-center mb-4">
|
||||||
<div class="row g-3 settings-grid">
|
<h3 class="me-auto">Permits Management</h3>
|
||||||
<!-- General Settings Card -->
|
|
||||||
<div class="col-12">
|
|
||||||
@include('common.notifications')
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-lg-4" id="viewPendingDiv">
|
|
||||||
<div class="settings-card">
|
<!-- Summaries Row -->
|
||||||
<div class="card-icon mb-3">
|
<div class="row mb-4">
|
||||||
<i class="fa-solid fa-hourglass-half fa-3x"></i>
|
<div class="col-md-3">
|
||||||
|
<div class="card shadow-sm summary-card card-total h-100">
|
||||||
|
<div class="card-body">
|
||||||
|
<h6 class="text-muted mb-2">Total Applications</h6>
|
||||||
|
<h3 class="mb-0">{{ number_format($summaries['total']) }}</h3>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="card-title mb-2">Pending <span class="badge bg-danger">
|
</div>
|
||||||
<?php $count = 0;
|
</div>
|
||||||
if (is_array($permits_arr['data'])) {
|
<div class="col-md-3">
|
||||||
foreach ($permits_arr['data'] as $row) {
|
<div class="card shadow-sm summary-card card-submitted h-100">
|
||||||
// code...
|
<div class="card-body">
|
||||||
if ($row['status'] == 'submitted') {
|
<h6 class="text-muted mb-2">Submitted / Pending</h6>
|
||||||
$count++;
|
<h3 class="mb-0">{{ number_format($summaries['submitted']) }}</h3>
|
||||||
}
|
</div>
|
||||||
}
|
</div>
|
||||||
}
|
</div>
|
||||||
echo $count;
|
<div class="col-md-3">
|
||||||
?>
|
<div class="card shadow-sm summary-card card-dev h-100">
|
||||||
|
<div class="card-body">
|
||||||
|
<h6 class="text-muted mb-2">Development Permits</h6>
|
||||||
|
<h3 class="mb-0">{{ number_format($summaries['development']) }}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card shadow-sm summary-card card-plan h-100">
|
||||||
|
<div class="card-body">
|
||||||
|
<h6 class="text-muted mb-2">Planning Permits</h6>
|
||||||
|
<h3 class="mb-0">{{ number_format($summaries['planning']) }}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Search Toolbar -->
|
||||||
|
<div class="card shadow-sm mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="input-group" style="max-width: 400px;">
|
||||||
|
<span class="input-group-text"><i class="bi bi-search"></i> Search</span>
|
||||||
|
<input id="permitSearch" class="form-control" type="text" placeholder="App Code, Location, or Type...">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Permits Table -->
|
||||||
|
<div class="card shadow-sm mb-4">
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover align-middle mb-0">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>Application Code</th>
|
||||||
|
<th>Permit Details</th>
|
||||||
|
<th>Location</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Submitted Date</th>
|
||||||
|
<th class="text-end pe-4">Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="permitBody">
|
||||||
|
@forelse($permits as $permit)
|
||||||
|
<tr>
|
||||||
|
<td class="fw-semibold text-primary">{{ $permit['application_code'] }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="fw-bold">{{ $permit['permit_type'] }}</div>
|
||||||
|
<div class="text-muted small">{{ ucwords(str_replace('_', ' ', $permit['permit_form_type'])) }}</div>
|
||||||
|
</td>
|
||||||
|
<td>{{ Str::limit($permit['project_location'], 30) }}</td>
|
||||||
|
<td>
|
||||||
|
@php $status = strtolower($permit['status']); @endphp
|
||||||
|
<span class="badge {{ $status === 'submitted' ? 'badge-submitted' : 'bg-secondary' }}">
|
||||||
|
{{ ucfirst($status) }}
|
||||||
</span>
|
</span>
|
||||||
</h3>
|
</td>
|
||||||
<p class="card-description mb-0">View and update applications</p>
|
<td>
|
||||||
|
@if(!empty($permit['submitted_at']))
|
||||||
|
{{ \Carbon\Carbon::parse($permit['submitted_at'])->format('d M, Y') }}
|
||||||
|
<div class="text-muted small">{{ \Carbon\Carbon::parse($permit['submitted_at'])->format('H:i') }}</div>
|
||||||
|
@else
|
||||||
|
<span class="text-muted">N/A</span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
<td class="text-end pe-4">
|
||||||
|
<a href="{{ url('/permits/viewapplication/'.$permit['application_code']) }}" class="btn btn-sm btn-outline-secondary">
|
||||||
|
View Details
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@empty
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="text-center text-muted py-4">No permits found matching your criteria.</td>
|
||||||
|
</tr>
|
||||||
|
@endforelse
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Billing Plan Settings Card -->
|
<!-- Pagination Component -->
|
||||||
<div class="col-12 col-md-6 col-lg-4">
|
<div id="permit-pagination" class="pt-3 px-3 pb-3">
|
||||||
<div class="settings-card">
|
{{ $permits->links() }}
|
||||||
<div class="card-icon mb-3">
|
|
||||||
<i class="fa-solid fa-clock fa-3x"></i>
|
|
||||||
</div>
|
|
||||||
<h3 class="card-title mb-2">Queried <span class="badge bg-warning">
|
|
||||||
<?php $count = 0;
|
|
||||||
if (is_array($permits_arr['data'])) {
|
|
||||||
foreach ($permits_arr['data'] as $row) {
|
|
||||||
// code...
|
|
||||||
if ($row['status'] == 'queried') {
|
|
||||||
$count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
echo $count;
|
|
||||||
?>
|
|
||||||
</span></h3>
|
|
||||||
<p class="card-description mb-0">View and update application</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Team Settings Card -->
|
|
||||||
<div class="col-12 col-md-6 col-lg-4">
|
|
||||||
<div class="settings-card">
|
|
||||||
<div class="card-icon mb-3">
|
|
||||||
<i class="fa-solid fa-square-check fa-3x"></i>
|
|
||||||
</div>
|
|
||||||
<h3 class="card-title mb-2">Completed <span class="badge bg-success">
|
|
||||||
<?php $count = 0;
|
|
||||||
if (is_array($permits_arr['data'])) {
|
|
||||||
foreach ($permits_arr['data'] as $row) {
|
|
||||||
if ($row['status'] == 'completed') {
|
|
||||||
$count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
echo $count;
|
|
||||||
?>
|
|
||||||
|
|
||||||
</span></h3>
|
|
||||||
<p class="card-description mb-0">View completed applications</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('page-js')
|
@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/permits_index.js') }}"></script>
|
||||||
|
|
||||||
|
|
||||||
<!-- <script src="{{ url('public/assets/js/permit_tools.js') }}" type="text/javascript" ></script> -->
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
$(document).ready(function(){
|
|
||||||
|
|
||||||
|
|
||||||
$('#viewPendingDiv').click(function(){
|
|
||||||
window.location.href = base_url + "/permits/status/pending";
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
@endsection
|
@endsection
|
||||||
104
php_code/resources/views/permits/dashboard_old.blade.php
Normal file
104
php_code/resources/views/permits/dashboard_old.blade.php
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
@extends('layouts.master')
|
||||||
|
@section('page-title')
|
||||||
|
Permits | {{ $page_title }}
|
||||||
|
@endsection
|
||||||
|
@section('page-css')
|
||||||
|
<link rel="stylesheet" href="{{ url('public/assets/css/dashboard.css') }}">
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
@section('page-content')
|
||||||
|
@include('layouts.partials.permits-navbar')
|
||||||
|
<div class="container mt-4">
|
||||||
|
<div class="row g-3 settings-grid">
|
||||||
|
<!-- General Settings Card -->
|
||||||
|
<div class="col-12">
|
||||||
|
@include('common.notifications')
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6 col-lg-4" id="viewPendingDiv">
|
||||||
|
<div class="settings-card">
|
||||||
|
<div class="card-icon mb-3">
|
||||||
|
<i class="fa-solid fa-hourglass-half fa-3x"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title mb-2">Pending <span class="badge bg-danger">
|
||||||
|
<?php $count = 0;
|
||||||
|
if (is_array($permits_arr['data'])) {
|
||||||
|
foreach ($permits_arr['data'] as $row) {
|
||||||
|
// code...
|
||||||
|
if ($row['status'] == 'submitted') {
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo $count;
|
||||||
|
?>
|
||||||
|
</span>
|
||||||
|
</h3>
|
||||||
|
<p class="card-description mb-0">View and update applications</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Billing Plan Settings Card -->
|
||||||
|
<div class="col-12 col-md-6 col-lg-4">
|
||||||
|
<div class="settings-card">
|
||||||
|
<div class="card-icon mb-3">
|
||||||
|
<i class="fa-solid fa-clock fa-3x"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title mb-2">Queried <span class="badge bg-warning">
|
||||||
|
<?php $count = 0;
|
||||||
|
if (is_array($permits_arr['data'])) {
|
||||||
|
foreach ($permits_arr['data'] as $row) {
|
||||||
|
// code...
|
||||||
|
if ($row['status'] == 'queried') {
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo $count;
|
||||||
|
?>
|
||||||
|
</span></h3>
|
||||||
|
<p class="card-description mb-0">View and update application</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Team Settings Card -->
|
||||||
|
<div class="col-12 col-md-6 col-lg-4">
|
||||||
|
<div class="settings-card">
|
||||||
|
<div class="card-icon mb-3">
|
||||||
|
<i class="fa-solid fa-square-check fa-3x"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title mb-2">Completed <span class="badge bg-success">
|
||||||
|
<?php $count = 0;
|
||||||
|
if (is_array($permits_arr['data'])) {
|
||||||
|
foreach ($permits_arr['data'] as $row) {
|
||||||
|
if ($row['status'] == 'completed') {
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo $count;
|
||||||
|
?>
|
||||||
|
|
||||||
|
</span></h3>
|
||||||
|
<p class="card-description mb-0">View completed applications</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
@section('page-js')
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function(){
|
||||||
|
|
||||||
|
|
||||||
|
$('#viewPendingDiv').click(function(){
|
||||||
|
window.location.href = base_url + "/permits/status/pending";
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
@endsection
|
||||||
@ -31,7 +31,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>Application #</th>
|
<th>Application #</th>
|
||||||
<th>Application Date</th>
|
<th>Application Date</th>
|
||||||
<th>Requested Use</th>
|
<th>Form Type</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th>Permit Type</th>
|
<th>Permit Type</th>
|
||||||
<th>Date Updated</th>
|
<th>Date Updated</th>
|
||||||
@ -55,7 +55,7 @@
|
|||||||
<tr class="applicationRow" id="{{ $row['application_code'] }}">
|
<tr class="applicationRow" id="{{ $row['application_code'] }}">
|
||||||
<td>{{ $row['application_code'] }}</td>
|
<td>{{ $row['application_code'] }}</td>
|
||||||
<td>{{ $submittedDate }}</td>
|
<td>{{ $submittedDate }}</td>
|
||||||
<td>Villa</td>
|
<td>{{ ucfirst(str_replace('_', ' ', $row['permit_form_type'])) }}</td>
|
||||||
<td><span class="badge text-bg-primary">{{ $row['status'] }}</span></td>
|
<td><span class="badge text-bg-primary">{{ $row['status'] }}</span></td>
|
||||||
<td>{{ $row['permit_type'] }}</td>
|
<td>{{ $row['permit_type'] }}</td>
|
||||||
<td>{{ $updatedDate }}</td>
|
<td>{{ $updatedDate }}</td>
|
||||||
|
|||||||
@ -48,16 +48,19 @@ Auth::routes([
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//reorganise this user block
|
||||||
Route::middleware(['auth','can:manage-users'])->prefix('admin')->name('admin.')->group(function(){
|
Route::middleware(['auth','can:manage-users'])->prefix('admin')->name('admin.')->group(function(){
|
||||||
Route::get('users', [UserController::class,'index'])->name('users.index'); // shows Blade
|
|
||||||
Route::get('users/list', [UserController::class,'list'])->name('users.list'); // returns JSON filtered list
|
|
||||||
Route::get('users/{id}', [UserController::class,'show'])->name('users.show'); // user details
|
|
||||||
Route::post('users', [UserController::class,'store'])->name('users.store'); // create
|
Route::get('users', [UserController::class,'index'])->name('users.index');
|
||||||
Route::put('users/{id}', [UserController::class,'update'])->name('users.update'); // update
|
Route::get('users/list', [UserController::class,'list'])->name('users.list');
|
||||||
Route::post('users/move', [UserController::class,'move'])->name('users.move'); // move multiple
|
Route::get('users/{id}', [UserController::class,'show'])->name('users.show');
|
||||||
Route::post('users/deactivate', [UserController::class,'deactivate'])->name('users.deactivate'); // bulk deactivate
|
Route::post('users', [UserController::class,'store'])->name('users.store');
|
||||||
Route::delete('users/{id}', [UserController::class,'destroy'])->name('users.destroy'); // delete
|
Route::put('users/{id}', [UserController::class,'update'])->name('users.update');
|
||||||
|
Route::post('users/move', [UserController::class,'move'])->name('users.move');
|
||||||
|
Route::post('users/deactivate', [UserController::class,'deactivate'])->name('users.deactivate');
|
||||||
|
Route::delete('users/{id}', [UserController::class,'destroy'])->name('users.destroy');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -69,7 +72,7 @@ Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name
|
|||||||
|
|
||||||
//Route::get('/test', [App\Http\Controllers\AdminController::class, 'indexNew'])->name('test');
|
//Route::get('/test', [App\Http\Controllers\AdminController::class, 'indexNew'])->name('test');
|
||||||
|
|
||||||
//Route::get('/sendsms', [App\Http\Controllers\UtilityController::class, 'sendSms'])->name('sendsms');
|
Route::get('/sendmsemail', [App\Http\Controllers\UtilityController::class, 'testMSEmail'])->name('sendmsemail');
|
||||||
|
|
||||||
Route::get('/user-login', [App\Http\Controllers\UserloginController::class, 'index']);
|
Route::get('/user-login', [App\Http\Controllers\UserloginController::class, 'index']);
|
||||||
Route::post('/user-login', [App\Http\Controllers\UserloginController::class, 'handleLogin']);
|
Route::post('/user-login', [App\Http\Controllers\UserloginController::class, 'handleLogin']);
|
||||||
@ -106,7 +109,7 @@ Route::middleware([CheckBackendSession::class])->group(function () {
|
|||||||
Route::get('/admin/districts/{region_id}', [App\Http\Controllers\AdminController::class, 'districts']);
|
Route::get('/admin/districts/{region_id}', [App\Http\Controllers\AdminController::class, 'districts']);
|
||||||
Route::get('/admin/permissions', [App\Http\Controllers\AdminController::class, 'systempermissions']);
|
Route::get('/admin/permissions', [App\Http\Controllers\AdminController::class, 'systempermissions']);
|
||||||
|
|
||||||
|
Route::get('users/positions-map', [App\Http\Controllers\UsersController::class, 'getPositionsMap']);
|
||||||
Route::get('/users/getprofile', [App\Http\Controllers\UsersController::class, 'getprofile_json']);
|
Route::get('/users/getprofile', [App\Http\Controllers\UsersController::class, 'getprofile_json']);
|
||||||
Route::get('/users/{user_id}', [App\Http\Controllers\UsersController::class, 'show']);
|
Route::get('/users/{user_id}', [App\Http\Controllers\UsersController::class, 'show']);
|
||||||
|
|
||||||
|
|||||||
63
workshop-koforidua-2026.md
Normal file
63
workshop-koforidua-2026.md
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# KOFORIDUA - Comments
|
||||||
|
|
||||||
|
## Portal
|
||||||
|
|
||||||
|
Add what happens after 30 days to the feedback, feedback during the process. These are to be Yes and No questions.
|
||||||
|
Remove building permit from the types of permit.
|
||||||
|
Who can apply ? Add categories to describe the sections below. Also, check the details listed there and align them.
|
||||||
|
Add certification of habitation to the FAQ. You need it to inhabit your development.
|
||||||
|
Add do I need a land use certificate.
|
||||||
|
Add links to the various section of the menu.
|
||||||
|
Add assembly contact to the district assemblies.
|
||||||
|
Planning permission definition to be on the landing page.
|
||||||
|
Add a number input box for adding more groups to the already numbered text.
|
||||||
|
Add disclaimer in indicate that the user is responsible for all data being accurate in the system.
|
||||||
|
Add document type to each upload.
|
||||||
|
Edit the applications received part after submit. Add comments to instruct the applicants that they have to upload their required documents and pay before application is actually received.
|
||||||
|
Summary receipt of the application form.
|
||||||
|
Upload documents should be clear (pdfs).
|
||||||
|
Max document size should also be clear.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## District
|
||||||
|
|
||||||
|
- District input box not working. `fixed`
|
||||||
|
- Add additional user positions to the positions. GIS, Plan preparation, standards and compliance, research, - `done` used the document we created in tamale
|
||||||
|
- Notifications on new permits coming in. `partial`
|
||||||
|
- There should be approval in principle. This comes before the permit. `done`
|
||||||
|
- Applicant to review should come before the application is received. `done`
|
||||||
|
- Also, add application accepted after the received. `done`
|
||||||
|
- First feedback should come after 7 days, then 14 days TSC to review. `partial`
|
||||||
|
- Get the boundaries of the site. `not started`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Parcel
|
||||||
|
|
||||||
|
Parcels should come in blocks. Currently, they come as individual structures.
|
||||||
|
We need guidelines for the parcel generations.
|
||||||
|
All parcels autogenerated roads all around them. This should be looked at.
|
||||||
|
Add shape file and iml to the exports.
|
||||||
|
Import data in from different formats.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Drawing Tools
|
||||||
|
|
||||||
|
Add a feature to be able to delete individual layers after the data has been collected.
|
||||||
|
Unable to roll the collapsible overlay tools.
|
||||||
|
Add a location detector to be able to pick current location of the user.
|
||||||
|
Mapping movements should also be added.
|
||||||
|
Add a report feature to the analysis on the drawing tools.
|
||||||
|
A feature to draw a buffer radius based on the user input.
|
||||||
|
When a layer is imported, it should be zoomed to that layer.
|
||||||
|
Add place holders to the map and a feature to delete specific placeholder without deleting all placeholders.
|
||||||
|
Add geo processing tools or features like dissolve and merge.
|
||||||
|
Create manuals and also video recordings of the help sections and how to use the system.
|
||||||
|
Imported data throws the location of the data to a different location.
|
||||||
80
workshop-tamale-2026.md
Normal file
80
workshop-tamale-2026.md
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
Comments LUPMIS - Northern Region
|
||||||
|
|
||||||
|
Public Portal
|
||||||
|
|
||||||
|
Remove 4 copies from the uploads. It should be one copy.
|
||||||
|
Check the gender in the group option.
|
||||||
|
Change gender to sex.Lock application after the District begins to work on the permit.
|
||||||
|
Add table for the comments to track all comments with an applicant.
|
||||||
|
Pre-vetting layer to be added.
|
||||||
|
Description of category drop-down.
|
||||||
|
Evidence of authorization to use land with dropdown to list types. This is to be gotten from the NEW LANDS ACT.
|
||||||
|
Add certificate of habitation to the FAQ.
|
||||||
|
Custom requirements per specific dropdown categories.
|
||||||
|
Add land use classification whether residential or commercial use.
|
||||||
|
Create a summarized sheet or document which the user signs against to confirm his application instead of bringing the hard copies to the district office.
|
||||||
|
Current status of development. Started, completed or not started. `this should be implemented from the portal side`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
District Backend
|
||||||
|
|
||||||
|
User password reset. `done`
|
||||||
|
Separate the Luspa users form the District users. `done`
|
||||||
|
Users are not exhaustive. -- `not clear`
|
||||||
|
Roles to be created b based on the actual responsibilities of the member to give their comments. -- `complete`
|
||||||
|
|
||||||
|
Recommendations and comments from members of the committee concerning a specific applications. We may have to create a table for this. `partial`
|
||||||
|
QR code to check the authenticity of the permits. `not started`
|
||||||
|
Auto populate the coordinates with a button click. `not started`
|
||||||
|
After application received, the days begin to be counted. `this must be implemented at the API level`
|
||||||
|
On the district verse page, district should only be able to see and add users within their jurisdiction. `partial`
|
||||||
|
Lock approved certifications and only make them available after payment. `not started`
|
||||||
|
There should a way to indicate and apply penalties based on the fee fixing. `not started`
|
||||||
|
|
||||||
|
Add the ability to take pictures.`not started`
|
||||||
|
Add search box for the officers to be able to search for the users. `done`
|
||||||
|
Also, add the district to the edit details of the admin page to be able to edit the details of the users or change if they have been redeployed to a different district. `done`
|
||||||
|
Add the details of the members that went to do the inspection. `not started`
|
||||||
|
Develop a site inspection report using the development inspection form. `not started`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Drawing Tools
|
||||||
|
|
||||||
|
Dock not showing below. We need to resize the screen.
|
||||||
|
Add dfx to the file formats to be uploaded in the upload section.
|
||||||
|
Inability to scroll on the mobile app.
|
||||||
|
Currently, deleting a feature deletes all imports. Delete should be updated to take out only specific parcels.
|
||||||
|
Parcels show info on them when in qgis but does not show info in the pwa app.
|
||||||
|
Addition of raster images to the pwa app.
|
||||||
|
There should be a way to change the units of measurements.
|
||||||
|
Offset button seems not to be working.
|
||||||
|
On the top right corner of the system, the icon there is not descriptive. We should have something like Saved Locations or export so users know what it means.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Parcel Tool
|
||||||
|
|
||||||
|
Change the word framing from draw to digitize.
|
||||||
|
Parcel is not yet mobile responsive. Have to update the UI and styles.
|
||||||
|
Test generation overwrites when multiple users use it. Generate parcels seems to be fine.
|
||||||
|
Unable to delete specific vertices when digitizing. Deleting takes away the whole parcel generation
|
||||||
|
Add a pan hand feature so that users can pan while editing a parcel.
|
||||||
|
The parcel tool should also come with arcs and not only lines.
|
||||||
|
When an area is selected for the parcel to be drawn, it does not take into consideration the whole boundary looking at the boundaries and corners.
|
||||||
|
Some of the measures in the panel does not make sense. Something like the depth measure. Clarity is needed here. If the depth stands for breadth or width then it should be changed.
|
||||||
|
Have the option to set the width of multiple different roads differently.
|
||||||
|
We should have the option to delete a specific line as well the that line is selected.
|
||||||
|
Corner radius does not change when the metrics are changed. Should be looked at. Also, the right terminology for the corn radius is Splay.
|
||||||
|
Addition of a progress bar to view the duration of a generation.
|
||||||
|
Also get the minimum and maximum areas that are acceptable for a good operation so the system does not run endlessly.
|
||||||
|
Measuring tool
|
||||||
|
Compare the parameters withe final parcels because it seems it does not match.
|
||||||
|
How do we identify different land use cases and their plotting. Residential and Commercial land use comes with different densification which should be catered for.
|
||||||
|
Roads should be given additional buttons to specify the type of road be it type 1, 2 or 3.
|
||||||
|
The app needs more flexibility.
|
||||||
|
Numbering and zoning of the parcels should be considered.
|
||||||
Loading…
x
Reference in New Issue
Block a user