diff --git a/php_code/app/Http/Controllers/Admin/UserController.php b/php_code/app/Http/Controllers/Admin/UserController.php new file mode 100644 index 00000000..37b9250d --- /dev/null +++ b/php_code/app/Http/Controllers/Admin/UserController.php @@ -0,0 +1,105 @@ +query('q'); + $category = $request->query('category'); // District/Regional/National or null + $statuses = $request->query('status') ?: []; // array + + $query = User::query(); + + if ($category) $query->where('category', $category); + if ($q) { + $query->where(function($sub) use ($q){ + $sub->where('name','like',"%{$q}%") + ->orWhere('email','like',"%{$q}%") + ->orWhere('id','like',"%{$q}%"); + }); + } + if (!empty($statuses)) $query->whereIn('status', $statuses); + + $users = $query->orderBy('last_activity_at','desc')->paginate(25); + + return response()->json($users); + } + + public function show($id) + { + $user = User::findOrFail($id); + return response()->json($user); + } + + public function store(Request $request) + { + $v = Validator::make($request->all(), [ + 'name'=>'required|string|max:255', + 'email'=>'required|email|unique:users,email', + 'category'=>['required', Rule::in(['District','Regional','National'])], + ]); + if ($v->fails()) return response()->json(['errors'=>$v->errors()], 422); + + $user = User::create($request->only(['name','email','category']) + ['status'=>'Active', 'password'=>bcrypt('temporary')]); + return response()->json($user, 201); + } + + public function update(Request $request, $id) + { + $user = User::findOrFail($id); + $v = Validator::make($request->all(), [ + 'name'=>'required|string|max:255', + 'email'=>['required','email', Rule::unique('users','email')->ignore($user->id)], + 'category'=>['required', Rule::in(['District','Regional','National'])], + ]); + if ($v->fails()) return response()->json(['errors'=>$v->errors()], 422); + + $user->update($request->only(['name','email','category'])); + return response()->json($user); + } + + public function move(Request $request) + { + $v = Validator::make($request->all(), [ + 'ids'=>'required|array', + 'target'=>'required|in:District,Regional,National', + ]); + if ($v->fails()) return response()->json(['errors'=>$v->errors()], 422); + + User::whereIn('id', $request->ids)->update(['category'=>$request->target]); + return response()->json(['moved'=>count($request->ids)]); + } + + public function deactivate(Request $request) + { + $v = Validator::make($request->all(), [ + 'ids'=>'required|array', + ]); + if ($v->fails()) return response()->json(['errors'=>$v->errors()], 422); + + User::whereIn('id', $request->ids)->update(['status'=>'Suspended']); + return response()->json(['deactivated'=>count($request->ids)]); + } + + public function destroy($id) + { + $user = User::findOrFail($id); + $user->delete(); + return response()->json(['deleted'=>true]); + } +} diff --git a/php_code/app/Http/Controllers/AdminController.php b/php_code/app/Http/Controllers/AdminController.php index 9f96d031..a2350d5f 100644 --- a/php_code/app/Http/Controllers/AdminController.php +++ b/php_code/app/Http/Controllers/AdminController.php @@ -9,10 +9,11 @@ use Illuminate\Support\Collection; class AdminController extends Controller { - public function index(){ + public function index() + { if (session('current_user.user_type') == 'district_user') { $users_url = "user_mgt/get_all_users_by_district.php"; - $data = ['district_id' => session('district_id'), 'api_token' => env('LUPMISAPIKEY')]; + $data = ['district_id' => session('current_user.district_id'), 'api_token' => env('LUPMISAPIKEY')]; } elseif(session('current_user.user_type') == 'regional_user'){ $users_url = "user_mgt/get_all_users_by_district.php"; @@ -20,13 +21,116 @@ class AdminController extends Controller } else{ $users_url = "user_mgt/get_all_users.php"; - $data = ['api_token' => env('LUPMISAPIKEY')]; + $data = ['api_token' => env('LUPMISAPIKEY') ]; } - // dd($users_url); + $result = ApiCalls::CurlPost(json_encode($data), $users_url); - + $users_arr = json_decode($result, true); - // dd($users_arr); + + if ($users_arr == null || $users_arr['success'] == false) { + return redirect()->back()->withErrors('Your request cannot be handled at this time. Try again later'); + } + + + $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 == null || $regions_arr['success'] == false) { + return redirect()->back()->withErrors('Your request cannot be handled at this time. Try again later'); + } + + + $users = collect($users_arr['data']); + // dd($users->sortBy('ua_id')); + // dump($users); + if (request()->has('search') && request()->search != '') { + $search = strtolower(request()->search); + + $users = $users->filter(function($u) use ($search) { + $name = strtolower($u['full_name'] ?? ''); + $email = strtolower($u['email'] ?? ''); + $username = strtolower($u['username'] ?? ''); + $phone = strtolower($u['phone'] ?? ''); + $ua_position = strtolower($u['ua_position'] ?? ''); + $allowed_apps = strtolower($u['allowed_apps'] ?? ''); + + return str_contains($name, $search) || + str_contains($email, $search) || + str_contains($username, $search) || + str_contains($phone, $search) || + str_contains($ua_position, $search) || + str_contains($allowed_apps, $search); + }); + } + $user_type_arr = [ + 'district_user' => 'District User', + 'regional_user' => 'Regional User', + 'national_user' => 'National User' + ]; + $nationalUsers = $users->filter(function($u) { + $type = trim(strtolower((string)($u['user_type'] ?? ''))); + $position = trim(strtolower((string)($u['ua_position'] ?? ''))); + + // Check if either the type OR the position contains 'national' + return str_contains($type, 'national') || str_contains($position, 'national'); + }); + + $regionalUsers = $users->filter(function($u) { + $type = trim(strtolower((string)($u['user_type'] ?? ''))); + $position = trim(strtolower((string)($u['ua_position'] ?? ''))); + + return str_contains($type, 'regional') || str_contains($position, 'regional'); + }); + + $districtUsers = $users->reject(function($u) { + $type = trim(strtolower((string)($u['user_type'] ?? ''))); + $position = trim(strtolower((string)($u['ua_position'] ?? ''))); + + $isNational = str_contains($type, 'national') || str_contains($position, 'national'); + $isRegional = str_contains($type, 'regional') || str_contains($position, 'regional'); + return $isNational || $isRegional; + }); + $paginatedDistrict = $this->paginateCollection($districtUsers, 10, 'district_page'); + $paginatedRegional = $this->paginateCollection($regionalUsers, 10, 'regional_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', [ + 'page_title' => 'User Admin', + 'regions_arr' => $regions_arr['data'], + 'user_type_arr' => $user_type_arr, + 'nationalUsers' => $paginatedNational, + 'regionalUsers' => $paginatedRegional, + 'districtUsers' => $paginatedDistrict, + 'totalUsers' => $users->count() + ]); + + } + public function indexSingle(){ + if (session('current_user.user_type') == 'district_user' || session('current_user.user_type') == 'District User' ) { + $users_url = "user_mgt/get_all_users_by_district.php"; + $data = ['district_id' => session('current_user.district_id'), 'api_token' => env('LUPMISAPIKEY')]; + } + elseif(session('current_user.user_type') == 'regional_user'){ + $users_url = "user_mgt/get_all_users_by_district.php"; + $data = ['region_id' => session('region_id'), 'api_token' => env('LUPMISAPIKEY')]; + } + else{ + $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); + // dump($users_arr); if ($users_arr == null || $users_arr['success'] == false) { return redirect()->back()->withErrors('Your request cannot be handled at this time. Try again later'); } @@ -67,6 +171,7 @@ class AdminController extends Controller $currentPage, ['path' => request()->url(), 'query' => request()->query()] ); + // dd($paginatedItems); $user_type_arr = [ 'district_user' => 'District User', 'regional_user' => 'Regional User', @@ -81,6 +186,7 @@ class AdminController extends Controller 'items' => $paginatedItems ]; + // return view('admin.home_new', $data); return view('admin.paginated', $data); // return view('admin.home', $data); @@ -182,4 +288,30 @@ class AdminController extends Controller ]; return view('common.notready', $data); } + /** + * Manually paginate a collection. + */ + private function paginateCollection(Collection $items, $perPage = 10, $pageName = 'page') + { + // 1. Get the current page from the URL (e.g., ?district_page=2) + $page = LengthAwarePaginator::resolveCurrentPage($pageName); + + // 2. Slice the collection to get only the items for the current page + $currentPageItems = $items->slice(($page - 1) * $perPage, $perPage)->values(); + + // 3. Create the paginator instance + $paginator = new LengthAwarePaginator( + $currentPageItems, + $items->count(), + $perPage, + $page, + [ + 'path' => LengthAwarePaginator::resolveCurrentPath(), + 'pageName' => $pageName, + ] + ); + + // Keep any other query parameters in the URL (like search keywords) + return $paginator->withQueryString(); + } } diff --git a/php_code/app/Http/Controllers/Controller.php b/php_code/app/Http/Controllers/Controller.php index 77ec359a..250c2bc2 100644 --- a/php_code/app/Http/Controllers/Controller.php +++ b/php_code/app/Http/Controllers/Controller.php @@ -9,4 +9,34 @@ use Illuminate\Routing\Controller as BaseController; class Controller extends BaseController { use AuthorizesRequests, ValidatesRequests; + + public function validateGhanaPhone($phone) { + // Remove spaces, dashes, etc. + $phone = preg_replace('/\D+/', '', $phone); + + // If it starts with 0 (e.g. 0241234567), strip the leading 0 + if (strpos($phone, '0') === 0) { + $phone = substr($phone, 1); + } + + // If it starts with Ghana country code without + (233...), add + + if (strpos($phone, '233') === 0) { + $phone = '+'.$phone; + } + + // If it doesn’t start with +233, prepend it + if (strpos($phone, '+233') !== 0) { + $phone = '+233'.$phone; + } + + // Now validate length: Ghana mobile numbers are 9 digits after +233 + $pattern = '/^\+233\d{9}$/'; + + if (preg_match($pattern, $phone)) { + return $phone; // valid, normalized + } else { + return false; // invalid + } +} + } diff --git a/php_code/app/Http/Controllers/PermitsController.php b/php_code/app/Http/Controllers/PermitsController.php index 1a11fde7..b7e0c3a7 100644 --- a/php_code/app/Http/Controllers/PermitsController.php +++ b/php_code/app/Http/Controllers/PermitsController.php @@ -83,6 +83,8 @@ class PermitsController extends Controller ]); $result = ApiCalls::CurlPost($data, $url); $result = json_decode($result, true); + + // dd($result); $allowed_users_to_comment = ['PPD Head', 'Works Department Head', 'luspa-it-head']; $data = [ 'page_title' => 'Permits Details', @@ -93,6 +95,46 @@ class PermitsController extends Controller } public function statusUpdate($id){ + } + public function reports(){ + $data = [ + 'page_title' => 'Permit Reports' + ]; + return view('common.notready', $data); + } + public function addComment(Request $request){ + + $url = "permit_comments/insert_application_comment.php"; + $data = json_encode([ + "application_code" => $request->application_code, + "client_generated_id" => "CLIENT-001", + "app_comments" => $request->comment_body, + "created_by" => session('current_user.username'), + "created_by_id" => session('current_user.user_id'), + 'api_token' => env('LUPMISAPIKEY') + ]); + + + $result = ApiCalls::CurlPost($data, $url); + $result = json_decode($result, true); + // dd($result); + return response()->json($result); + } + public function getComments(Request $request){ + + $url = "permit_comments/select_application_comments.php"; + $data = json_encode([ + "application_code" => $request->application_code, + "client_generated_id" => "CLIENT-001", + "app_comments" => $request->comment_body, + "created_by" => session('current_user.username'), + "created_by_id" => session('current_user.user_id'), + 'api_token' => env('LUPMISAPIKEY') + ]); + $result = ApiCalls::CurlPost($data, $url); + $result = json_decode($result, true); + + return response()->json($result); } public function viewPdf($filename){ $path = storage_path('app/public/site_plans/' . $filename); diff --git a/php_code/app/Http/Controllers/UserloginController.php b/php_code/app/Http/Controllers/UserloginController.php index 05675074..3e2e6853 100644 --- a/php_code/app/Http/Controllers/UserloginController.php +++ b/php_code/app/Http/Controllers/UserloginController.php @@ -29,11 +29,12 @@ class UserloginController extends Controller $data = ['user' => $request->username, 'pass' => $request->password, 'api_token' => env('LUPMISAPIKEY')]; $check_user = ApiCalls::CurlPost(json_encode($data), $check_user_url); - + // dd($check_user); if($check_user == false){ return redirect("user-login")->withErrors(array("System not available at the moment. Try again later!"))->withInput(); } $result = json_decode($check_user, true); + if($result['success'] == false){ return redirect("user-login")->withErrors(array("Incorrect Email/Password. Check and try again!"))->withInput(); } @@ -41,6 +42,7 @@ class UserloginController extends Controller ##return redirect("user-login")->withErrors(array("Your Account has been disabled. Contact your administrator!"))->withInput(); } $logged_in = $result['data']; + // dd($logged_in); $plainToken = Str::random(60); // $hashedToken = hash('sha256', $plainToken); @@ -49,7 +51,6 @@ class UserloginController extends Controller 'token' => hash('sha256', $plainToken), 'created_at' => now(), ]); - $request->session()->regenerate(true); $request->session()->put('current_user.ua_id', $logged_in['ua_id']); $request->session()->put('current_user.user_id', $logged_in['user_id']); @@ -64,6 +65,7 @@ class UserloginController extends Controller $request->session()->put('current_user.region_id', $logged_in['region_id']); $request->session()->put('current_user.is_password_changed', $logged_in['is_password_changed']); $request->session()->put('current_user.district_id', $logged_in['district_id']); + $request->session()->put('current_user.district_name', $logged_in['vr_district_name']); // $request->session()->put('current_user.hashedToken', $hashedToken); $request->session()->put('current_user.plainToken', $plainToken); diff --git a/php_code/app/Http/Controllers/UsersController.php b/php_code/app/Http/Controllers/UsersController.php index 4f88a298..640d8c9f 100644 --- a/php_code/app/Http/Controllers/UsersController.php +++ b/php_code/app/Http/Controllers/UsersController.php @@ -9,6 +9,8 @@ use Illuminate\Support\Facades\Mail; use App\Mail\UserAccountsMail; use App\Mail\PasswordResetMail; use Illuminate\Support\Str; +use Illuminate\Validation\Rule; +use App\Rules\GhanaPhoneRule; class UsersController extends Controller @@ -26,8 +28,6 @@ class UsersController extends Controller return view('user-auth.reset', $data); } public function check_reset_email(Request $request){ - // code... - // dd('foo bar'); $url = "user_mgt/get_user_by_user_id.php"; $user_id = "34ba702b-18f8-4d85-948d-8c55e8500f32"; $data = json_encode([ @@ -139,12 +139,52 @@ class UsersController extends Controller } + + public function store(Request $request){ $url = "user_mgt/add_usr_user.php"; - // return ['success' => true]; - // $password = ApiCalls::generatePassword(10); - $password = $randomString = Str::random(10); + $this->validate($request, [ + 'full_name' => 'required|string|max:255', + 'username' => 'required|string|max:255|unique:users,username', + 'ua_position' => 'required|string', + 'allowed_apps'=> 'required|array', + 'user_status' => 'required|string', + 'gender' => 'required|in:male,female', + 'districtid' => [ + Rule::requiredIf(function () use ($request) { + return in_array($request->user_type, ['district_user', 'regional_luspa']); + }), + 'integer' + ], + 'region_id' => [ + Rule::requiredIf(function () use ($request) { + return in_array($request->user_type, ['regional_luspa']); + }), + 'integer' + ], + 'user_type' => 'required|string', + 'email' => 'required|email|unique:users,email', + 'phone' => ['required', new GhanaPhoneRule], + ], [ + 'full_name.required' => 'Please provide the full name.', + 'username.required' => 'A username is required.', + 'username.unique' => 'This username is already taken.', + 'ua_position.required' => 'Position is mandatory.', + 'allowed_apps.required'=> 'Select at least one application.', + 'gender.required' => 'Gender is required.', + 'district_id.required' => 'District must be selected.', + 'region_id.required' => 'Region is required', + 'user_type.required' => 'User type is required.', + 'email.required' => 'Email address is required.', + 'email.email' => 'Please enter a valid email address.', + 'user_status.required' => 'Please select user status.', + 'email.unique' => 'This email is already registered.', + 'phone.required' => 'Phone number is required.', + ]); + + // Generate random password + $password = Str::random(10); $data = json_encode([ 'full_name' => $request['full_name'], 'username' => $request['username'], @@ -154,46 +194,90 @@ class UsersController extends Controller 'allowed_apps' => implode(", ", $request['allowed_apps']), 'is_password_changed' => false, 'password_hint' => 'none', - 'phone' => $request['phone'], + 'phone' => str_replace('+', '',$request['phone']), 'gender' => $request['gender'], 'user_type' => $request['user_type'], 'pass' => $password, + 'is_disabled' => false, 'region_id' => $request['region_id'], 'district_id' => $request['districtid'], - 'api_token' => env('LUPMISAPIKEY'), //'1c46538c712e9b5b' // make the API token a constant + 'api_token' => env('LUPMISAPIKEY'), ]); // dd($data); $result = ApiCalls::CurlPost($data, $url); $result = json_decode($result, true); + + if ($result['success'] == false) { + return response()->json($result); + } + \Log::info("Your Password is $password"); - $recipientEmail = 'recipient@example.com'; - Mail::to($recipientEmail)->send(new UserAccountsMail($password, $request->username)); - //dd('Email sent!'); - $sms_message = "Hello $request->full_name your LUPMIS account has been successfully created\n"; - $sms_message .= "Username : . $request->username \n"; - $sms_message .= "Password : $password\n"; - $sms_message .= 'Login URL : https://lupmis4luspa.org'; + Mail::to('recipient@example.com')->send(new UserAccountsMail($password, $request->username)); + + $sms_message = "Hello {$request->full_name}, your LUPMIS account has been successfully created\n"; + $sms_message .= "Username: {$request->username}\n"; + $sms_message .= "Password: $password\n"; + $sms_message .= "Login URL: https://lupmis4luspa.org"; + $sms_data = [ 'recipient' => $request['phone'], 'message' => $sms_message ]; - #$sms_result = SmsLibrary::SendMnotitySms($sms_data); // will send this the API - \Log::info("SMS Body : $sms_message"); - #\Log::info("SMS API Response : $sms_result"); - if (request()->expectsJson()) { + if ($request->expectsJson()) { return response()->json($result); } } + public function update(Request $request){ $url = "user_mgt/update_usr_user.php"; // return ['success' => true]; // dd($request->all()); + $this->validate($request, [ + 'full_name' => 'required|string|max:255', + 'username' => 'required|string|max:255|unique:users,username', + 'ua_position' => 'required|string', + 'allowed_apps'=> 'required|array', + 'user_status' => 'required|string', + 'gender' => 'required|in:male,female', + // 'districtid' => 'required|integer', + 'districtid' => [ + Rule::requiredIf(function () use ($request) { + return in_array($request->user_type, ['district_user']); + }), + 'integer' + ], + 'region_id' => [ + Rule::requiredIf(function () use ($request) { + return in_array($request->user_type, ['regional_luspa', 'national_luspa']); + }), + 'integer' + ], + 'user_type' => 'required|string', + 'email' => 'required|email|unique:users,email', + 'phone' => ['required', new GhanaPhoneRule], + ], [ + 'full_name.required' => 'Please provide the full name.', + 'username.required' => 'A username is required.', + 'username.unique' => 'This username is already taken.', + 'ua_position.required' => 'Position is mandatory.', + 'allowed_apps.required'=> 'Select at least one application.', + 'gender.required' => 'Gender is required.', + 'district_id.required' => 'District must be selected.', + 'region_id.required' => 'Region is required', + 'user_type.required' => 'User type is required.', + 'user_status.required' => 'Please select user status.', + 'email.required' => 'Email address is required.', + 'email.email' => 'Please enter a valid email address.', + 'email.unique' => 'This email is already registered.', + 'phone.required' => 'Phone number is required.', + ]); + $is_disabled = ($request->user_status == 'active') ? 'false' : 'true'; $user_data = [ 'full_name' => $request['full_name'], 'username' => $request['username'], @@ -202,11 +286,15 @@ class UsersController extends Controller 'email' => $request['email'], 'title' => $request['title'], 'allowed_apps' => implode(", ", $request['allowed_apps']), - 'phone' => $request['phone'], + 'phone' => str_replace('+', '',$request['phone']), 'gender' => $request['gender'], - 'user_type' => 'District User', + 'user_type' => $request['user_type'], 'api_token' => env('LUPMISAPIKEY'), + 'is_disabled' => $is_disabled, + // 'region_id' => $request['region_id'], + 'district_id' => $request['districtid'], ]; + if ($request->has('expire_password')) { $user_data['is_password_changed'] = 'NO'; } diff --git a/php_code/app/Models/PermitApplicationComments.php b/php_code/app/Models/PermitApplicationComments.php new file mode 100644 index 00000000..ca038e22 --- /dev/null +++ b/php_code/app/Models/PermitApplicationComments.php @@ -0,0 +1,10 @@ +id(); + $table->foreignId('user_id')->constrained()->nullOnDelete(); + $table->string('application_code')->index(); + $table->string('status'); + $table->text('comment_body')->nullable(); + $table->timestamps(); + }); + } + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('permit_application_comments'); + } +}; diff --git a/php_code/info.md b/php_code/info.md index 53f5aee6..a21b6135 100644 --- a/php_code/info.md +++ b/php_code/info.md @@ -2,6 +2,9 @@ - assiamah/win - kwesilupmis/7aa0478bce +Username: saxiquzipa/lwCDfAMaBy + + composer create-project laravel/laravel:^11.0 my-laravel-11-project chmod -R 0777 storage/ chmod -R 0777 bootstrap/ @@ -26,6 +29,11 @@ add measurements to the backend for works department 216.55.137.19 1c46538c712e9b5b +206.225.87.174 + + +216.55.185.131 + ua_id": 10, "user_id": "34ba702b-18f8-4d85-948d-8c55e8500f32", "username": "hyhix", @@ -46,4 +54,17 @@ ua_id": 10, "allowed_apps": "permit-tools", "region_id": 3, "district_id": 180, - "user_type": "District User" \ No newline at end of file + "user_type": "District User" + + + + +# 1. Strip the restrictive header coming from the backend server +proxy_hide_header X-Frame-Options; + +# 2. Inject the correct Content-Security-Policy +# IMPORTANT: Replace the URL below with your actual LIVE Laravel domain (No trailing slash) +add_header Content-Security-Policy "frame-ancestors 'self' https://lupmis4luspa.org" always; +add_header Content-Security-Policy "frame-ancestors 'self' https://lupmis.housebanson.net" always; + + diff --git a/php_code/live.env b/php_code/live.env new file mode 100644 index 00000000..918fd6eb --- /dev/null +++ b/php_code/live.env @@ -0,0 +1,55 @@ +cat .env +APP_NAME=lupmisBackend +APP_ENV=local +APP_KEY=base64:pmEAeuW8clKrfKKjcMWylo68exoDO/Xr2hUhXvB7dS0= +APP_DEBUG=true +APP_URL=http:https://lupmis4luspa.org +LOG_CHANNEL=daily + +LUPMISAPIKEY=1c46538c712e9b5b +MNOTOFYKEY=hFsiPMAPS3sIdwYSIthRO5JtS +#DB_CONNECTION=mysql +#DB_HOST=host.docker.internal + +DB_CONNECTION=sqlite +#DB_DATABASE=database/lupmis.sqlite +DB_DATABASE=/var/www/html/database/lupmis.sqlite + +DB_PORT=3306 +#DB_DATABASE=lupmis.sqlite +DB_USERNAME=root +DB_PASSWORD=p@ssw0rd + +BROADCAST_DRIVER=log +CACHE_DRIVER=file +QUEUE_CONNECTION=sync +SESSION_DRIVER=file +SESSION_LIFETIME=120 +SESSION_DOMAIN=.lupmis4luspa.org + +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_MAILER=log +MAIL_HOST=smtp.mailtrap.io +MAIL_PORT=2525 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null +MAIL_FROM_ADDRESS=lupmis@luspa.gov.gh +MAIL_FROM_NAME="${APP_NAME}" + +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION=us-east-1 +AWS_BUCKET= + +PUSHER_APP_ID= +PUSHER_APP_KEY= +PUSHER_APP_SECRET= +PUSHER_APP_CLUSTER=mt1 + +VITE_APP_NAME="${APP_NAME}" +VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}" +VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" \ No newline at end of file diff --git a/php_code/public/assets/css/permit_show.css b/php_code/public/assets/css/permit_show.css new file mode 100644 index 00000000..1a40f523 --- /dev/null +++ b/php_code/public/assets/css/permit_show.css @@ -0,0 +1,108 @@ + @media (max-width: 768px) { + #permit-map { height: 350px; } + } + /* Container for the entire timeline */ + .timeline { + position: relative; + padding-left: 2rem; /* Creates space for the vertical line and icons */ + margin-top: 1rem; + } + + /* The Vertical Line */ + .timeline::before { + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0.85rem; /* Centers the line behind the 32px icons */ + width: 2px; + background-color: #dee2e6; /* Standard Bootstrap gray border */ + z-index: 0; + } + + /* Wrapper for each timeline event */ + .timeline-item { + position: relative; + margin-bottom: 1.5rem; + } + + /* The Circular Icons / Dots */ + .timeline-icon { + position: absolute; + top: 0; + left: -2rem; /* Pulls the icon left to sit precisely on the vertical line */ + width: 32px; + height: 32px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 1rem; + z-index: 1; /* Ensures icons sit above the vertical line */ + } + + /* The Event Content Box */ + .timeline-content { + margin-left: 0.5rem; /* Pushes the card slightly away from the icon */ + background-color: #fff; + transition: all 0.2s ease; + } + + .timeline-content:hover { + box-shadow: 0 .5rem 1rem rgba(0,0,0,.08)!important; + } + + /* Vertical Line */ +.planning-stepper { + position: relative; + padding-left: 1.25rem; +} +.planning-stepper::before { + content: ''; + position: absolute; + top: 6px; + bottom: 0; + left: 4px; /* Centers the line exactly under the dots */ + width: 2px; + background-color: #e9ecef; /* Bootstrap light gray */ + z-index: 0; +} + +/* Individual Steps */ +.stepper-item { + position: relative; + padding-bottom: 1.75rem; +} +.stepper-item:last-child { + padding-bottom: 0; /* Removes extra space at the bottom of the list */ +} + +/* The Dots */ +.stepper-dot { + position: absolute; + left: -1.25rem; + top: 0.25rem; + width: 10px; + height: 10px; + border-radius: 50%; + z-index: 1; + background-color: #dee2e6; /* Default pending gray */ +} + +/* Dot States */ +.stepper-dot.completed { + background-color: #20c997; /* Teal/Success green */ +} +.stepper-dot.active { + background-color: #fd7e14; /* Orange */ + box-shadow: 0 0 0 5px rgba(253, 126, 20, 0.15); /* Soft orange halo */ +} +.stepper-dot.pending { + background-color: #e2e8f0; /* Muted gray */ +} + +/* Faded text state for pending items */ +.stepper-item.pending .step-title, +.stepper-item.pending .step-desc { + opacity: 0.6; +} \ No newline at end of file diff --git a/php_code/public/assets/js/add_edit_user copy 2.js b/php_code/public/assets/js/add_edit_user copy 2.js new file mode 100644 index 00000000..f2054b9b --- /dev/null +++ b/php_code/public/assets/js/add_edit_user copy 2.js @@ -0,0 +1,477 @@ +$(document).ready(function () { + + let iti; + + $('#editUserModal').on('shown.bs.modal', function () { + const phoneInput = document.querySelector("#editPhone"); + if (!iti) { + iti = window.intlTelInput(phoneInput, { + initialCountry: "gh", + onlyCountries: ["gh"], + nationalMode: false, + autoPlaceholder: "polite", + utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/js/utils.js" + }); + + phoneInput.addEventListener("blur", function () { + let rawNumber = phoneInput.value.trim(); + console.log(rawNumber); + if (rawNumber.startsWith("0")) { + rawNumber = rawNumber.substring(1); + phoneInput.value = "+233" + rawNumber; + } + if (iti.isValidNumber()) { + phoneInput.value = iti.getNumber(); // clean +233XXXXXXXXX + } + }); + } + }); + + $('#addUserModal').on('shown.bs.modal', function () { + const phoneInput = document.querySelector("#addUserphone"); + if (!iti) { + iti = window.intlTelInput(phoneInput, { + initialCountry: "gh", + onlyCountries: ["gh"], + nationalMode: false, + autoPlaceholder: "polite", + utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/js/utils.js" + }); + + phoneInput.addEventListener("blur", function () { + let rawNumber = phoneInput.value.trim(); + + if (rawNumber.startsWith("0")) { + rawNumber = rawNumber.substring(1); + phoneInput.value = "+233" + rawNumber; + } + if (iti.isValidNumber()) { + phoneInput.value = iti.getNumber(); + } + }); + } + }); + + let lastTrigger = null; + // When edit modal closes, return focus to trigger + $('#editUserModal').on('hidden.bs.modal', function(){ + if (lastTrigger && document.contains(lastTrigger)) lastTrigger.focus(); + lastTrigger = null; + }); + + // Submit edit (updates row inline) + $('#editFormXX').on('submit', function(e){ + e.preventDefault(); + const id = $('#editId').val(); + const name = $('#editName').val(); + const email = $('#editEmail').val(); + const category = $('#editCategory').val(); + + const row = $(`.user-row[data-id="${id}"]`); + row.data('name', name).data('email', email).data('category', category); + row.find('.fw-semibold').text(name); + row.find('td').eq(2).text(email); + row.find('.category-badge').removeClass('badge-district badge-regional badge-national'); + if (category === 'District') row.find('.category-badge').addClass('badge-district').text('District'); + if (category === 'Regional') row.find('.category-badge').addClass('badge-regional').text('Regional'); + if (category === 'National') row.find('.category-badge').addClass('badge-national').text('National'); + const targetBody = category === 'District' ? '#districtBody' : (category === 'Regional' ? '#regionalBody' : '#nationalBody'); + if (!row.parent().is(targetBody)) { + row.appendTo($(targetBody)); + } + + updateCounts(); + $('#editModal').modal('hide'); + }); + + + var selectedValue = $("input[name='user_type']:checked").val(); + const $dropdown = $("#uaPostionAdd"); + + const optionsMap = { + 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"] + + }; + $dropdown.empty(); + $dropdown.append(''); + + if (optionsMap['district_user']) { + $.each(optionsMap['district_user'], function(index, value) { + $dropdown.append($("").attr("value", value.toLowerCase()).text(value)); + }); + } + + $("input[name='user_type']").change(function() { + var userValue = $(this).val(); + if (userValue == 'district_user') { + $('#regionID').prop('disabled', false); + $('#districtID').prop('disabled', false); + + $('#editRegionID').prop('disabled', false); + $('#editdistrictID').prop('disabled', false); + + } + if (userValue == 'national_luspa') { + $('#regionID').prop('disabled', true); + $('#districtID').prop('disabled', true); + + $('#editRegionID').prop('disabled', true); + $('#editdistrictID').prop('disabled', true); + + } + if (userValue == 'regional_luspa') { + $('#districtID').prop('disabled', true); + $('#regionID').prop('disabled', false); + + $('#editdistrictID').prop('disabled', true); + $('#editRegionID').prop('disabled', false); + + } + + $dropdown.empty(); + $dropdown.append(''); + + if (optionsMap[userValue]) { + $.each(optionsMap[userValue], function(index, value) { + $dropdown.append($("") + .attr("value", value.toLowerCase()) + .text(value)); + }); + } + + }); + + + + $('#editAllowedApps').select2({ + dropdownParent: $('#editUserModal'), + placeholder : "Select options, multiple allowed" + }); + + $('#allowedApps').select2({ + dropdownParent: $('#addUserModal'), + placeholder : "Select options, multiple allowed" + }); + + $('#inputPermissions').select2({ + dropdownParent: $('#editUserModal'), + placeholder : "Select options, multiple allowed" + }); + + $('.editUserBtn').click(function(evnt){ + evnt.preventDefault(); + // var selectedUserId = $(this).siblings('.userIdinput').val(); + const row = $(this).closest('.user-row'); + var selectedUserId = row.data('id'); + console.log('selectedUserId'); + lastTrigger = this; + + // $('#editId').val(row.data('id')); + + const formData = new FormData(); + formData.append('user_id', selectedUserId); + + $.ajax({ + url: base_url + '/users/edit/' + selectedUserId, + type: 'GET', + processData: false, + contentType: false, + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'crossDomain': false + }, + beforeSend: function() { + $('#editSuccessArea').text(""); + $('#editErrorArea').text("Please wait ... loading user details!!"); + }, + success: function(data) { + $('#editErrorArea').text(''); + var jason = data.data; + if(data.success == true){ + var allowedAppsArray = []; + if (jason['allowed_apps']) { + allowedAppsArray = jason['allowed_apps'].split(","); + } + $('#editFullName').val(jason['full_name']); + $('#editEmail').val(jason['email']); + $('#editUsername').val(jason['username']); + $('#editGender').val(jason['gender']); + $('#editTitle').val(jason['title']); + $('#editUaPostion').val(jason['ua_position']); + $('#editPhone').val(jason['phone']); + $('#editAllowedApps').val(allowedAppsArray).trigger('change'); + $('#editRegionID').val(jason['region_id']); + $('#editDistrictId').val(jason['district_id']); + $('#editUaPostion').val(jason['ua_position']); + $('#editGender').val(jason['gender']); + $("input[name='user_id']").val(jason.user_id); + + } + //$('#editUserModal').modal('show'); + }, + error: function(xhr, status, error) { + console.error('Error:', error); + $('#errorArea').text(error); + $('#errorArea').text(error); + } + }); + + }); + $("#editUserForm").submit(function(evt){ + evt.preventDefault(); + const $successArea = $("#editSuccessArea"); + const $errorArea = $("#editErrorArea"); + $('#editSuccessArea').addClass('d-none'); + $('#editErrorArea').removeClass('d-none'); + + const formData = new FormData($(this)[0]); + // formData = new FormData(this); + let errors = []; + if (iti) { + let formattedPhone = iti.getNumber(); + if (formattedPhone.startsWith("+2330")) { + formattedPhone = "+233" + formattedPhone.substring(5); + } + formattedPhone = formattedPhone.trim(); + if (!iti.isValidNumber()) { + errors.push("001 | Please enter a valid Ghana phone number."); + } else { + formData.set("phone", formattedPhone); + } + } + const username = $("#editUsername").val().trim(); + const email = $("#editEmail").val().trim(); + const fullName = $("#editFullName").val().trim(); + + if (!fullName) errors.push("Full name is required."); + if (!username) errors.push("Username is required."); + if (!email) { + errors.push("Email is required."); + } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { + errors.push("Invalid email format."); + } + + if (errors.length > 0) { + $('#editSuccessArea').addClass("d-none").text(""); + $errorArea.removeClass("d-none").html(errors.join("
")); + return; + } + + + $.ajax({ + url: base_url + '/userupdate', + type: 'POST', + data: formData, + dataType: 'json', + processData: false, + contentType: false, + beforeSend: function() { + // $('#updateBtn').addClass('d-none'); + // $('#uodateProgressBtn').removeClass('d-none'); + // $('#updateResultsDiv').removeClass('d-none'); + // $('#updateResultsParagraph').text("Processing Please wait ..."); + }, + success: function(data) { + console.log(data); + console.log(data['success']); + if (data['success'] == true) { + $('#editSuccessArea').removeClass('d-none'); + $('#editErrorArea').addClass('d-none'); + $('#editSuccessArea').text(""); + $('#editSuccessArea').text("User successfully details updated!"); + $.alert({ + title: 'Alert!', + content: 'User successfully details updated!!', + }); + setTimeout(() => location.reload(), 2000); + } + else{ + $('#editErrorArea').removeClass('d-none'); + $('#editErrorArea').text(data['msg']); + $.alert({ + title: 'Alert!', + content: data['msg'], + }); + } + }, + error: function(xhr, status, error) { + console.error('Error:', error); + $('#editErrorArea').removeClass('d-none'); + $('#editErrorArea').text(error); + + if (xhr.status === 422) { + // Laravel validation error + let errors = xhr.responseJSON.errors; + let messages = []; + + $.each(errors, function (field, msgs) { + messages.push(msgs.join("
")); + }); + + $('#editErrorArea').removeClass("d-none").html(messages.join("
")); + + $.alert({ + title: "Validation Error", + content: messages.join("
"), + }); + } else { + $('#editErrorArea').removeClass('d-none').text("Request failed : " + error); + + $.alert({ + title: "Error", + content: "Request failed: " + error, + }); + } + } + }); + }); + $('#regionID').change(function(){ + console.log('change is coming'); + var options = $('#districtID'); + var region_id = $('#regionID').val(); + $.ajax({ + url: base_url + '/admin/districts/' + region_id, + type: 'GET', + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'crossDomain': false + }, + success: function(data) { + $.each(data['districts'], function(id, row) { + $('#districtID').append($("'); + + if (optionsMap['district_user']) { + $.each(optionsMap['district_user'], function(index, value) { + $dropdown.append($("").attr("value", value.toLowerCase()).text(value)); + }); + } + + $("input[name='user_type']").change(function() { + var userValue = $(this).val(); + if (userValue == 'district_user') { + $('#regionID').prop('disabled', false); + $('#districtID').prop('disabled', false); + + $('#editRegionID').prop('disabled', false); + $('#editdistrictID').prop('disabled', false); + + } + if (userValue == 'national_luspa') { + $('#regionID').prop('disabled', true); + $('#districtID').prop('disabled', true); + + $('#editRegionID').prop('disabled', true); + $('#editdistrictID').prop('disabled', true); + + } + if (userValue == 'regional_luspa') { + $('#districtID').prop('disabled', true); + $('#regionID').prop('disabled', false); + + $('#editdistrictID').prop('disabled', true); + $('#editRegionID').prop('disabled', false); + + } + + $dropdown.empty(); + $dropdown.append(''); + + if (optionsMap[userValue]) { + $.each(optionsMap[userValue], function(index, value) { + $dropdown.append($("") + .attr("value", value.toLowerCase()) + .text(value)); + }); + } + + }); + + + + $('#editAllowedApps').select2({ + dropdownParent: $('#editUserModal'), + placeholder : "Select options, multiple allowed" + }); + + $('#allowedApps').select2({ + dropdownParent: $('#addUserModal'), + placeholder : "Select options, multiple allowed" + }); + + $('#inputPermissions').select2({ + dropdownParent: $('#editUserModal'), + placeholder : "Select options, multiple allowed" + }); + + $('.editUserBtn').click(function(evnt){ + evnt.preventDefault(); + // var selectedUserId = $(this).siblings('.userIdinput').val(); + const row = $(this).closest('.user-row'); + var selectedUserId = row.data('id'); + console.log('selectedUserId'); + lastTrigger = this; + + // $('#editId').val(row.data('id')); + + const formData = new FormData(); + formData.append('user_id', selectedUserId); + + $.ajax({ + url: base_url + '/users/edit/' + selectedUserId, + type: 'GET', + processData: false, + contentType: false, + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'crossDomain': false + }, + beforeSend: function() { + $('#editSuccessArea').text(""); + $('#editErrorArea').text("Please wait ... loading user details!!"); + }, + success: function(data) { + $('#editErrorArea').text(''); + var jason = data.data; + if(data.success == true){ + var allowedAppsArray = []; + if (jason['allowed_apps']) { + allowedAppsArray = jason['allowed_apps'].split(","); + } + $('#editFullName').val(jason['full_name']); + $('#editEmail').val(jason['email']); + $('#editUsername').val(jason['username']); + $('#editGender').val(jason['gender']); + $('#editTitle').val(jason['title']); + $('#editUaPostion').val(jason['ua_position']); + $('#editPhone').val(jason['phone']); + $('#editAllowedApps').val(allowedAppsArray).trigger('change'); + $('#editRegionID').val(jason['region_id']); + $('#editDistrictId').val(jason['district_id']); + $('#editUaPostion').val(jason['ua_position']); + $('#editGender').val(jason['gender']); + $("input[name='user_id']").val(jason.user_id); + + } + //$('#editUserModal').modal('show'); + }, + error: function(xhr, status, error) { + console.error('Error:', error); + $('#errorArea').text(error); + $('#errorArea').text(error); + } + }); + + }); + $("#editUserForm").submit(function(evt){ + evt.preventDefault(); + const $successArea = $("#editSuccessArea"); + const $errorArea = $("#editErrorArea"); + $('#editSuccessArea').addClass('d-none'); + $('#editErrorArea').removeClass('d-none'); + + const formData = new FormData($(this)[0]); + // formData = new FormData(this); + let errors = []; + if (iti) { + let formattedPhone = iti.getNumber(); + if (formattedPhone.startsWith("+2330")) { + formattedPhone = "+233" + formattedPhone.substring(5); + } + formattedPhone = formattedPhone.trim(); + if (!iti.isValidNumber()) { + errors.push("001 | Please enter a valid Ghana phone number."); + } else { + formData.set("phone", formattedPhone); + } + } + const username = $("#editUsername").val().trim(); + const email = $("#editEmail").val().trim(); + const fullName = $("#editFullName").val().trim(); + + if (!fullName) errors.push("Full name is required."); + if (!username) errors.push("Username is required."); + if (!email) { + errors.push("Email is required."); + } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { + errors.push("Invalid email format."); + } + + if (errors.length > 0) { + $('#editSuccessArea').addClass("d-none").text(""); + $errorArea.removeClass("d-none").html(errors.join("
")); + return; + } + + + $.ajax({ + url: base_url + '/userupdate', + type: 'POST', + data: formData, + dataType: 'json', + processData: false, + contentType: false, + beforeSend: function() { + // $('#updateBtn').addClass('d-none'); + // $('#uodateProgressBtn').removeClass('d-none'); + // $('#updateResultsDiv').removeClass('d-none'); + // $('#updateResultsParagraph').text("Processing Please wait ..."); + }, + success: function(data) { + console.log(data); + console.log(data['success']); + if (data['success'] == true) { + $('#editSuccessArea').removeClass('d-none'); + $('#editErrorArea').addClass('d-none'); + $('#editSuccessArea').text(""); + $('#editSuccessArea').text("User successfully details updated!"); + $.alert({ + title: 'Alert!', + content: 'User successfully details updated!!', + }); + setTimeout(() => location.reload(), 2000); + } + else{ + $('#editErrorArea').removeClass('d-none'); + $('#editErrorArea').text(data['msg']); + $.alert({ + title: 'Alert!', + content: data['msg'], + }); + } + }, + error: function(xhr, status, error) { + console.error('Error:', error); + $('#editErrorArea').removeClass('d-none'); + $('#editErrorArea').text(error); + + if (xhr.status === 422) { + // Laravel validation error + let errors = xhr.responseJSON.errors; + let messages = []; + + $.each(errors, function (field, msgs) { + messages.push(msgs.join("
")); + }); + + $('#editErrorArea').removeClass("d-none").html(messages.join("
")); + + $.alert({ + title: "Validation Error", + content: messages.join("
"), + }); + } else { + $('#editErrorArea').removeClass('d-none').text("Request failed : " + error); + + $.alert({ + title: "Error", + content: "Request failed: " + error, + }); + } + } + }); + }); + $('#regionID').change(function(){ + console.log('change is coming'); + var options = $('#districtID'); + var region_id = $('#regionID').val(); + $.ajax({ + url: base_url + '/admin/districts/' + region_id, + type: 'GET', + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'crossDomain': false + }, + success: function(data) { + $.each(data['districts'], function(id, row) { + $('#districtID').append($("'); + if (optionsMap[userType]) { + $.each(optionsMap[userType], function(index, value) { + targetDropdown.append($("").attr("value", value.toLowerCase()).text(value)); + }); + } + } + + let initialUserType = $("input[name='user_type']:checked").val(); + if(initialUserType) populatePositions(initialUserType, $("#uaPostionAdd")); + + // Handle Radio Changes + $("input[name='user_type']").change(function() { + let userType = $(this).val(); + + let isDistrict = (userType === 'district_user'); + let isRegional = (userType === 'regional_luspa'); + + $('#regionID, #editRegionID').prop('disabled', !isDistrict && !isRegional); + $('#districtID, #editdistrictID').prop('disabled', !isDistrict); + + populatePositions(userType, $("#uaPostionAdd")); + }); + + + $('.regionIDD').change(function() { + let region_id = $(this).val(); + let $districtSelect = $('.districtIDD'); + + $districtSelect.empty().append(''); + + if(!region_id) return; + + $.ajax({ + url: base_url + '/admin/districts/' + region_id, + type: 'GET', + success: function(data) { + if(data.districts) { + $.each(data.districts, function(id, row) { + $districtSelect.append($("'); + + if (optionsMap['district_user']) { + $.each(optionsMap['district_user'], function(index, value) { + $dropdown.append($("").attr("value", value.toLowerCase()).text(value)); + }); + } + + $("input[name='user_type']").change(function() { + var userValue = $(this).val(); + if (userValue == 'district_user') { + $('#regionID').prop('disabled', false); + $('#districtID').prop('disabled', false); + + $('#editRegionID').prop('disabled', false); + $('#editdistrictID').prop('disabled', false); + + } + if (userValue == 'national_luspa') { + $('#regionID').prop('disabled', true); + $('#districtID').prop('disabled', true); + + $('#editRegionID').prop('disabled', true); + $('#editdistrictID').prop('disabled', true); + + } + if (userValue == 'regional_luspa') { + $('#districtID').prop('disabled', true); + $('#regionID').prop('disabled', false); + + $('#editdistrictID').prop('disabled', true); + $('#editRegionID').prop('disabled', false); + + } + + $dropdown.empty(); + $dropdown.append(''); + + if (optionsMap[userValue]) { + $.each(optionsMap[userValue], function(index, value) { + $dropdown.append($("") + .attr("value", value.toLowerCase()) + .text(value)); + }); + } + + }); + + + + $('#editAllowedApps').select2({ + dropdownParent: $('#editUserModal'), + placeholder : "Select options, multiple allowed" + }); + + $('#allowedApps').select2({ + dropdownParent: $('#addUserModal'), + placeholder : "Select options, multiple allowed" + }); + + $('#inputPermissions').select2({ + dropdownParent: $('#editUserModal'), + placeholder : "Select options, multiple allowed" + }); + + $('.editUserBtn').click(function(evnt){ + evnt.preventDefault(); + // var selectedUserId = $(this).siblings('.userIdinput').val(); + const row = $(this).closest('.user-row'); + var selectedUserId = row.data('id'); + console.log('selectedUserId'); + lastTrigger = this; + + // $('#editId').val(row.data('id')); + + const formData = new FormData(); + formData.append('user_id', selectedUserId); + + $.ajax({ + url: base_url + '/users/edit/' + selectedUserId, + type: 'GET', + processData: false, + contentType: false, + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'crossDomain': false + }, + beforeSend: function() { + $('#editSuccessArea').text(""); + $('#editErrorArea').text("Please wait ... loading user details!!"); + }, + success: function(data) { + $('#editErrorArea').text(''); + var jason = data.data; + if(data.success == true){ + var allowedAppsArray = []; + if (jason['allowed_apps']) { + allowedAppsArray = jason['allowed_apps'].split(","); + } + $('#editFullName').val(jason['full_name']); + $('#editEmail').val(jason['email']); + $('#editUsername').val(jason['username']); + $('#editGender').val(jason['gender']); + $('#editTitle').val(jason['title']); + $('#editUaPostion').val(jason['ua_position']); + $('#editPhone').val(jason['phone']); + $('#editAllowedApps').val(allowedAppsArray).trigger('change'); + $('#editRegionID').val(jason['region_id']); + $('#editDistrictId').val(jason['district_id']); + $('#editUaPostion').val(jason['ua_position']); + $('#editGender').val(jason['gender']); + $("input[name='user_id']").val(jason.user_id); + + } + //$('#editUserModal').modal('show'); + }, + error: function(xhr, status, error) { + console.error('Error:', error); + $('#errorArea').text(error); + $('#errorArea').text(error); + } + }); + + }); + $("#editUserForm").submit(function(evt){ + evt.preventDefault(); + const $successArea = $("#editSuccessArea"); + const $errorArea = $("#editErrorArea"); + $('#editSuccessArea').addClass('d-none'); + $('#editErrorArea').removeClass('d-none'); + + const formData = new FormData($(this)[0]); + // formData = new FormData(this); + let errors = []; + if (iti) { + let formattedPhone = iti.getNumber(); + if (formattedPhone.startsWith("+2330")) { + formattedPhone = "+233" + formattedPhone.substring(5); + } + formattedPhone = formattedPhone.trim(); + if (!iti.isValidNumber()) { + errors.push("001 | Please enter a valid Ghana phone number."); + } else { + formData.set("phone", formattedPhone); + } + } + const username = $("#editUsername").val().trim(); + const email = $("#editEmail").val().trim(); + const fullName = $("#editFullName").val().trim(); + + if (!fullName) errors.push("Full name is required."); + if (!username) errors.push("Username is required."); + if (!email) { + errors.push("Email is required."); + } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { + errors.push("Invalid email format."); + } + + if (errors.length > 0) { + $('#editSuccessArea').addClass("d-none").text(""); + $errorArea.removeClass("d-none").html(errors.join("
")); + return; + } + + + $.ajax({ + url: base_url + '/userupdate', + type: 'POST', + data: formData, + dataType: 'json', + processData: false, + contentType: false, + beforeSend: function() { + // $('#updateBtn').addClass('d-none'); + // $('#uodateProgressBtn').removeClass('d-none'); + // $('#updateResultsDiv').removeClass('d-none'); + // $('#updateResultsParagraph').text("Processing Please wait ..."); + }, + success: function(data) { + console.log(data); + console.log(data['success']); + if (data['success'] == true) { + $('#editSuccessArea').removeClass('d-none'); + $('#editErrorArea').addClass('d-none'); + $('#editSuccessArea').text(""); + $('#editSuccessArea').text("User successfully details updated!"); + $.alert({ + title: 'Alert!', + content: 'User successfully details updated!!', + }); + setTimeout(() => location.reload(), 2000); + } + else{ + $('#editErrorArea').removeClass('d-none'); + $('#editErrorArea').text(data['msg']); + $.alert({ + title: 'Alert!', + content: data['msg'], + }); + } + }, + error: function(xhr, status, error) { + console.error('Error:', error); + $('#editErrorArea').removeClass('d-none'); + $('#editErrorArea').text(error); + + if (xhr.status === 422) { + // Laravel validation error + let errors = xhr.responseJSON.errors; + let messages = []; + + $.each(errors, function (field, msgs) { + messages.push(msgs.join("
")); + }); + + $('#editErrorArea').removeClass("d-none").html(messages.join("
")); + + $.alert({ + title: "Validation Error", + content: messages.join("
"), + }); + } else { + $('#editErrorArea').removeClass('d-none').text("Request failed : " + error); + + $.alert({ + title: "Error", + content: "Request failed: " + error, + }); + } + } + }); + }); + $('#regionID').change(function(){ + console.log('change is coming'); + var options = $('#districtID'); + var region_id = $('#regionID').val(); + $.ajax({ + url: base_url + '/admin/districts/' + region_id, + type: 'GET', + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'crossDomain': false + }, + success: function(data) { + $.each(data['districts'], function(id, row) { + $('#districtID').append($("'); + + if (optionsMap['district_user']) { + $.each(optionsMap['district_user'], function(index, value) { + $dropdown.append($("").attr("value", value.toLowerCase()).text(value)); + }); + } + + $("input[name='user_type']").change(function() { + var userValue = $(this).val(); + if (userValue == 'district_user') { + $('#regionID').prop('disabled', false); + $('#districtID').prop('disabled', false); + + } + if (userValue == 'national_luspa') { + $('#regionID').prop('disabled', true); + $('#districtID').prop('disabled', true); + + } + if (userValue == 'regional_luspa') { + $('#districtID').prop('disabled', true); + $('#regionID').prop('disabled', false); + + } + + $dropdown.empty(); + $dropdown.append(''); + + if (optionsMap[userValue]) { + $.each(optionsMap[userValue], function(index, value) { + $dropdown.append($("") + .attr("value", value.toLowerCase()) + .text(value)); + }); + } + + }); + + + + $('#editAllowedApps').select2({ + dropdownParent: $('#editUserModal'), + placeholder : "Select options, multiple allowed" + }); + + $('#allowedApps').select2({ + dropdownParent: $('#addUserModal'), + placeholder : "Select options, multiple allowed" + }); + + $('#inputPermissions').select2({ + dropdownParent: $('#editUserModal'), + placeholder : "Select options, multiple allowed" + }); + + $('.editUserBtn').click(function(evnt){ + evnt.preventDefault(); + var selectedUserId = $(this).siblings('.userIdinput').val(); + + const formData = new FormData(); + formData.append('user_id', selectedUserId); + + $.ajax({ + url: base_url + '/users/edit/' + selectedUserId, + type: 'GET', + processData: false, + contentType: false, + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'crossDomain': false + }, + beforeSend: function() { + $('#editSuccessArea').text(""); + $('#editErrorArea').text("Please wait ... loading user details!!"); + }, + success: function(data) { + $('#editErrorArea').text(''); + var jason = data.data; + if(data.success == true){ + var allowedAppsArray = []; + if (jason['allowed_apps']) { + allowedAppsArray = jason['allowed_apps'].split(","); + } + $('#editFullName').val(jason['full_name']); + $('#editEmail').val(jason['email']); + $('#editUsername').val(jason['username']); + $('#editGender').val(jason['gender']); + $('#editTitle').val(jason['title']); + $('#editUaPostion').val(jason['ua_position']); + $('#editPhone').val(jason['phone']); + $('#editAllowedApps').val(allowedAppsArray).trigger('change'); + $('#editRegionID').val(jason['region_id']); + $('#editDistrictId').val(jason['district_id']); + $('#editUaPostion').val(jason['ua_position']); + $('#editGender').val(jason['gender']); + $("input[name='user_id']").val(jason.user_id); + + } + //$('#editUserModal').modal('show'); + }, + error: function(xhr, status, error) { + console.error('Error:', error); + $('#errorArea').text(error); + $('#errorArea').text(error); + } + }); + + }); + + + + $('.viewUserBtn').click(function(evnt){ + evnt.preventDefault(); + var selectedUserId = $(this).siblings('.userIdinput').val(); + + const formData = new FormData(); + formData.append('user_id', selectedUserId); + + $.ajax({ + url: base_url + '/users/' + selectedUserId, + type: 'GET', + processData: false, + contentType: false, + beforeSend: function() { + $('#viewSuccessArea').text(""); + $('#viewErrorArea').text("Please wait ... loading user details!"); + }, + success: function(data) { + var jason = data.data; + if(data.success == true){ + var allowedAppsArray = []; + if (jason['allowed_apps']) { + allowedAppsArray = jason['allowed_apps'].split(","); + } + console.log(jason['full_name']); + $('#viewFullName').val(jason['full_name']); + $('#viewEmail').val(jason['email']); + $('#viewUsername').val(jason['username']); + $('#viewGender').val(jason['gender']); + $('#viewTitle').val(jason['title']); + $('#viewUaPostion').val(jason['ua_position']); + $('#viewPhone').val(jason['phone']); + $('#viewAllowedApps').val(allowedAppsArray).trigger('change'); + $('#viewRegionID').val(jason['region_id']); + $('#viewDistrictId').val(jason['district_id']); + $('#viewUaPostion').val(jason['ua_position']); + $('#viewGender').val(jason['gender']); + $("input[name='user_id']").val(jason.ua_id); + + } + //$('#editUserModal').modal('show'); + }, + error: function(xhr, status, error) { + console.error('Error:', error); + $('#errorArea').text(error); + $('#errorArea').text(error); + } + }); + + }); + + $("#newUserFormXX").submit(function(evt){ + evt.preventDefault(); + $('#newUserSuccessArea').addClass('d-none'); + $('#newUserErrorsArea').removeClass('d-none'); + var formData = new FormData($(this)[0]); + + $.ajax({ + url: base_url + '/users', + type: 'POST', + data: formData, + processData: false, + contentType: false, + beforeSend: function() { + $('#newUserSuccessArea').text(""); + $('#newUserSuccessArea').text("Please wait ... user creation in progress!"); + }, + success: function(data) { + console.log(data); + if (data['success'] == true) { + $('#newUserSuccessArea').removeClass('d-none'); + $('#newUserErrorsArea').addClass('d-none'); + + $('#newUserSuccessArea').text(""); + $('#newUserSuccessArea').text("User successfully created!"); + $.alert({ + title: 'Alert!', + content: 'User successfully created!', + }); + setTimeout(function() { + location.reload(); // Reloads the current page + }, 2000); + } + else{ + $('#newUserSuccessArea').addClass('d-none'); + $('#newUserErrorsArea').removeClass('d-none'); + $('#newUserErrorsArea').text(""); + $('#newUserErrorsArea').text(data['msg']); + $.alert({ + title: 'Alert!', + content: data['msg'], + }); + } + }, + error: function(xhr, status, error) { + console.error('Error:', error); + $('#newUserSuccessArea').text(error); + $('#newUserSuccessArea').text(error); + } + }); + }); + + $("#newUserForm").on("submit", function (evt) { + evt.preventDefault(); + + const $successArea = $("#newUserSuccessArea"); + const $errorArea = $("#newUserErrorArea"); // corrected selector + const formData = new FormData(this); + + // Example validation rules + const username = $("#username").val().trim(); + const email = $("#email").val().trim(); + const fullName = $("#fullName").val().trim(); + + let errors = []; + + if (!fullName) { + errors.push("Full name is required."); + } + if (!username) { + errors.push("Username is required."); + } + if (!email) { + errors.push("Email is required."); + } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { + errors.push("Invalid email format."); + } + + if (errors.length > 0) { + $successArea.addClass("d-none").text(""); + $errorArea.removeClass("d-none").html(errors.join("
")); + return; // Stop submission if validation fails + } + + // Reset messages + $successArea.addClass("d-none").text(""); + $errorArea.addClass("d-none").text(""); + + $.ajax({ + url: base_url + "/users", + type: "POST", + data: formData, + processData: false, + contentType: false, + beforeSend: function () { + $successArea.removeClass("d-none").text("Please wait ... user creation in progress!"); + }, + success: function (data) { + if (data.success) { + $successArea.removeClass("d-none").text("User successfully created!"); + $errorArea.addClass("d-none"); + + $.alert({ + title: "Success", + content: "User successfully created!", + }); + + setTimeout(() => location.reload(), 2000); + } else { + $successArea.addClass("d-none"); + $errorArea.removeClass("d-none").text(data.msg || "An error occurred."); + + $.alert({ + title: "Error", + content: data.msg || "An error occurred.", + }); + } + }, + error: function (xhr, status, error) { + $successArea.addClass("d-none"); + $errorArea.removeClass("d-none").text("Request failed: " + error); + + $.alert({ + title: "Error", + content: "Request failed: " + error, + }); + }, + }); + }); + + + + + $("#editUserForm").submit(function(evt){ + evt.preventDefault(); + $('#successArea').addClass('d-none'); + $('#errorsArea').removeClass('d-none'); + var formData = new FormData($(this)[0]); + $.ajax({ + url: base_url + '/userupdate', + type: 'POST', + data: formData, + dataType: 'json', + processData: false, + contentType: false, + beforeSend: function() { + // $('#updateBtn').addClass('d-none'); + // $('#uodateProgressBtn').removeClass('d-none'); + // $('#updateResultsDiv').removeClass('d-none'); + // $('#updateResultsParagraph').text("Processing Please wait ..."); + }, + success: function(data) { + console.log(data); + console.log(data['success']); + if (data['success'] == true) { + $('#editSuccessArea').removeClass('d-none'); + $('#editErrorArea').addClass('d-none'); + $('#editSuccessArea').text(""); + $('#editSuccessArea').text("User successfully details updated!"); + $.alert({ + title: 'Alert!', + content: 'User successfully details updated!!', + }); + } + else{ + $('#editErrorArea').removeClass('d-none'); + $('#editErrorArea').text(data['msg']); + $.alert({ + title: 'Alert!', + content: data['msg'], + }); + } + }, + error: function(xhr, status, error) { + console.error('Error:', error); + $('#editErrorArea').removeClass('d-none'); + $('#editErrorArea').text(error); + // location.reload(); + $.alert({ + title: 'Alert!', + content: error, + }); + } + }); + }); + + $('#regionID').change(function(){ + var options = $('#districtID'); + var region_id = $('#regionID').val(); + // $.get( base_url + '/admin/districts/' + region_id, function (data) { + // $('#districtID').empty(); + // $.each(data['districts'], function(id, row) { + // $('#districtID').append($("