diff --git a/Modules/HospitalPortal/Http/Controllers/Api/AuthController.php b/Modules/HospitalPortal/Http/Controllers/Api/AuthController.php index 55eaa1a7..bf221968 100644 --- a/Modules/HospitalPortal/Http/Controllers/Api/AuthController.php +++ b/Modules/HospitalPortal/Http/Controllers/Api/AuthController.php @@ -23,7 +23,6 @@ class AuthController extends Controller 'email' => $request->email, 'password' => $request->password ]; - $validator = Validator::make($request->all(), [ 'email' => 'required|email', 'password' => 'required' @@ -39,7 +38,7 @@ class AuthController extends Controller } else { - $user = User::with('getOrganization.organization')->where('email', $request->email)->first(); + $user = User::where('email', $request->email)->first(); if (!$user) { return ApiResponse::apiResponse('Not Found', $data, trans('message.not_found'), 404); } diff --git a/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php b/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php index e70991c4..54d56720 100644 --- a/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php +++ b/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php @@ -18,6 +18,7 @@ use Modules\HospitalPortal\Transformers\ClaimRequestShowResource; use PDF; use Illuminate\Support\Facades\DB; use Modules\HospitalPortal\Helpers\ApiResponse; +use Illuminate\Support\Facades\Validator; class ClaimRequestController extends Controller { @@ -63,90 +64,93 @@ class ClaimRequestController extends Controller */ public function store(Request $request) { - $request->validate([ + $data = [ + 'request_logs_id' => $request->request_logs_id, + 'member_id' => $request->member_id, + 'service_code' => $request->service_code + ]; + $validator = Validator::make($request->all(), [ + 'request_logs_id' => 'required', 'member_id' => 'required', 'service_code' => 'required' + ], [ + 'request_logs_id.required' => trans('Validation.required',['attribute' => 'Request Log ID']), + 'member_id.required' => trans('Validation.required',['attribute' => 'Member ID']), + 'service_code.required' => trans('Validation.required',['attribute' => 'Service Code']) ]); - $code = $this->getNextCode(); - $member = Member::find($request->member_id); - $newClaimRequest = ClaimRequestService::storeClaimRequest( - row: [], - code: $code, - member: $member, - paymentType: 'reimbursement', - serviceCode: $request->service_code - ); - - ClaimRequested::dispatch($newClaimRequest); - - // Log History - $newClaimRequest->histories()->create([ - 'title' => 'New Claim Requested', - 'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})", - 'type' => 'info', - 'system_origin' => 'hospital-portal' - ]); - - // Claim Log - DB::table('claim_logs') - ->insert([ - 'claim_request_id' => $newClaimRequest->id, - 'status' => 'requested', - 'date' => date('Y-m-d H:i:s'), - 'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})", - 'system_origin' => 'hospital-portal', - 'created_by' => auth()->user()->id, - 'created_at' => date('Y-m-d H:i:s'), - 'updated_at'=> date('Y-m-d H:i:s'), - ]); - - - if ($request->hasFile('result_files')) { - foreach ($request->result_files as $file) { - $pathFile = File::storeFile('claim-result', $newClaimRequest->id, $file); - $newClaimRequest->files()->updateOrCreate([ - 'type' => 'claim-result', - 'name' => File::getFileName('claim-result', $newClaimRequest->id, $file), - 'original_name' => $file->getClientOriginalName(), - 'extension' => $file->getClientOriginalExtension(), - 'path' => $pathFile, - 'created_by' => auth()->user()->id, - 'updated_by' => auth()->user()->id, - ]); - } + if ($validator->fails()) + { + return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400); } - - if ($request->hasFile('diagnosa_files')) { - foreach ($request->diagnosa_files as $file) { - $pathFile = File::storeFile('claim-diagnosis', $newClaimRequest->id, $file); - $newClaimRequest->files()->updateOrCreate([ - 'type' => 'claim-diagnosis', - 'name' => File::getFileName('claim-diagnosis', $newClaimRequest->id, $file), - 'original_name' => $file->getClientOriginalName(), - 'extension' => $file->getClientOriginalExtension(), - 'path' => $pathFile, - 'created_by' => auth()->user()->id, - 'updated_by' => auth()->user()->id, - ]); + else + { + $check_claim_requests = DB::table('claim_requests') + ->where('claim_requests.request_log_id', '=', $request->request_logs_id) + ->first(); + if(!$check_claim_requests) + { + try { + DB::beginTransaction(); + $code = $this->getNextCode(); + $member = Member::find($request->member_id); + $newClaimRequest = ClaimRequestService::storeClaimRequest( + row: [], + code: $code, + member: $member, + paymentType: 'reimbursement', + serviceCode: $request->service_code, + requestLogID: $request->request_logs_id, + ); + // Log History + $newClaimRequest->histories()->create([ + 'title' => 'New Claim Requested', + 'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})", + 'type' => 'info', + 'system_origin' => 'hospital-portal' + ]); + + // Claim Log + DB::table('claim_logs') + ->insert([ + 'claim_request_id' => $newClaimRequest->id, + 'status' => 'requested', + 'date' => date('Y-m-d H:i:s'), + 'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})", + 'system_origin' => 'hospital-portal', + 'created_by' => auth()->user()->id, + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at'=> date('Y-m-d H:i:s'), + ]); + + + if ($request->hasFile('additional_files')) { + foreach ($request->additional_files as $file) { + $pathFile = File::storeFile('additional-files', $newClaimRequest->id, $file); + $newClaimRequest->files()->updateOrCreate([ + 'type' => 'additional-files', + 'name' => File::getFileName('additional-files', $newClaimRequest->id, $file), + 'original_name' => $file->getClientOriginalName(), + 'extension' => $file->getClientOriginalExtension(), + 'path' => $pathFile, + 'created_by' => auth()->user()->id, + 'updated_by' => auth()->user()->id, + ]); + } + } + DB::commit(); + return ApiResponse::apiResponse('Success', $data, trans('Message.success'), 200); + } + catch (\Exception $e) { + DB::rollback(); + return ApiResponse::apiResponse("Error", $data, $e->getMessage(), 500); + } } - } - - if ($request->hasFile('kondisi_files')) { - foreach ($request->kondisi_files as $file) { - $pathFile = File::storeFile('claim-kondisi', $newClaimRequest->id, $file); - $newClaimRequest->files()->updateOrCreate([ - 'type' => 'claim-kondisi', - 'name' => File::getFileName('claim-kondisi', $newClaimRequest->id, $file), - 'original_name' => $file->getClientOriginalName(), - 'extension' => $file->getClientOriginalExtension(), - 'path' => $pathFile, - 'created_by' => auth()->user()->id, - 'updated_by' => auth()->user()->id, - ]); + else + { + return ApiResponse::apiResponse("Error", $data, trans('Message.already_exists'), 409); } + } - - return ApiResponse::apiResponse("Success", [], trans('message.success'), 200); } /** @@ -253,12 +257,13 @@ class ClaimRequestController extends Controller ->leftJoin('corporate_divisions', 'corporate_employees.division_id', '=', 'corporate_divisions.id') ->when($request->input('search'), function ($query, $search) { $query->where(function ($query) use ($search) { - $query->orWhere('claim_requests.code', 'like', "%" . $search . "%") + $query->orWhere('claim_requests.code', 'like', "%" . ($search == 'outpatient' || $search == 'Outpatient' ? 'OP' : 'IP') . "%") ->orWhere('members.member_id', 'like', "%" . $search . "%") ->orWhere('members.name', 'like', "%" . $search . "%") ->orWhere('corporate_divisions.name', 'like', "%" . $search . "%") ->orWhere('claim_requests.status', 'like', "%" . $search . "%") - ->orWhere('claim_requests.submission_date', 'like', "%" . $search . "%"); + ->orWhere('claim_requests.submission_date', 'like', "%" . $search . "%") + ->orWhere('claims.status', 'like', "%" . $search . "%"); }); }) ->when($request->has('orderBy'), function ($query) use ($request) { @@ -296,7 +301,12 @@ class ClaimRequestController extends Controller }); }) - ->select('members.id', 'claim_requests.code','members.member_id', 'members.name as full_name', 'corporate_divisions.name AS division_name', + ->select( + 'members.id', + 'claim_requests.code', + 'members.member_id', + 'members.name as full_name', + 'corporate_divisions.name AS division_name', DB::raw(' CASE WHEN claim_requests.status = "requested" THEN "requested" @@ -308,7 +318,16 @@ class ClaimRequestController extends Controller ELSE "" END AS status '), - 'claim_requests.id AS claim_request_id', 'claim_requests.submission_date') + 'claim_requests.id AS claim_request_id', + 'claim_requests.submission_date', + DB::raw(' + CASE + WHEN service_code = "OP" THEN "Outpatient" + WHEN service_code = "IP" THEN "Inpatient" + ELSE "" + END AS service_type + ') + ) ->paginate($limit); return response()->json(Helper::paginateResources($results)); } diff --git a/Modules/HospitalPortal/Http/Controllers/Api/MemberController.php b/Modules/HospitalPortal/Http/Controllers/Api/MemberController.php index b11abbb0..4a69d876 100644 --- a/Modules/HospitalPortal/Http/Controllers/Api/MemberController.php +++ b/Modules/HospitalPortal/Http/Controllers/Api/MemberController.php @@ -43,6 +43,7 @@ class MemberController extends Controller ->where('members.birth_date', '=', $request->birth_date) ->select( 'members.id', + 'members.name', 'members.member_id', 'member_policies.policy_id', 'persons.nik', @@ -54,26 +55,55 @@ class MemberController extends Controller 'members.race', 'members.relation_with_principal') ->first(); - $res_data['members'] = $members; + if($members) + { + $res_data['members'] = $members; - $benefits = DB::table('member_plans') - ->leftJoin('corporate_benefits','corporate_benefits.plan_id', '=', 'member_plans.plan_id') - ->leftJoin('benefits', 'benefits.id', '=', 'corporate_benefits.benefit_id') - ->where('member_plans.member_id', '=', $members->id) - ->select('benefits.description','benefits.code','corporate_benefits.corporate_id') - ->get(); - $res_data['benefits'] = $benefits; + $benefits = DB::table('member_plans') + ->leftJoin('corporate_benefits','corporate_benefits.plan_id', '=', 'member_plans.plan_id') + ->leftJoin('benefits', 'benefits.id', '=', 'corporate_benefits.benefit_id') + ->leftJoin('plans', 'plans.id', '=', 'member_plans.plan_id') + ->leftJoin('services', 'services.code', '=', 'plans.service_code') + ->where('member_plans.member_id', '=', $members->id) + ->select( + 'benefits.description', + 'benefits.code', + 'corporate_benefits.corporate_id', + 'plans.service_code' + ) + ->get(); + $res_data['benefits'] = $benefits; - $services = DB::table('member_plans') - ->leftJoin('plans', 'plans.id', '=', 'member_plans.plan_id') - ->leftJoin('services', 'services.code', '=', 'plans.service_code') - ->where('member_plans.member_id', $members->id) - ->select('plans.service_code', 'services.name') - ->get(); - $res_data['services'] = $services; + $services = DB::table('member_plans') + ->leftJoin('plans', 'plans.id', '=', 'member_plans.plan_id') + ->leftJoin('services', 'services.code', '=', 'plans.service_code') + ->where('member_plans.member_id', $members->id) + ->select('plans.service_code', 'services.name') + ->get(); + $res_data['services'] = $services; + // Group Services + $groupServices = []; + foreach ($res_data['benefits'] as $benefit) { + $serviceCode = $benefit->service_code; + $groupServices[$serviceCode][] = [ + 'description' => $benefit->description, + 'code' => $benefit->code, + ]; + } + + $res_data['groupServices'] = $groupServices; + + $res_data['type'] = $request->type; + + + return ApiResponse::apiResponse("Success", $res_data, trans('Message.success'), 200); + } + else + { + return ApiResponse::apiResponse("Data Not Found", $data, trans('Message.not_found'), 404); + } - return ApiResponse::apiResponse("Success", $res_data, trans('Message.success'), 200); } } } diff --git a/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php b/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php new file mode 100644 index 00000000..a3d8ea35 --- /dev/null +++ b/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php @@ -0,0 +1,284 @@ + $request->member_id, + 'service_code' => $request->service_code + ]; + $validator = Validator::make($request->all(), [ + 'member_id' => 'required', + 'service_code' => 'required' + ], [ + 'member_id.required' => trans('Validation.required',['attribute' => 'Member ID']), + 'service_code.required' => trans('Validation.required',['attribute' => 'Service Code']), + ]); + if ($validator->fails()) + { + return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400); + } + else + { + + $requestLogControllerInstance = new PrimeCenterRequestLog(); + $response = $requestLogControllerInstance->createNew($request); + + if($response->original['statusCode'] == 200) + { + return ApiResponse::apiResponse("Success", $data, trans('Message.success'), 200); + } + else + { + return ApiResponse::apiResponse('Server Error', $data, trans('Message.server_error'), 500); + } + } + } + + public function getRequestLog(Request $request) + { + + $limit = $request->has('per_page') ? $request->input('per_page') : 10; + + $results = DB::table('request_logs') + ->leftJoin('members', 'request_logs.member_id', '=', 'members.id') + ->when($request->input('search'), function ($query, $search) { + $query->where(function ($query) use ($search) { + $query->orWhere('request_logs.code', 'like', "%" . $search . "%") + ->orWhere('members.name', 'like', "%" . $search . "%") + ->orWhere('request_logs.submission_date', 'like', "%" . $search . "%"); + }); + }) + ->when($request->has('orderBy'), function ($query) use ($request) { + $orderBy = $request->orderBy; + $direction = $request->order ?? 'asc'; + + $query->orderBy($orderBy, $direction); + }) + ->when($request->input('start_date') && !$request->input('end_date'), function ($query, $start_date) { + $query->where(function ($query) use ($start_date) { + $query->where('request_logs.submission_date', '<', $start_date); + }); + }) + ->when($request->input('status'), function ($query, $status) { + $query->where(function ($query) use ($status) { + + if ($status === 'requested') { + $query->where('request_logs.status', '=', 'requested'); + } + + if ($status === 'reviewed') { + $query->where('request_logs.status', '=', 'approved'); + } + + if ($status === 'approved') { + $query->where('request_logs.status', '=', 'approved'); + } + + if ($status === 'declined') { + $query->where('request_logs.status', '=', 'declined'); + } + + }); + }) + ->select( + 'request_logs.id', + 'request_logs.final_log', + 'request_logs.code', + 'members.name as full_name', + 'members.member_id as no_polis', + 'members.birth_date', + DB::raw(' + CASE + WHEN request_logs.status = "requested" THEN "requested" + WHEN request_logs.status = "approved" THEN "approved" + WHEN request_logs.status = "declined" THEN "declined" + WHEN request_logs.status = "reviewed" THEN "reviewed" + ELSE "" + END AS status + '), + 'request_logs.submission_date') + ->paginate($limit); + return response()->json(Helper::paginateResources($results)); + } + + public function getFinalLog(Request $request) + { + + $limit = $request->has('per_page') ? $request->input('per_page') : 10; + + $results = DB::table('request_logs') + ->leftJoin('members', 'request_logs.member_id', '=', 'members.id') + ->when($request->input('search'), function ($query, $search) { + $query->where(function ($query) use ($search) { + $query->orWhere('request_logs.code', 'like', "%" . $search . "%") + ->orWhere('members.name', 'like', "%" . $search . "%") + ->orWhere('request_logs.submission_date', 'like', "%" . $search . "%") + ->orWhere('request_logs.service_code', 'like', "%" . ($search == 'outpatient' || $search == 'Outpatient' ? 'OP' : 'IP') . "%"); + }); + }) + ->when($request->has('orderBy'), function ($query) use ($request) { + $orderBy = $request->orderBy; + $direction = $request->order ?? 'asc'; + + $query->orderBy($orderBy, $direction); + }) + ->when($request->input('start_date') && !$request->input('end_date'), function ($query, $start_date) { + $query->where(function ($query) use ($start_date) { + $query->where('request_logs.submission_date', '<', $start_date); + }); + }) + ->when($request->input('status'), function ($query, $status) { + $query->where(function ($query) use ($status) { + + if ($status === 'requested') { + $query->where('request_logs.status_final_log', '=', 'requested'); + } + + if ($status === 'reviewed') { + $query->where('request_logs.status_final_log', '=', 'approved'); + } + + if ($status === 'approved') { + $query->where('request_logs.status_final_log', '=', 'approved'); + } + + if ($status === 'declined') { + $query->where('request_logs.status_final_log', '=', 'declined'); + } + + }); + }) + ->where('request_logs.final_log', '=', 1) + ->select( + 'request_logs.id', + 'request_logs.final_log', + 'request_logs.code', + 'members.name as full_name', + 'members.member_id as no_polis', + 'members.id AS member_id', + 'request_logs.service_code', + 'members.birth_date', + DB::raw(' + CASE + WHEN request_logs.status_final_log = "requested" THEN "requested" + WHEN request_logs.status_final_log = "approved" THEN "approved" + WHEN request_logs.status_final_log = "declined" THEN "declined" + WHEN request_logs.status_final_log = "reviewed" THEN "reviewed" + ELSE "" + END AS status + '), + 'request_logs.submission_date', + DB::raw(' + CASE + WHEN service_code = "OP" THEN "Outpatient" + WHEN service_code = "IP" THEN "Inpatient" + ELSE "" + END AS service_type + '), + DB::raw(' + (Select request_log_id FROM claim_requests WHERE claim_requests.request_log_id = request_logs.id LIMIT 1) AS check_claim + ') + ) + ->paginate($limit); + return response()->json(Helper::paginateResources($results)); + } + + public function requestFinalLog(Request $request) + { + $data = [ + 'request_logs_id' => $request->request_logs_id + ]; + $validator = Validator::make($request->all(), [ + 'request_logs_id' => 'required' + ], [ + 'request_logs_id.required' => trans('Validation.required',['attribute' => 'Request Logs ID']) + ]); + if ($validator->fails()) + { + return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400); + } + else + { + try { + DB::beginTransaction(); + DB::table('request_logs') + ->where('request_logs.id', '=', $request->request_logs_id) + ->update([ + 'status_final_log' => 'requested', + 'final_log' => 1 + ]); + if ($request->hasFile('result_files')) { + foreach ($request->result_files as $file) { + $pathFile = File::storeFile('final-log-result', $request->request_logs_id, $file); + File::updateOrCreate([ + 'fileable_type' => 'App\Models\RequestLog', + 'fileable_id' => $request->request_logs_id, + 'type' => 'final-log-result', + 'name' => File::getFileName('final-log-result', $request->request_logs_id, $file), + 'original_name' => $file->getClientOriginalName(), + 'extension' => $file->getClientOriginalExtension(), + 'path' => $pathFile, + 'created_by' => auth()->user()->id, + 'updated_by' => auth()->user()->id, + ]); + } + } + if ($request->hasFile('diagnosa_files')) { + foreach ($request->diagnosa_files as $file) { + $pathFile = File::storeFile('final-log-diagnosis', $request->request_logs_id, $file); + File::updateOrCreate([ + 'fileable_type' => 'App\Models\RequestLog', + 'fileable_id' => $request->request_logs_id, + 'type' => 'final-log-diagnosis', + 'name' => File::getFileName('final-log-diagnosis', $request->request_logs_id, $file), + 'original_name' => $file->getClientOriginalName(), + 'extension' => $file->getClientOriginalExtension(), + 'path' => $pathFile, + 'created_by' => auth()->user()->id, + 'updated_by' => auth()->user()->id, + ]); + } + } + if ($request->hasFile('kondisi_files')) { + foreach ($request->kondisi_files as $file) { + $pathFile = File::storeFile('final-log-kondisi', $request->request_logs_id, $file); + File::updateOrCreate([ + 'fileable_type' => 'App\Models\RequestLog', + 'fileable_id' => $request->request_logs_id, + 'type' => 'final-log-kondisi', + 'name' => File::getFileName('final-log-kondisi', $request->request_logs_id, $file), + 'original_name' => $file->getClientOriginalName(), + 'extension' => $file->getClientOriginalExtension(), + 'path' => $pathFile, + 'created_by' => auth()->user()->id, + 'updated_by' => auth()->user()->id, + ]); + } + } + DB::commit(); + return ApiResponse::apiResponse('Success', $data, trans('Message.success'), 200); + } + catch (\Exception $e) { + DB::rollback(); + return ApiResponse::apiResponse("Error", $data, $e->getMessage(), 500); + } + } + } +} diff --git a/Modules/HospitalPortal/Routes/api.php b/Modules/HospitalPortal/Routes/api.php index 2aff378c..fabf81c9 100644 --- a/Modules/HospitalPortal/Routes/api.php +++ b/Modules/HospitalPortal/Routes/api.php @@ -6,6 +6,7 @@ use Modules\HospitalPortal\Http\Controllers\Api\ClaimRequestController; use Modules\HospitalPortal\Http\Controllers\Api\MemberController; use Modules\HospitalPortal\Http\Controllers\ClaimController; use Modules\HospitalPortal\Http\Controllers\Api\NotificationController; +use Modules\HospitalPortal\Http\Controllers\Api\RequestLogController; use Modules\HospitalPortal\Http\Middleware\Authentication; use Modules\HospitalPortal\Http\Middleware\Authorization; @@ -47,6 +48,13 @@ Route::prefix('v1')->group(function() { Route::controller(MemberController::class)->group(function () { Route::post('search-member', 'search'); }); + // Request LOG + Route::controller(RequestLogController::class)->group(function () { + Route::post('request-log', 'requestLog'); + Route::get('get-request-log', 'getRequestLog'); + Route::get('get-final-log', 'getFinalLog'); + Route::post('request-final-log', 'requestFinalLog'); + }); //Notification Route::controller(NotificationController::class)->group(function() { //get notifications @@ -55,8 +63,16 @@ Route::prefix('v1')->group(function() { Route::post('set-read-notification', 'setReadNotification'); }); }); + // Request Final LOG + Route::controller(RequestLogController::class)->group(function () { + Route::post('request-final-log', 'requestFinalLog'); + }); + // Claim Submit + Route::controller(ClaimRequestController::class)->group(function () { + Route::post('claim-requests', 'store'); + }); Route::get('claim-requests', [ClaimRequestController::class, 'index'])->name('claim-requests.index'); - Route::post('claim-requests', [ClaimRequestController::class, 'store'])->name('claim-requests.store'); + // Route::post('claim-requests', [ClaimRequestController::class, 'store'])->name('claim-requests.store'); Route::get('claim-requests/{claim_request_id}/log', [ClaimRequestController::class, 'generateLog'])->name('claim-requests.generate-log'); Route::get('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show'); Route::get('get-claim-requests', [ClaimRequestController::class, 'get_claim_requests'])->name('claim-requests.get_claim_requests'); diff --git a/app/Models/ClaimRequest.php b/app/Models/ClaimRequest.php index c6f2c68b..6622efc4 100644 --- a/app/Models/ClaimRequest.php +++ b/app/Models/ClaimRequest.php @@ -27,7 +27,8 @@ class ClaimRequest extends Model 'status', 'claim_id', 'organization_id', - 'code' + 'code', + 'request_log_id' ]; protected $hidden = [ diff --git a/app/Models/File.php b/app/Models/File.php index f12dfdc3..627dc1a4 100644 --- a/app/Models/File.php +++ b/app/Models/File.php @@ -19,6 +19,8 @@ class File extends Model 'original_name', 'extension', 'path', + 'created_by', + 'updated_by', ]; protected $hidden = [ @@ -48,6 +50,7 @@ class File extends Model 'final-log-diagnosis' => 'final-log/', 'final-log-kondisi' => 'final-log/', 'docs' => 'docs/', + 'additional-files' => 'additional-files/', ]; public function fileable() diff --git a/app/Services/ClaimRequestService.php b/app/Services/ClaimRequestService.php index b03cabc9..71626fc4 100644 --- a/app/Services/ClaimRequestService.php +++ b/app/Services/ClaimRequestService.php @@ -20,7 +20,7 @@ use Str; class ClaimRequestService{ - public static function storeClaimRequest($row = null, $code, $member, $paymentType, $serviceCode, $submissionDate = null, $status = 'requested', $organization_code = null) + public static function storeClaimRequest($row = null, $code, $member, $paymentType, $serviceCode, $requestLogID, $submissionDate = null, $status = 'requested', $organization_code = null) { // try { $organization = False; @@ -38,6 +38,7 @@ class ClaimRequestService{ $claimRequestData = [ 'code' => $code, + 'request_log_id' => $requestLogID, 'member_id' => $member->id, 'submission_date' => $submissionDate ?? now(), 'status' => $status, diff --git a/frontend/hospital-portal/public/image/en-US.json b/frontend/hospital-portal/public/image/en-US.json deleted file mode 100644 index baef7538..00000000 --- a/frontend/hospital-portal/public/image/en-US.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "greeting": "Hello", - "buttonText": "Click Me", - "infoLogin": "Enter the registered account", - "txtLogin1" : "Sign in to Hospital Portal", - "txtLogin2" : "Enter your details below", - "txtCardSearchMember1" : "Guarantee Submission", - "txtCardSearchMember2" : "Find Member", - "txtCardSearchMember3" : "Date Birth", - "txtCardSearchMember4" : "Member ID", - "txtCardSearchMember5" : "Member", - "txtDialogMember1" : "Benefit Summary", - "txtDialogMember2" : "Request LOG", - "txtDialogMember3" : "Member Detail" -} diff --git a/frontend/hospital-portal/public/image/id-ID.json b/frontend/hospital-portal/public/image/id-ID.json deleted file mode 100644 index 41db3e54..00000000 --- a/frontend/hospital-portal/public/image/id-ID.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "greeting": "Halo", - "buttonText": "Klik Saya", - "infoLogin": "Masukan akun yang telah terdaftar", - "txtLogin1" : "Masuk ke Hospital Portal", - "txtLogin2" : "Masukkan detail Anda di bawah ini", - "txtCardSearchMember1" : "Pengajuan Jaminan", - "txtCardSearchMember2" : "Cari Anggota", - "txtCardSearchMember3" : "Tanggal Lahir", - "txtCardSearchMember4" : "Member ID", - "txtCardSearchMember5" : "Member", - "txtDialogMember1" : "Ringkasan Manfaat", - "txtDialogMember2" : "Request LOG", - "txtDialogMember3" : "Detail Member" -} diff --git a/frontend/hospital-portal/public/lang/en-US.json b/frontend/hospital-portal/public/lang/en-US.json index 7850d55b..c8060371 100644 --- a/frontend/hospital-portal/public/lang/en-US.json +++ b/frontend/hospital-portal/public/lang/en-US.json @@ -6,10 +6,33 @@ "txtLogin2" : "Enter your details below", "txtCardSearchMember1" : "Membership Query", "txtCardSearchMember2" : "Search Member", - "txtCardSearchMember3" : "Date Birth", + "txtCardSearchMember3" : "Date of Birth", "txtCardSearchMember4" : "Member ID", "txtCardSearchMember5" : "Member", - "txtDialogMember1" : "Benefit", + "txtDialogMember1" : "Services", "txtDialogMember2" : "Request LOG", - "txtDialogMember3" : "Detail" + "txtDialogMember3" : "Detail", + "txtDialogMember4" : "Please select services", + "txtDialogMember5" : "Submission Date", + "txtDateBirth" : "Date of Birth", + "txtGender" : "Gender", + "txtMaritalStatus" : "Marital Status", + "txtLanguage" : "Language", + "txtRelationship" : "Relationship", + "txtRequestDate" : "Request Date", + "txtMemberID" : "Member ID", + "txtClaimCode" : "Claim Code", + "txtRequestCode" : "Request Code", + "txtName" : "Name", + "txtStatus" : "Status", + "txtSearch" : "Search Name or Member ID...", + "txtAll" : "All", + "txtSubmissionDate" : "Submission Date", + "txtDataNotFound" : "Data Not Found", + "txtConditionDocument" : "Condition Document", + "txtDiagnosisDokument" : "Diagnosis Dokument", + "txtSupportingResultDocument" : "Supporting Result Document", + "txtAddResult" : "Add Result", + "txtServiceType" : "Service Type", + "txtAdditionalDocuments" : "Additional Documents" } diff --git a/frontend/hospital-portal/public/lang/id-ID.json b/frontend/hospital-portal/public/lang/id-ID.json index 182c705d..5ca6e767 100644 --- a/frontend/hospital-portal/public/lang/id-ID.json +++ b/frontend/hospital-portal/public/lang/id-ID.json @@ -9,7 +9,30 @@ "txtCardSearchMember3" : "Tanggal Lahir", "txtCardSearchMember4" : "Member ID", "txtCardSearchMember5" : "Member", - "txtDialogMember1" : "Manfaat", + "txtDialogMember1" : "Layanan", "txtDialogMember2" : "Request LOG", - "txtDialogMember3" : "Detail" + "txtDialogMember3" : "Detail", + "txtDialogMember4" : "Mohon pilih layanan", + "txtDialogMember5" : "Tanggal Pengajuan", + "txtDateBirth" : "Tanggal Lahir", + "txtGender" : "Jenis Kelamin", + "txtMaritalStatus" : "Status Perkawinan", + "txtLanguage" : "Bahasa", + "txtRelationship" : "Hubungan", + "txtRequestDate" : "Tanggal Permintaan", + "txtMemberID" : "ID Anggota", + "txtClaimCode" : "Kode Klaim", + "txtRequestCode" : "Kode Pengajuan", + "txtName" : "Nama", + "txtStatus" : "Status", + "txtSearch" : "Cari Nama atau ID Anggota...", + "txtAll" : "Semua", + "txtSubmissionDate" : "Tanggal Pengajuan", + "txtDataNotFound" : "Data Tidak Ditemukan", + "txtConditionDocument" : "Dokumen Kondisi", + "txtDiagnosisDokument" : "Dokumen Diagnosa", + "txtSupportingResultDocument" : "Dokumen Hasil Pendukung", + "txtAddResult" : "Tambah Hasil", + "txtServiceType" : "Tipe Layanan", + "txtAdditionalDocuments" : "Dokumen Tambahan" } diff --git a/frontend/hospital-portal/src/components/Table.tsx b/frontend/hospital-portal/src/components/Table.tsx index 172bb0a7..a60bc862 100644 --- a/frontend/hospital-portal/src/components/Table.tsx +++ b/frontend/hospital-portal/src/components/Table.tsx @@ -42,6 +42,8 @@ import { Download, Search as SearchIcon, Upload } from '@mui/icons-material'; import { DivisionDataProps, Order, PaginationTableProps, TableListProps } from '../@types/table'; import { InputAdornment } from '@mui/material'; import GetAppIcon from '@mui/icons-material/GetApp'; +import { LanguageContext } from '@/contexts/LanguageContext'; + /* --------------------------------- styled --------------------------------- */ const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({ height: 10, @@ -83,6 +85,8 @@ export default function Table({ ]); params.setAppliedParams(parameters); }; + + const { localeData }: any = useContext(LanguageContext); /* -------------------------------------------------------------------------- */ /* -------------------------- enchanced table head -------------------------- */ @@ -219,7 +223,7 @@ export default function Table({ ), }} - placeholder="Search Name or Member ID... " + placeholder={localeData.txtSearch} /> @@ -239,7 +243,7 @@ export default function Table({ ), }} - placeholder="Search Name or Member ID... " + placeholder={localeData.txtSearch} /> @@ -299,7 +303,7 @@ export default function Table({ label="Status" onChange={filterStatus.config.handleStatusChange} > - All + {localeData.txtAll} {filterStatus.config.filterData.map((row: StatusDataProps, index) => ( {row.name} @@ -336,7 +340,7 @@ export default function Table({ {/* End Table Header */} {/* Table Body */} - {loadings.isLoading && rows.length >= 1 ? ( + {loadings.isLoading ? ( Loading . . . @@ -358,7 +362,7 @@ export default function Table({ ) : ( - No Data Found + {localeData.txtDataNotFound} )} diff --git a/frontend/hospital-portal/src/layouts/dashboard/navbar/NavConfig.tsx b/frontend/hospital-portal/src/layouts/dashboard/navbar/NavConfig.tsx index 2e1efd95..33d562e3 100644 --- a/frontend/hospital-portal/src/layouts/dashboard/navbar/NavConfig.tsx +++ b/frontend/hospital-portal/src/layouts/dashboard/navbar/NavConfig.tsx @@ -12,7 +12,7 @@ const ICONS = { ecommerce: getIcon('ic_ecommerce'), analytics: getIcon('ic_analytics'), dashboard: getIcon('ic_dashboard'), - hospital: getIcon('ic_banking'), + ic_booking: getIcon('ic_booking'), }; const navConfig = [ @@ -21,6 +21,9 @@ const navConfig = [ { items: [{ title: 'Dashboard', path: '/dashboard', icon: ICONS.dashboard }], }, + { + items: [{ title: 'Claim', path: '/claim', icon: ICONS.ic_booking }], + }, // Membership // ---------------------------------------------------------------------- diff --git a/frontend/hospital-portal/src/layouts/dashboard/navbar/NavbarDocs.tsx b/frontend/hospital-portal/src/layouts/dashboard/navbar/NavbarDocs.tsx index a12453a1..5ede566c 100644 --- a/frontend/hospital-portal/src/layouts/dashboard/navbar/NavbarDocs.tsx +++ b/frontend/hospital-portal/src/layouts/dashboard/navbar/NavbarDocs.tsx @@ -25,7 +25,7 @@ export default function NavbarDocs() { - Hak Cipta © 2023 - 2024 Link Sehat + Hak Cipta © 2023 - 2024 Link Medis Sehat ); diff --git a/frontend/hospital-portal/src/pages/Claim.tsx b/frontend/hospital-portal/src/pages/Claim.tsx new file mode 100644 index 00000000..d06a81a5 --- /dev/null +++ b/frontend/hospital-portal/src/pages/Claim.tsx @@ -0,0 +1,119 @@ +// @mui +import { Typography, Container, Grid, Card } from '@mui/material'; +// hooks +import useSettings from '@/hooks/useSettings'; +// components +import Page from '@/components/Page'; +// theme +import CardNotification from '@/sections/dashboard/CardNotification'; +import CardSearchMember from '@/sections/dashboard/CardSearchMember' +import { useContext, useEffect, useState } from 'react'; +import axios from '@/utils/axios'; +import { Stack } from '@mui/system'; +import { Input } from '@mui/material'; +//sections +import TableList from '@/sections/claim/TableList'; +import { fDate } from '@/utils/formatTime'; +import DialogDetailClaim from '@/components/dialogs/DialogDetailClaim'; +import HeaderBreadcrumbs from "@/components/HeaderBreadcrumbs"; + +// ---------------------------------------------------------------------- + +// const [notifications, setNotifications] = useState([]) + +const itemList = [ + { info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '08:00 WIB' }, + { info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '09:00 WIB' }, + { info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '10:00 WIB' }, + { info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '11:00 WIB' }, +]; + +// ---------------------------------------------------------------------- + +/* ---------------------------------- types --------------------------------- */ + +type PolicyProps = { + myLimit: { + balance: number; + total: number; + percentage: number; + }; + lockLimit: { + balance: number; + percentage: number; + }; +}; + +/* -------------------------------------------------------------------------- */ + +/* ------------------------------ default data ------------------------------ */ +const defaultPolicyData = { + myLimit: { + balance: 0, + total: 0, + percentage: 0, + }, + lockLimit: { + balance: 0, + percentage: 0, + }, +}; +/* -------------------------------------------------------------------------- */ + +export default function Claim() { + const { themeStretch } = useSettings(); + + // const [tableData, setTableData] = useState([]); + const [policyData, setPolicyData] = useState(defaultPolicyData); + + // TODO Remove This + //const [itemList, setItemList] = useState([]); + function handleDataLoaded(dataTable:any) { + let dummyData = []; + dataTable.map(function(data:any) { + if (data.status == 'approved') { + dummyData.push({ + info: `LOG Approved for member ${data.member.full_name}`, + date: fDate(data.created_at, "dd MMMM"), + time: fDate(data.created_at, "HH:mm") + }) + } + }) + + //setItemList(dummyData); + } + + return ( + + + + {/* + + */} + {/* + + */} + + + + + + + + + + + ); +} diff --git a/frontend/hospital-portal/src/routes/index.tsx b/frontend/hospital-portal/src/routes/index.tsx index 4815a322..b3006919 100644 --- a/frontend/hospital-portal/src/routes/index.tsx +++ b/frontend/hospital-portal/src/routes/index.tsx @@ -82,6 +82,27 @@ export default function Router() { }, ], }, + { + path: '/', + element: ( + + + + + + ), + children: [ + { element: , index: true }, + { + path: 'claim', + element: , + }, + { + path: '/detail/:id', + element: , + }, + ], + }, { path: '*', @@ -101,6 +122,7 @@ const ForgetPassword = Loadable(lazy(() => import('@/pages/auth/ForgetPassword') // Dashboard const Dashboard = Loadable(lazy(() => import('@/pages/Dashboard'))); +const Claim = Loadable(lazy(() => import('@/pages/Claim'))); const NotFound = Loadable(lazy(() => import('@/pages/Page404'))); const DetailClaimReport = Loadable(lazy(()=> import('@/sections/dashboard/Detail'))); diff --git a/frontend/hospital-portal/src/sections/claim/TableList.tsx b/frontend/hospital-portal/src/sections/claim/TableList.tsx new file mode 100644 index 00000000..513ea292 --- /dev/null +++ b/frontend/hospital-portal/src/sections/claim/TableList.tsx @@ -0,0 +1,365 @@ +/* ---------------------------------- @mui ---------------------------------- */ +import { Stack, Button, MenuItem, SelectChangeEvent, Tab, Tabs, Card, Box } from '@mui/material'; +/* ---------------------------------- axios --------------------------------- */ +// import axios from 'axios'; +import axios from '../../utils/axios'; +import { styled } from '@mui/material/styles'; +/* ---------------------------------- react --------------------------------- */ +import { useContext, useEffect, useState } from 'react'; + +/* -------------------------------- component ------------------------------- */ +import Iconify from '../../components/Iconify'; +import TableComponent from '../../components/Table'; +/* ---------------------------------- theme --------------------------------- */ +import palette from '../../theme/palette'; +//import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; +import { HeadCell, Order, PaginationTableProps } from '../../@types/table'; +import { useSearchParams, useNavigate } from 'react-router-dom'; +import { fDate, fDateSuffix } from '../../utils/formatTime'; +import Typography from '@mui/material/Typography'; +import { format } from 'date-fns'; +import TableMoreMenu from '../../components/table/TableMoreMenu'; +import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; +import HistoryIcon from '@mui/icons-material/History'; +import SearchIcon from '@mui/icons-material/Search'; +import Label from '../../components/Label'; +import { enqueueSnackbar } from 'notistack'; +import { LoadingButton, TabPanel } from "@mui/lab"; +import { LanguageContext } from '@/contexts/LanguageContext'; +import MuiDialog from '@/components/MuiDialog'; +import DialogMember from '@/sections/dashboard/DialogMember'; +import DialogClaimSubmit from '@/sections/dashboard/DialogClaimSubmit'; +import { fPostFormat } from '@/utils/formatTime'; + +export default function TableList() { + const navigate = useNavigate(); + const { localeData }: any = useContext(LanguageContext); + + const [data, setData] = useState([]); + + // Download LOG + async function handleDownloadLog(claimRequest:any) { + return axios + .get(`claim-requests/${claimRequest}/log`, { + responseType: 'blob', + }) + .then((response) => { + window.open(URL.createObjectURL(response.data)); + // setLoadingLog(false); + }) + // .then((blobFile) => { + // new File([blobFile], 'asdads.pdf', { type: blobFile.type }) + // setLoadingLog(false); + // }) + .catch((response) => { + console.log(response); + enqueueSnackbar(response.message, { variant: 'error' }); + // setLoadingLog(false); + }); + } + + /* -------------------------------------------------------------------------- */ + /* setting up for the table */ + /* -------------------------------------------------------------------------- */ + const [isLoading, setIsLoading] = useState(true); + + const loadings = { + isLoading: isLoading, + setIsLoading: setIsLoading, + }; + + /* ------------------------------ handle params ----------------------------- */ + const [searchParams, setSearchParams] = useSearchParams(); + const [appliedParams, setAppliedParams] = useState({}); + + const params = { + searchParams: searchParams, + setSearchParams: setSearchParams, + appliedParams: appliedParams, + setAppliedParams: setAppliedParams, + }; + /* -------------------------------------------------------------------------- */ + + /* ------------------------------ handle order ------------------------------ */ + const [order, setOrder] = useState('desc'); + const [orderBy, setOrderBy] = useState('submission_date'); + + const orders = { + order: order, + setOrder: setOrder, + orderBy: orderBy, + setOrderBy: setOrderBy, + }; + /* -------------------------------------------------------------------------- */ + + /* ---------------------------- handle pagination --------------------------- */ + const [page, setPage] = useState(0); + const [rowsPerPage, setRowsPerPage] = useState(10); + + const [paginationTable, setPaginationTable] = useState({ + current_page: 0, + from: 0, + last_page: 0, + links: [], + path: '', + per_page: 0, + to: 0, + total: 0, + }); + + const paginations = { + page: page, + setPage: setPage, + rowsPerPage: rowsPerPage, + setRowsPerPage: setRowsPerPage, + paginationTable: paginationTable, + setPaginationTable: setPaginationTable, + }; + + /* -------------------------------------------------------------------------- */ + + /* ------------------------------ handle search ----------------------------- */ + const [searchText, setSearchText] = useState(''); + + const handleSearchSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + + if (searchText === '') { + searchParams.delete('search'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([...searchParams.entries(), ['search', searchText]]); + setAppliedParams(params); + } + }; + + const searchs = { + useSearchs: true, + searchText: searchText, + setSearchText: setSearchText, + handleSearchSubmit: handleSearchSubmit, + }; + + /* ------------------------------ handle filter ----------------------------- */ + const [statusValue, setStatusValue] = useState('all'); + const [filterData, setStatusData] = useState([]); + + // handle status + const handleStatusChanges = (event: SelectChangeEvent) => { + setStatusValue(event.target.value as string); + + if (event.target.value === 'all') { + searchParams.delete('status'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([ + ...searchParams.entries(), + ['status', event.target.value as string], + ]); + setAppliedParams(params); + } + }; + + const filterStatus = { + useFilter: true, + config: { + label: 'Status', + statusValue: statusValue, + filterData: filterData, + handleStatusChange: handleStatusChanges, + }, + }; + + // handle start date + const [startDateValue, setStartDateValue] = useState(''); + + const handleStartDateChanges = async (event: React.FormEvent) => { + event.preventDefault(); + const newStartDateValue = event.currentTarget.elements['date-input'].value; + setStartDateValue(newStartDateValue); + if (newStartDateValue === '') { + searchParams.delete('start_date'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([...searchParams.entries(), ['start_date', newStartDateValue]]); + setAppliedParams(params); + } + }; + + const filterStartDate = { + useFilter: true, + startDate: startDateValue, + setStartDate: setStartDateValue, + handleStartDateChange: handleStartDateChanges, + }; + + // handle end date + const [endDateValue, setEndDateValue] = useState(''); + + const handleEndDateChanges = async (event: React.FormEvent) => { + event.preventDefault(); + const newEndDateValue = event.currentTarget.elements['date-input'].value; + setEndDateValue(newEndDateValue); + if (newEndDateValue === '') { + searchParams.delete('end_date'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([...searchParams.entries(), ['end_date', newEndDateValue]]); + setAppliedParams(params); + } + }; + + const filterEndDate = { + useFilter: true, + endDate: endDateValue, + setEndDate: setEndDateValue, + handleEndDateChange: handleEndDateChanges, + }; + + /* -------------------------------- headCell Claim -------------------------------- */ + const headCells: HeadCell[] = [ + { + id: 'code', + align: 'left', + label: localeData.txtRequestCode, + isSort: true, + }, + { + id: 'full_name', + align: 'left', + label: localeData.txtName, + isSort: true, + }, + { + id: 'submission_date', + align: 'center', + label: localeData.txtSubmissionDate, + isSort: true, + }, + { + id: 'service_type', + align: 'center', + label: localeData.txtServiceType, + isSort: true, + }, + { + id: 'status', + align: 'center', + label: localeData.txtStatus, + isSort: true, + }, + { + id: 'action', + align: 'right', + label: '', + isSort: false, + }, + ]; + + + useEffect(() => { + getData(); + }, [appliedParams, searchParams, order, orderBy, setSearchParams]); + + function getData() + { + (async () => { + setIsLoading(true); + + await new Promise((resolve) => setTimeout(resolve, 250)); + + const parameters = + Object.keys(appliedParams).length !== 0 + ? appliedParams + : Object.fromEntries([...searchParams.entries(), ['order', order], ['orderBy', orderBy]]); + + const response = await axios.get(`/get-claim-requests`, { + params: { ...parameters, type: 'final-log' }, + }); + setData( + response.data.data.map((obj: any) => ({ + ...obj, + status: + obj.status === 'requested' ? ( + + ) : obj.status === 'approved' ? ( + + ) : obj.status === 'declined' ? ( + + ) : obj.status === 'reviewed' ? ( + + ) : ( + + ), + submission_date: + + , + action: + + + + View + + + } /> + })) + ); + + setPaginationTable(response.data); + setRowsPerPage(response.data.per_page); + + if (searchParams.get('page')) { + //@ts-ignore + const currentPage = parseInt(searchParams.get('page')) - 1; + + paginationTable.current_page = currentPage; + setPage(currentPage); + } + + const status:any = [ + {"id": "requested", "name": "Request" }, + {"id": "reviewed", "name": "Review" }, + {"id": "approved", "name": "Approval" }, + {"id": "declined", "name": "Decline" }, + ]; + setStatusData(status) + + setIsLoading(false); + })(); + } + + + return ( + <> + + + ); +} \ No newline at end of file diff --git a/frontend/hospital-portal/src/sections/dashboard/CardSearchMember.tsx b/frontend/hospital-portal/src/sections/dashboard/CardSearchMember.tsx index 0f8a1453..77ae25a2 100644 --- a/frontend/hospital-portal/src/sections/dashboard/CardSearchMember.tsx +++ b/frontend/hospital-portal/src/sections/dashboard/CardSearchMember.tsx @@ -46,8 +46,8 @@ const ItemNotificationStyle = styled(Card)(({ theme }) => ({ // ---------------------------------------------------------------------- -export default function CardSearchMember(handleSubmitSuccess) { - const { localeData } = useContext(LanguageContext); +export default function CardSearchMember(handleSubmitSuccess:()=> void) { + const { localeData }: any = useContext(LanguageContext); const {enqueueSnackbar} = useSnackbar(); const [noPolis, setNoPolis] = useState('AW001-01'); @@ -112,7 +112,7 @@ export default function CardSearchMember(handleSubmitSuccess) { { + onChange={(newValue:any) => { setBirthDate( (newValue)); }} inputFormat="dd-MM-yyyy" @@ -144,7 +144,7 @@ export default function CardSearchMember(handleSubmitSuccess) { openDialog={openDialogBenefit} setOpenDialog={setOpenDialogBenefit} content={DialogMember(currentMember, () => {setOpenDialogBenefit(false); handleSubmitSuccess()})} - maxWidth="md" + maxWidth="sm" /> ); diff --git a/frontend/hospital-portal/src/sections/dashboard/DialogClaimSubmit.tsx b/frontend/hospital-portal/src/sections/dashboard/DialogClaimSubmit.tsx new file mode 100644 index 00000000..914fa652 --- /dev/null +++ b/frontend/hospital-portal/src/sections/dashboard/DialogClaimSubmit.tsx @@ -0,0 +1,164 @@ +import { styled } from '@mui/material/styles'; +import Iconify from '@/components/Iconify'; +import { fCurrency } from '@/utils/formatNumber'; +import { LoadingButton } from '@mui/lab'; +import { Avatar, Button, Divider, LinearProgress, linearProgressClasses, ButtonBase, Box } from '@mui/material'; +import { Card } from '@mui/material'; +import { Stack, Typography } from '@mui/material'; +import { fPostFormat } from '@/utils/formatTime'; +import axios from '@/utils/axios'; +import { enqueueSnackbar } from 'notistack'; +import { useRef, useState, useContext } from 'react'; +import { makeFormData } from '@/utils/jsonToFormData'; +import { format } from 'date-fns'; +import { LanguageContext } from '@/contexts/LanguageContext'; + +export default function DialogClaimSubmit({ member, getData, onClose, handleSubmitSuccess }: any) { + const { localeData }: any = useContext(LanguageContext); + + // ---------------------------------------------------------------------- + // Files Result Tambahan + + const fileAdditionalInput = useRef(null); + const [fileAdditionals, setFileAdditionals] = useState([]); + + const handleKondisiInputChange = (event:any) => { + if (event.target.files[0]) { + setFileAdditionals([...fileAdditionals, ...event.target.files]); + } else { + console.log('NO FILE'); + } + }; + const removeKondisiFiles = (filesState:any, index:any) => { + setFileAdditionals( + filesState.filter((file:any, fileIndex:any) => { + return fileIndex != index; + }) + ); + }; + + // -------------------------------------------------------------- + // Submit Form + + const [submitLoading, setSubmitLoading] = useState(false); + function submitRequestClaim() { + setSubmitLoading(true); + const formData = makeFormData({ + request_logs_id: member.id, + service_code: member.service_code, + member_id: member.member_id, + additional_files: fileAdditionals + }); + axios + .post('/claim-requests', formData) + .then((response) => { + enqueueSnackbar(response.data.meta.message ?? 'Berhasil membuat data', { variant: 'success' }); + handleSubmitSuccess(); + onClose({ someData: 'example data' }, getData); + }) + .catch(({ response }) => { + enqueueSnackbar(response.data.meta.message ?? 'Something Went Wrong', { variant: 'error' }); + }) + .then(() => { + setSubmitLoading(false); + }); + } + + return ( + + + + {localeData.txtDialogMember5} + + {format(member?.submission_date ? new Date(member.submission_date) : new Date(), "d MMM yyyy")} + + + + + + + {member?.full_name ?? ''} + {member?.no_polis ?? ''} + + + + + } + spacing={4} + sx={{ marginY: 2, marginBottom: 6 }} + > + {/* -------------------------------Upload Dokumen Tambahan------------------------------- */} + + + {localeData.txtAdditionalDocuments} + + {/* Hasil Lab, */} + } + spacing={1} + sx={{ marginY: 2 }} + > + {fileAdditionals && + fileAdditionals.map((file:any, index:any) => ( + + {file.name} + { + removeKondisiFiles(fileAdditionals, index); + }} + > + + ))} + + fileAdditionalInput.current?.click()}> + + + + {localeData.txtAddResult} + + + + + + + + { + submitRequestClaim(); + }} + loading={submitLoading} + > + Submit Claim + + + ); +} diff --git a/frontend/hospital-portal/src/sections/dashboard/DialogFinalLog.tsx b/frontend/hospital-portal/src/sections/dashboard/DialogFinalLog.tsx new file mode 100644 index 00000000..3326616e --- /dev/null +++ b/frontend/hospital-portal/src/sections/dashboard/DialogFinalLog.tsx @@ -0,0 +1,328 @@ +import { styled } from '@mui/material/styles'; +import Iconify from '@/components/Iconify'; +import { fCurrency } from '@/utils/formatNumber'; +import { LoadingButton } from '@mui/lab'; +import { Avatar, Button, Divider, LinearProgress, linearProgressClasses, ButtonBase, Box } from '@mui/material'; +import { Card } from '@mui/material'; +import { Stack, Typography } from '@mui/material'; +import { fPostFormat } from '@/utils/formatTime'; +import axios from '@/utils/axios'; +import { enqueueSnackbar } from 'notistack'; +import { useRef, useState, useContext } from 'react'; +import { makeFormData } from '@/utils/jsonToFormData'; +import { format } from 'date-fns'; +import { LanguageContext } from '@/contexts/LanguageContext'; + +export default function DialogFinalLog({ member, getData, onClose, handleSubmitSuccess }: any) { + const { localeData }: any = useContext(LanguageContext); + + // ---------------------------------------------------------------------- + // Files Diagnosa + + const fileDiagnosaInput = useRef(null); + const [fileDiagnosas, setFileDiagnosas] = useState([]); + + const handleDiagnosaInputChange = (event:any) => { + if (event.target.files[0]) { + setFileDiagnosas([...fileDiagnosas, ...event.target.files]); + } else { + console.log('NO FILE'); + } + }; + const removeDiagnosaFiles = (filesState:any, index:any) => { + setFileDiagnosas( + filesState.filter((file:any, fileIndex:any) => { + return fileIndex != index; + }) + ); + }; + + // ---------------------------------------------------------------------- + // Files Result Kondisi + + const fileKondisiInput = useRef(null); + const [fileKondisis, setFileKondisis] = useState([]); + + const handleKondisiInputChange = (event:any) => { + if (event.target.files[0]) { + setFileKondisis([...fileKondisis, ...event.target.files]); + } else { + console.log('NO FILE'); + } + }; + const removeKondisiFiles = (filesState:any, index:any) => { + setFileKondisis( + filesState.filter((file:any, fileIndex:any) => { + return fileIndex != index; + }) + ); + }; + + // ---------------------------------------------------------------------- + // Files Result Hasil Penunjang + + const fileHasilPenunjangInput = useRef(null); + const [fileHasilPenunjangs, setFileHasilPenunjangs] = useState([]); + + const handleResultInputChange = (event:any) => { + if (event.target.files[0]) { + setFileHasilPenunjangs([...fileHasilPenunjangs, ...event.target.files]); + } else { + console.log('NO FILE'); + } + }; + const removeFiles = (filesState:any, index:any) => { + setFileHasilPenunjangs( + filesState.filter((file:any, fileIndex:any) => { + return fileIndex != index; + }) + ); + }; + + // -------------------------------------------------------------- + // Submit Form + + const [submitLoading, setSubmitLoading] = useState(false); + function submitRequestFinalLog() { + setSubmitLoading(true); + const formData = makeFormData({ + request_logs_id: member.id, + result_files: fileHasilPenunjangs, + diagnosa_files: fileDiagnosas, + kondisi_files: fileKondisis + }); + axios + .post('/request-final-log', formData) + .then((response) => { + enqueueSnackbar(response.data.meta.message ?? 'Berhasil membuat data', { variant: 'success' }); + handleSubmitSuccess(); + onClose({ someData: 'example data' }, getData); + }) + .catch(({ response }) => { + enqueueSnackbar(response.data.meta.message ?? 'Something Went Wrong', { variant: 'error' }); + }) + .then(() => { + setSubmitLoading(false); + }); + } + + return ( + + + + {localeData.txtDialogMember5} + + {format(member?.submission_date ? new Date(member.submission_date) : new Date(), "d MMM yyyy")} + + + + + + + {member?.full_name ?? ''} + {member?.no_polis ?? ''} + + + + + } + spacing={4} + sx={{ marginY: 2, marginBottom: 6 }} + > + {/* -------------------------------Upload Dokumen Kondisi------------------------------- */} + + + {localeData.txtConditionDocument} + + {/* Hasil Lab, */} + } + spacing={1} + sx={{ marginY: 2 }} + > + {fileKondisis && + fileKondisis.map((file:any, index:any) => ( + + {file.name} + { + removeKondisiFiles(fileKondisis, index); + }} + > + + ))} + + fileKondisiInput.current?.click()}> + + + + {localeData.txtAddResult} + + + + + + + {/* -------------------------------Upload Dokumen Diagnosa------------------------------- */} + + + {localeData.txtDiagnosisDokument} + + {/* Hasil Lab, */} + } + spacing={1} + sx={{ marginY: 2 }} + > + {fileDiagnosas && + fileDiagnosas.map((file:any, index:any) => ( + + {file.name} + { + removeDiagnosaFiles(fileDiagnosas, index); + }} + > + + ))} + {/* + Nama File .pdf + + */} + + {/* { JSON.stringify(filesResult) } */} + fileDiagnosaInput.current?.click()}> + + + + {localeData.txtAddResult} + + + + + + + {/* -------------------------------Upload Dokumen Hasil Penunjang------------------------------- */} + + + {localeData.txtSupportingResultDocument} + + {/* Hasil Lab, */} + } + spacing={1} + sx={{ marginY: 2 }} + > + {fileHasilPenunjangs && + fileHasilPenunjangs.map((file:any, index:any) => ( + + {file.name} + { + removeFiles(fileHasilPenunjangs, index); + }} + > + + ))} + {/* + Nama File .pdf + + */} + + {/* { JSON.stringify(filesResult) } */} + fileHasilPenunjangInput.current?.click()}> + + + + {localeData.txtAddResult} + + + + + + + + { + submitRequestFinalLog(); + }} + loading={submitLoading} + > + Request Final LOG + + + ); +} diff --git a/frontend/hospital-portal/src/sections/dashboard/DialogMember.tsx b/frontend/hospital-portal/src/sections/dashboard/DialogMember.tsx index c6863e48..0c95dec6 100644 --- a/frontend/hospital-portal/src/sections/dashboard/DialogMember.tsx +++ b/frontend/hospital-portal/src/sections/dashboard/DialogMember.tsx @@ -1,7 +1,22 @@ // mui import { styled } from '@mui/material/styles'; import { LoadingButton, TabPanel } from "@mui/lab"; -import { Button, Card, Divider, Grid, LinearProgress, linearProgressClasses, Typography } from "@mui/material"; +import { + Button, + Card, + Divider, + Grid, + LinearProgress, + linearProgressClasses, + Typography, + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Collapse, } from "@mui/material"; import { Tab, Tabs } from "@mui/material"; import { Box, Stack } from "@mui/material"; import React, { useEffect, useState, useContext } from "react"; @@ -10,12 +25,15 @@ import { fPostFormat } from '@/utils/formatTime'; import { Avatar } from '@mui/material'; import Iconify from '@/components/Iconify'; import FormRequestClaim from './FormRequestClaim'; +import FormRequestLog from './FormRequestLog'; import { LanguageContext } from '@/contexts/LanguageContext'; import { format } from 'date-fns'; +import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; +import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; -export default function DialogMember(member, handleSubmitSuccess) { - const { localeData } = useContext(LanguageContext); - const [currentTab, setCurrentTab] = useState('request') +export default function DialogMember(member:any, handleSubmitSuccess:() => void) { + const { localeData }: any = useContext(LanguageContext); + const [currentTab, setCurrentTab] = useState('request'); // ---------------------------------------------------------------------- @@ -41,7 +59,7 @@ export default function DialogMember(member, handleSubmitSuccess) { }, })); - function TabPanel(props) { + function TabPanel(props:any) { const { children, value, index, ...other } = props; return (
); } + + const [openRows, setOpenRows] = useState({}); + + const handleRowToggle = (index:number) => { + setOpenRows((prevOpenRows:any) => ({ + ...prevOpenRows, + [index]: !prevOpenRows[index], + })); + }; return (
@@ -69,8 +96,10 @@ export default function DialogMember(member, handleSubmitSuccess) { aria-label="wrapped label tabs example" > - - + + {member?.type !== 'view' ? ( + + ) : ''} @@ -96,19 +125,19 @@ export default function DialogMember(member, handleSubmitSuccess) { {member?.members.email ?? '-'} - Date of Birth + {localeData.txtDateBirth} {member?.members.birth_date ? format(new Date(member.members.birth_date), "d MMM yyyy") : '-'} - Gender + {localeData.txtGender} {member?.members.gender ?? '-'} - Marital Status + {localeData.txtMaritalStatus} {member?.members.marital_status ?? '-'} - Language + {localeData.txtLanguage} {member?.members.language ?? '-'} @@ -116,29 +145,51 @@ export default function DialogMember(member, handleSubmitSuccess) { {member?.members.race ?? '-'} - Relationship + {localeData.txtRelationship} {member?.members.relation_with_principal != '' ? member?.members.relation_with_principal : '-'} - - - - { member && member?.benefits?.map((corporateBenefit, index) => {return ( - - - {corporateBenefit.description} - {corporateBenefit.code} - - - - )})} - + + + + {member && member.groupServices && Object.keys(member.groupServices).map((serviceCode, index) => ( + + + {serviceCode} + + {openRows[index] ? ( + handleRowToggle(index)} /> + ) : ( + handleRowToggle(index)} /> + )} + + + + + {/* COLLAPSIBLE ROW */} + + + {/* Loop through the array for the current serviceCode */} + {member.groupServices[serviceCode].map((item:any, innerIndex:number) => ( + + + {item.description} + {item.code} + + + ))} + + + + + + ))} +
+
- - - +
diff --git a/frontend/hospital-portal/src/sections/dashboard/FormRequestLog.tsx b/frontend/hospital-portal/src/sections/dashboard/FormRequestLog.tsx new file mode 100644 index 00000000..9110d837 --- /dev/null +++ b/frontend/hospital-portal/src/sections/dashboard/FormRequestLog.tsx @@ -0,0 +1,128 @@ +import { LoadingButton } from '@mui/lab'; +import +{ + Avatar, + FormControl, + InputLabel, + Select, + FormHelperText, + MenuItem +} from '@mui/material'; +import { Card } from '@mui/material'; +import { Stack, Typography } from '@mui/material'; +import axios from '@/utils/axios'; +import { enqueueSnackbar } from 'notistack'; +import { useRef, useState, useContext } from 'react'; +import { makeFormData } from '@/utils/jsonToFormData'; +import { format } from 'date-fns'; +import { LanguageContext } from '@/contexts/LanguageContext'; + +interface MemberType { + members: any; + services: any; +} +interface FormRequestClaimProps { + member: MemberType; + handleSubmitSuccess: () => void; +} +export default function FormRequestClaim({ member, handleSubmitSuccess }: FormRequestClaimProps) { + const { localeData }: any = useContext(LanguageContext); + const [serviceCode, setServiceCode] = useState(''); + + const [submitLoading, setSubmitLoading] = useState(false); + function submitRequest() { + if(serviceCode == '') + { + enqueueSnackbar(localeData.txtDialogMember4, { variant: 'warning' }); + return false; + } + setSubmitLoading(true); + const formData = { + member_id: member.members.id, + service_code: serviceCode + }; + axios + .post('/request-log', formData) + .then((response) => { + console.log(response); + if (response && response.data && response.data.meta) { + enqueueSnackbar(response.data.meta.message, { variant: 'success' }); + handleSubmitSuccess(); + } + }) + .catch(({ response }) => { + if (response && response.data && response.data.meta) { + enqueueSnackbar(response.data.meta.message, { variant: 'error' }); + } + }) + .then(() => { + setSubmitLoading(false); + }); + } + + interface MemberService { + service_code: string; + name: string; + } + + return ( + + + + {localeData.txtDialogMember5} + + {format(new Date(), "d MMM yyyy")} + + + + + {localeData.txtDialogMember1}* + + + {localeData.txtDialogMember1} + + + + + + + + + + + + {member?.members.name ?? ''} + {member?.members.member_id ?? ''} + + + + + { + submitRequest(); + }} + loading={submitLoading} + > + {localeData.txtDialogMember2} + + + ); +} diff --git a/frontend/hospital-portal/src/sections/dashboard/TableList.tsx b/frontend/hospital-portal/src/sections/dashboard/TableList.tsx index fa14ad4d..b1575b08 100644 --- a/frontend/hospital-portal/src/sections/dashboard/TableList.tsx +++ b/frontend/hospital-portal/src/sections/dashboard/TableList.tsx @@ -1,8 +1,9 @@ /* ---------------------------------- @mui ---------------------------------- */ -import { Stack, Button, MenuItem, SelectChangeEvent } from '@mui/material'; +import { Stack, Button, MenuItem, SelectChangeEvent, Tab, Tabs, Card, Box } from '@mui/material'; /* ---------------------------------- axios --------------------------------- */ // import axios from 'axios'; import axios from '../../utils/axios'; +import { styled } from '@mui/material/styles'; /* ---------------------------------- react --------------------------------- */ import { useContext, useEffect, useState } from 'react'; @@ -23,9 +24,26 @@ import HistoryIcon from '@mui/icons-material/History'; import SearchIcon from '@mui/icons-material/Search'; import Label from '../../components/Label'; import { enqueueSnackbar } from 'notistack'; +import { LoadingButton, TabPanel } from "@mui/lab"; +import { LanguageContext } from '@/contexts/LanguageContext'; +import MuiDialog from '@/components/MuiDialog'; +import DialogMember from './DialogMember'; +import DialogFinalLog from './DialogFinalLog'; +import { fPostFormat } from '@/utils/formatTime'; +import TableListFinalLog from './TableListFinalLog'; -export default function TableList2() { +export default function TableList() { const navigate = useNavigate(); + const { localeData }: any = useContext(LanguageContext); + const [currentTab, setCurrentTab] = useState('request_log'); + + useEffect(() => { + setCurrentTab('request_log') +}, []) + +function handleChangeTab(event: React.SyntheticEvent, newValue: string) { + setCurrentTab(newValue) +} //const { corporateValue } = useContext(UserCurrentCorporateContext); //const { corporateValue } = useContext(null); @@ -33,7 +51,7 @@ export default function TableList2() { const [data, setData] = useState([]); // Download LOG - async function handleDownloadLog(claimRequest) { + async function handleDownloadLog(claimRequest:any) { return axios .get(`claim-requests/${claimRequest}/log`, { responseType: 'blob', @@ -215,36 +233,30 @@ export default function TableList2() { handleEndDateChange: handleEndDateChanges, }; - /* -------------------------------- headCell -------------------------------- */ + /* -------------------------------- headCell Request LOG -------------------------------- */ const headCells: HeadCell[] = [ - { - id: 'submission_date', - align: 'center', - label: 'Request Date', - isSort: true, - }, - { - id: 'member_id', - align: 'left', - label: 'Member ID', - isSort: true, - }, { id: 'code', align: 'left', - label: 'Claim Code', + label: localeData.txtRequestCode, isSort: true, }, { id: 'full_name', align: 'left', - label: 'Name', + label: localeData.txtName, + isSort: true, + }, + { + id: 'submission_date', + align: 'center', + label: localeData.txtSubmissionDate, isSort: true, }, { id: 'status', align: 'center', - label: 'Status', + label: localeData.txtStatus, isSort: true, }, { @@ -254,8 +266,47 @@ export default function TableList2() { isSort: false, }, ]; + + + function handleSearchMember(noPolis:any, birthDate:any) { + setLoadingClaim(false) + axios.post('/search-member', { + no_polis: noPolis, + birth_date: birthDate ? fPostFormat(birthDate, 'yyyy-MM-dd') : null, + type: 'view' + }) + .then((response) => { + setOpenDialogBenefit(true) + setCurrentMember(response.data.data) + setNameMember(response.data.data.members.name); + }) + .catch(({response}) => { + enqueueSnackbar(response.data.errors ? response.data.errors[0] : (response.data ? response.data.meta.message : 'Opps, Something went Wrong!'), {variant : "error"}) + }) + .then(() => { + }); + } + + + + function handleRequestFinalLog(id:any, full_name:any, no_polis:any, submission_date:any) + { + setOpenDialogFinalLog(true); + const datas_view = { + 'id' : id, + 'full_name' : full_name, + 'no_polis' : no_polis, + 'submission_date' : submission_date + }; + setDataViewFinalDialog(datas_view); + } useEffect(() => { + getData(); + }, [appliedParams, searchParams, order, orderBy, setSearchParams]); + + function getData() + { (async () => { setIsLoading(true); @@ -266,10 +317,9 @@ export default function TableList2() { ? appliedParams : Object.fromEntries([...searchParams.entries(), ['order', order], ['orderBy', orderBy]]); - const response = await axios.get(`/get-claim-requests`, { - params: { ...parameters, type: 'claim-request' }, + const response = await axios.get(`/get-request-log`, { + params: { ...parameters, type: 'request-log' }, }); - setData( response.data.data.map((obj: any) => ({ ...obj, @@ -303,14 +353,22 @@ export default function TableList2() { action: - navigate ('/detail/'+obj.claim_request_id)}> + handleSearchMember(obj.no_polis, obj.birth_date) }> View + {obj.status === 'approved' ? ( handleDownloadLog(obj.claim_request_id)}> Download LOG + ):''} + {obj.final_log === 0 ? ( + handleRequestFinalLog(obj.id, obj.full_name, obj.no_polis, obj.submission_date) }> + + Request Final LOG + + ):''} } /> })) @@ -327,32 +385,116 @@ export default function TableList2() { setPage(currentPage); } - const status = [ + const status:any = [ {"id": "requested", "name": "Request" }, {"id": "reviewed", "name": "Review" }, {"id": "approved", "name": "Approval" }, {"id": "declined", "name": "Decline" }, - ] + ]; setStatusData(status) setIsLoading(false); })(); - }, [appliedParams, searchParams, order, orderBy, setSearchParams]); + } + + const RootNotificationStyle = styled(Card)(({ theme }) => ({ + boxShadow: 'none', + padding: '1rem 0.5rem', + color: 'black', + borderRadius: 0, + backgroundColor: theme.palette.grey[200], + // maxHeight: '240px', + })); + + function TabPanel(props:any) { + const { children, value, index, ...other } = props; + return ( + + ); + } + + // const [noPolis, setNoPolis] = useState('AW001-01'); + //const [birthDate, setBirthDate] = useState('1991-01-10'); + const [loadingBenefit, setLoadingBenefit] = useState(false); + const [loadingClaim, setLoadingClaim] = useState(false); + const [openDialogBenefit, setOpenDialogBenefit] = useState(false); + const [openDialogFinalLog, setOpenDialogFinalLog] = useState(false); + const [openDialogClaim, setOpenDialogClaim] = useState(false); + const [currentMember, setCurrentMember] = useState(null); + const [nameMember, setNameMember] = useState(''); + const [setIsRequestFinalLog, isRequestFinalLog] = useState(false); + const [dataViewFinalDialog, setDataViewFinalDialog] = useState(null); return ( - - - + + + + + + + + + + + + + + setOpenDialogBenefit(false)) + } + maxWidth="sm" + /> + + { + console.log('Data returned:', data); + getData(); + setOpenDialogFinalLog(false); + }} + handleSubmitSuccess={() => { + }} + /> + } + maxWidth="sm" + /> + ); } diff --git a/frontend/hospital-portal/src/sections/dashboard/TableListFinalLog.tsx b/frontend/hospital-portal/src/sections/dashboard/TableListFinalLog.tsx new file mode 100644 index 00000000..06dc44d8 --- /dev/null +++ b/frontend/hospital-portal/src/sections/dashboard/TableListFinalLog.tsx @@ -0,0 +1,441 @@ +/* ---------------------------------- @mui ---------------------------------- */ +import { Stack, Button, MenuItem, SelectChangeEvent, Tab, Tabs, Card, Box } from '@mui/material'; +/* ---------------------------------- axios --------------------------------- */ +// import axios from 'axios'; +import axios from '../../utils/axios'; +import { styled } from '@mui/material/styles'; +/* ---------------------------------- react --------------------------------- */ +import { useContext, useEffect, useState } from 'react'; + +/* -------------------------------- component ------------------------------- */ +import Iconify from '../../components/Iconify'; +import TableComponent from '../../components/Table'; +/* ---------------------------------- theme --------------------------------- */ +import palette from '../../theme/palette'; +//import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; +import { HeadCell, Order, PaginationTableProps } from '../../@types/table'; +import { useSearchParams, useNavigate } from 'react-router-dom'; +import { fDate, fDateSuffix } from '../../utils/formatTime'; +import Typography from '@mui/material/Typography'; +import { format } from 'date-fns'; +import TableMoreMenu from '../../components/table/TableMoreMenu'; +import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; +import HistoryIcon from '@mui/icons-material/History'; +import SearchIcon from '@mui/icons-material/Search'; +import Label from '../../components/Label'; +import { enqueueSnackbar } from 'notistack'; +import { LoadingButton, TabPanel } from "@mui/lab"; +import { LanguageContext } from '@/contexts/LanguageContext'; +import MuiDialog from '@/components/MuiDialog'; +import DialogMember from './DialogMember'; +import DialogClaimSubmit from './DialogClaimSubmit'; +import { fPostFormat } from '@/utils/formatTime'; + +export default function TableListFinalLog() { + const navigate = useNavigate(); + const { localeData }: any = useContext(LanguageContext); + + const [data, setData] = useState([]); + + // Download LOG + async function handleDownloadLog(claimRequest:any) { + return axios + .get(`claim-requests/${claimRequest}/log`, { + responseType: 'blob', + }) + .then((response) => { + window.open(URL.createObjectURL(response.data)); + // setLoadingLog(false); + }) + // .then((blobFile) => { + // new File([blobFile], 'asdads.pdf', { type: blobFile.type }) + // setLoadingLog(false); + // }) + .catch((response) => { + console.log(response); + enqueueSnackbar(response.message, { variant: 'error' }); + // setLoadingLog(false); + }); + } + + /* -------------------------------------------------------------------------- */ + /* setting up for the table */ + /* -------------------------------------------------------------------------- */ + const [isLoading, setIsLoading] = useState(true); + + const loadings = { + isLoading: isLoading, + setIsLoading: setIsLoading, + }; + + /* ------------------------------ handle params ----------------------------- */ + const [searchParams, setSearchParams] = useSearchParams(); + const [appliedParams, setAppliedParams] = useState({}); + + const params = { + searchParams: searchParams, + setSearchParams: setSearchParams, + appliedParams: appliedParams, + setAppliedParams: setAppliedParams, + }; + /* -------------------------------------------------------------------------- */ + + /* ------------------------------ handle order ------------------------------ */ + const [order, setOrder] = useState('desc'); + const [orderBy, setOrderBy] = useState('submission_date'); + + const orders = { + order: order, + setOrder: setOrder, + orderBy: orderBy, + setOrderBy: setOrderBy, + }; + /* -------------------------------------------------------------------------- */ + + /* ---------------------------- handle pagination --------------------------- */ + const [page, setPage] = useState(0); + const [rowsPerPage, setRowsPerPage] = useState(10); + + const [paginationTable, setPaginationTable] = useState({ + current_page: 0, + from: 0, + last_page: 0, + links: [], + path: '', + per_page: 0, + to: 0, + total: 0, + }); + + const paginations = { + page: page, + setPage: setPage, + rowsPerPage: rowsPerPage, + setRowsPerPage: setRowsPerPage, + paginationTable: paginationTable, + setPaginationTable: setPaginationTable, + }; + + /* -------------------------------------------------------------------------- */ + + /* ------------------------------ handle search ----------------------------- */ + const [searchText, setSearchText] = useState(''); + + const handleSearchSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + + if (searchText === '') { + searchParams.delete('search'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([...searchParams.entries(), ['search', searchText]]); + setAppliedParams(params); + } + }; + + const searchs = { + useSearchs: true, + searchText: searchText, + setSearchText: setSearchText, + handleSearchSubmit: handleSearchSubmit, + }; + + /* ------------------------------ handle filter ----------------------------- */ + const [statusValue, setStatusValue] = useState('all'); + const [filterData, setStatusData] = useState([]); + + // handle status + const handleStatusChanges = (event: SelectChangeEvent) => { + setStatusValue(event.target.value as string); + + if (event.target.value === 'all') { + searchParams.delete('status'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([ + ...searchParams.entries(), + ['status', event.target.value as string], + ]); + setAppliedParams(params); + } + }; + + const filterStatus = { + useFilter: true, + config: { + label: 'Status', + statusValue: statusValue, + filterData: filterData, + handleStatusChange: handleStatusChanges, + }, + }; + + // handle start date + const [startDateValue, setStartDateValue] = useState(''); + + const handleStartDateChanges = async (event: React.FormEvent) => { + event.preventDefault(); + const newStartDateValue = event.currentTarget.elements['date-input'].value; + setStartDateValue(newStartDateValue); + if (newStartDateValue === '') { + searchParams.delete('start_date'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([...searchParams.entries(), ['start_date', newStartDateValue]]); + setAppliedParams(params); + } + }; + + const filterStartDate = { + useFilter: true, + startDate: startDateValue, + setStartDate: setStartDateValue, + handleStartDateChange: handleStartDateChanges, + }; + + // handle end date + const [endDateValue, setEndDateValue] = useState(''); + + const handleEndDateChanges = async (event: React.FormEvent) => { + event.preventDefault(); + const newEndDateValue = event.currentTarget.elements['date-input'].value; + setEndDateValue(newEndDateValue); + if (newEndDateValue === '') { + searchParams.delete('end_date'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([...searchParams.entries(), ['end_date', newEndDateValue]]); + setAppliedParams(params); + } + }; + + const filterEndDate = { + useFilter: true, + endDate: endDateValue, + setEndDate: setEndDateValue, + handleEndDateChange: handleEndDateChanges, + }; + + /* -------------------------------- headCell Final LOG -------------------------------- */ + const headCells: HeadCell[] = [ + { + id: 'code', + align: 'left', + label: localeData.txtRequestCode, + isSort: true, + }, + { + id: 'full_name', + align: 'left', + label: localeData.txtName, + isSort: true, + }, + { + id: 'submission_date', + align: 'center', + label: localeData.txtSubmissionDate, + isSort: true, + }, + { + id: 'service_type', + align: 'center', + label: localeData.txtServiceType, + isSort: true, + }, + { + id: 'status', + align: 'center', + label: localeData.txtStatus, + isSort: true, + }, + { + id: 'action', + align: 'right', + label: '', + isSort: false, + }, + ]; + function handleSearchMember(noPolis:any, birthDate:any) { + setLoadingClaim(false) + axios.post('/search-member', { + no_polis: noPolis, + birth_date: birthDate ? fPostFormat(birthDate, 'yyyy-MM-dd') : null, + type: 'view' + }) + .then((response) => { + setOpenDialogBenefit(true) + setCurrentMember(response.data.data) + setNameMember(response.data.data.members.name); + }) + .catch(({response}) => { + enqueueSnackbar(response.data.errors ? response.data.errors[0] : (response.data ? response.data.meta.message : 'Opps, Something went Wrong!'), {variant : "error"}) + }) + .then(() => { + }); + } + const [openDialogClaimSubmit, setOpenDialogClaimSubmit] = useState(false); + const [dataViewClaimSubmit, setDataViewClaimSubmit] = useState(null); + function handleRequestClaimSubmit(member_id:any, service_code:any, id:any, full_name:any, no_polis:any, submission_date:any) + { + setOpenDialogClaimSubmit(true); + const datas_view = { + 'member_id' : member_id, + 'service_code' : service_code, + 'id' : id, + 'full_name' : full_name, + 'no_polis' : no_polis, + 'submission_date' : submission_date + }; + setDataViewClaimSubmit(datas_view); + } + + useEffect(() => { + getData(); + }, [appliedParams, searchParams, order, orderBy, setSearchParams]); + + function getData() + { + (async () => { + setIsLoading(true); + + await new Promise((resolve) => setTimeout(resolve, 250)); + + const parameters = + Object.keys(appliedParams).length !== 0 + ? appliedParams + : Object.fromEntries([...searchParams.entries(), ['order', order], ['orderBy', orderBy]]); + + const response = await axios.get(`/get-final-log`, { + params: { ...parameters, type: 'final-log' }, + }); + setData( + response.data.data.map((obj: any) => ({ + ...obj, + status: + obj.status === 'requested' ? ( + + ) : obj.status === 'approved' ? ( + + ) : obj.status === 'declined' ? ( + + ) : obj.status === 'reviewed' ? ( + + ) : ( + + ), + submission_date: + + , + action: + + handleSearchMember(obj.no_polis, obj.birth_date) }> + + View + + {obj.status === 'approved' ? ( + handleDownloadLog(obj.claim_request_id)}> + + Download LOG + + ):''} + {!obj.check_claim ? ( + handleRequestClaimSubmit(obj.member_id, obj.service_code, obj.id, obj.full_name, obj.no_polis, obj.submission_date) }> + + Submit Claim + + ):''} + + } /> + })) + ); + + setPaginationTable(response.data); + setRowsPerPage(response.data.per_page); + + if (searchParams.get('page')) { + //@ts-ignore + const currentPage = parseInt(searchParams.get('page')) - 1; + + paginationTable.current_page = currentPage; + setPage(currentPage); + } + + const status:any = [ + {"id": "requested", "name": "Request" }, + {"id": "reviewed", "name": "Review" }, + {"id": "approved", "name": "Approval" }, + {"id": "declined", "name": "Decline" }, + ]; + setStatusData(status) + + setIsLoading(false); + })(); + } + + const [loadingClaim, setLoadingClaim] = useState(false); + const [openDialogBenefit, setOpenDialogBenefit] = useState(false); + const [currentMember, setCurrentMember] = useState(null); + const [nameMember, setNameMember] = useState(''); + + return ( + <> + + setOpenDialogBenefit(false)) + } + maxWidth="sm" + /> + { + console.log('Data returned:', data); + getData(); + setOpenDialogClaimSubmit(false); + }} + handleSubmitSuccess={() => { + }} + /> + } + maxWidth="sm" + /> + + ); +} \ No newline at end of file diff --git a/frontend/hospital-portal/src/sections/dashboard/TableListReqLog.tsx b/frontend/hospital-portal/src/sections/dashboard/TableListReqLog.tsx new file mode 100644 index 00000000..1e5b224f --- /dev/null +++ b/frontend/hospital-portal/src/sections/dashboard/TableListReqLog.tsx @@ -0,0 +1,425 @@ +/* ---------------------------------- @mui ---------------------------------- */ +import { Stack, Button, MenuItem, SelectChangeEvent, Tab, Tabs, Card, Box } from '@mui/material'; +/* ---------------------------------- axios --------------------------------- */ +// import axios from 'axios'; +import axios from '../../utils/axios'; +import { styled } from '@mui/material/styles'; +/* ---------------------------------- react --------------------------------- */ +import { useContext, useEffect, useState } from 'react'; + +/* -------------------------------- component ------------------------------- */ +import Iconify from '../../components/Iconify'; +import TableComponent from '../../components/Table'; +/* ---------------------------------- theme --------------------------------- */ +import palette from '../../theme/palette'; +//import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; +import { HeadCell, Order, PaginationTableProps } from '../../@types/table'; +import { useSearchParams, useNavigate } from 'react-router-dom'; +import { fDate, fDateSuffix } from '../../utils/formatTime'; +import Typography from '@mui/material/Typography'; +import { format } from 'date-fns'; +import TableMoreMenu from '../../components/table/TableMoreMenu'; +import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; +import HistoryIcon from '@mui/icons-material/History'; +import SearchIcon from '@mui/icons-material/Search'; +import Label from '../../components/Label'; +import { enqueueSnackbar } from 'notistack'; +import { LoadingButton, TabPanel } from "@mui/lab"; +import { LanguageContext } from '@/contexts/LanguageContext'; + +export default function TableList() { + const navigate = useNavigate(); + const { localeData }: any = useContext(LanguageContext); + const [currentTab, setCurrentTab] = useState('request_log'); + + useEffect(() => { + setCurrentTab('request_log') +}, []) + +function handleChangeTab(event: React.SyntheticEvent, newValue: string) { + setCurrentTab(newValue) +} + + //const { corporateValue } = useContext(UserCurrentCorporateContext); + //const { corporateValue } = useContext(null); + + const [data, setData] = useState([]); + + // Download LOG + async function handleDownloadLog(claimRequest) { + return axios + .get(`claim-requests/${claimRequest}/log`, { + responseType: 'blob', + }) + .then((response) => { + window.open(URL.createObjectURL(response.data)); + // setLoadingLog(false); + }) + // .then((blobFile) => { + // new File([blobFile], 'asdads.pdf', { type: blobFile.type }) + // setLoadingLog(false); + // }) + .catch((response) => { + console.log(response); + enqueueSnackbar(response.message, { variant: 'error' }); + // setLoadingLog(false); + }); + } + + /* -------------------------------------------------------------------------- */ + /* setting up for the table */ + /* -------------------------------------------------------------------------- */ + const [isLoading, setIsLoading] = useState(true); + + const loadings = { + isLoading: isLoading, + setIsLoading: setIsLoading, + }; + + /* ------------------------------ handle params ----------------------------- */ + const [searchParams, setSearchParams] = useSearchParams(); + const [appliedParams, setAppliedParams] = useState({}); + + const params = { + searchParams: searchParams, + setSearchParams: setSearchParams, + appliedParams: appliedParams, + setAppliedParams: setAppliedParams, + }; + /* -------------------------------------------------------------------------- */ + + /* ------------------------------ handle order ------------------------------ */ + const [order, setOrder] = useState('desc'); + const [orderBy, setOrderBy] = useState('submission_date'); + + const orders = { + order: order, + setOrder: setOrder, + orderBy: orderBy, + setOrderBy: setOrderBy, + }; + /* -------------------------------------------------------------------------- */ + + /* ---------------------------- handle pagination --------------------------- */ + const [page, setPage] = useState(0); + const [rowsPerPage, setRowsPerPage] = useState(10); + + const [paginationTable, setPaginationTable] = useState({ + current_page: 0, + from: 0, + last_page: 0, + links: [], + path: '', + per_page: 0, + to: 0, + total: 0, + }); + + const paginations = { + page: page, + setPage: setPage, + rowsPerPage: rowsPerPage, + setRowsPerPage: setRowsPerPage, + paginationTable: paginationTable, + setPaginationTable: setPaginationTable, + }; + + /* -------------------------------------------------------------------------- */ + + /* ------------------------------ handle search ----------------------------- */ + const [searchText, setSearchText] = useState(''); + + const handleSearchSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + + if (searchText === '') { + searchParams.delete('search'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([...searchParams.entries(), ['search', searchText]]); + setAppliedParams(params); + } + }; + + const searchs = { + useSearchs: true, + searchText: searchText, + setSearchText: setSearchText, + handleSearchSubmit: handleSearchSubmit, + }; + + /* ------------------------------ handle filter ----------------------------- */ + const [statusValue, setStatusValue] = useState('all'); + const [filterData, setStatusData] = useState([]); + + // handle status + const handleStatusChanges = (event: SelectChangeEvent) => { + setStatusValue(event.target.value as string); + + if (event.target.value === 'all') { + searchParams.delete('status'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([ + ...searchParams.entries(), + ['status', event.target.value as string], + ]); + setAppliedParams(params); + } + }; + + const filterStatus = { + useFilter: true, + config: { + label: 'Status', + statusValue: statusValue, + filterData: filterData, + handleStatusChange: handleStatusChanges, + }, + }; + + // handle start date + const [startDateValue, setStartDateValue] = useState(''); + + const handleStartDateChanges = async (event: React.FormEvent) => { + event.preventDefault(); + const newStartDateValue = event.currentTarget.elements['date-input'].value; + setStartDateValue(newStartDateValue); + if (newStartDateValue === '') { + searchParams.delete('start_date'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([...searchParams.entries(), ['start_date', newStartDateValue]]); + setAppliedParams(params); + } + }; + + const filterStartDate = { + useFilter: true, + startDate: startDateValue, + setStartDate: setStartDateValue, + handleStartDateChange: handleStartDateChanges, + }; + + // handle end date + const [endDateValue, setEndDateValue] = useState(''); + + const handleEndDateChanges = async (event: React.FormEvent) => { + event.preventDefault(); + const newEndDateValue = event.currentTarget.elements['date-input'].value; + setEndDateValue(newEndDateValue); + if (newEndDateValue === '') { + searchParams.delete('end_date'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([...searchParams.entries(), ['end_date', newEndDateValue]]); + setAppliedParams(params); + } + }; + + const filterEndDate = { + useFilter: true, + endDate: endDateValue, + setEndDate: setEndDateValue, + handleEndDateChange: handleEndDateChanges, + }; + + /* -------------------------------- headCell -------------------------------- */ + const headCells: HeadCell[] = [ + { + id: 'submission_date', + align: 'center', + label: localeData.txtRequestDate, + isSort: true, + }, + { + id: 'member_id', + align: 'left', + label: localeData.txtMemberID, + isSort: true, + }, + { + id: 'code', + align: 'left', + label: localeData.txtClaimCode, + isSort: true, + }, + { + id: 'full_name', + align: 'left', + label: localeData.txtName, + isSort: true, + }, + { + id: 'status', + align: 'center', + label: localeData.txtStatus, + isSort: true, + }, + { + id: 'action', + align: 'right', + label: '', + isSort: false, + }, + ]; + + useEffect(() => { + (async () => { + setIsLoading(true); + + await new Promise((resolve) => setTimeout(resolve, 250)); + + const parameters = + Object.keys(appliedParams).length !== 0 + ? appliedParams + : Object.fromEntries([...searchParams.entries(), ['order', order], ['orderBy', orderBy]]); + + const response = await axios.get(`/get-claim-requests`, { + params: { ...parameters, type: 'claim-request' }, + }); + + setData( + response.data.data.map((obj: any) => ({ + ...obj, + status: + obj.status === 'requested' ? ( + + ) : obj.status === 'approved' ? ( + + ) : obj.status === 'declined' ? ( + + ) : obj.status === 'reviewed' ? ( + + ) : ( + + ), + submission_date: + + , + action: + + navigate ('/detail/'+obj.claim_request_id)}> + + View + + handleDownloadLog(obj.claim_request_id)}> + + Download LOG + + + } /> + })) + ); + + setPaginationTable(response.data); + setRowsPerPage(response.data.per_page); + + if (searchParams.get('page')) { + //@ts-ignore + const currentPage = parseInt(searchParams.get('page')) - 1; + + paginationTable.current_page = currentPage; + setPage(currentPage); + } + + const status = [ + {"id": "requested", "name": "Request" }, + {"id": "reviewed", "name": "Review" }, + {"id": "approved", "name": "Approval" }, + {"id": "declined", "name": "Decline" }, + ] + setStatusData(status) + + setIsLoading(false); + })(); + }, [appliedParams, searchParams, order, orderBy, setSearchParams]); + + const RootNotificationStyle = styled(Card)(({ theme }) => ({ + boxShadow: 'none', + padding: '1rem 0.5rem', + color: 'black', + borderRadius: 0, + backgroundColor: theme.palette.grey[200], + // maxHeight: '240px', + })); + + function TabPanel(props:any) { + const { children, value, index, ...other } = props; + return ( + + ); + } + + return ( + + + + + + + + + + + + + + + ); +} diff --git a/resources/lang/en/Message.php b/resources/lang/en/Message.php index 0cd2443f..d0167b2b 100644 --- a/resources/lang/en/Message.php +++ b/resources/lang/en/Message.php @@ -6,4 +6,5 @@ return [ 'not_found' => 'Data not found', 'password' => 'Password wrong. Please try again.', 'read_notification' => 'Notification has been read.', + 'already_exists' => 'Data already exists.', ]; diff --git a/resources/lang/id/Message.php b/resources/lang/id/Message.php index 61ed1c80..475a5731 100644 --- a/resources/lang/id/Message.php +++ b/resources/lang/id/Message.php @@ -6,4 +6,5 @@ return [ 'not_found' => 'Data tidak ditemukan.', 'password' => 'Password salah. Silakan coba lagi.', 'read_notification' => 'Notifikasi telah dibaca.', + 'already_exists' => 'Data sudah ada.', ];