From e76c480ce9e44e69f9788ad29c84dc51b7a1eaf7 Mon Sep 17 00:00:00 2001 From: Tb Fajri Date: Tue, 12 Dec 2023 14:35:12 +0700 Subject: [PATCH 1/3] update final log --- .../Http/Controllers/Api/AuthController.php | 3 +- .../Http/Controllers/Api/ClaimController.php | 2 +- .../Api/RequestLogBenefitController.php | 141 ++++ .../Controllers/Api/RequestLogController.php | 26 +- Modules/Internal/Routes/api.php | 9 +- .../Transformers/RequestLogResource.php | 3 +- .../Transformers/RequestLogShowResource.php | 80 +++ app/Helpers/Helper.php | 61 +- app/Models/File.php | 5 +- app/Models/OrganizationUser.php | 20 + app/Models/RequestLog.php | 2 + app/Models/RequestLogBenefit.php | 27 + app/Models/User.php | 5 + app/Services/RequestLogService.php | 12 +- ...dd_columns_corporate_id_to_users_table.php | 32 + ..._30_092154_add_columns_to_request_logs.php | 35 + ..._30_101523_add_columns_to_request_logs.php | 32 + ..._12_09_090301_create_organization_user.php | 34 + ...0126_create_request_log_benefits_table.php | 38 ++ frontend/dashboard/src/@types/claims.ts | 2 +- frontend/dashboard/src/@types/member.ts | 1 + .../dashboard/src/components/MuiDialog.tsx | 11 +- .../layouts/dashboard/navbar/NavConfig.tsx | 3 +- .../Components/FormCreate.tsx | 355 ++++++++++ .../Components/FormCreateBtnChoose.tsx | 39 ++ .../Components/FormCreateBtnUpload.tsx | 39 ++ .../Components/FormCreateFilesUpload.tsx | 25 + .../Components/FormCreateListChoose.tsx | 78 +++ .../Components/FormCreateSearch.tsx | 70 ++ .../Components/FormEdit.tsx | 456 +++++++++++++ .../InpatientMonitoring/CreateUpdate.tsx | 63 ++ .../InpatientMonitoring/Detail.tsx | 306 +++++++++ .../InpatientMonitoring/DetailStepper.tsx | 58 ++ .../InpatientMonitoring/DetailTimeline.tsx | 426 ++++++++++++ .../InpatientMonitoring/Index.tsx | 30 + .../InpatientMonitoring/List.tsx | 582 +++++++++++++++++ .../InpatientMonitoring/Model/Functions.tsx | 79 +++ .../InpatientMonitoring/Model/Types.tsx | 36 ++ .../Corporates/DiagnosisExclusion/List.tsx | 2 +- .../CustomerService/Components/CardDetail.tsx | 57 ++ .../Components/CardExclusion.tsx | 117 ++++ .../Components/CardService.tsx | 105 +++ .../Components/DetailBenefit.tsx | 115 ++++ .../FinalLog/Components/DialogBenefit.tsx | 343 ++++++++++ .../Components/DialogConfirmation.tsx | 109 ++++ .../FinalLog/Components/DialogDelete.tsx | 69 ++ .../FinalLog/Components/DialogEditBenefit.tsx | 220 +++++++ .../Components/DialogHospitalCare.tsx | 155 +++++ .../FinalLog/Components/DialogMedicine.tsx | 160 +++++ .../pages/CustomerService/FinalLog/Detail.tsx | 611 ++++++++++-------- .../pages/CustomerService/FinalLog/List.tsx | 37 +- .../FinalLog/Model/Functions.tsx | 74 +++ .../CustomerService/FinalLog/Model/Types.tsx | 117 +++- .../Request/Components/DialogConfirmation.tsx | 109 ++++ .../pages/CustomerService/Request/Detail.tsx | 371 ++++------- .../pages/CustomerService/Request/List.tsx | 26 +- .../CustomerService/Request/Model/Types.tsx | 56 +- frontend/dashboard/src/routes/index.tsx | 22 +- frontend/dashboard/src/utils/formatTime.ts | 6 + 59 files changed, 5524 insertions(+), 583 deletions(-) create mode 100644 Modules/Internal/Http/Controllers/Api/RequestLogBenefitController.php create mode 100644 Modules/Internal/Transformers/RequestLogShowResource.php create mode 100644 app/Models/OrganizationUser.php create mode 100644 app/Models/RequestLogBenefit.php create mode 100644 database/migrations/2023_11_07_124118_add_columns_corporate_id_to_users_table.php create mode 100644 database/migrations/2023_11_30_092154_add_columns_to_request_logs.php create mode 100644 database/migrations/2023_11_30_101523_add_columns_to_request_logs.php create mode 100644 database/migrations/2023_12_09_090301_create_organization_user.php create mode 100644 database/migrations/2023_12_11_100126_create_request_log_benefits_table.php create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreate.tsx create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnChoose.tsx create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnUpload.tsx create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateFilesUpload.tsx create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateListChoose.tsx create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateSearch.tsx create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormEdit.tsx create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/CreateUpdate.tsx create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Detail.tsx create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailStepper.tsx create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailTimeline.tsx create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Index.tsx create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/List.tsx create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Functions.tsx create mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Types.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/Components/CardDetail.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/Components/CardExclusion.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/Components/CardService.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/Components/DetailBenefit.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogBenefit.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogConfirmation.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogDelete.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogEditBenefit.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogHospitalCare.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogMedicine.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/Request/Components/DialogConfirmation.tsx diff --git a/Modules/HospitalPortal/Http/Controllers/Api/AuthController.php b/Modules/HospitalPortal/Http/Controllers/Api/AuthController.php index bf221968..55eaa1a7 100644 --- a/Modules/HospitalPortal/Http/Controllers/Api/AuthController.php +++ b/Modules/HospitalPortal/Http/Controllers/Api/AuthController.php @@ -23,6 +23,7 @@ class AuthController extends Controller 'email' => $request->email, 'password' => $request->password ]; + $validator = Validator::make($request->all(), [ 'email' => 'required|email', 'password' => 'required' @@ -38,7 +39,7 @@ class AuthController extends Controller } else { - $user = User::where('email', $request->email)->first(); + $user = User::with('getOrganization.organization')->where('email', $request->email)->first(); if (!$user) { return ApiResponse::apiResponse('Not Found', $data, trans('message.not_found'), 404); } diff --git a/Modules/Internal/Http/Controllers/Api/ClaimController.php b/Modules/Internal/Http/Controllers/Api/ClaimController.php index 2d79fc2f..5b84078c 100644 --- a/Modules/Internal/Http/Controllers/Api/ClaimController.php +++ b/Modules/Internal/Http/Controllers/Api/ClaimController.php @@ -34,7 +34,7 @@ class ClaimController extends Controller */ public function index(Request $request) { - $serviceCode = 'IP'; + // $serviceCode = 'IP'; $claims = Claim::with([ 'member', 'member.currentCorporate', diff --git a/Modules/Internal/Http/Controllers/Api/RequestLogBenefitController.php b/Modules/Internal/Http/Controllers/Api/RequestLogBenefitController.php new file mode 100644 index 00000000..97788e6f --- /dev/null +++ b/Modules/Internal/Http/Controllers/Api/RequestLogBenefitController.php @@ -0,0 +1,141 @@ + 'Kolom :attribute wajib diisi.', + 'numeric' => 'Kolom :attribute harus berupa angka.', + ]; + + $validator = Validator::make($request->all(), [ + 'benefit_data' => 'required|array', + 'benefit_data.*' => 'required', + ], $customMessages); + + if ($validator->fails()) { + return Helper::responseJson([],'error', 400, $validator->errors()); + } else { + $benefitData = $request->benefit_data; + + if (count($benefitData)>0){ + // BeginTransaction + DB::beginTransaction(); + foreach($benefitData as $key => $value){ + $data = [ + 'request_log_id' => $value['request_log_id'], + 'benefit_id' => $value['benefit_id'], + 'amount_incurred' => $value['amount_incurred'], + 'amount_approved' => $value['amount_approved'], + 'amount_not_approved' => $value['amount_not_approved'], + 'excess_paid' => $value['excess_paid'], + 'keterangan' => $value['keterangan'], + + ]; + // Insert Data + try { + RequestLogBenefit::create($data); + } catch (\Throwable $th) { + DB::rollBack(); + return Helper::responseJson(status: 'failed', statusCode: 500, message: $th->getMessage()); + } + } + DB::commit(); + return Helper::responseJson(status: 'success', statusCode: 201, message: 'success', data: $request->toArray()); + }; + + } + + + $requestLogBenefit = RequestLogBenefit::insert($data); + return $requestLogBenefit; + } + + /** + * Show the form for editing the specified resource. + * @param int $id + * @return Renderable + */ + public function edit($id) + { + return view('internal::edit'); + } + + /** + * Update the specified resource in storage. + * @param Request $request + * @param int $id + * @return Renderable + */ + public function update(Request $request, $id) + { + $requestLogBenefit = requestLogBenefit::findOrFail($id); + $requestLogBenefit->amount_approved = $request->amount_approved; + $requestLogBenefit->amount_incurred = $request->amount_incurred; + $requestLogBenefit->amount_not_approved = $request->amount_not_approved; + $requestLogBenefit->excess_paid = $request->excess_paid; + $requestLogBenefit->keterangan = $request->keterangan; + + $requestLogBenefit->save(); + + return response()->json([ + 'error' => false, + 'message' => 'Update succses', + 'data' => $requestLogBenefit], + 200); + } + + /** + * Remove the specified resource from storage. + * @param int $id + * @return Renderable + */ + public function destroy($id) + { + $requestLogBenefit = RequestLogBenefit::findOrFail($id); + $requestLogBenefit->delete(); + } + +} diff --git a/Modules/Internal/Http/Controllers/Api/RequestLogController.php b/Modules/Internal/Http/Controllers/Api/RequestLogController.php index 23a99492..b4b0f168 100644 --- a/Modules/Internal/Http/Controllers/Api/RequestLogController.php +++ b/Modules/Internal/Http/Controllers/Api/RequestLogController.php @@ -57,8 +57,11 @@ class RequestLogController extends Controller ->when(empty($request->orderBy), function ($q) { $q->orderBy('created_at', 'desc'); }) - ->when($request->status, function($q, $status) { - $q->where('status', $status); + ->when($request->final_log, function($q, $final_log) { + $q->where('final_log', $final_log); + }) + ->when($request->service_code, function($q, $service_code) { + $q->where('service_code', $service_code); }) // ->where('status', $request->status) ->with(['member', 'files', 'service', 'member.currentPolicy']) @@ -165,6 +168,9 @@ class RequestLogController extends Controller }, 'files', 'member', + 'member.currentPlan' => function($memberPlan) { + $memberPlan->join('request_logs', 'request_logs.service_code', '=', 'plans.service_code'); + }, 'claim', 'organization', ]); @@ -293,10 +299,20 @@ class RequestLogController extends Controller ]); } - public function updateFinalLog(Request $request, $id) + /** + * Submit Request LOG to Final LOG + */ + public function updateFinalLog(Request $request) { + $id = $request->id; $requestLog = RequestLog::findOrFail($id); + // Update Request LOG untuk lanjut ke Final LOG + $requestLog->final_log = 1; + $requestLog->status_final_log = 'requested'; + $requestLog->save(); + + if ($request->hasFile('result_files')) { foreach ($request->result_files as $file) { $pathFile = File::storeFile('final-log-result', $id, $file); @@ -335,7 +351,7 @@ class RequestLogController extends Controller 'name' => File::getFileName('final-log-kondisi', $id, $file), 'original_name' => $file->getClientOriginalName(), 'extension' => $file->getClientOriginalExtension(), - 'path' => $pathFile, + 'path' => $pathFile, 'created_by' => auth()->user()->id, 'updated_by' => auth()->user()->id, ]); @@ -345,7 +361,7 @@ class RequestLogController extends Controller return response()->json([ 'error' => false, 'message' => 'Update succses', - 'data' => $updateClaimRequest], + 'data' => $requestLog], 200); } diff --git a/Modules/Internal/Routes/api.php b/Modules/Internal/Routes/api.php index 1977019a..f4a08dc7 100644 --- a/Modules/Internal/Routes/api.php +++ b/Modules/Internal/Routes/api.php @@ -8,6 +8,7 @@ use Modules\Internal\Http\Controllers\Api\BenefitController; use Modules\Internal\Http\Controllers\Api\CityController; use Modules\Internal\Http\Controllers\Api\ClaimController; use Modules\Internal\Http\Controllers\Api\RequestLogController; +use Modules\Internal\Http\Controllers\Api\RequestLogBenefitController; use Modules\Internal\Http\Controllers\Api\ClaimRequestController; use Modules\Internal\Http\Controllers\Api\CorporateBenefitController; use Modules\Internal\Http\Controllers\Api\CorporateController; @@ -251,11 +252,17 @@ Route::prefix('internal')->group(function () { Route::get('customer-service/request', [RequestLogController::class, 'index']); Route::post('customer-service/request', [RequestLogController::class, 'createNew']); Route::put('customer-service/request/{id}', [RequestLogController::class, 'update']); + Route::get('customer-service/request/{id}', [RequestLogController::class, 'show']); Route::get('customer-service/request/{id}/download', [RequestLogController::class, 'generateRequestLog']); Route::post('customer-service/request/import', [RequestLogController::class, 'importRequestLog']); Route::get('customer-service/request/data', [RequestLogController::class, 'generateDataRequestLogExcel']); - + Route::post('customer-service/request/final-log', [RequestLogController::class, 'updateFinalLog']); + // insert benefit + Route::post('customer-service/request/insert-benefit', [RequestLogBenefitController::class, 'store']); + Route::delete('customer-service/request/benefit_data/{id}', [RequestLogBenefitController::class, 'destroy']); + Route::put('customer-service/request/benefit_data/{id}', [RequestLogBenefitController::class, 'update']); + Route::get('search-organizations', [OrganizationController::class, 'searchOrganization']); Route::get('search-specialities', [SpecialityController::class, 'searchSpeciality']); diff --git a/Modules/Internal/Transformers/RequestLogResource.php b/Modules/Internal/Transformers/RequestLogResource.php index bb900cfd..06b43fa2 100644 --- a/Modules/Internal/Transformers/RequestLogResource.php +++ b/Modules/Internal/Transformers/RequestLogResource.php @@ -23,8 +23,9 @@ class RequestLogResource extends JsonResource 'id' => $this->id, 'code' => $this->code, 'submission_date' => $this->submission_date, - 'member' => $this->member, + 'member_name' => $this->member->name, 'status' => $this->status ?? 'unknown', + 'status_final_log' => $this->status_final_log ?? 'unknown', 'service_name' => $this->service ? $this->service->name : '', 'payment_type' => $this->payment_type, 'payment_type_name' => $this->payment_type_name, diff --git a/Modules/Internal/Transformers/RequestLogShowResource.php b/Modules/Internal/Transformers/RequestLogShowResource.php new file mode 100644 index 00000000..e9a5c60e --- /dev/null +++ b/Modules/Internal/Transformers/RequestLogShowResource.php @@ -0,0 +1,80 @@ +where('plan_id', $corporateId)->get()->toArray(); + $benefitDetailLog = RequestLogBenefit::with('benefit')->where('request_log_id', $requestLog['id'])->get()->toArray(); + $benefitData = []; + if (count($benefit)){ + foreach($benefit as $data){ + array_push($benefitData, $data['benefit']); + } + } + + // Service Rule + $corporateService = CorporateService::query() + ->where('corporate_id', $corporateId) + ->where('service_code', $requestLog['service_code']) + ->with(['configs']) + ->first(); + $config = $corporateService->configs->pluck('value', 'name')->toArray(); + + // Exclusion Service or diagnosis + $exclusions = Exclusion::query() + ->where('corporate_id', $corporateId) + ->where('type', 'diagnosis') + ->with(['exclusionable', 'rules']) + ->get()->toArray(); + + $data = [ + 'id' => $requestLog['id'], + 'code' => $requestLog['code'], + 'member_id' => $requestLog['member']['member_id'], + 'policy_number' => $requestLog['member']['current_policy']['code'], + 'name' => $requestLog['member']['name'], + 'date_of_birth' => $requestLog['member']['birth_date'], + 'gender' => $requestLog['member']['gender'], + 'marital_status' => Helper::maritalNormalization($requestLog['member']['marital_status']), + 'member_type' => Helper::memberType($requestLog['member']['record_type']), + 'principal_id' => $requestLog['member']['principal_id'] ? $requestLog['member']['principal_id'] : '-', + 'principal_name' => $requestLog['member']['principal_id'] ? Helper::principalName($requestLog['member']['principal_id']) : '-', + 'relation_with_principal' => Helper::relationWithPrincipal($requestLog['member']['relation_with_principal']), + 'submission_date' => $requestLog['submission_date'], + 'service_type' => Helper::serviceName($requestLog['service_code']), + 'claim_method' => $requestLog['payment_type'], + 'status' => $requestLog['status'], + 'status_final_log' => $requestLog['status_final_log'], + 'benefit' => $benefitData, + 'benefit_data' => $benefitDetailLog, + 'config_service' => $config, + 'exclusion' => $exclusions, + 'files' => $requestLog['files'], + + + ]; + + return $data; + } +} diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 59629850..5ce5c9a4 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -8,24 +8,39 @@ use Illuminate\Http\JsonResponse; use Symfony\Component\HttpFoundation\Response; use PHPMailer\PHPMailer\PHPMailer; use Illuminate\Support\Facades\DB; +use App\Models\Member; +use App\Models\Service; class Helper { public static function genderNormalization($anyGenderCode) { if ($anyGenderCode == 'M') { - return 'male'; + return 'Male'; } else if ($anyGenderCode == 'F') { - return 'female'; + return 'Female'; } else if ($anyGenderCode == 'O') { - return 'others'; + return 'Others'; } else if ($anyGenderCode == 'U') { - return 'unknown'; + return 'Unknown'; } else { return null; } } + public static function maritalNormalization($code) + { + if ($code == 'M') { + return 'Married'; + } else if ($code == 'D') { + return 'Divorced'; + } else if ($code == 'S') { + return 'Single'; + } else { + return '-'; + } + } + public static function genderPerson($anyGenderCode) { if ($anyGenderCode == 'M') { @@ -41,6 +56,44 @@ class Helper } } + public static function memberType($code){ + if ($code == 'P') { + return 'Principal'; + } else if ($code == 'D') { + return 'Dependent'; + } else { + '-'; + } + } + + public static function relationWithPrincipal($code){ + if ($code == 'H') { + return 'Husbund'; + } + else if ($code == 'W') { + return 'Wife'; + } + else if ($code == 'S') { + return 'Son'; + } + else if ($code == 'D') { + return 'Daughter'; + } + else { + '-'; + } + } + + public static function principalName($code){ + $principalName = Member::where('member_id', $code)->get()->first(); + return $principalName->name; + } + + public static function serviceName($code){ + $serviceName = Service::where('code', $code)->get()->first(); + return $serviceName->name; + } + public static function paginateResources($resource) { return [ diff --git a/app/Models/File.php b/app/Models/File.php index f172de82..f12dfdc3 100644 --- a/app/Models/File.php +++ b/app/Models/File.php @@ -44,6 +44,9 @@ class File extends Model 'claim-diagnosis' => 'claim/', 'claim-kondisi' => 'claim/', 'claim-invoice' => 'claim/', + 'final-log-result' => 'final-log/', + 'final-log-diagnosis' => 'final-log/', + 'final-log-kondisi' => 'final-log/', 'docs' => 'docs/', ]; @@ -54,7 +57,7 @@ class File extends Model public static function getDirectory($type) { - return self::$file_directories[$type] ?? 'any'; + return self::$file_directories[$type] ?? 'any/'; } public static function getFileName($type, $id) diff --git a/app/Models/OrganizationUser.php b/app/Models/OrganizationUser.php new file mode 100644 index 00000000..21f98751 --- /dev/null +++ b/app/Models/OrganizationUser.php @@ -0,0 +1,20 @@ +hasOne(Organization::class, 'id', 'organization_id'); + } +} diff --git a/app/Models/RequestLog.php b/app/Models/RequestLog.php index 827cd846..8f93fd52 100644 --- a/app/Models/RequestLog.php +++ b/app/Models/RequestLog.php @@ -24,7 +24,9 @@ class RequestLog extends Model 'payment_type', 'service_code', 'policy_id', + 'final_log', 'status', + 'status_final_log', 'source', 'claim_id', 'organization_id', diff --git a/app/Models/RequestLogBenefit.php b/app/Models/RequestLogBenefit.php new file mode 100644 index 00000000..331227f1 --- /dev/null +++ b/app/Models/RequestLogBenefit.php @@ -0,0 +1,27 @@ +belongsTo(Benefit::class, 'benefit_id', 'id'); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index d4090eca..22b1bee4 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -105,4 +105,9 @@ class User extends Authenticatable { return $this->morphMany(NotificationToken::class, 'notifiabletoken'); } + + public function getOrganization() + { + return $this->hasOne(OrganizationUser::class, 'user_id'); + } } diff --git a/app/Services/RequestLogService.php b/app/Services/RequestLogService.php index 76d124cb..5a5a5c64 100644 --- a/app/Services/RequestLogService.php +++ b/app/Services/RequestLogService.php @@ -154,12 +154,16 @@ class RequestLogService{ } // Update Request LOG Status & Link with Claim - $requestLog->update([ - 'status' => $row['status'] - ]); - $requestLog->save(); + DB::beginTransaction(); + $requestLog->update([ + 'status' => $row['status'] + ]); + $requestLog->save(); + DB::commit(); return $requestLog; } catch (\Exception $e) { + DB::rollBack(); + throw $e; } } diff --git a/database/migrations/2023_11_07_124118_add_columns_corporate_id_to_users_table.php b/database/migrations/2023_11_07_124118_add_columns_corporate_id_to_users_table.php new file mode 100644 index 00000000..78f562be --- /dev/null +++ b/database/migrations/2023_11_07_124118_add_columns_corporate_id_to_users_table.php @@ -0,0 +1,32 @@ +integer('corporate_id')->default(0)->after('phone'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('corporate_id'); + }); + } +}; diff --git a/database/migrations/2023_11_30_092154_add_columns_to_request_logs.php b/database/migrations/2023_11_30_092154_add_columns_to_request_logs.php new file mode 100644 index 00000000..94df90fd --- /dev/null +++ b/database/migrations/2023_11_30_092154_add_columns_to_request_logs.php @@ -0,0 +1,35 @@ +integer('final_log') + ->default(0) + ->after('status') + ->comment('untuk flag request masuk ke final, jika 0 masih request dan 1 itu sudah masuk ke finallog'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('request_logs', function (Blueprint $table) { + $table->dropColumn('final_log'); + }); + } +}; diff --git a/database/migrations/2023_11_30_101523_add_columns_to_request_logs.php b/database/migrations/2023_11_30_101523_add_columns_to_request_logs.php new file mode 100644 index 00000000..ded8a874 --- /dev/null +++ b/database/migrations/2023_11_30_101523_add_columns_to_request_logs.php @@ -0,0 +1,32 @@ +string('status_final_log')->after('status')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('request_logs', function (Blueprint $table) { + $table->dropColumn('status_final_log'); + }); + } +}; diff --git a/database/migrations/2023_12_09_090301_create_organization_user.php b/database/migrations/2023_12_09_090301_create_organization_user.php new file mode 100644 index 00000000..320d9227 --- /dev/null +++ b/database/migrations/2023_12_09_090301_create_organization_user.php @@ -0,0 +1,34 @@ +id(); + $table->foreignId('user_id'); + $table->foreignId('organization_id'); + $table->integer('status')->nullable()->default(1); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('organization_user'); + } +}; diff --git a/database/migrations/2023_12_11_100126_create_request_log_benefits_table.php b/database/migrations/2023_12_11_100126_create_request_log_benefits_table.php new file mode 100644 index 00000000..070b64d9 --- /dev/null +++ b/database/migrations/2023_12_11_100126_create_request_log_benefits_table.php @@ -0,0 +1,38 @@ +id(); + $table->timestamps(); + $table->foreignId('request_log_id'); + $table->foreignId('benefit_id'); + $table->integer('amount_incurred'); + $table->integer('amount_approved'); + $table->integer('amount_not_approved'); + $table->integer('excess_paid'); + $table->string('keterangan'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('request_log_benefits'); + } +}; diff --git a/frontend/dashboard/src/@types/claims.ts b/frontend/dashboard/src/@types/claims.ts index 15c068bc..61e098cc 100644 --- a/frontend/dashboard/src/@types/claims.ts +++ b/frontend/dashboard/src/@types/claims.ts @@ -61,7 +61,7 @@ export type ClaimHistoryCare = { id: number; claim_id: number; service_code: string; - admision_date: string; + admission_date: string; discharge_date: string; main_diagnosis_id: number; main_diagnosis_name: string; diff --git a/frontend/dashboard/src/@types/member.ts b/frontend/dashboard/src/@types/member.ts index bd2edf24..45bfc833 100644 --- a/frontend/dashboard/src/@types/member.ts +++ b/frontend/dashboard/src/@types/member.ts @@ -22,4 +22,5 @@ export type Member = { active: string, current_plans: Plan, current_corporate: Corporate, + full_name: string, }; diff --git a/frontend/dashboard/src/components/MuiDialog.tsx b/frontend/dashboard/src/components/MuiDialog.tsx index 54ee1110..599eb60f 100644 --- a/frontend/dashboard/src/components/MuiDialog.tsx +++ b/frontend/dashboard/src/components/MuiDialog.tsx @@ -1,4 +1,4 @@ -import { Dialog, DialogTitle, DialogContent, Stack, Typography, IconButton } from '@mui/material'; +import { Dialog, DialogTitle, DialogContent, Stack, Typography, IconButton, DialogActions } from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; import { ReactElement } from 'react'; import Iconify from './Iconify'; @@ -13,12 +13,13 @@ type MuiDialogProps = { openDialog: boolean; setOpenDialog: Function; content?: ReactElement; + action?: ReactElement; maxWidth?: string; }; // ---------------------------------------------------------------------- -const MuiDialog = ({ title, openDialog, setOpenDialog, content, maxWidth }: MuiDialogProps) => { +const MuiDialog = ({ title, openDialog, setOpenDialog, content, action, maxWidth }: MuiDialogProps) => { const handleClose = () => { setOpenDialog(false); }; @@ -46,9 +47,15 @@ const MuiDialog = ({ title, openDialog, setOpenDialog, content, maxWidth }: MuiD + {content ? content : 'Testing Content Dialog'} + + {action ? ( + {action} + ) : ''} + ); }; diff --git a/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx b/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx index 3ca34a56..0827cd38 100644 --- a/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx +++ b/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx @@ -77,6 +77,7 @@ const navConfig = [ children: [ { title: 'Daily Monitoring', path: '/case_management/daily_monitoring' }, { title: 'Laboratorium Result', path: '/case_management/laboratorium_result' }, + { title: 'Inpatient Monitoring', path: '/case_management/inpatient_monitoring' }, ], }, { @@ -84,7 +85,7 @@ const navConfig = [ children: [ { title: 'Request', path: '/custormer-service/request' }, // { title: 'Membership', path: '/cs-membership' }, - { title: 'Final LOG', path: '/custormer-service/final-request' }, + { title: 'Final LOG', path: '/custormer-service/final-log' }, ], }, { diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreate.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreate.tsx new file mode 100644 index 00000000..d952f5e3 --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreate.tsx @@ -0,0 +1,355 @@ +/** + * Core + * ============================================ + */ +import { useEffect, useState } from 'react'; +import { useNavigate } from 'react-router'; +import { Box, FormControlLabel, Grid, Checkbox, Typography, CircularProgress , Button, styled, Stack, IconButton, Card} from '@mui/material'; +import { LoadingButton } from '@mui/lab'; + +/** + * Components + * ============================================ +*/ +// - Global - +import Label from '@/components/Label'; +// - Local - +import FormCreateSearch from './FormCreateSearch'; +import FormCreateListChoose from './FormCreateListChoose'; +import FormCreateBtnUpload from './FormCreateBtnUpload'; + +/** + * Icon, Utils, Types, Functions, theme, hook + * ============================================ + */ +import { ArrowBackIosNew } from '@mui/icons-material'; +import { fDateTimesecond } from '@/utils/formatTime'; +import { MemberListType } from '../Model/Types'; +import { addClaimRequest, getMemberList } from '../Model/Functions'; +import palette from '@/theme/palette'; +import FormCreateFilesUpload from './FormCreateFilesUpload'; +import useLoadOnScroll from '@/hooks/useLoadOnScroll'; +import useCollapseDrawer from '@/hooks/useCollapseDrawer'; +import FormCreateBtnChoose from './FormCreateBtnChoose'; +import axios from '../../../utils/axios'; + +export default function FormCreate() { + const navigate = useNavigate() + const defaultListChoosed:MemberListType[] = []; + + // State + // ------------------------- + const [keyword, setKeyword] = useState(''); + const [listChoosed, setListChoosed] = useState([]); + const [isChoosed, setIsChoosed] = useState(false); + const [formIsLoading, setFormIsLoading] = useState(false); + + // List Choose - auto Scroll + // ------------------------- + const fetchFunction = async (page: number): Promise => getMemberList(page, keyword) + + const {data: MemberList, isLoading: scrollIsLoading, setData, resetLastPage, refetchData} = useLoadOnScroll(fetchFunction); + + // List Choose - Search + // ------------------------- + const handleSearch = (keyword: string) => { + setData([]) + resetLastPage() + setKeyword(keyword) + refetchData() + } + + // Function - Clear Form + // ----------------------------- + const clearForm = () => { + setListChoosed(defaultListChoosed); + setIsChoosed(false); + } + + // Function - Choose Patien Type + // ----------------------------- + const handleChoosePatienType = (data: MemberListType, type: string) => { + let newListChoosed = listChoosed.map((list) => { + if (data.id == list.id) { + list.patien_type = type + } + + return list; + }) + setListChoosed(newListChoosed) + } + + // Function - Handle Btn Upload + // ----------------------------- + const handleChangeInput = (data: MemberListType, type_file: 'kondisi'|'diagnosa'|'penunjang', file: any) => { + let newListChoosed = listChoosed.map((list) => { + if (data.id == list.id) { + if (type_file == 'kondisi') { + if (list.file_kondisi == undefined) { + list.file_kondisi = [file]; + } + else { + list.file_kondisi.push(file); + } + } + + if (type_file == 'diagnosa') { + if (list.file_diagnosa == undefined) { + list.file_diagnosa = [file]; + } + else { + list.file_diagnosa.push(file); + } + } + + if (type_file == 'penunjang') { + if (list.file_penunjang == undefined) { + list.file_penunjang = [file]; + } + else { + list.file_penunjang.push(file); + } + } + } + + return list; + }) + + setListChoosed(newListChoosed) + } + + // Function - Handle Remove Fle + // ----------------------------- + const handleRemoveFile = (data: MemberListType, type_file: 'kondisi'|'diagnosa'|'penunjang', target_index: number) => { + let newListChoosed = listChoosed.map((list) => { + if (data.id == list.id) { + if (type_file == 'kondisi') { + list.file_kondisi = list.file_kondisi?.filter((file: any, index: number) =>{ + if (target_index !== index) { + return file; + } + }); + } + + if (type_file == 'diagnosa') { + list.file_diagnosa = list.file_diagnosa?.filter((file: any, index: number) =>{ + if (target_index !== index) { + return file; + } + }); + } + + if (type_file == 'penunjang') { + list.file_penunjang = list.file_penunjang?.filter((file: any, index: number) =>{ + if (target_index !== index) { + return file; + } + }); + } + } + + return list; + }) + + setListChoosed(newListChoosed) + } + + // Function - Handle Submit Form + // ----------------------------- + const handleSubmit = async () => { + setFormIsLoading(true) + let response = await addClaimRequest(listChoosed) + setFormIsLoading(false) + + if (response == true) { + clearForm() + } + } + + + + let isDirty = listChoosed.some((row) => { + if (row.patien_type == undefined) { + return true + } + }) + + return ( + + {/* Back Button */} + + isChoosed==false ? navigate(`/claim-requests`) : setIsChoosed(false)} > + + + + + {'Create Claim Requests'} + + + + {/* Choose Section */} + + {/* Search */} + + handleSearch('')} onSubmit={(keyword) => handleSearch(keyword)} /> + + + + + {/* List */} + + + { + MemberList.map((row, index) => { + return ( + { + checked ? setListChoosed((prevData) => [...prevData, data]) : setListChoosed((items) => items.filter(item => item.id != data.id)) + }} + /> + ) + }) + } + + + + {/* Loading */} + + + + + {/* Submit List */} + + setIsChoosed(true)} /> + + + + + + {/* Input Section */} + + { + listChoosed.map((row, index) => { + return ( + + + {/* Patien Name */} + + + + + {row.name} + + + {row.member_id} + + + + + + + {/* Patien Type */} + + + {row.service_type.map((r,i) => { + const code = r.code + return ( + + + + ) + })} + + + + {/* File Kondisi */} + + + + Condition Document + + + {row.file_kondisi && row.file_kondisi.map((file, index) => ( + + handleRemoveFile(row, 'kondisi', index)} /> + + ))} + + + handleChangeInput(row, 'kondisi', file)} /> + + + + + {/* File Diagnosa */} + + + + Diagnosis Document + + + {row.file_diagnosa && row.file_diagnosa.map((file, index) => ( + + handleRemoveFile(row, 'diagnosa', index)} /> + + ))} + + + handleChangeInput(row, 'diagnosa', file)} /> + + + + + {/* File Penunjang */} + + + + Supporting Result Document + + + {row.file_penunjang && row.file_penunjang.map((file, index) => ( + + handleRemoveFile(row, 'penunjang', index)} /> + + ))} + + + handleChangeInput(row, 'penunjang', file)} /> + + + + + + + ) + }) + } + + + + + handleSubmit()}> + Save Changes + + + + + + ) +} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnChoose.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnChoose.tsx new file mode 100644 index 00000000..cffd3bc3 --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnChoose.tsx @@ -0,0 +1,39 @@ +import { styled, Button } from "@mui/material"; +import useCollapseDrawer from "@/hooks/useCollapseDrawer"; + +/** + * Custom Style + * ============================================ +*/ +const DivCustom1 = styled('div')(({ theme }) => ({ + background: 'white', + position: 'fixed', + left: '350px', + right: 0, + bottom: 0, + paddingLeft: '32px', + paddingRight: '32px', + paddingTop: '32px', + paddingBottom: '48px', + [theme.breakpoints.between('sm', 'lg')]: { + left: '0px', + }, +})); + +type Props = { + disabled: boolean, + title : string, + handleClickProp: () => void +} + +export default function FormCreateBtnChoose ({disabled, title, handleClickProp}: Props) { + const { collapseClick } = useCollapseDrawer(); + + return ( + + + + ) +} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnUpload.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnUpload.tsx new file mode 100644 index 00000000..23df5ed5 --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnUpload.tsx @@ -0,0 +1,39 @@ +import { useRef } from "react"; +import { Box, ButtonBase, Typography } from "@mui/material"; +import Iconify from "@/components/Iconify"; + +type Props = { + handleChangeInputProp: (event: any) => void +} + +export default function FormCreateBtnUpload ({handleChangeInputProp}: Props) { + const fileInput = useRef(null); + + return ( + fileInput.current?.click()}> + + + + Upload Result + + + handleChangeInputProp(event.target.files ? event.target.files[0] : {})} + accept="application/pdf" + /> + + ) +} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateFilesUpload.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateFilesUpload.tsx new file mode 100644 index 00000000..7ab9d7bd --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateFilesUpload.tsx @@ -0,0 +1,25 @@ +import Iconify from "@/components/Iconify"; +import { ArrowBackIosNew, InsertDriveFile } from '@mui/icons-material'; +import { Stack, Typography } from "@mui/material"; + +type Props = { + file: any, + handleRemoveFileProp: () => void, +} + +export default function FormCreateFilesUpload({ file, handleRemoveFileProp }: Props) { + return ( + + + + {file.name ? file.name : '-'} + + {handleRemoveFileProp()}} + sx={{cursor: 'pointer'}} + > + + ) +} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateListChoose.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateListChoose.tsx new file mode 100644 index 00000000..03c8d0b1 --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateListChoose.tsx @@ -0,0 +1,78 @@ +/** + * Core + * ============================================ + */ +import { useEffect, useState } from 'react'; +import { Box, FormControlLabel, Grid, Checkbox, Typography, Card} from '@mui/material'; + +/** + * Components + * ============================================ +*/ +// - Global - +import Label from '@/components/Label'; +// - Local - + +/** + * Icon, Utils, Types, Functions, theme, hook + * ============================================ + */ +import { fDateTimesecond } from '@/utils/formatTime'; +import { MemberListType } from '../Model/Types'; +import palette from '@/theme/palette'; + +/** + * Props + * ===================================================== + */ +type Props = { + data: MemberListType, + ListChoosed: MemberListType[], + handleCheckedProp: (checked: boolean, data: MemberListType) => void, +}; + +export default function FormCreateListChoose({data, ListChoosed, handleCheckedProp}: Props) { + const [isChoosed, setIsChoosed] = useState(false) + + useEffect(() => { + setIsChoosed(false); + + ListChoosed.forEach(list => { + if (list.id == data.id) { + setIsChoosed(true); + } + }) + }, [ListChoosed]) + + return ( + + { + return isChoosed ? palette.light.primary.lighter : palette.light.background.default + } + }}> + + handleCheckedProp(checked, data)} />} + checked={isChoosed} + /> + + + + {data.name} + + + {data.member_id} + + + + + + + + ) +} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateSearch.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateSearch.tsx new file mode 100644 index 00000000..026b886b --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateSearch.tsx @@ -0,0 +1,70 @@ +/** + * Core + * ============================================ + */ +import { useEffect } from 'react'; +import { useForm } from 'react-hook-form'; +import { Grid } from '@mui/material'; + +/** + * Components + * ============================================ +*/ +// - Global - +import { FormProvider, RHFTextField } from '@/components/hook-form'; +// - Local - + +/** + * Icon, Utils, Types, Functions + * ============================================ + */ +import { Search } from '@mui/icons-material'; +import { SearchType } from '../Model/Types'; + +type Props = { + onSubmit: (keyword: string) => void, + onEmpty: () => void, +}; + +const FormCreateSearch = ({ onSubmit, onEmpty }: Props) => { + const defaultValuesSearchForm = { + keyword: '' + }; + + const methodsSearchForm = useForm({ + defaultValues: defaultValuesSearchForm + }); + + const { handleSubmit, formState: { isDirty } } = methodsSearchForm; + + // search on submit + const onSubmitSearch = (data: SearchType ) => { + onSubmit(data.keyword); + } + + // search on empty + useEffect(() => { + if (isDirty === false) { + onEmpty() + } + },[isDirty]) + + return ( + + + + }} + sx={{ input: { paddingLeft: '14px' } }} + /> + + + + ) +} + +export default FormCreateSearch diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormEdit.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormEdit.tsx new file mode 100644 index 00000000..faa95bf0 --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormEdit.tsx @@ -0,0 +1,456 @@ +import * as Yup from 'yup'; +import { useSnackbar } from 'notistack'; +import { useNavigate } from 'react-router-dom'; +import { yupResolver } from '@hookform/resolvers/yup'; +import { Controller, useForm } from 'react-hook-form'; +import React, { useRef, useEffect, useMemo, useState } from 'react'; +import axios from '../../../utils/axios'; +import { FormProvider, RHFTextField } from '../../../components/hook-form'; + +import { makeFormData } from '@/utils/jsonToFormData'; +import { + Autocomplete, + Button, + Grid, + Stack, + Table, + TableBody, + TableCell, + TableRow, + TextField, + Typography, + useTheme, + List, + ListItem, + IconButton, + ListItemAvatar, + Avatar, + ListItemText, + Card, + InputAdornment, + Divider, + ButtonBase, + Box, +} from '@mui/material'; +import Iconify from '../../../components/Iconify'; +import CalendarTodayIcon from '@mui/icons-material/CalendarToday'; +import { LoadingButton } from '@mui/lab'; +import { fCurrency } from '../../../utils/formatNumber'; +import MemberSelectDialog from '../../../components/dialogs/MemberSelectDialog'; +import { Add, ArrowBackIosNew, DeleteOutline } from '@mui/icons-material'; +import { ClaimRequest, Files } from '@/@types/claims'; +import { fDateTimesecond } from '@/utils/formatTime'; + +interface FormValuesProps extends Partial { + taxes: boolean; + inStock: boolean; +} + +type Props = { + isEdit: boolean; + currentClaim?: ClaimRequest; +}; + +export default function FormEdit({ isEdit, currentClaim }: Props) { + const navigate = useNavigate(); + + const { enqueueSnackbar } = useSnackbar(); + + const EditClaimSchema = Yup.object().shape({ + organization_id: Yup.string().required('Code Provider is required'), + }); + + const defaultValues = useMemo( + () => ({ + id: currentClaim?.id || '-', + code: currentClaim?.code || '-', + member_name: currentClaim?.member?.name || '-', + date: currentClaim?.submission_date ? fDateTimesecond(currentClaim?.submission_date) : '-', + claim_method: currentClaim?.payment_type || '-', + service_type: currentClaim?.service_code || '-', + organization_id: currentClaim?.organization?.code || '-', + }), + [currentClaim] + ); + + useEffect(() => { + if (isEdit && currentClaim) { + reset(defaultValues); + } + if (!isEdit) { + reset(defaultValues); + } + // setFileKondisis(currentClaim?.files_by_type?.claim_diagnosis); + // setFileDiagnosas(currentClaim?.files_by_type?.claim_diagnosis); + setFileHasilPenunjangCurrent(currentClaim?.files_by_type?.claim_result); + }, [isEdit, currentClaim]); + + + const methods = useForm({ + resolver: yupResolver(EditClaimSchema), + defaultValues, + }); + + const { + reset, + watch, + control, + setValue, + getValues, + setError, + handleSubmit, + formState: { isSubmitting }, + } = methods; + + const values = watch(); + + const [isCheckingLimit, setIsCheckingLimit] = useState(false); + const [isEligible, setIsEligible] = useState(false); + const [memberBenefits, setMemberBenefits] = useState([]); + const [diagnosisOption, setDiagnosisOption] = useState([]); + const [isMemberDialogOpen, setIsMemberDialogOpen] = useState(false); + const [member, setMember] = useState({}) + + // ---------------------------------------------------------------------- + + // Files Result Kondisi + const fileKondisiInput = useRef(null); + const [fileKondisis, setFileKondisis] = useState([]); + + const handleKondisiInputChange = (event) => { + if (event.target.files[0]) { + setFileKondisis([...fileKondisis, ...event.target.files]); + } else { + console.log('NO FILE'); + } + }; + const removeKondisiFiles = (filesState, index) => { + setFileKondisis( + filesState.filter((file, fileIndex) => { + return fileIndex != index; + }) + ); + }; + + // Files Result Diagnosa + const fileDiagnosaInput = useRef(null); + const [fileDiagnosas, setFileDiagnosas] = useState([]); + + const handleDiagnosaInputChange = (event) => { + if (event.target.files[0]) { + setFileDiagnosas([...fileDiagnosas, ...event.target.files]); + } else { + console.log('NO FILE'); + } + }; + const removeDiagnosaFiles = (filesState, index) => { + setFileDiagnosas( + filesState.filter((file, fileIndex) => { + return fileIndex != index; + }) + ); + }; + + // Files Result Hasil Penunjang + const fileHasilPenunjangInput = useRef(null); + const [fileHasilPenunjangs, setFileHasilPenunjangs] = useState([]); + const [fileHasilPenunjangsCurrent, setFileHasilPenunjangCurrent] = useState([]); + + const handleResultInputChange = (event) => { + if (event.target.files[0]) { + setFileHasilPenunjangs([...fileHasilPenunjangs, ...event.target.files]); + } else { + console.log('NO FILE'); + } + }; + const removeFiles = (filesState, index) => { + setFileHasilPenunjangs( + filesState.filter((file, fileIndex) => { + return fileIndex != index; + }) + ); + }; + + + const onSubmit = async (data: FormValuesProps) => { + try { + // const formData = new FormData(); + // formData.append('result_files', fileHasilPenunjangs); + // formData.append('diagnosa_files', fileDiagnosaInput); + // formData.append('kondisi_files', fileKondisiInput); + // formData.append('provider_code', data.organization_id); + // formData.append('_method', 'PUT'); + const formData = makeFormData({ + result_files: fileHasilPenunjangs, + diagnosa_files: fileDiagnosas, + kondisi_files: fileKondisis, + provider_code: data.organization_id, + _method: 'PUT' + }); + + const response = await axios.put(`/claim-requests/${data.id}`, formData); + + reset(); + enqueueSnackbar('Claim Request Updated Successfully!', { variant: 'success' }); + navigate('/claim-requests'); + } catch (error: any) { + if (error && error.response.status === 422) { + for (const [key, value] of Object.entries(error.response.data.errors)) { + // setError(key, { message: value[0] }); + enqueueSnackbar('Failed Processing Request', { variant: 'error' }); + } + } else { + enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' }); + } + } + }; + + + return ( + + + + navigate(`/claim-requests`)} > + + + + + {'Edit Claim Requests'} + + + + + + + + Code* + + + Name* + + + + + + + + {/* */} + + + + + + Date of Submission* + + + Claim Method* + + + Service Type* + + + Code Provider* + + + + + + + + ), }} + name="date" label="Date of Submission" disabled/> + + + + + + + + + + + + + {/* -------------------------------Upload Dokumen Kondisi------------------------------- */} + + + Condition Document + + + {fileKondisis && + fileKondisis.map((file, index) => ( + + {file.name} + { + removeKondisiFiles(fileKondisis, index); + }} + > + + ))} + + + fileKondisiInput.current?.click()}> + + + + Add File + + + + + + + {/* -------------------------------Upload Dokumen Diagnosa------------------------------- */} + + + Diagnosis Document + + + {fileDiagnosas && + fileDiagnosas.map((file, index) => ( + + {file.name} + { + removeDiagnosaFiles(fileDiagnosas, index); + }} + > + + ))} + + + fileDiagnosaInput.current?.click()}> + + + + Add Result + + + + + + + {/* -------------------------------Upload Result Hasil Penunjang------------------------------- */} + + + Supporting Result Document + + + {fileHasilPenunjangs && + fileHasilPenunjangs.map((file, index) => ( + + {file.name} + { + removeFiles(fileHasilPenunjangs, index); + }} + > + + ))} + + + fileHasilPenunjangInput.current?.click()}> + + + + Add Result + + + + + + + + + + + + + + + Update + + + + + + ); +} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/CreateUpdate.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/CreateUpdate.tsx new file mode 100644 index 00000000..c710deaa --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/CreateUpdate.tsx @@ -0,0 +1,63 @@ +import * as Yup from 'yup'; +import { Box, IconButton } from '@mui/material'; +import { ArrowBackIosNew } from '@mui/icons-material'; +import { yupResolver } from '@hookform/resolvers/yup'; +import { Autocomplete, Button, Card, Collapse, Container, Divider, Grid, Stack, Table, TableBody, TableCell, TableRow, TextField, Typography } from '@mui/material'; +import { Controller, useForm } from 'react-hook-form'; +import { useParams } from 'react-router-dom'; +import HeaderBreadcrumbs from '../../components/HeaderBreadcrumbs'; +import { FormProvider, RHFCheckbox, RHFSelect, RHFTextField } from '../../components/hook-form'; +import Page from '../../components/Page'; +import useSettings from '../../hooks/useSettings'; +import { useEffect, useMemo, useRef, useState } from 'react'; +import MemberSelectDialog from '../../components/dialogs/MemberSelectDialog'; +import { styled } from '@mui/system'; +import axios from '../../utils/axios'; +import { enqueueSnackbar } from 'notistack'; +import { LoadingButton } from '@mui/lab'; +import { fCurrency } from '../../utils/formatNumber'; +import Iconify from '../../components/Iconify'; +import { ClaimRequest } from '@/@types/claims'; +import FormEdit from './Components/FormEdit'; +import FormCreate from './Components/FormCreate'; + +export default function ClaimsCreateUpdate() { + + const { themeStretch } = useSettings(); + const { id } = useParams(); + + const isEdit = id ? true : false; + + const [currentClaim, setCurrentClaim] = useState(); + + useEffect(() => { + if (isEdit) { + axios.get('/claim-requests/' + id).then((res) => { + console.log('Yeet', res.data); + setCurrentClaim(res.data.data); + }); + + console.log(currentClaim) + } + }, [id]); + + + return ( + + + { + id == undefined + ? + ( + + ) + : + ( + + ) + } + + + + ); +} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Detail.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Detail.tsx new file mode 100644 index 00000000..39aa66ab --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Detail.tsx @@ -0,0 +1,306 @@ +// mui +import { Container, Grid, Stack, Typography, Card, TextField, Divider, ButtonBase, Box, IconButton } from '@mui/material'; +// components +import Page from '../../components/Page'; +// utils +import useSettings from '../../hooks/useSettings'; +// react +import { useNavigate, useParams, useLocation } from 'react-router-dom'; +import { useEffect, useState, useRef } from 'react'; +import axios from '../../utils/axios'; +// pages +import DetailTimeline from '../../pages/ClaimRequests/DetailTimeline'; +import DetailStepper from '../../pages/ClaimRequests/DetailStepper'; +import { format } from 'date-fns'; +import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; +import Button from '@mui/material/Button'; +import AddIcon from '@mui/icons-material/Add'; +import RemoveIcon from '@mui/icons-material/Remove'; +import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; +import Iconify from '@/components/Iconify'; +import { fPostFormat } from '@/utils/formatTime'; +import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; +import DownloadIcon from '@mui/icons-material/Download'; +import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material'; +import CloseIcon from '@mui/icons-material/Close'; +import { fDateTimesecond } from '@/utils/formatTime'; +import { makeFormData } from '@/utils/jsonToFormData'; + +import { enqueueSnackbar } from 'notistack'; + +// ---------------------------------------------------------------------- + +export default function Detail() { + const location = useLocation(); + const queryParams = new URLSearchParams(location.search); + const code = queryParams.get('code'); + + const navigate = useNavigate(); + const { themeStretch } = useSettings(); + const [data, setData] = useState(); + const [dataDialog, setDataDialog] = useState(); + const [document, setDocument] = useState(null); + + const { id } = useParams(); + + useEffect(() => { + axios + .get('/claim-requests/detail/'+id) + .then((response) => { + setData(response.data); + setDataDialog(response.data.data.dialog_submits); + setDocument(response.data.data.documents); + + }) + .catch((error) => { + console.error(error); + }); + + }, []); + + const [isInvoiceVisible, setInvoiceVisibility] = useState(false); + + const handleInvoice = () => { + setInvoiceVisibility(!isInvoiceVisible); + } + const currentDate = new Date(); + const formattedCurrentDate = format(currentDate, 'dd MMM yyyy'); + const [dateInvoice, setDateInvoice] = useState(currentDate); + + const fileInvoiceInput = useRef(null); + const [fileInvoices, setFileInvoices] = useState([]); + + const handleInvoiceInputChange = (event) => { + if (event.target.files[0]) { + setFileInvoices([...fileInvoices, ...event.target.files]); + } else { + console.log('NO FILE'); + } + }; + const removeInvoiceFiles = (filesState, index) => { + setFileInvoices( + filesState.filter((file, fileIndex) => { + return fileIndex != index; + }) + ); + }; + const date = dateInvoice ? fPostFormat(dateInvoice, 'yyyy-MM-dd') : null; + + const [openDialogSubmit, setOpenDialogSubmit] = useState(false); + const handleCloseDialogSubmit = () => { + setOpenDialogSubmit(false); + } + const handleSubmitData = () => { + // if(fileInvoices.length > 0) + // { + //submit data + axios + .post('claim-requests/'+id+'/approve') + .then((response) => { + enqueueSnackbar('Success Submit Claim Request', { variant: 'success' }); + setOpenDialogSubmit(false); + }) + .catch(({ response }) => { + enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' }); + }); + //Upload file invoices + const formData = makeFormData({ + date:date, + invoice_files: fileInvoices, + }); + axios + .post('claim-requests/'+id+'/invoice-files', formData) + .then((response) => { + enqueueSnackbar(response.data.message ?? 'Success upload invoice', { variant: 'success' }); + }) + .catch(({ response }) => { + enqueueSnackbar(response.data.message ?? 'Something Went Wrong', { variant: 'error' }); + }); + // } + // else + // { + // enqueueSnackbar('Please upload file invoice, before submit', { variant: 'warning' }); + // } + + setTimeout(() => + { + window.location.reload(); + }, 5000); + + }; + + const check_invoice = document?.find((dataInvoice) => dataInvoice.type === 'claim-invoice'); + + return ( + + + + navigate(-1)} sx={{cursor:'pointer'}}/> + {(data && data.data) ? data.data.status.code : ''} + {data ? ( + + Submission Date + {(data && data.data) ? format(new Date(data.data.status.submission_date), "d MMM yyyy") : ''} + + ) : ''} + + {data ? ( + + + + + + + Format Claim + + + + {check_invoice ? ( + + + Request Claim + + + + ) : ''} + + + + + { + setDateInvoice(newValue); + }} + inputFormat="dd MMM yyyy" + renderInput={(params) => } + /> + + } + spacing={1} + sx={{ marginY: 2 }} + > + {fileInvoices && + fileInvoices.map((file, index) => ( + + + + {file.name ? file.name : '-'} + + { + removeInvoiceFiles(fileInvoices, index); + }} + sx={{cursor: 'pointer'}} + > + + ))} + + fileInvoiceInput.current?.click()}> + + + + Upload Invoice + + + + + + + + + + + + + {dataDialog && dataDialog.status === 'requested' ? ( + <> + + + + ) : ''} + {/* Dialog Submits */} + + + + + Confirmation + + + + + + + + {dataDialog ? ( + + Are you sure to submit this claim ? + + + Code + {dataDialog.code} + + + Name + {dataDialog.name} + + + Date Submission + {fDateTimesecond(dataDialog.submission_date)} + + + Claim Method + Service Type + + + Service Type + + {dataDialog.service_code === 'IP' ? 'Inpatient' : 'Outpatient'} + + + + + ) : ''} + + + + + + + + + + ) : ''} + + + ); +} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailStepper.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailStepper.tsx new file mode 100644 index 00000000..b788e29f --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailStepper.tsx @@ -0,0 +1,58 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import Stepper from '@mui/material/Stepper'; +import Step from '@mui/material/Step'; +import StepLabel from '@mui/material/StepLabel'; +import { useEffect, useState } from 'react'; +import ClearIcon from '@mui/icons-material/Clear'; + +const steps = [ + 'Request', + 'Review', + 'Approval', + 'Decline', + ]; + + export default function HorizontalLinearAlternativeLabelStepper({data}) { + const [active, setActive] = useState(0); + const [status, SetStatus] = useState(null); + let updatedSteps = [...steps]; + useEffect(() => { + if (data && data.data) { + if (data.data.status.status === 'requested') { + setActive(1); + updatedSteps = updatedSteps.filter(step => step !== 'Decline'); + } + else if (data.data.status.status === 'reviewed') { + setActive(2); + updatedSteps = updatedSteps.filter(step => step !== 'Decline'); + } + else if (data.data.status.status === 'approved') + { + setActive(3); + updatedSteps = updatedSteps.filter(step => step !== 'Decline'); + } + else if(data.data.status.status === 'declined') + { + setActive(4) + updatedSteps = updatedSteps.filter(step => step !== 'Approval'); + } + } + SetStatus(updatedSteps); + }, [data]); + + + + + return ( + + + {status?.map((label) => ( + + : ''}>{label} + + ))} + + + ); +} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailTimeline.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailTimeline.tsx new file mode 100644 index 00000000..f62a706d --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailTimeline.tsx @@ -0,0 +1,426 @@ +import * as React from 'react'; +import Timeline from '@mui/lab/Timeline'; +import TimelineItem, { timelineItemClasses } from '@mui/lab/TimelineItem'; +import TimelineSeparator from '@mui/lab/TimelineSeparator'; +import TimelineConnector from '@mui/lab/TimelineConnector'; +import TimelineContent from '@mui/lab/TimelineContent'; +import TimelineDot from '@mui/lab/TimelineDot'; +import {Typography, Card, Stack, ButtonBase, Box, Divider} from '@mui/material'; +import { styled } from '@mui/material/styles'; +import Paper from '@mui/material/Paper'; +import Button from '@mui/material/Button'; +import AddIcon from '@mui/icons-material/Add'; +import Iconify from '../../components/Iconify'; +import { useEffect, useState, useRef } from 'react'; +import { format } from 'date-fns'; +import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; +import DescriptionIcon from '@mui/icons-material/Description'; +import { LoadingButton } from '@mui/lab'; +import axios from '../../utils/axios'; +import { makeFormData } from '@/utils/jsonToFormData'; +import { enqueueSnackbar } from 'notistack'; +import { useParams} from 'react-router-dom'; + +const Item1 = styled(Paper)(({ theme }) => ({ + ...theme.typography.body2, + padding: theme.spacing(1), + textAlign: 'center', + backgroundColor: '#919EAB29', + color: '#637381', + width: 'fit-content', + marginRight: 'auto', +})); + +const Item2 = styled(Paper)(({ theme }) => ({ + backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff', + ...theme.typography.body2, + padding: theme.spacing(1), + textAlign: 'center', + color: theme.palette.text.secondary, + width: 'fit-content', + marginLeft: 'auto', +})); + +export default function NoOppositeContent({data}) { + const [timeline, setTimeline] = useState(null); + const [requestFile, setRequestFile] = useState(null); + const [document, setDocument] = useState(null); + useEffect(() => { + if (data && data.data) { + setTimeline(data.data.timeline); + setRequestFile(data.data.request_files); + setDocument(data.data.documents); + } + + }, [data]); + + // Diagnosis + const fileRequestDocumentInputDiagnosis = useRef(null); + const [fileDiagnosis, setFileDiagnosis] = useState([]); + const handleRequestDocumentInputChangeDiagnosis = (event) => { + if (event.target.files[0]) { + setFileDiagnosis([...fileDiagnosis, ...event.target.files]); + } + }; + const removeFileDiagnois = (filesState, index) => { + setFileDiagnosis( + filesState.filter((file, fileIndex) => { + return fileIndex != index; + }) + ); + }; + // Kondisi + const fileRequestDocumentInputKondisi = useRef(null); + const [fileKondisi, setFileKondisi] = useState([]); + const handleRequestDocumentInputChangeKondisi = (event) => { + if (event.target.files[0]) { + setFileKondisi([...fileKondisi, ...event.target.files]); + } + }; + const removeFileKondisi = (filesState, index) => { + setFileKondisi( + filesState.filter((file, fileIndex) => { + return fileIndex != index; + }) + ); + }; + // Result + const fileRequestDocumentInputResult = useRef(null); + const [fileResult, setFileResult] = useState([]); + const handleRequestDocumentInputChangeResult = (event) => { + if (event.target.files[0]) { + setFileResult([...fileResult, ...event.target.files]); + } + }; + const removeFileResult = (filesState, index) => { + setFileResult( + filesState.filter((file, fileIndex) => { + return fileIndex != index; + }) + ); + }; + const { id } = useParams(); + const [submitLoading, setSubmitLoading] = useState(false); + const submitRequestFiles = () => { + setSubmitLoading(true); + const formData = makeFormData({ + fileDiagnosis: fileDiagnosis, + fileKondisis: fileKondisi, + fileResults: fileResult + }); + axios + .post('claim-requests/'+id+'/request-files', formData) + .then((response) => { + window.location.reload(); + }) + .catch(({ response }) => { + enqueueSnackbar(response.data.message ?? 'Something Went Wrong', { variant: 'error' }); + }); + } + const submitButton = requestFile?.find((dataRequestFile) => dataRequestFile.check_files === null); + return ( + <> + {timeline?.map((dataTimeline, index) => ( + + {dataTimeline.date ? format(new Date(dataTimeline.date), "d MMM yyyy") : ''} + + + + + + + + + + {dataTimeline.date ? format(new Date(dataTimeline.date), "HH : mm") : ''} + {dataTimeline.txt_status} + + + Detail: + {dataTimeline.description} + + {dataTimeline.status === 'reviewed' && requestFile ? ( + <> + {submitButton ? ( + Request Document + ) : ( + Request Document Success Uploaded + )} + {/* Diagnosis */} + {requestFile?.map((dataRequestFile, index) => { + if(dataRequestFile.type !== 'claim-diagnosis' || dataRequestFile.check_files !== null){ + return null; + } + return ( + + + Diagnosis + + } + spacing={1} + sx={{ marginY: 2 }} + > + {fileDiagnosis && + fileDiagnosis.map((file, index) => ( + + + + {file.name ? file.name : '-'} + + { + removeFileDiagnois(fileDiagnosis, index); + }} + sx={{cursor: 'pointer'}} + > + + ))} + + fileRequestDocumentInputDiagnosis.current?.click()} + > + + + + Add Result + + + handleRequestDocumentInputChangeDiagnosis(event)} + accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf" + /> + + + ); + })} + {/* Kondisi */} + {requestFile?.map((dataRequestFile, index) => { + if(dataRequestFile.type !== 'claim-kondisi' || dataRequestFile.check_files !== null){ + return null; + } + return ( + + + Condition + + } + spacing={1} + sx={{ marginY: 2 }} + > + {fileKondisi && + fileKondisi.map((file, index) => ( + + + + {file.name ? file.name : '-'} + + { + removeFileKondisi(fileKondisi, index); + }} + sx={{cursor: 'pointer'}} + > + + ))} + + fileRequestDocumentInputKondisi.current?.click()} + > + + + + Add Result + + + handleRequestDocumentInputChangeKondisi(event)} + accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf" + /> + + + ); + })} + {/* Supporting Result */} + {requestFile?.map((dataRequestFile, index) => { + if(dataRequestFile.type !== 'claim-result' || dataRequestFile.check_files !== null){ + return null; + } + return ( + + + Supporting Result + + } + spacing={1} + sx={{ marginY: 2 }} + > + {fileResult && + fileResult.map((file, index) => ( + + + + {file.name ? file.name : '-'} + + { + removeFileResult(fileResult, index); + }} + sx={{cursor: 'pointer'}} + > + + ))} + + fileRequestDocumentInputResult.current?.click()} + > + + + + Add Result + + + handleRequestDocumentInputChangeResult(event)} + accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf" + /> + + + ); + })} + {submitButton ? ( + { + submitRequestFiles(); + }} + loading={submitLoading} + > + Submit + + ) : ''} + + ) : ''} + + + {dataTimeline.status === 'requested' ? ( + + + + + Documents + + + {document?.map((dataDocument, index) => ( + + + {dataDocument.type === 'claim-diagnosis' ? + 'Diagnosis' + : dataDocument.type === 'claim-kondisi' ? + 'Condition' + : dataDocument.type === 'claim-result' ? + 'Supporting Result' + : dataDocument.type === 'claim-invoice' ? + 'Invoice' + : ''} + + + + + {dataDocument.original_name ? dataDocument.original_name : '-'} + + + + ))} + + + + ) : ''} + + + + ))} + + ); +} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Index.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Index.tsx new file mode 100644 index 00000000..d26903b0 --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Index.tsx @@ -0,0 +1,30 @@ +import { Card, Stack } from "@mui/material"; +import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs"; +import Page from "../../../components/Page"; +import List from "./List"; + + + +export default function Claims() { + + const pageTitle = 'Claim Request'; + return ( + + + + + {/* */} + + {/* */} + + ); +} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/List.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/List.tsx new file mode 100644 index 00000000..8bc34214 --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/List.tsx @@ -0,0 +1,582 @@ +// @mui +import { + Box, + Button, + Card, + Collapse, + IconButton, + MenuItem, + Table, + TableBody, + TableCell, + TableRow, + TextField, + Typography, + Stack, + Menu, + ButtonGroup, + Link, + Chip, + TableHead, + Grid, +} from '@mui/material'; +import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; +import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; +import AddIcon from '@mui/icons-material/Add'; +import UploadIcon from '@mui/icons-material/Upload'; +import CancelIcon from '@mui/icons-material/Cancel'; + +import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined'; +import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; +// hooks +import React, { ChangeEvent, useEffect, useRef, useState } from 'react'; +import { Navigate, useNavigate, useSearchParams } from 'react-router-dom'; +import useSettings from '@/hooks/useSettings'; +// components +import axios from '../../../utils/axios'; +import { LaravelPaginatedData, LaravelPaginatedDataDefault } from '../../../@types/paginated-data'; +import DataTable from '../../../components/LaravelTable'; +import { fCurrency } from '../../../utils/formatNumber'; +import EditRoundedIcon from '@mui/icons-material/EditRounded'; +import { LoadingButton } from '@mui/lab'; +import { enqueueSnackbar } from 'notistack'; +import { Divider } from '@mui/material'; +import Iconify from '@/components/Iconify'; +import DialogDetailClaim from '@/components/dialogs/DialogDetailClaim'; +import { fDateTimesecond } from '@/utils/formatTime'; +import { capitalizeFirstLetter } from '@/utils/formatString'; +import Label from '@/components/Label'; +import TableMoreMenu from '@/components/table/TableMoreMenu'; +import { Import } from '@/@types/claims'; + +import { FinalLogType } from './Model/Types'; +// import LoadingButton from '@/theme/overrides/LoadingButton'; + +export default function List() { + const { themeColorPresets } = useSettings(); + const [searchParams, setSearchParams] = useSearchParams(); + const [importResult, setImportResult] = useState(null); + + const navigate = useNavigate() + + function SearchInput(props: any) { + // SEARCH + const searchInput = useRef(null); + const [searchText, setSearchText] = useState(''); + + const handleSearchChange = (event: any) => { + const newSearchText = event.target.value ?? ''; + setSearchText(newSearchText); + }; + + const handleSearchSubmit = (event: any) => { + event.preventDefault(); + props.onSearch({ search: searchText }); // Trigger to Parent + }; + + useEffect(() => { + // Trigger First Search + setSearchText(searchParams.get('search') ?? ''); + }, []); + + return ( +
+ + + ); + } + + function ImportForm(props: any) { + // IMPORT + // Create Button Menu + const [anchorEl, setAnchorEl] = React.useState(null); + const createMenu = Boolean(anchorEl); + const importForm = useRef(null); + const [currentImportFileName, setCurrentImportFileName] = useState(null); + const [importLoading, setImportLoading] = useState(false); + + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + }; + + const handleImportButton = () => { + if (importForm?.current) { + handleClose(); + importForm.current ? importForm.current.click() : console.log('No File selected'); + } else { + alert('No file selected'); + } + }; + + const handleCancelImportButton = () => { + importForm.current.value = ''; + importForm.current.dispatchEvent(new Event('change', { bubbles: true })); + }; + + const handleImportChange = (event: any) => { + if (event.target.files[0]) { + setCurrentImportFileName(event.target.files[0].name); + } else { + setCurrentImportFileName(null); + } + }; + + const handleUpload = () => { + if (importForm.current?.files.length) { + const formData = new FormData(); + formData.append('file', importForm.current?.files[0]); + + setImportLoading(true); + axios + .post(`claim-requests/import`, formData) + .then((response) => { + handleCancelImportButton(); + loadDataTableData(); + setImportResult(response.data); + // alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows'); + setImportLoading(false); + }) + .catch((response) => { + enqueueSnackbar( + 'Looks like something went wrong. Please check your data and try again. ' + + response.message, + { variant: 'error' } + ); + setImportLoading(false); + }); + } else { + enqueueSnackbar('No File Selected', { variant: 'warning' }); + } + }; + + const handleGetTemplate = (type :string) => { + axios.get('corporates/import-document-example/' + type) + .then((response) => { + const link = document.createElement('a'); + link.href = response.data.data.file_url; + link.setAttribute('download', response.data.data.file_name); + document.body.appendChild(link); + link.click(); + handleClose(); + }) + } + + const handleGetData = (type :string) => { + axios.get(`corporates/${corporate_id}/data-plan-benefit`) + .then((response) => { + const link = document.createElement('a'); + link.href = response.data.data.file_url; + link.setAttribute('download', response.data.data.file_name); + document.body.appendChild(link); + link.click(); + handleClose(); + }) + } + + return ( +
+ + {!currentImportFileName && ( + + + + + Import + {handleGetTemplate('claim-request')}}>Download Template + {handleGetData('data-plan-benefit')}}>Download Claim Request + + {/* */} + + )} + + {currentImportFileName && ( + + + + + + + } + sx={{ p: 1.8 }} + onClick={handleUpload} + loading={importLoading} + > + Upload + + + )} + {importResult && ( + + + Last Import Result Report :{' '} + + {importResult.result_file?.name ?? '-'} + + + + )} +
+ ); + } + + // Dummy Default Data + const [dataTableIsLoading, setDataTableLoading] = useState(true); + const [dataTableData, setDataTableData] = useState( + LaravelPaginatedDataDefault + ); + + const loadDataTableData = async (appliedFilter: any | null = null) => { + setDataTableLoading(true); + const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]); + const response = await axios.get('/customer-service/request?final_log=1&service_code=IP', { params: filter }); + // console.log(response.data); + setDataTableLoading(false); + + setDataTableData(response.data); + }; + + const applyFilter = async (searchFilter: { search: string }) => { + await loadDataTableData(searchFilter); + setSearchParams(searchFilter); + }; + + const handlePageChange = (event: ChangeEvent, value: number): void => { + const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]); + loadDataTableData(filter); + setSearchParams(filter); + }; + + const handleApprove = (claimRequest) => { + axios + .post(`claim-requests/${claimRequest.id}/approve`) + .then((response) => { + enqueueSnackbar('Success Approve', { variant: 'success' }); + loadDataTableData(); + }) + .catch(({ response }) => { + enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' }); + }); + }; + + useEffect(() => { + loadDataTableData(); + }, []); + + const headStyle = { + fontWeight: 'bold', + }; + + // Called on every row to map the data to the columns + function createData(data: FinalLogType) { + return { + ...data, + }; + } + + { + /* ------------------ TABLE ROW ------------------ */ + } + function Row(props: { row: ReturnType }) { + const { row } = props; + const [open, setOpen] = React.useState(false); + const [loadingApprove, setLoadingApprove] = React.useState(false); + + return ( + + *': { borderBottom: 'unset' } }}> + {/* + setOpen(!open)}> + {open ? : } + + */ } + + { + // handleShowClaim(row); + // }} + > + {row.id} + + + {row.code} + {row.member?.full_name} + + {row.service_name} + {row.payment_type_name} + + { row.status_final_log == "requested" ? + () : + row.status_final_log == "declined" ? + () + : + () + } + + + + navigate(`/claim-requests/edit/${row.id}`)}> + + Edit + + navigate ('/claim-requests/detail/'+row.id+'')}> + + Detail + + + } /> + + {/* + + { + handleShowClaim(row); + }} + > + + + */} + + {/* COLLAPSIBLE ROW */} + + + + + } + spacing={1} + sx={{ marginY: 2 }} + > + + Berkas Hasil Penunjang + {/* {row.files_by_type?.claim_kondisi && + row.files_by_type?.claim_kondisi.map((file, index) => ( + + -{' '} + + {file.name} + + + ))} */} + + {row.files_by_type?.claim_kondisi && ( + <> + - Kondisi + {row.files_by_type?.claim_kondisi.map((file, index) => ( + + + + {file.name} + + + ))} + + )} + + {row.files_by_type?.claim_diagnosis && ( + <> + - Diagnosa + {row.files_by_type?.claim_diagnosis.map((file, index) => ( + + + + {file.name} + + + ))} + + )} + + {row.files_by_type?.claim_result && ( + <> + - Hasil + {row.files_by_type?.claim_result.map((file, index) => ( + + + + {file.name} + + + ))} + + )} + {(!row.files_by_type?.claim_result && !row.files_by_type?.claim_diagnosis && !row.files_by_type?.claim_kondisi)&& Tidak ada berkas} + + + + + + + + ); + } + { + /* ------------------ END TABLE ROW ------------------ */ + } + + function TableContent() { + return ( + + {/* ------------------ TABLE HEADER ------------------ */} + + + {/* */} + + ID Request LOG + + + Code + + + Name + + + Date of Submission + + + Service Type + + + Claim Method + + + Status + + + + + {/* ------------------ END TABLE HEADER ------------------ */} + + {/* ------------------ TABLE ROW ------------------ */} + {dataTableIsLoading ? ( + + + + Loading + + + + ) : dataTableData.data.length === 0 ? ( + + + + No Data + + + + ) : ( + + {dataTableData.data.map((row) => ( + + ))} + + )} + {/* ------------------ END TABLE ROW ------------------ */} +
+ ); + } + + // --------------------------------------------------------- + // Dialog Detail Claim Request + const [openDialogDetailClaim, setOpenDialogDetailClaim] = useState(false); + const [loadingClaimDetail, setLoadingClaimDetail] = useState(true); + const [currentClaim, setCurrentClaim] = useState(null); + + function handleShowClaim(claimRequest) { + setLoadingClaimDetail(true); + setOpenDialogDetailClaim(true); + + axios + .get(`/claim-requests/${claimRequest.id}`) + .then(({ data }) => { + setCurrentClaim(data.data); + setLoadingClaimDetail(false); + }) + .catch((err) => { + enqueueSnackbar(err.message, { variant: 'error' }); + }); + } + + function handleDownloadLog() {} + + return ( + + + + + + + } + /> + + + + + + ); +} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Functions.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Functions.tsx new file mode 100644 index 00000000..da72ff60 --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Functions.tsx @@ -0,0 +1,79 @@ +import axios from '@/utils/axios'; +import { enqueueSnackbar } from 'notistack'; +import { MemberListType } from './Types'; +import { makeFormData } from '@/utils/jsonToFormData'; + +/** + * Listing Member + */ +export const getMemberList = async ( page: number, keyword: string ): Promise => { + const response = await axios.get(`/claim-requests/list-member?page=${page}&keyword=${keyword}`) + .then((res) =>{ + return res.data.data.member_list; + }) + .catch((res) => { + enqueueSnackbar("server error !", { + variant: 'error', + }); + + return []; + }); + + return response; +}; + +/** + * Add Claim Request + */ +export const addClaimRequest = async ( data: MemberListType[] ): Promise => { + // Mapping + const formData = new FormData(); + + data.map((row, index) => { + formData.append(`member_id[${index}]`, row.id.toString()); + formData.append(`service_code[${index}]`, row.patien_type??''); + + if (row.file_kondisi != undefined) { + row.file_kondisi.forEach((file, file_index) => { + console.log(file); + + formData.append(`file_kondisi[member_${row.id}][${file_index}]`, file); + }); + } + + if (row.file_diagnosa != undefined) { + row.file_diagnosa.forEach((file, file_index) => { + console.log(file); + + formData.append(`file_diagnosa[member_${row.id}][${file_index}]`, file); + }); + } + + if (row.file_penunjang != undefined) { + row.file_penunjang.forEach((file, file_index) => { + console.log(file); + + formData.append(`file_penunjang[member_${row.id}][${file_index}]`, file); + }); + } + }) + + // Axios + const response = await axios.post(`/claim-requests`, formData) + .then((res) =>{ + enqueueSnackbar("Berhasil membuat data !", { + variant: 'success', + }); + + return true; + }) + .catch((res) => { + enqueueSnackbar("server error !", { + variant: 'error', + }); + + return false; + }); + + return response; +}; diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Types.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Types.tsx new file mode 100644 index 00000000..e1d99d40 --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Types.tsx @@ -0,0 +1,36 @@ +import { Member } from "@/@types/member" + +/** + * Search Type + */ +export type SearchType = { + keyword: string, +} + +/** + * Member List + */ +export type FinalLogType = { + id : number, + code : string, + member : Member, + submission_date : string, + service_name : string, + payment_type_name : string, + status_final_log : string, + status : string, + files_by_type : files_by_type, +} + +export type files_by_type = { + claim_diagnosis : file[], + claim_kondisi : file[], + claim_result : file[], +} + +export type file = { + name: string, + url: string[], +} + + diff --git a/frontend/dashboard/src/pages/Corporates/DiagnosisExclusion/List.tsx b/frontend/dashboard/src/pages/Corporates/DiagnosisExclusion/List.tsx index 0bb45008..8f6b4c03 100644 --- a/frontend/dashboard/src/pages/Corporates/DiagnosisExclusion/List.tsx +++ b/frontend/dashboard/src/pages/Corporates/DiagnosisExclusion/List.tsx @@ -687,7 +687,7 @@ export default function List(props: any) { - Play : + Plan : diff --git a/frontend/dashboard/src/pages/CustomerService/Components/CardDetail.tsx b/frontend/dashboard/src/pages/CustomerService/Components/CardDetail.tsx new file mode 100644 index 00000000..39db8867 --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/Components/CardDetail.tsx @@ -0,0 +1,57 @@ +import { Card, Typography } from "@mui/material"; +import { Stack } from '@mui/material'; +import { DetailFinalLogType } from "../FinalLog/Model/Types"; +import { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime"; + + +type CardDetail = { + requestLog: DetailFinalLogType|undefined; +} + +const style1 = { + color: '#919EAB', + width: '30%' +} +const style2 = { + width: '70%' +} +const marginBottom1 = { + marginBottom: 1, +} +const marginBottom2 = { + marginBottom: 2, +} + + +export default function CardDetail({requestLog} : CardDetail ) { + return ( + + Detail + + Member ID + {requestLog?.member_id} + + + Policy Number + {requestLog?.policy_number} + + + Name + {requestLog?.name} + + + Date Of Birth + {requestLog?.date_of_birth ? fDate(requestLog?.date_of_birth) : '-'} + + + Marital Status + {requestLog?.marital_status} + + + Submission Date + {requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : '-'} + + + ) + +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/Components/CardExclusion.tsx b/frontend/dashboard/src/pages/CustomerService/Components/CardExclusion.tsx new file mode 100644 index 00000000..4369074d --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/Components/CardExclusion.tsx @@ -0,0 +1,117 @@ +import { Accordion, AccordionDetails, AccordionSummary, Card, Typography } from "@mui/material"; +import { Stack } from '@mui/material'; +import { DetailFinalLogType } from "../FinalLog/Model/Types"; +import { toTitleCase } from "@/utils/formatTime"; +import Label from '@/components/Label'; +import { ExpandMore } from "@mui/icons-material"; + + + +type CardDetail = { + requestLog: DetailFinalLogType|undefined; +} + +const style1 = { + color: '#919EAB', + width: '30%' +} +const style2 = { + width: '70%' +} +const marginBottom2 = { + marginBottom: 2, +} + + +export default function CardExclusion({requestLog} : CardDetail ) { + return ( + + Exclusion + {requestLog?.exclusion?.length > 0 ? requestLog?.exclusion.map((r, index) => ( + + } + aria-controls='panelia-content' + id='panel1a-header' + > + {r.exclusionable.code} + {r.exclusionable.name} + + + + MSC + + {r.rules.length > 0 && r?.rules?.map((text, i) => { + return text.name === 'msc' ? + text.values.split(',').map((text2, j) => { + let labelMSC: string = text2; + switch (labelMSC) { + case 'm': + labelMSC = 'Member'; + break; + case 'c': + labelMSC = 'Child'; + break; + case 's': + labelMSC = 'Spouse'; + break; + default: + labelMSC = 'Member'; + } + return ( + + ); + }) + : null; + })} + + + + Gender + + {r.rules.length > 0 && r?.rules?.map((text, i) => { + return text.name === 'gender' ? + text.values.split(',').map((text2, j) => { + let labelGender: string = toTitleCase(text2); + return ( + + ); + }) + : null; + })} + + + + Min Age + + {r.rules.length > 0 && r?.rules?.map((text, i) => { + return text.name === 'min_age' ? + {text.values} : null + })} + + + + Max Age + + {r.rules.length > 0 && r?.rules?.map((text, i) => { + return text.name === 'max_age' ? + {text.values} : null + })} + + + + Plan + + {r.rules.length > 0 && r?.rules?.map((text, i) => { + return text.name === 'plan' ? + {text.values} : null + })} + + + + + )) : null} + + ) + +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/Components/CardService.tsx b/frontend/dashboard/src/pages/CustomerService/Components/CardService.tsx new file mode 100644 index 00000000..0ef1a11e --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/Components/CardService.tsx @@ -0,0 +1,105 @@ +import { Card, Typography } from "@mui/material"; +import { Stack } from '@mui/material'; +import { DetailFinalLogType } from "../FinalLog/Model/Types"; +import { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime"; +import Label from '@/components/Label'; + + + +type CardDetail = { + requestLog: DetailFinalLogType|undefined; + isFinalLog: boolean +} + +const style1 = { + color: '#919EAB', + width: '30%' +} +const style2 = { + width: '70%' +} +const marginBottom1 = { + marginBottom: 1, +} +const marginBottom2 = { + marginBottom: 2, +} + + +export default function CardService({requestLog, isFinalLog = true} : CardDetail ) { + return ( + + Service + + Service Type + {requestLog?.service_type} + + + Claim Method + {toTitleCase(requestLog?.claim_method ?? '-')} + + {/* + Benefit + +
    + {requestLog?.benefit.length > 0 ? requestLog?.benefit.map((r, index) => ( +
  • {r.code } - {r.description}
  • + )) :
  • -
  • } +
+
+
*/} + {/* General Practitioner */} + + General Practitioner + External Doctor : + {requestLog?.config_service?.gp_external_doctor_online == '1' ? () : '-'} + {requestLog?.config_service?.gp_external_doctor_offline == '1' ? () : '-'} + + + + + Internal Doctor : + {requestLog?.config_service?.gp_internal_doctor_online == '1' ? () : '-'} + {requestLog?.config_service?.gp_internal_doctor_offline == '1' ? () : '-'} + + + + {/* Specialist Practitioner */} + + Specialist Practitioner + External Doctor : + {requestLog?.config_service?.sp_external_doctor_online == '1' ? () : '-'} + {requestLog?.config_service?.sp_external_doctor_offline == '1' ? () : '-'} + + + + + Internal Doctor : + {requestLog?.config_service?.gp_internal_doctor_online == '1' ? () : '-'} + {requestLog?.config_service?.gp_internal_doctor_offline == '1' ? () : '-'} + + + + {/* Medicine */} + + Medicine + +
    + {requestLog?.config_service?.vitamins == '1' ? (
  • Suplemen
  • ) : (
  • -
  • )} + {requestLog?.config_service?.delivery_fee == '1' ? (
  • Delivery Fee
  • ) : (
  • -
  • )} +
+
+
+ + Admin Fee + + {requestLog?.config_service?.general_practitioner_fee == '1' ? () : '-'} + {requestLog?.config_service?.specialist_practitioner_fee == '1' ? () : '-'} + + + + +
+ ) + +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/Components/DetailBenefit.tsx b/frontend/dashboard/src/pages/CustomerService/Components/DetailBenefit.tsx new file mode 100644 index 00000000..de3371b2 --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/Components/DetailBenefit.tsx @@ -0,0 +1,115 @@ +import { Card, Grid, Typography } from "@mui/material"; +import { Stack } from '@mui/material'; +import { DetailFinalLogType } from "../FinalLog/Model/Types"; +import { useEffect, useState, useRef, useMemo } from 'react'; +import { Box } from "@mui/material"; + + +import { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime"; +import Label from '@/components/Label'; + +import AddIcon from '@mui/icons-material/Add'; +import { Button } from "@mui/material"; + + + +type CardDetail = { + requestLog: DetailFinalLogType|undefined; +} + +const style1 = { + color: '#919EAB', + width: '30%' +} +const style2 = { + width: '70%' +} +const marginBottom1 = { + marginBottom: 1, +} +const marginBottom2 = { + marginBottom: 2, +} + + + +export default function DetailBenefit({requestLog} : CardDetail ) { + return ( + {requestLog.benefitData?.map((item, index) => ( + + + + + {item.description} + + + + + + + Amount Incurred* + + + + + + + + + + + + + Amount Approved* + + + + + + + + + + + + + Amount Not Approved* + + + + + + + + + + + + + Excess Paid* + + + + + + + + + + + + + Keterangan* + + + + + + + + + + ))} + ) + +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogBenefit.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogBenefit.tsx new file mode 100644 index 00000000..353b61c8 --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogBenefit.tsx @@ -0,0 +1,343 @@ +import * as Yup from 'yup'; +import { yupResolver } from '@hookform/resolvers/yup'; + +import MuiDialog from "@/components/MuiDialog"; +import { Checkbox, Typography, FormControl, Card, Grid, DialogActions } from "@mui/material"; +import { Paper } from "@mui/material"; +import { Stack } from '@mui/material'; +import React, { useEffect, useState } from 'react'; +import { DetailFinalLogType } from "../Model/Types"; +import { BenefitConfigurationListType } from "../Model/Types"; +import { InputLabel, Select, FormHelperText } from "@mui/material"; +import FormGroup from '@mui/material/FormGroup'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import Button from '@mui/material/Button'; +import { fNumber } from "@/utils/formatNumber"; +import palette from "@/theme/palette"; +import { Box } from "@mui/material"; +import { FormProvider, RHFTextField } from "@/components/hook-form"; +import RHFTextFieldMoney from '@/components/hook-form/v2/RHFTextFieldMoney'; + +import { useFieldArray, useForm } from 'react-hook-form'; +import { LoadingButton } from '@mui/lab'; +import { postAddBenefit } from '../Model/Functions'; +import { useNavigate } from 'react-router'; +import { description } from '@/_mock/text'; + + +type DialogConfirmationType = { + openDialog: boolean; + setOpenDialog: any; + onSubmit?: void; + requestLog: DetailFinalLogType|undefined; +} + +type BenefitSelected = { + id: number, + description: string, + benefit_id: number, +} + + + +export default function DialogBenefit({requestLog, setOpenDialog, openDialog } : DialogConfirmationType ) { + + // Add Benefit + const [addBenefit, setAddBenefit] = useState(false) + const navigate = useNavigate() + //Benefit Name + const [valBenefitNames, setValBenefitNames] = useState([]); + const [valBenefitNameError, setValBenefitNameError] = useState(''); + const benefitNameData = requestLog?.benefit; + const [benefitSelected, setBenefitSelected] = useState([]); + + const handleConditionChangeService = (event) => { + const selectedItem = event.target.value; + + if (valBenefitNames.includes(selectedItem)) { + // Item is already selected, remove it + setValBenefitNames(valBenefitNames.filter(item => item !== selectedItem)); + } else { + // Item is not selected, add it + setValBenefitNames([...valBenefitNames, selectedItem]); + } + }; + + useEffect(() => { + const datax: any[] = [] + + valBenefitNames.map((data) => { + benefitNameData?.map((row) => { + if(row.id == data) { + datax.push(row) + } + }) + }) + + // for data information + let temp = datax.map((item, indx) => { + return { + benefit_id: item.id, + description: item.description, + request_log_id: requestLog?.id, + amount_incurred: 0, + amount_approved: 0, + amount_not_approved: 0, + excess_paid: 0, + keterangan: '', + } + }) + + reset({benefit_data: temp}) + + setBenefitSelected(datax) + + }, [valBenefitNames]) + + const handleCloseDialogBenefit = () => { + // setOpenDialog(false); + setAddBenefit(false) + setBenefitSelected([]) + setValBenefitNames([]) + } + + const handleAddDialogBenefit = () => { + setAddBenefit(true) + } + + const defaultValues: BenefitConfigurationListType = { + request_log_id: requestLog?.id, + benefit_name: '', + amount_incurred: 0, + amount_approved: 0, + amount_not_approved: 0, + excess_paid: 0, + }; + + const validationSchema = Yup.object().shape({ + benefit_data: Yup.array().of( + Yup.object().shape({ + amount_incurred : Yup.number().typeError('').required(''), + amount_approved : Yup.number().typeError('').required(''), + amount_not_approved : Yup.number().typeError('').required(''), + excess_paid : Yup.number().typeError('').required(''), + }) + ) + }) + + const methods = useForm({ + resolver: yupResolver(validationSchema), + defaultValues + }); + + const {fields, append, remove} = useFieldArray({name: 'benefit_data',control: methods.control}) + + const { handleSubmit, reset, watch, setValue, formState: { isDirty, isSubmitting, errors } } = methods; + // Submit Form + // ===================================== + const submitHandler = async (data: BenefitConfigurationListType) => { + + const response = await postAddBenefit(data); + + if (response == true) { + reset(); + // navigate('custormer-service/final-log/detail/'+requestLog?.id); + window.location.reload() + } + } + + const getContent = () => !addBenefit ? ( + + + + Benefit Name* + + + Benefit Name + + + {valBenefitNameError} + + + + + ) : + + ( + + + {/* */} + {fields?.map((item, index) => + ( + + + + + {item.description} + + + + + + + + Amount Incurred* + + + + + + + + + + + + + Amount Approved* + + + + append({amount_approved: ''}) } + id='amount_approved' + key={item.id} + name={`benefit_data.${index}.amount_approved`} + placeholder='Amount Approved' + required + /> + + + + + + + + + Amount Not Approved* + + + + append({amount_not_approved: ''}) } + id='amount_not_approved' + key={item.id} + name={`benefit_data.${index}.amount_not_approved`} + placeholder='Amount Not Approved' + required + /> + + + + + + + + + Excess Paid* + + + + append({excess_paid: ''}) } + id='excess_paid' + key={item.id} + name={`benefit_data.${index}.excess_paid`} + placeholder='Excess Paid' + required + /> + + + + + + + + + Keterangan* + + + + append({keterangan: ''}) } + id='keterangan' + key={item.id} + name={`benefit_data.${index}.keterangan`} + placeholder='Keterangan' + required + /> + + + + + + ))} + + + {/* */} + + + + + Save + + + + + + + ); + + const getAction = () => !addBenefit ? ( + + + + + ) : null; + + + return ( + + ); +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogConfirmation.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogConfirmation.tsx new file mode 100644 index 00000000..b53cc2f0 --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogConfirmation.tsx @@ -0,0 +1,109 @@ +import MuiDialog from "@/components/MuiDialog"; +import { Button, Card, Checkbox, DialogActions, Grid, Typography } from "@mui/material"; +import { Paper } from "@mui/material"; +import { Stack } from '@mui/material'; +import React, { useState } from 'react'; +import { DetailFinalLogType } from "../Model/Types"; +import { fDateTimesecond, toTitleCase } from "@/utils/formatTime"; +import axios from "@/utils/axios"; +import { enqueueSnackbar } from "notistack"; +import { useNavigate } from "react-router"; + + +type DialogConfirmationType = { + openDialog: boolean; + setOpenDialog: any; + onSubmit?: void; + approve: string; + requestLog: DetailFinalLogType|undefined; +} + +export default function DialogConfirmation({requestLog, setOpenDialog, openDialog, approve, onSubmit} : DialogConfirmationType ) { + + const navigate = useNavigate(); + const handleSubmit = () => { + const formData = { + status : approve + } + axios + .put(`customer-service/request/${requestLog?.id}`, formData) + .then((response) => { + enqueueSnackbar('Verification Request LOG Success', { variant: 'success' }); + setOpenDialog(false); + navigate('/custormer-service/request') + }) + .catch(({ response }) => { + enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' }); + }); + } + + const style1 = { + color: '#919EAB', + width: '30%' + } + const style2 = { + width: '70%' + } + const marginBottom1 = { + marginBottom: 1, + } + + const handleCloseDialog = () => { + setOpenDialog(false); + } + + const getContent = () => ( + + Are you sure to {approve == 'approved' ? 'approve' : 'deciline'} this request ? + + + + Member ID + {requestLog?.member_id} + + + Policy Number + {requestLog?.policy_number} + + + Name + {requestLog?.name} + + + Submission Date + {requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : '-'} + + + Claim Method + {requestLog?.claim_method ? toTitleCase(requestLog?.claim_method) : '-'} + + + Service Type + {requestLog?.service_type} + + + + + + + {approve == 'approved' ? ( + + ) : ( + + ) } + + + + ); + + + return ( + + ); +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogDelete.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogDelete.tsx new file mode 100644 index 00000000..1d493427 --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogDelete.tsx @@ -0,0 +1,69 @@ +import MuiDialog from "@/components/MuiDialog"; +import { Button, Card, Checkbox, DialogActions, Grid, Typography } from "@mui/material"; +import { Paper } from "@mui/material"; +import { Stack } from '@mui/material'; +import React, { useState } from 'react'; +import { DetailFinalLogType } from "../Model/Types"; +import { fDateTimesecond, toTitleCase } from "@/utils/formatTime"; +import axios from "@/utils/axios"; +import { enqueueSnackbar } from "notistack"; +import { useNavigate } from "react-router"; + + +type DialogDeleteType = { + openDialog: boolean; + setOpenDialog: any; + onSubmit?: void; + id: number|undefined; +} + +export default function DialogDelete({id, setOpenDialog, openDialog,onSubmit} : DialogDeleteType ) { + const handleSubmit = () => { + axios + .delete(`customer-service/request/benefit_data/${id}`) + .then((response) => { + enqueueSnackbar('Benefit Data has Deleted', { variant: 'success' }); + setOpenDialog(false); + window.location.reload() + }) + .catch(({ response }) => { + enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' }); + }); + } + + const style1 = { + color: '#919EAB', + width: '30%' + } + const style2 = { + width: '70%' + } + const marginBottom1 = { + marginBottom: 1, + } + + const handleCloseDialog = () => { + setOpenDialog(false); + } + + const getContent = () => ( + + Are you sure to delete this detail benefit ? + + + + + + ); + + + return ( + + ); +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogEditBenefit.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogEditBenefit.tsx new file mode 100644 index 00000000..50860d19 --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogEditBenefit.tsx @@ -0,0 +1,220 @@ +import * as Yup from 'yup'; +import { yupResolver } from '@hookform/resolvers/yup'; + +import MuiDialog from "@/components/MuiDialog"; +import { Box, Button, Card, Checkbox, DialogActions, Grid, Typography } from "@mui/material"; +import { Paper } from "@mui/material"; +import { Stack } from '@mui/material'; +import React, { useEffect, useState } from 'react'; +import { DetailFinalLogType } from "../Model/Types"; +import { fDateTimesecond, toTitleCase } from "@/utils/formatTime"; +import axios from "@/utils/axios"; +import { enqueueSnackbar } from "notistack"; +import { useNavigate } from "react-router"; +import { BenefitConfigurationListType } from "../Model/Types"; +import { postEditBenefit } from "../Model/Functions"; +import { useForm } from 'react-hook-form'; +import { FormProvider, RHFTextField } from "@/components/hook-form"; +import RHFTextFieldMoney from "@/components/hook-form/v2/RHFTextFieldMoney"; +import { LoadingButton } from "@mui/lab"; + + +type DialogDeleteType = { + openDialog: boolean; + setOpenDialog: any; + onSubmit?: void; + data: BenefitConfigurationListType|undefined; + id: number; +} + +export default function DialogEditBenefit({id, data, setOpenDialog, openDialog,onSubmit} : DialogDeleteType ) { + const handleCloseDialog = () => { + setOpenDialog(false); + } + + // setup form + // ==================================== + const defaultValues: BenefitConfigurationListType = { + request_log_id: 0, + benefit_name: '', + amount_incurred: 0, + amount_approved: 0, + amount_not_approved: 0, + excess_paid: 0, + keterangan: '-', + description: '-' + }; + + const validationSchema = Yup.object().shape({ + amount_incurred : Yup.string().typeError('').required(''), + amount_approved : Yup.string().typeError('').required(''), + amount_not_approved : Yup.string().typeError('').required(''), + excess_paid : Yup.string().typeError('').required(''), + }); + + const methods = useForm({ + resolver: yupResolver(validationSchema), + defaultValues + }); + + const { handleSubmit, reset, watch, setValue, formState: { isDirty, isSubmitting, errors } } = methods; + + // Submit Form + // ===================================== + const submitHandler = async (data: BenefitConfigurationListType) => { + + const response = await postEditBenefit(id, data); + + if (response == true) { + reset(); + // navigate('custormer-service/final-log/detail/'+requestLog?.id); + window.location.reload() + } + } + + // Set Value Form + // ===================================== + useEffect(() => { + setValue('amount_incurred', data?.amount_incurred) + setValue('amount_approved', data?.amount_approved) + setValue('amount_not_approved', data?.amount_not_approved) + setValue('excess_paid', data?.excess_paid) + setValue('keterangan', data?.keterangan) + }, [data]) + + const getContent = () => ( + + + {/* */} + + + + + {data?.benefit?.description} + + + + + + + + Amount Incurred* + + + + + + + + + + + + + Amount Approved* + + + + append({amount_approved: ''}) } + id='amount_approved' + key={id} + name={`amount_approved`} + placeholder='Amount Approved' + required + /> + + + + + + + + + Amount Not Approved* + + + + append({amount_not_approved: ''}) } + id='amount_not_approved' + key={id} + name={`amount_not_approved`} + placeholder='Amount Not Approved' + required + /> + + + + + + + + + Excess Paid* + + + + append({excess_paid: ''}) } + id='excess_paid' + key={id} + name={`excess_paid`} + placeholder='Excess Paid' + required + /> + + + + + + + + + Keterangan* + + + + append({keterangan: ''}) } + id='keterangan' + key={id} + name={`keterangan`} + placeholder='Keterangan' + required + /> + + + + + + {/* */} + + + + + Save + + + + + + ); + + + return ( + + ); +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogHospitalCare.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogHospitalCare.tsx new file mode 100644 index 00000000..c2467a21 --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogHospitalCare.tsx @@ -0,0 +1,155 @@ +import MuiDialog from "@/components/MuiDialog"; +import { Button, Autocomplete, Card, Checkbox, DialogActions, Grid, Typography } from "@mui/material"; +import { Paper } from "@mui/material"; +import { Stack } from '@mui/material'; +import React, { useState } from 'react'; +import { DetailFinalLogType } from "../Model/Types"; +import { fDateTimesecond, toTitleCase } from "@/utils/formatTime"; +import { useFieldArray, useForm } from 'react-hook-form'; +import { FormProvider, RHFDatepicker, RHFSelect, RHFTextField } from '@/components/hook-form'; + +import axios from "@/utils/axios"; +import { enqueueSnackbar } from "notistack"; +import { useNavigate } from "react-router"; +import { LoadingButton } from '@mui/lab'; +import AddIcon from '@mui/icons-material/Add'; + + + + +type DialogConfirmationType = { + openDialog: boolean; + setOpenDialog: any; + onSubmit?: void; + requestLog: DetailFinalLogType|undefined; +} + +export default function DialogHospitalCare({requestLog, setOpenDialog, openDialog } : DialogConfirmationType ) { + + interface FormValuesProps extends Partial { + taxes: boolean; + inStock: boolean; + } + + const onSubmit = async (data: DetailFinalLogType) => { + + reset(); + } + + const methods = useForm(); + const { + reset, + watch, + control, + setValue, + getValues, + setError, + handleSubmit, + resetField, + formState: { isSubmitting }, + } = methods; + + const {fields, append, remove} = useFieldArray({name: "secondary_diagnosis_id", control}) + + const getContent = () => ( + + + + {/* Location */} + + Location* + + + + {/* Dokter */} + + Doctor* + + + + + Medical Record Number* + + + + + Symptoms* + + + + + Sign* + + + + + Diagnosis* + + + + {/* + + + + + + + + + Examination and Result* + + + + {/* + + + + + + + + + + + Invoice* + + + + + + + + + + Save + + + + + ); + + + + + return ( + + ); +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogMedicine.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogMedicine.tsx new file mode 100644 index 00000000..53cd0ad8 --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogMedicine.tsx @@ -0,0 +1,160 @@ +import MuiDialog from "@/components/MuiDialog"; +import { Button, Autocomplete, Card, Checkbox, DialogActions, Grid, Typography } from "@mui/material"; +import { Paper } from "@mui/material"; +import { Stack } from '@mui/material'; +import React, { useState } from 'react'; +import { DetailFinalLogType } from "../Model/Types"; +import { fDateTimesecond, toTitleCase } from "@/utils/formatTime"; +import { useFieldArray, useForm } from 'react-hook-form'; +import { FormProvider, RHFDatepicker, RHFSelect, RHFTextField } from '@/components/hook-form'; + +import axios from "@/utils/axios"; +import { enqueueSnackbar } from "notistack"; +import { useNavigate } from "react-router"; +import { LoadingButton } from '@mui/lab'; +import AddIcon from '@mui/icons-material/Add'; +import RHFTextFieldMoney from "@/components/hook-form/v2/RHFTextFieldMoney"; + + +type DialogConfirmationType = { + openDialog: boolean; + setOpenDialog: any; + onSubmit?: void; + requestLog: DetailFinalLogType|undefined; +} + +export default function DialogHMedicine({requestLog, setOpenDialog, openDialog } : DialogConfirmationType ) { + + interface FormValuesProps extends Partial { + taxes: boolean; + inStock: boolean; + } + + const onSubmit = async (data: DetailFinalLogType) => { + + reset(); + } + + const handleCloseDialogMedicine = () => { + setOpenDialog(false) + setMedicines([]) + } + const [medicines, setMedicines] = useState([]); + + const addMedicine = () => { + setMedicines((prevMedicines) => [...prevMedicines, { medicine: '', price: '' }]); + + }; + + const handleDelete = (index) => { + // Update the medicines state to remove the medicine at the given index + setMedicines((prevMeds) => prevMeds.filter((med, medIndex) => medIndex !== index)); + }; + + const removeMedicene = (i:number) => { + const index = medicines.indexOf(i); + if (index > -1) { // only splice array when item is found + medicines.splice(index, 1); // 2nd parameter means remove one item only + } + } + + + const methods = useForm(); + const { + reset, + watch, + control, + setValue, + getValues, + setError, + handleSubmit, + resetField, + formState: { isSubmitting }, + } = methods; + + const {fields, append, remove} = useFieldArray({name: "secondary_diagnosis_id", control}) + + const getContent = () => ( + + + + {/* Medicine */} + + + Medicine* + + + + + {/* Listing */} + + + + + + + {medicines.map((medicine, index) => ( + + + + + + + + {/* + + */} + + + ))} + + + + + + ); + + const getAction = () => ( + + + + + ); + + + + return ( + + ); +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx index 39aa66ab..f1e97362 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx @@ -1,305 +1,412 @@ -// mui -import { Container, Grid, Stack, Typography, Card, TextField, Divider, ButtonBase, Box, IconButton } from '@mui/material'; +import { + Container, + Grid, + Stack, + Typography, + Card, + Dialog, + TableRow, + Tab, + TableCell, + Collapse, + AccordionSummary, + AccordionDetails, + } from '@mui/material'; // components -import Page from '../../components/Page'; +import Page from '../../../components/Page'; // utils -import useSettings from '../../hooks/useSettings'; +import useSettings from '../../../hooks/useSettings'; // react import { useNavigate, useParams, useLocation } from 'react-router-dom'; -import { useEffect, useState, useRef } from 'react'; -import axios from '../../utils/axios'; +import { useEffect, useState, useRef, useMemo } from 'react'; +import axios from '../../../utils/axios'; // pages -import DetailTimeline from '../../pages/ClaimRequests/DetailTimeline'; -import DetailStepper from '../../pages/ClaimRequests/DetailStepper'; -import { format } from 'date-fns'; import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; -import Button from '@mui/material/Button'; +import { DetailFinalLogType } from './Model/Types'; +import { fDate, fDateTimesecond } from '@/utils/formatTime'; +import { Button } from '@mui/material'; +import DialogConfirmation from '../FinalLog/Components/DialogConfirmation'; +import Label from '@/components/Label'; +import { Box } from '@mui/system'; +import { Accordion } from '@mui/material'; +import { Delete, EditOutlined, ExpandMore } from '@mui/icons-material'; +import {BenefitData } from '../FinalLog/Model/Types' import AddIcon from '@mui/icons-material/Add'; -import RemoveIcon from '@mui/icons-material/Remove'; -import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers'; -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; -import Iconify from '@/components/Iconify'; -import { fPostFormat } from '@/utils/formatTime'; -import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; -import DownloadIcon from '@mui/icons-material/Download'; -import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material'; -import CloseIcon from '@mui/icons-material/Close'; -import { fDateTimesecond } from '@/utils/formatTime'; -import { makeFormData } from '@/utils/jsonToFormData'; -import { enqueueSnackbar } from 'notistack'; +// Import Card Detail Final LOG +import CardDetail from '../Components/CardDetail'; +import CardService from '../Components/CardService'; +import CardExclusion from '../Components/CardExclusion'; + +// Import Dialog +import DialogHospitalCare from './Components/DialogHospitalCare'; +import DialogBenefit from './Components/DialogBenefit'; +import DialogMedicine from './Components/DialogMedicine'; +import DetailBenefit from '../Components/DetailBenefit'; +import DialogEditBenefit from './Components/DialogEditBenefit'; + +import MoreMenu from '@/components/MoreMenu'; +import { MenuItem } from '@mui/material'; +import { fNumber } from '@/utils/formatNumber'; +import palette from '@/theme/palette'; +import DialogDelete from './Components/DialogDelete'; + // ---------------------------------------------------------------------- export default function Detail() { const location = useLocation(); const queryParams = new URLSearchParams(location.search); - const code = queryParams.get('code'); const navigate = useNavigate(); const { themeStretch } = useSettings(); - const [data, setData] = useState(); - const [dataDialog, setDataDialog] = useState(); - const [document, setDocument] = useState(null); + const [requestLog, setRequestLog] = useState(); + const { id } = useParams(); useEffect(() => { axios - .get('/claim-requests/detail/'+id) + .get('customer-service/request/'+id) .then((response) => { - setData(response.data); - setDataDialog(response.data.data.dialog_submits); - setDocument(response.data.data.documents); - + setRequestLog(response.data.data) }) .catch((error) => { console.error(error); - }); - - }, []); - - const [isInvoiceVisible, setInvoiceVisibility] = useState(false); - - const handleInvoice = () => { - setInvoiceVisibility(!isInvoiceVisible); - } - const currentDate = new Date(); - const formattedCurrentDate = format(currentDate, 'dd MMM yyyy'); - const [dateInvoice, setDateInvoice] = useState(currentDate); - - const fileInvoiceInput = useRef(null); - const [fileInvoices, setFileInvoices] = useState([]); - - const handleInvoiceInputChange = (event) => { - if (event.target.files[0]) { - setFileInvoices([...fileInvoices, ...event.target.files]); - } else { - console.log('NO FILE'); - } - }; - const removeInvoiceFiles = (filesState, index) => { - setFileInvoices( - filesState.filter((file, fileIndex) => { - return fileIndex != index; }) - ); - }; - const date = dateInvoice ? fPostFormat(dateInvoice, 'yyyy-MM-dd') : null; + }, [id]); + + const style1 = { + color: '#919EAB', + width: '30%' + } + const style2 = { + width: '70%' + } + const marginBottom1 = { + marginBottom: 1, + } + const marginBottom2 = { + marginBottom: 2, + } const [openDialogSubmit, setOpenDialogSubmit] = useState(false); - const handleCloseDialogSubmit = () => { - setOpenDialogSubmit(false); - } - const handleSubmitData = () => { - // if(fileInvoices.length > 0) - // { - //submit data - axios - .post('claim-requests/'+id+'/approve') - .then((response) => { - enqueueSnackbar('Success Submit Claim Request', { variant: 'success' }); - setOpenDialogSubmit(false); - }) - .catch(({ response }) => { - enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' }); - }); - //Upload file invoices - const formData = makeFormData({ - date:date, - invoice_files: fileInvoices, - }); - axios - .post('claim-requests/'+id+'/invoice-files', formData) - .then((response) => { - enqueueSnackbar(response.data.message ?? 'Success upload invoice', { variant: 'success' }); - }) - .catch(({ response }) => { - enqueueSnackbar(response.data.message ?? 'Something Went Wrong', { variant: 'error' }); - }); - // } - // else - // { - // enqueueSnackbar('Please upload file invoice, before submit', { variant: 'warning' }); - // } + const [openDialogHospital, setDialogHospital] = useState(false); + const [openDialogBenefit, setDialogBenefit] = useState(false); + const [openDialogMedicine, setDialogMedicine] = useState(false); - setTimeout(() => - { - window.location.reload(); - }, 5000); + // Handel Delete Detail Benefit + const [idBenefitData, setIdBenefitData] = useState(); + const [openDialogDeleteBenefit, setDialogDeleteBenefit] = useState(false) - }; - - const check_invoice = document?.find((dataInvoice) => dataInvoice.type === 'claim-invoice'); + const [approve, setApprove] = useState('') + // Handle Edit Detail Benefit + const [openDialogEditBenefit, setDialogEditBenefit] = useState(false) + const [BenefitConfigurationData, setBenefitConfigurationData] = useState(); return ( navigate(-1)} sx={{cursor:'pointer'}}/> - {(data && data.data) ? data.data.status.code : ''} - {data ? ( - - Submission Date - {(data && data.data) ? format(new Date(data.data.status.submission_date), "d MMM yyyy") : ''} + {(requestLog && requestLog.code ? requestLog.code : '')} - ) : ''} - - {data ? ( + {/* Detail */} - + + - - - Format Claim - - + + {/* Service */} + + + - {check_invoice ? ( - - - Request Claim - + + {/* Exclusion */} + + + + + + {/* Hospital Care */} + {/* + + + History of Hospital Care + - - ) : ''} - - - - - { - setDateInvoice(newValue); - }} - inputFormat="dd MMM yyyy" - renderInput={(params) => } - /> - - } - spacing={1} - sx={{ marginY: 2 }} - > - {fileInvoices && - fileInvoices.map((file, index) => ( - - - - {file.name ? file.name : '-'} - - { - removeInvoiceFiles(fileInvoices, index); - }} - sx={{cursor: 'pointer'}} - > + + + + */} + + {/* Benefit */} + + + + Benefit + + + + {requestLog?.benefit_data?.map((item, index) => ( + + + + + + + {item.benefit?.description} + + + + + { + setDialogEditBenefit(true) + setIdBenefitData(item.id) + setBenefitConfigurationData(item) + }} + > + + Edit + + { + setIdBenefitData(item.id) + setDialogDeleteBenefit(true) + }} + > + + Delete + + + } /> + + + + + + + + {/* Amount Incurred */} + + + + + Amount Incurred + + + + + {fNumber(item.amount_incurred)} + + + + + + {/* Amount Approved */} + + + + + Amount Approved + + + + + {fNumber(item.amount_approved)} + + + + + + {/* Amount Not Approved */} + + + + + Amount Not Approved + + + + + {fNumber(item.amount_not_approved)} + + + + + + {/* Excess Paid* */} + + + + + Excess Paid* + + + + + {fNumber(item.excess_paid)} + + + + + + {/* Keterangan* */} + + + + + Keterangan* + + + + + {item.keterangan} + + + + + + + + + + + + ))} + + + + + + + {/* Dialog Edit */} + + + + {/* Dialog Delete */} + + + + {/* Medicine */} + + + + Medicine + + + + + + + + {/* File */} + + + + + Files History + {requestLog?.files?.map((documentType, index) => ( + + + + {documentType.original_name ? documentType.original_name : '-'} + - ))} - - fileInvoiceInput.current?.click()}> - - - - Upload Invoice - - - - + + ))} + - - - - - - {dataDialog && dataDialog.status === 'requested' ? ( - <> - - - - ) : ''} - {/* Dialog Submits */} - - - - - Confirmation - - - - - - - - {dataDialog ? ( - - Are you sure to submit this claim ? - - - Code - {dataDialog.code} - - - Name - {dataDialog.name} - - - Date Submission - {fDateTimesecond(dataDialog.submission_date)} - - - Claim Method - Service Type - - - Service Type - - {dataDialog.service_code === 'IP' ? 'Inpatient' : 'Outpatient'} - - - - - ) : ''} - - - - - - + + {requestLog?.status_final_log == 'requested' ? ( + + + <> +
+ +
+
+ +
+ +
+ ) : null} +
- ) : ''}
); diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/List.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/List.tsx index ece99d47..fe591df7 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/List.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/List.tsx @@ -48,6 +48,8 @@ import { capitalizeFirstLetter } from '@/utils/formatString'; import Label from '@/components/Label'; import TableMoreMenu from '@/components/table/TableMoreMenu'; import { Import } from '@/@types/claims'; + +import { FinalLogType } from '../FinalLog/Model/Types'; // import LoadingButton from '@/theme/overrides/LoadingButton'; export default function List() { @@ -217,7 +219,7 @@ export default function List() { {handleGetTemplate('claim-request')}}>Download Template {handleGetData('data-plan-benefit')}}>Download Claim Request - + */} )} @@ -281,7 +283,7 @@ export default function List() { const loadDataTableData = async (appliedFilter: any | null = null) => { setDataTableLoading(true); const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]); - const response = await axios.get('/customer-service/request?status=approved', { params: filter }); + const response = await axios.get('/customer-service/request?final_log=1&service_code=OP', { params: filter }); // console.log(response.data); setDataTableLoading(false); @@ -320,7 +322,7 @@ export default function List() { }; // Called on every row to map the data to the columns - function createData(data: any): any { + function createData(data: FinalLogType) { return { ...data, }; @@ -342,7 +344,7 @@ export default function List() { {open ? : } */ } - + {/* { // handleShowClaim(row); @@ -350,26 +352,29 @@ export default function List() { > {row.id} - - {row.member?.code} + */} + {row.code} {row.member?.full_name} {row.service_name} {row.payment_type_name} - { row.status == "requested" ? - () : - () - } + { row.status_final_log == "requested" ? + () : + row.status_final_log == "declined" ? + () + : + () + } - navigate(`/claim-requests/edit/${row.id}`)}> + {/* navigate(`/claim-requests/edit/${row.id}`)}> Edit - - navigate ('/claim-requests/detail/'+row.id+'')}> + */} + navigate ('/custormer-service/final-log/detail/'+row.id+'')}> Detail @@ -471,9 +476,9 @@ export default function List() { {/* */} - + {/* ID Request LOG - + */} Code diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Functions.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Functions.tsx index da72ff60..c0831263 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Functions.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Functions.tsx @@ -1,6 +1,7 @@ import axios from '@/utils/axios'; import { enqueueSnackbar } from 'notistack'; import { MemberListType } from './Types'; +import { BenefitConfigurationListType } from './Types'; import { makeFormData } from '@/utils/jsonToFormData'; /** @@ -77,3 +78,76 @@ export const addClaimRequest = async ( data: MemberListType[] ): Promise => { + const response = await axios.post(`customer-service/request/insert-benefit`, { + ...data + }) + .then((res) =>{ + enqueueSnackbar(res.data.message, { + variant: 'success', + }); + + return true; + }) + .catch((res) => { + if (res.response.status == 400) { + let arr_message = res.response.data.message; + + // for (const key in arr_message) { + enqueueSnackbar(arr_message, { + variant: 'warning', + }); + // } + } + else { + enqueueSnackbar("server error !", { + variant: 'error', + }); + } + + return false; + }); + + return response; +} + +/** + * Edit Benefit + */ +export const postEditBenefit = async (id:number, data: BenefitConfigurationListType):Promise => { + const response = await axios.put(`customer-service/request/benefit_data/${id}`, { + ...data + }) + .then((res) =>{ + enqueueSnackbar(res.data.message, { + variant: 'success', + }); + + return true; + }) + .catch((res) => { + if (res.response.status == 400) { + let arr_message = res.response.data.message; + + // for (const key in arr_message) { + enqueueSnackbar(arr_message, { + variant: 'warning', + }); + // } + } + else { + enqueueSnackbar("server error !", { + variant: 'error', + }); + } + + return false; + }); + + return response; +} diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Types.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Types.tsx index 81b7da49..c89f0369 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Types.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Types.tsx @@ -1,3 +1,5 @@ +import { Member } from "@/@types/member" + /** * Search Type */ @@ -8,18 +10,109 @@ export type SearchType = { /** * Member List */ -export type MemberListType = { - id : string, - member_id : string, - name : string, - service_type : ServiceType[], - patien_type? : string, - file_kondisi? : any[], - file_diagnosa? : any[], - file_penunjang? : any[], +export type FinalLogType = { + id : number, + code : string, + member : Member, + submission_date : string, + service_name : string, + payment_type_name : string, + status_final_log : string, + status : string, + files_by_type : files_by_type, } -export type ServiceType = { - code : string - name : string + +export type DetailFinalLogType = { + id : number, + code : string, + member_id : string, + policy_number : string, + name : string|any, + date_of_birth : string, + gender : string, + marital_status : string, + submission_date : string, + service_type : string, + claim_method : string, + status : string, + status_final_log : string, + benefit : Benefit[], + benefit_data : BenefitData[], + config_service : ConfigService, + exclusion : Exclusion[], + files : file[], } + +export type BenefitData = { + amount_incurred : number, + amount_approved : number, + amount_not_approved : number, + excess_paid : number, + keterangan : string, + benefit : Benefit, + id : number, +} + +export type Benefit = { + id: number, + code: string, + description: string +} + +export type files_by_type = { + claim_diagnosis : file[], + claim_kondisi : file[], + claim_result : file[], +} + +export type file = { + original_name: string, + name: string, + path: string, + url: string, +} + +export type ConfigService = { + gp_external_doctor_online: string, + gp_external_doctor_offline: string, + gp_internal_doctor_online: string, + gp_internal_doctor_offline: string, + sp_external_doctor_online: string, + sp_external_doctor_offline: string, + sp_internal_doctor_online: string, + sp_internal_doctor_offline: string, + vitamins: string, + delivery_fee: string, + general_practitioner_fee: string, + specialist_practitioner_fee: string +} + +export type Exclusion = { + exclusionable: { + code: string, + name: string + }, + rules: Rule[] +} + +export type Rule = { + id: number, + exclusion_id: number, + name: string, + values: string, + +} + + +export type BenefitConfigurationListType = { + request_log_id: number|undefined, + benefit_name: string, + amount_incurred: number, + amount_approved: number, + amount_not_approved: number, + excess_paid: number, + keterangan: string, + description: string, +} + diff --git a/frontend/dashboard/src/pages/CustomerService/Request/Components/DialogConfirmation.tsx b/frontend/dashboard/src/pages/CustomerService/Request/Components/DialogConfirmation.tsx new file mode 100644 index 00000000..fe3a734b --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/Request/Components/DialogConfirmation.tsx @@ -0,0 +1,109 @@ +import MuiDialog from "@/components/MuiDialog"; +import { Button, Card, Checkbox, DialogActions, Grid, Typography } from "@mui/material"; +import { Paper } from "@mui/material"; +import { Stack } from '@mui/material'; +import React, { useState } from 'react'; +import { DetailRequestLogType } from "../Model/Types"; +import { fDateTimesecond, toTitleCase } from "@/utils/formatTime"; +import axios from "@/utils/axios"; +import { enqueueSnackbar } from "notistack"; +import { useNavigate } from "react-router"; + + +type DialogConfirmationType = { + openDialog: boolean; + setOpenDialog: any; + onSubmit?: void; + approve: string; + requestLog: DetailRequestLogType|undefined; +} + +export default function DialogConfirmation({requestLog, setOpenDialog, openDialog, approve, onSubmit} : DialogConfirmationType ) { + + const navigate = useNavigate(); + const handleSubmit = () => { + const formData = { + status : approve + } + axios + .put(`customer-service/request/${requestLog?.id}`, formData) + .then((response) => { + enqueueSnackbar('Verification Request LOG Success', { variant: 'success' }); + setOpenDialog(false); + navigate('/custormer-service/request') + }) + .catch(({ response }) => { + enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' }); + }); + } + + const style1 = { + color: '#919EAB', + width: '30%' + } + const style2 = { + width: '70%' + } + const marginBottom1 = { + marginBottom: 1, + } + + const handleCloseDialog = () => { + setOpenDialog(false); + } + + const getContent = () => ( + + Are you sure to {approve == 'approved' ? 'approve' : 'deciline'} this request ? + + + + Member ID + {requestLog?.member_id} + + + Policy Number + {requestLog?.policy_number} + + + Name + {requestLog?.name} + + + Submission Date + {requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : '-'} + + + Claim Method + {requestLog?.claim_method ? toTitleCase(requestLog?.claim_method) : '-'} + + + Service Type + {requestLog?.service_type} + + + + + + + {approve == 'approved' ? ( + + ) : ( + + ) } + + + + ); + + + return ( + + ); +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/Request/Detail.tsx b/frontend/dashboard/src/pages/CustomerService/Request/Detail.tsx index 77f9e59e..db8cc17d 100644 --- a/frontend/dashboard/src/pages/CustomerService/Request/Detail.tsx +++ b/frontend/dashboard/src/pages/CustomerService/Request/Detail.tsx @@ -1,305 +1,174 @@ -// mui -import { Container, Grid, Stack, Typography, Card, TextField, Divider, ButtonBase, Box, IconButton } from '@mui/material'; +import { + Container, + Grid, + Stack, + Typography, + Card, + Dialog, + } from '@mui/material'; // components import Page from '../../../components/Page'; // utils import useSettings from '../../../hooks/useSettings'; // react import { useNavigate, useParams, useLocation } from 'react-router-dom'; -import { useEffect, useState, useRef } from 'react'; +import { useEffect, useState, useRef, useMemo } from 'react'; import axios from '../../../utils/axios'; // pages -import DetailTimeline from '../../../pages/ClaimRequests/DetailTimeline'; -import DetailStepper from '../../../pages/ClaimRequests/DetailStepper'; -import { format } from 'date-fns'; import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; -import Button from '@mui/material/Button'; -import AddIcon from '@mui/icons-material/Add'; -import RemoveIcon from '@mui/icons-material/Remove'; -import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers'; -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; -import Iconify from '@/components/Iconify'; -import { fPostFormat } from '@/utils/formatTime'; -import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; -import DownloadIcon from '@mui/icons-material/Download'; -import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material'; -import CloseIcon from '@mui/icons-material/Close'; -import { fDateTimesecond } from '@/utils/formatTime'; -import { makeFormData } from '@/utils/jsonToFormData'; - -import { enqueueSnackbar } from 'notistack'; +import { DetailRequestLogType } from './Model/Types'; +import { fDate, fDateTimesecond } from '@/utils/formatTime'; +import { Button } from '@mui/material'; +import DialogConfirmation from './Components/DialogConfirmation'; // ---------------------------------------------------------------------- export default function Detail() { const location = useLocation(); const queryParams = new URLSearchParams(location.search); - const code = queryParams.get('code'); const navigate = useNavigate(); const { themeStretch } = useSettings(); - const [data, setData] = useState(); - const [dataDialog, setDataDialog] = useState(); - const [document, setDocument] = useState(null); + const [requestLog, setRequestLog] = useState(); + const { id } = useParams(); useEffect(() => { axios - .get('/claim-requests/detail/'+id) + .get('customer-service/request/'+id) .then((response) => { - setData(response.data); - setDataDialog(response.data.data.dialog_submits); - setDocument(response.data.data.documents); - + setRequestLog(response.data.data) }) .catch((error) => { console.error(error); - }); - - }, []); - - const [isInvoiceVisible, setInvoiceVisibility] = useState(false); - - const handleInvoice = () => { - setInvoiceVisibility(!isInvoiceVisible); - } - const currentDate = new Date(); - const formattedCurrentDate = format(currentDate, 'dd MMM yyyy'); - const [dateInvoice, setDateInvoice] = useState(currentDate); - - const fileInvoiceInput = useRef(null); - const [fileInvoices, setFileInvoices] = useState([]); - - const handleInvoiceInputChange = (event) => { - if (event.target.files[0]) { - setFileInvoices([...fileInvoices, ...event.target.files]); - } else { - console.log('NO FILE'); - } - }; - const removeInvoiceFiles = (filesState, index) => { - setFileInvoices( - filesState.filter((file, fileIndex) => { - return fileIndex != index; }) - ); - }; - const date = dateInvoice ? fPostFormat(dateInvoice, 'yyyy-MM-dd') : null; + }, [id]); + + function toTitleCase(str: string | null) { + return str.replace(/\w\S*/g, function(txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + }); + } + + const style1 = { + color: '#919EAB', + width: '30%' + } + const style2 = { + width: '70%' + } + const marginBottom1 = { + marginBottom: 1, + } const [openDialogSubmit, setOpenDialogSubmit] = useState(false); const handleCloseDialogSubmit = () => { setOpenDialogSubmit(false); } - const handleSubmitData = () => { - // if(fileInvoices.length > 0) - // { - //submit data - axios - .post('claim-requests/'+id+'/approve') - .then((response) => { - enqueueSnackbar('Success Submit Claim Request', { variant: 'success' }); - setOpenDialogSubmit(false); - }) - .catch(({ response }) => { - enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' }); - }); - //Upload file invoices - const formData = makeFormData({ - date:date, - invoice_files: fileInvoices, - }); - axios - .post('claim-requests/'+id+'/invoice-files', formData) - .then((response) => { - enqueueSnackbar(response.data.message ?? 'Success upload invoice', { variant: 'success' }); - }) - .catch(({ response }) => { - enqueueSnackbar(response.data.message ?? 'Something Went Wrong', { variant: 'error' }); - }); - // } - // else - // { - // enqueueSnackbar('Please upload file invoice, before submit', { variant: 'warning' }); - // } - setTimeout(() => - { - window.location.reload(); - }, 5000); - - }; - - const check_invoice = document?.find((dataInvoice) => dataInvoice.type === 'claim-invoice'); + const [approve, setApprove] = useState('') return ( navigate(-1)} sx={{cursor:'pointer'}}/> - {(data && data.data) ? data.data.status.code : ''} - {data ? ( - - Submission Date - {(data && data.data) ? format(new Date(data.data.status.submission_date), "d MMM yyyy") : ''} + {(requestLog && requestLog.code ? requestLog.code : '')} - ) : ''} - - {data ? ( - - - - - Format Claim - - - - {check_invoice ? ( - - - Request Claim - + + Detail + + Member ID + {requestLog?.member_id} - - ) : ''} - - - - - { - setDateInvoice(newValue); - }} - inputFormat="dd MMM yyyy" - renderInput={(params) => } - /> - - } - spacing={1} - sx={{ marginY: 2 }} - > - {fileInvoices && - fileInvoices.map((file, index) => ( - - - - {file.name ? file.name : '-'} - - { - removeInvoiceFiles(fileInvoices, index); - }} - sx={{cursor: 'pointer'}} - > - - ))} - - fileInvoiceInput.current?.click()}> - - - - Upload Invoice - - - - + + Policy Number + {requestLog?.policy_number} + + + Name + {requestLog?.name} + + + Date Of Birth + {requestLog?.date_of_birth ? fDate(requestLog?.date_of_birth) : '-'} + + + Marital Status + {requestLog?.marital_status} + + + Submission Date + {requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : '-'} - - + + + Service + + Service Type + {requestLog?.service_type} + + + Claim Method + {toTitleCase(requestLog?.claim_method ?? '-')} + + {/* + Benefit + +
    + {requestLog?.benefit.length > 0 ? requestLog?.benefit.map((r, index) => ( +
  • {r.code } - {r.description}
  • + )) :
  • -
  • } +
+
+
*/} +
- - - {dataDialog && dataDialog.status === 'requested' ? ( - <> - - - - ) : ''} - {/* Dialog Submits */} - - - - - Confirmation - - - - - - - - {dataDialog ? ( - - Are you sure to submit this claim ? - - - Code - {dataDialog.code} - - - Name - {dataDialog.name} - - - Date Submission - {fDateTimesecond(dataDialog.submission_date)} - - - Claim Method - Service Type - - - Service Type - - {dataDialog.service_code === 'IP' ? 'Inpatient' : 'Outpatient'} - - - - - ) : ''} - - - - - - + {requestLog?.status == 'requested' ? ( + + + <> +
+ +
+
+ +
+ +
+ ) : null} +
- ) : ''}
); diff --git a/frontend/dashboard/src/pages/CustomerService/Request/List.tsx b/frontend/dashboard/src/pages/CustomerService/Request/List.tsx index 4e9927a1..1a2b3179 100644 --- a/frontend/dashboard/src/pages/CustomerService/Request/List.tsx +++ b/frontend/dashboard/src/pages/CustomerService/Request/List.tsx @@ -51,6 +51,8 @@ import { capitalizeFirstLetter } from '@/utils/formatString'; import Label from '@/components/Label'; import TableMoreMenu from '@/components/table/TableMoreMenu'; import { Import } from '@/@types/claims'; + +import { RequestLogType } from '../Request/Model/Types'; // import SvgIconStyle from '@/components/SvgIconStyle'; import SvgIconStyle from '../../../components/SvgIconStyle'; // import LoadingButton from '@/theme/overrides/LoadingButton'; @@ -323,7 +325,7 @@ export default function List() { }; // Called on every row to map the data to the columns - function createData(data: any): any { + function createData(data: RequestLogType): any { return { ...data, }; @@ -345,7 +347,7 @@ export default function List() { {open ? : }
*/ } - + {/* { // handleShowClaim(row); @@ -353,9 +355,9 @@ export default function List() { > {row.id} - + */} {row.code} - {row.member?.full_name} + {row.member_name} {row.service_name} {row.payment_type_name} @@ -371,19 +373,11 @@ export default function List() { - navigate ('/claim-requests/detail/'+row.id+'')}> + navigate ('/custormer-service/request/detail/'+row.id+'')}> Detail - navigate ('/claim-requests/detail/'+row.id+'')}> - - {/* credit: plus icon from https://heroicons.com/ */} - - - - - Konfirmasi - + } /> @@ -482,9 +476,9 @@ export default function List() { {/* */} - + {/* ID Request LOG - + */} Code diff --git a/frontend/dashboard/src/pages/CustomerService/Request/Model/Types.tsx b/frontend/dashboard/src/pages/CustomerService/Request/Model/Types.tsx index 81b7da49..0091c213 100644 --- a/frontend/dashboard/src/pages/CustomerService/Request/Model/Types.tsx +++ b/frontend/dashboard/src/pages/CustomerService/Request/Model/Types.tsx @@ -1,3 +1,5 @@ +import { Member } from "@/@types/member" + /** * Search Type */ @@ -8,18 +10,48 @@ export type SearchType = { /** * Member List */ -export type MemberListType = { - id : string, - member_id : string, - name : string, - service_type : ServiceType[], - patien_type? : string, - file_kondisi? : any[], - file_diagnosa? : any[], - file_penunjang? : any[], +export type RequestLogType = { + id : number, + code : string, + member : Member, + submission_date : string, + service_name : string, + payment_type_name : string, + status_final_log : string, + status : string, + files_by_type : files_by_type, } -export type ServiceType = { - code : string - name : string +export type files_by_type = { + claim_diagnosis : file[], + claim_kondisi : file[], + claim_result : file[], } + +export type file = { + name: string, + url: string, +} + +export type DetailRequestLogType = { + id : number, + code : string, + member_id : string, + policy_number : string, + name : string, + date_of_birth : string, + gender : string, + marital_status : string, + submission_date : string, + service_type : string, + claim_method : string, + status : string, + benefit : Benefit[], +} + +export type Benefit = { + code: string, + description: string +} + + diff --git a/frontend/dashboard/src/routes/index.tsx b/frontend/dashboard/src/routes/index.tsx index fd49827c..3d0a249c 100644 --- a/frontend/dashboard/src/routes/index.tsx +++ b/frontend/dashboard/src/routes/index.tsx @@ -252,6 +252,10 @@ export default function Router() { path: 'laboratorium_result/:member_id/claims/:claim_code/list_lab_result', element: }, + { + path: 'inpatient_monitoring', // Inpatient Monitoring + element: + }, ] }, { @@ -475,9 +479,17 @@ export default function Router() { element: , }, { - path: 'custormer-service/final-request', + path: 'custormer-service/request/detail/:id', + element: , + }, + { + path: 'custormer-service/final-log', element: , }, + { + path: 'custormer-service/final-log/detail/:id', + element: , + }, ], }, // { @@ -594,6 +606,8 @@ const LaboratoriumResult = Loadable(lazy(() => import('../pages/CaseManage const LaboratoriumResultClaims = Loadable(lazy(() => import('../pages/CaseManagement/LaboratoriumResult/Claim'))) const DetailLabResultForm = Loadable(lazy(() => import('../pages/CaseManagement/LaboratoriumResult/Components/DetailLabResultForm'))) const DetailLabResultList = Loadable(lazy(() => import('../pages/CaseManagement/LaboratoriumResult/Components/DetailLabResultList'))) +// Inpatient Monitoring +const InpatientMonitoring = Loadable(lazy(() => import('../pages/CaseManagement/InpatientMonitoring/Index'))) /** @@ -601,7 +615,13 @@ const DetailLabResultList = Loadable(lazy(() => import('../pages/CaseManage */ // Request const RequestLog = Loadable(lazy(() => import('../pages/CustomerService/Request/Index'))) +const RequestLogDetail = Loadable(lazy(() => import('../pages/CustomerService/Request/Detail'))) +// Final LOG const FinalLog = Loadable(lazy(() => import('../pages/CustomerService/FinalLog/Index'))) +const FinalLogDetail = Loadable(lazy(() => import('../pages/CustomerService/FinalLog/Detail'))) + + + const MasterDiagnosisTemplate = Loadable(lazy(() => import('../pages/Master/Diagnosis/Master/Index'))); const MasterDiagnosisTemplateCreate = Loadable(lazy(() => import('../pages/Master/Diagnosis/Master/CreateUpdate'))); diff --git a/frontend/dashboard/src/utils/formatTime.ts b/frontend/dashboard/src/utils/formatTime.ts index 33f90e55..2bca0113 100644 --- a/frontend/dashboard/src/utils/formatTime.ts +++ b/frontend/dashboard/src/utils/formatTime.ts @@ -35,3 +35,9 @@ export function fPostFormat(date: Date | string | number) { export function fDateOnly(date: Date | string | number) { return format(new Date(date), 'yyyy-MM-dd'); } + +export function toTitleCase(str: string | null) { + return str.replace(/\w\S*/g, function(txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + }); +} From 40371bd53af6d4e8bde2d05b677af3dca2c9ad89 Mon Sep 17 00:00:00 2001 From: Tb Fajri Date: Tue, 19 Dec 2023 08:56:18 +0700 Subject: [PATCH 2/3] Update customer service --- .../Api/DailyMonitoringController.php | 32 +- .../Controllers/Api/RequestLogController.php | 4 +- .../Api/RequestLogMedicineController.php | 136 ++++++ Modules/Internal/Routes/api.php | 10 +- .../Transformers/RequestLogShowResource.php | 15 +- app/Models/RequestLogMedicine.php | 30 ++ ...954_create_request_log_medicines_table.php | 34 ++ ..._15_153059_add_columns_to_request_logs.php | 32 ++ ...te_request_log_daily_monitoring_table.php} | 13 +- .../dashboard/src/components/MuiDialog.tsx | 2 +- .../Components/ClaimListRow.tsx | 30 +- .../Components/DailyMonitoringList.tsx | 2 + .../Components/DailyMonitoringListRow.tsx | 9 + .../DailyMonitoring/Model/Types.ts | 2 + .../Components/FormCreate.tsx | 355 -------------- .../Components/FormCreateBtnChoose.tsx | 39 -- .../Components/FormCreateBtnUpload.tsx | 39 -- .../Components/FormCreateFilesUpload.tsx | 25 - .../Components/FormCreateListChoose.tsx | 78 --- .../Components/FormCreateSearch.tsx | 70 --- .../Components/FormEdit.tsx | 456 ------------------ .../InpatientMonitoring/CreateUpdate.tsx | 63 --- .../InpatientMonitoring/Detail.tsx | 306 ------------ .../InpatientMonitoring/DetailStepper.tsx | 58 --- .../InpatientMonitoring/DetailTimeline.tsx | 426 ---------------- .../InpatientMonitoring/Index.tsx | 6 +- .../InpatientMonitoring/List.tsx | 18 +- .../InpatientMonitoring/Model/Functions.tsx | 79 --- .../InpatientMonitoring/Model/Types.tsx | 36 -- .../Components/CardBenefit.tsx | 214 ++++++++ .../CustomerService/Components/CardFile.tsx | 50 ++ .../Components/CardMedicine.tsx | 65 +++ .../Components/DetailBenefit.tsx | 115 ----- .../Components/DialogConfirmation.tsx | 11 +- .../FinalLog/Components/DialogDelete.tsx | 51 ++ .../Components/DialogDeleteMedicine.tsx | 69 +++ .../FinalLog/Components/DialogEditBenefit.tsx | 2 +- .../FinalLog/Components/DialogMedicine.tsx | 171 ++++--- .../pages/CustomerService/FinalLog/Detail.tsx | 76 +-- .../FinalLog/Model/Functions.tsx | 41 +- .../CustomerService/FinalLog/Model/Types.tsx | 41 +- resources/views/pdf/guaranted_leter.blade.php | 44 +- 42 files changed, 1027 insertions(+), 2328 deletions(-) create mode 100644 Modules/Internal/Http/Controllers/Api/RequestLogMedicineController.php create mode 100644 app/Models/RequestLogMedicine.php create mode 100644 database/migrations/2023_12_13_091954_create_request_log_medicines_table.php create mode 100644 database/migrations/2023_12_15_153059_add_columns_to_request_logs.php rename database/migrations/{2023_10_27_111432_create_claim_daily_monitoring_table.php => 2023_12_15_154820_create_request_log_daily_monitoring_table.php} (66%) delete mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreate.tsx delete mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnChoose.tsx delete mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnUpload.tsx delete mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateFilesUpload.tsx delete mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateListChoose.tsx delete mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateSearch.tsx delete mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormEdit.tsx delete mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/CreateUpdate.tsx delete mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Detail.tsx delete mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailStepper.tsx delete mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailTimeline.tsx delete mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Functions.tsx delete mode 100644 frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Types.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/Components/CardBenefit.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/Components/CardFile.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/Components/CardMedicine.tsx delete mode 100644 frontend/dashboard/src/pages/CustomerService/Components/DetailBenefit.tsx create mode 100644 frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogDeleteMedicine.tsx diff --git a/Modules/Internal/Http/Controllers/Api/DailyMonitoringController.php b/Modules/Internal/Http/Controllers/Api/DailyMonitoringController.php index 3bb34c82..09347128 100644 --- a/Modules/Internal/Http/Controllers/Api/DailyMonitoringController.php +++ b/Modules/Internal/Http/Controllers/Api/DailyMonitoringController.php @@ -35,12 +35,15 @@ class DailyMonitoringController extends Controller */ public function GetMemberList() { - $memberList = DB::table('claims') - ->leftJoin('members', 'claims.member_id', '=', 'members.id') - ->leftJoin('member_plans', 'members.id', '=', 'member_plans.id') - ->select('members.member_id','members.name','member_plans.start AS startdate','member_plans.end AS enddate') - ->groupBy('claims.member_id') - ->orderBy('claims.created_at', 'desc') + $memberList = DB::table('request_logs') + ->leftJoin('members', 'request_logs.member_id', '=', 'members.id') + ->leftJoin('member_plans', 'request_logs.member_id', '=', 'member_plans.member_id') + ->leftJoin('organizations', 'organizations.id', '=', 'request_logs.organization_id') + ->select('members.member_id','members.name','member_plans.start AS startdate','member_plans.end AS enddate', 'request_logs.submission_date as addmision_date', 'organizations.name as provider' ) + ->where('request_logs.service_code', 'IP') + ->where('request_logs.status_final_log', 'approved') + ->groupBy('request_logs.member_id') + ->orderBy('request_logs.created_at', 'desc') ->get(); return response()->json([ @@ -62,15 +65,14 @@ class DailyMonitoringController extends Controller ->where('member_id', $member_id) ->first(); - $claimList = DB::table('claims') - ->leftJoin('claim_requests', 'claims.claim_request_id', '=', 'claim_requests.id') - ->leftJoin('claim_history_cares', 'claims.id', '=', 'claim_history_cares.claim_id') - ->leftJoin('services', 'claim_requests.service_code', '=', 'services.code') - ->leftJoin('members', 'claims.member_id', '=', 'members.id') - ->select('claims.id AS claim_id','claim_history_cares.admission_date','claim_history_cares.discharge_date','claim_requests.code AS claim_code','services.name AS service_type','claims.status AS claim_status','members.member_id',) - ->where("claims.member_id", "=", $memberDetail->id) - ->where("claim_requests.claim_id", "!=",null) - ->orderBy("claims.created_at", "desc") + $claimList = DB::table('request_logs') + ->leftJoin('services', 'services.code', '=', 'request_logs.service_code') + ->leftJoin('members', 'members.id', '=', 'request_logs.member_id') + ->select('request_logs.id','request_logs.submission_date AS admission_date','request_logs.discharge_date','request_logs.code','services.name as service_name','request_logs.status','members.name',) + ->where('request_logs.service_code', 'IP') + ->where('request_logs.status_final_log', 'approved') + ->where("request_logs.member_id", "=", $memberDetail->id) + ->orderBy("request_logs.created_at", "desc") ->get(); return response()->json([ diff --git a/Modules/Internal/Http/Controllers/Api/RequestLogController.php b/Modules/Internal/Http/Controllers/Api/RequestLogController.php index b4b0f168..ba8e088f 100644 --- a/Modules/Internal/Http/Controllers/Api/RequestLogController.php +++ b/Modules/Internal/Http/Controllers/Api/RequestLogController.php @@ -306,10 +306,12 @@ class RequestLogController extends Controller { $id = $request->id; $requestLog = RequestLog::findOrFail($id); + $status = $request->status ?? 'requested'; + // Update Request LOG untuk lanjut ke Final LOG $requestLog->final_log = 1; - $requestLog->status_final_log = 'requested'; + $requestLog->status_final_log = $status; $requestLog->save(); diff --git a/Modules/Internal/Http/Controllers/Api/RequestLogMedicineController.php b/Modules/Internal/Http/Controllers/Api/RequestLogMedicineController.php new file mode 100644 index 00000000..d9aaeb59 --- /dev/null +++ b/Modules/Internal/Http/Controllers/Api/RequestLogMedicineController.php @@ -0,0 +1,136 @@ + 'Kolom :attribute wajib diisi.', + 'numeric' => 'Kolom :attribute harus berupa angka.', + ]; + + $validator = Validator::make($request->all(), [ + 'medicine' => 'required|array', + 'medicine.*' => 'required', + ], $customMessages); + + if ($validator->fails()) { + return Helper::responseJson([],'error', 400, $validator->errors()); + } else { + $medicine = $request->medicine; + + if (count($medicine)>0){ + // BeginTransaction + DB::beginTransaction(); + foreach($medicine as $key => $value){ + $data = [ + 'request_log_id' => $value['request_log_id'], + 'medicine' => $value['medicine_name'], + 'price' => $value['medicine_price'], + ]; + // Insert Data + try { + RequestLogMedicine::create($data); + } catch (\Throwable $th) { + DB::rollBack(); + return Helper::responseJson(status: 'failed', statusCode: 500, message: $th->getMessage()); + } + } + DB::commit(); + return Helper::responseJson(status: 'success', statusCode: 201, message: 'success', data: $request->toArray()); + }; + + } + + + $requestLogMedicine = RequestLogMedicine::insert($data); + return $requestLogMedicine; + } + + /** + * Show the form for editing the specified resource. + * @param int $id + * @return Renderable + */ + public function edit($id) + { + return view('internal::edit'); + } + + /** + * Update the specified resource in storage. + * @param Request $request + * @param int $id + * @return Renderable + */ + public function update(Request $request, $id) + { + $requestLogBenefit = requestLogBenefit::findOrFail($id); + $requestLogBenefit->amount_approved = $request->amount_approved; + $requestLogBenefit->amount_incurred = $request->amount_incurred; + $requestLogBenefit->amount_not_approved = $request->amount_not_approved; + $requestLogBenefit->excess_paid = $request->excess_paid; + $requestLogBenefit->keterangan = $request->keterangan; + + $requestLogBenefit->save(); + + return response()->json([ + 'error' => false, + 'message' => 'Update succses', + 'data' => $requestLogBenefit], + 200); + } + + /** + * Remove the specified resource from storage. + * @param int $id + * @return Renderable + */ + public function destroy($id) + { + $RequestLogMedicine = RequestLogMedicine::findOrFail($id); + $RequestLogMedicine->delete(); + } + +} diff --git a/Modules/Internal/Routes/api.php b/Modules/Internal/Routes/api.php index f4a08dc7..c97454bd 100644 --- a/Modules/Internal/Routes/api.php +++ b/Modules/Internal/Routes/api.php @@ -7,9 +7,10 @@ use Modules\Internal\Http\Controllers\Api\AppointmentController; use Modules\Internal\Http\Controllers\Api\BenefitController; use Modules\Internal\Http\Controllers\Api\CityController; use Modules\Internal\Http\Controllers\Api\ClaimController; +use Modules\Internal\Http\Controllers\Api\ClaimRequestController; use Modules\Internal\Http\Controllers\Api\RequestLogController; use Modules\Internal\Http\Controllers\Api\RequestLogBenefitController; -use Modules\Internal\Http\Controllers\Api\ClaimRequestController; +use Modules\Internal\Http\Controllers\Api\RequestLogMedicineController; use Modules\Internal\Http\Controllers\Api\CorporateBenefitController; use Modules\Internal\Http\Controllers\Api\CorporateController; use Modules\Internal\Http\Controllers\Api\CorporateFormulariumController; @@ -258,12 +259,17 @@ Route::prefix('internal')->group(function () { Route::get('customer-service/request/data', [RequestLogController::class, 'generateDataRequestLogExcel']); Route::post('customer-service/request/final-log', [RequestLogController::class, 'updateFinalLog']); + // insert benefit Route::post('customer-service/request/insert-benefit', [RequestLogBenefitController::class, 'store']); Route::delete('customer-service/request/benefit_data/{id}', [RequestLogBenefitController::class, 'destroy']); Route::put('customer-service/request/benefit_data/{id}', [RequestLogBenefitController::class, 'update']); - + // insert medicine + Route::post('customer-service/request/medicine-data', [RequestLogMedicineController::class, 'store']); + Route::delete('customer-service/request/medicine-data/{id}', [RequestLogMedicineController::class, 'destroy']); + Route::put('customer-service/request/medicine-data/{id}', [RequestLogMedicineController::class, 'update']); + Route::get('search-organizations', [OrganizationController::class, 'searchOrganization']); Route::get('search-specialities', [SpecialityController::class, 'searchSpeciality']); Route::resource('organizations', OrganizationController::class); diff --git a/Modules/Internal/Transformers/RequestLogShowResource.php b/Modules/Internal/Transformers/RequestLogShowResource.php index e9a5c60e..480eb3f1 100644 --- a/Modules/Internal/Transformers/RequestLogShowResource.php +++ b/Modules/Internal/Transformers/RequestLogShowResource.php @@ -7,6 +7,7 @@ use App\Models\CorporateBenefit; use App\Models\ClaimRequest; use App\Models\CorporateService; use App\Models\RequestLogBenefit; +use App\Models\RequestLogMedicine; use App\Models\Exclusion; use App\Models\Icd; use App\Helpers\Helper; @@ -26,6 +27,7 @@ class RequestLogShowResource extends JsonResource $corporateId = $requestLog['member']['current_plan']['corporate_id'] ?? 0; $benefit = CorporateBenefit::with('benefit')->where('plan_id', $corporateId)->get()->toArray(); $benefitDetailLog = RequestLogBenefit::with('benefit')->where('request_log_id', $requestLog['id'])->get()->toArray(); + $medicineDetailLog = RequestLogMedicine::where('request_log_id', $requestLog['id'])->get()->toArray(); $benefitData = []; if (count($benefit)){ foreach($benefit as $data){ @@ -33,13 +35,23 @@ class RequestLogShowResource extends JsonResource } } + // Medicine + $medicineData = []; + if (count($medicineDetailLog)){ + foreach($medicineDetailLog as $data){ + array_push($medicineData, $data); + } + } // Service Rule $corporateService = CorporateService::query() ->where('corporate_id', $corporateId) ->where('service_code', $requestLog['service_code']) ->with(['configs']) ->first(); - $config = $corporateService->configs->pluck('value', 'name')->toArray(); + $config = []; + if ($corporateService) { + $config = $corporateService->configs->pluck('value', 'name')->toArray(); + } // Exclusion Service or diagnosis $exclusions = Exclusion::query() @@ -70,6 +82,7 @@ class RequestLogShowResource extends JsonResource 'benefit_data' => $benefitDetailLog, 'config_service' => $config, 'exclusion' => $exclusions, + 'medicine' => $medicineData, 'files' => $requestLog['files'], diff --git a/app/Models/RequestLogMedicine.php b/app/Models/RequestLogMedicine.php new file mode 100644 index 00000000..2cd1cec8 --- /dev/null +++ b/app/Models/RequestLogMedicine.php @@ -0,0 +1,30 @@ +belongsTo(Benefit::class, 'benefit_id', 'id'); + } +} diff --git a/database/migrations/2023_12_13_091954_create_request_log_medicines_table.php b/database/migrations/2023_12_13_091954_create_request_log_medicines_table.php new file mode 100644 index 00000000..3013006a --- /dev/null +++ b/database/migrations/2023_12_13_091954_create_request_log_medicines_table.php @@ -0,0 +1,34 @@ +id(); + $table->timestamps(); + $table->foreignId('request_log_id'); + $table->integer('price'); + $table->string('medicine'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('request_log_medicines'); + } +}; diff --git a/database/migrations/2023_12_15_153059_add_columns_to_request_logs.php b/database/migrations/2023_12_15_153059_add_columns_to_request_logs.php new file mode 100644 index 00000000..81bb25c6 --- /dev/null +++ b/database/migrations/2023_12_15_153059_add_columns_to_request_logs.php @@ -0,0 +1,32 @@ +dateTime('discharge_date')->after('submission_date')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('request_logs', function (Blueprint $table) { + $table->dropColumn('discharge_date'); + }); + } +}; diff --git a/database/migrations/2023_10_27_111432_create_claim_daily_monitoring_table.php b/database/migrations/2023_12_15_154820_create_request_log_daily_monitoring_table.php similarity index 66% rename from database/migrations/2023_10_27_111432_create_claim_daily_monitoring_table.php rename to database/migrations/2023_12_15_154820_create_request_log_daily_monitoring_table.php index 61713605..f09cf94e 100644 --- a/database/migrations/2023_10_27_111432_create_claim_daily_monitoring_table.php +++ b/database/migrations/2023_12_15_154820_create_request_log_daily_monitoring_table.php @@ -13,9 +13,10 @@ return new class extends Migration */ public function up() { - Schema::create('claim_daily_monitoring', function (Blueprint $table) { - $table->bigIncrements('id'); - $table->integer('claim_id'); + Schema::create('request_log_daily_monitorings', function (Blueprint $table) { + $table->id(); + $table->foreignId('request_log_id'); + $table->timestamps(); $table->text('subject'); $table->decimal('body_temperature', 11, 2); $table->decimal('respiration_rate', 11, 2); @@ -23,7 +24,9 @@ return new class extends Migration $table->decimal('diastole', 11, 2); $table->text('analysis'); $table->text('complaints'); - $table->timestamps(); + $table->dateTime('lab_date')->nullable(); + $table->string('provider')->nullable(); + $table->string('examination')->nullable(); }); } @@ -34,6 +37,6 @@ return new class extends Migration */ public function down() { - Schema::dropIfExists('claim_daily_monitoring'); + Schema::dropIfExists('request_log_daily_monitorings'); } }; diff --git a/frontend/dashboard/src/components/MuiDialog.tsx b/frontend/dashboard/src/components/MuiDialog.tsx index 599eb60f..c9b57835 100644 --- a/frontend/dashboard/src/components/MuiDialog.tsx +++ b/frontend/dashboard/src/components/MuiDialog.tsx @@ -13,7 +13,7 @@ type MuiDialogProps = { openDialog: boolean; setOpenDialog: Function; content?: ReactElement; - action?: ReactElement; + action?: ReactElement|null; maxWidth?: string; }; diff --git a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/ClaimListRow.tsx b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/ClaimListRow.tsx index d89c0ef7..67e46a89 100644 --- a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/ClaimListRow.tsx +++ b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/ClaimListRow.tsx @@ -37,7 +37,7 @@ export default function ClaimListRow ({ ...props }: Props) { td': { borderBottom: '1' } }}> - {props.row.admission_date == "0000-00-00 00:00:00" ? + {props.row.admission_date == null? ('-') : ( @@ -50,7 +50,7 @@ export default function ClaimListRow ({ ...props }: Props) { )} - {props.row.discharge_date == "0000-00-00 00:00:00" ? + {props.row.discharge_date == null ? ('-') : ( @@ -62,9 +62,29 @@ export default function ClaimListRow ({ ...props }: Props) { )} - {props.row.claim_code} - {props.row.service_type} - {props.row.claim_status} + {props.row.code} + {props.row.service_name} + + {props.row.discharge_date == null ? + ( + + ) : + ( + + ) + } + + e.stopPropagation()}> Name Start Date End Date + Admission Date + Provider diff --git a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DailyMonitoringListRow.tsx b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DailyMonitoringListRow.tsx index 40dc5395..2b6df13b 100644 --- a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DailyMonitoringListRow.tsx +++ b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DailyMonitoringListRow.tsx @@ -53,6 +53,15 @@ export default function DailyMonitoringListRow ({ ...props }: Props) { {fDate(props.row.enddate)}
+ + + + {props.row.provider} e.stopPropagation()}> (''); - const [listChoosed, setListChoosed] = useState([]); - const [isChoosed, setIsChoosed] = useState(false); - const [formIsLoading, setFormIsLoading] = useState(false); - - // List Choose - auto Scroll - // ------------------------- - const fetchFunction = async (page: number): Promise => getMemberList(page, keyword) - - const {data: MemberList, isLoading: scrollIsLoading, setData, resetLastPage, refetchData} = useLoadOnScroll(fetchFunction); - - // List Choose - Search - // ------------------------- - const handleSearch = (keyword: string) => { - setData([]) - resetLastPage() - setKeyword(keyword) - refetchData() - } - - // Function - Clear Form - // ----------------------------- - const clearForm = () => { - setListChoosed(defaultListChoosed); - setIsChoosed(false); - } - - // Function - Choose Patien Type - // ----------------------------- - const handleChoosePatienType = (data: MemberListType, type: string) => { - let newListChoosed = listChoosed.map((list) => { - if (data.id == list.id) { - list.patien_type = type - } - - return list; - }) - setListChoosed(newListChoosed) - } - - // Function - Handle Btn Upload - // ----------------------------- - const handleChangeInput = (data: MemberListType, type_file: 'kondisi'|'diagnosa'|'penunjang', file: any) => { - let newListChoosed = listChoosed.map((list) => { - if (data.id == list.id) { - if (type_file == 'kondisi') { - if (list.file_kondisi == undefined) { - list.file_kondisi = [file]; - } - else { - list.file_kondisi.push(file); - } - } - - if (type_file == 'diagnosa') { - if (list.file_diagnosa == undefined) { - list.file_diagnosa = [file]; - } - else { - list.file_diagnosa.push(file); - } - } - - if (type_file == 'penunjang') { - if (list.file_penunjang == undefined) { - list.file_penunjang = [file]; - } - else { - list.file_penunjang.push(file); - } - } - } - - return list; - }) - - setListChoosed(newListChoosed) - } - - // Function - Handle Remove Fle - // ----------------------------- - const handleRemoveFile = (data: MemberListType, type_file: 'kondisi'|'diagnosa'|'penunjang', target_index: number) => { - let newListChoosed = listChoosed.map((list) => { - if (data.id == list.id) { - if (type_file == 'kondisi') { - list.file_kondisi = list.file_kondisi?.filter((file: any, index: number) =>{ - if (target_index !== index) { - return file; - } - }); - } - - if (type_file == 'diagnosa') { - list.file_diagnosa = list.file_diagnosa?.filter((file: any, index: number) =>{ - if (target_index !== index) { - return file; - } - }); - } - - if (type_file == 'penunjang') { - list.file_penunjang = list.file_penunjang?.filter((file: any, index: number) =>{ - if (target_index !== index) { - return file; - } - }); - } - } - - return list; - }) - - setListChoosed(newListChoosed) - } - - // Function - Handle Submit Form - // ----------------------------- - const handleSubmit = async () => { - setFormIsLoading(true) - let response = await addClaimRequest(listChoosed) - setFormIsLoading(false) - - if (response == true) { - clearForm() - } - } - - - - let isDirty = listChoosed.some((row) => { - if (row.patien_type == undefined) { - return true - } - }) - - return ( - - {/* Back Button */} - - isChoosed==false ? navigate(`/claim-requests`) : setIsChoosed(false)} > - - - - - {'Create Claim Requests'} - - - - {/* Choose Section */} - - {/* Search */} - - handleSearch('')} onSubmit={(keyword) => handleSearch(keyword)} /> - - - - - {/* List */} - - - { - MemberList.map((row, index) => { - return ( - { - checked ? setListChoosed((prevData) => [...prevData, data]) : setListChoosed((items) => items.filter(item => item.id != data.id)) - }} - /> - ) - }) - } - - - - {/* Loading */} - - - - - {/* Submit List */} - - setIsChoosed(true)} /> - - - - - - {/* Input Section */} - - { - listChoosed.map((row, index) => { - return ( - - - {/* Patien Name */} - - - - - {row.name} - - - {row.member_id} - - - - - - - {/* Patien Type */} - - - {row.service_type.map((r,i) => { - const code = r.code - return ( - - - - ) - })} - - - - {/* File Kondisi */} - - - - Condition Document - - - {row.file_kondisi && row.file_kondisi.map((file, index) => ( - - handleRemoveFile(row, 'kondisi', index)} /> - - ))} - - - handleChangeInput(row, 'kondisi', file)} /> - - - - - {/* File Diagnosa */} - - - - Diagnosis Document - - - {row.file_diagnosa && row.file_diagnosa.map((file, index) => ( - - handleRemoveFile(row, 'diagnosa', index)} /> - - ))} - - - handleChangeInput(row, 'diagnosa', file)} /> - - - - - {/* File Penunjang */} - - - - Supporting Result Document - - - {row.file_penunjang && row.file_penunjang.map((file, index) => ( - - handleRemoveFile(row, 'penunjang', index)} /> - - ))} - - - handleChangeInput(row, 'penunjang', file)} /> - - - - - - - ) - }) - } - - - - - handleSubmit()}> - Save Changes - - - - - - ) -} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnChoose.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnChoose.tsx deleted file mode 100644 index cffd3bc3..00000000 --- a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnChoose.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { styled, Button } from "@mui/material"; -import useCollapseDrawer from "@/hooks/useCollapseDrawer"; - -/** - * Custom Style - * ============================================ -*/ -const DivCustom1 = styled('div')(({ theme }) => ({ - background: 'white', - position: 'fixed', - left: '350px', - right: 0, - bottom: 0, - paddingLeft: '32px', - paddingRight: '32px', - paddingTop: '32px', - paddingBottom: '48px', - [theme.breakpoints.between('sm', 'lg')]: { - left: '0px', - }, -})); - -type Props = { - disabled: boolean, - title : string, - handleClickProp: () => void -} - -export default function FormCreateBtnChoose ({disabled, title, handleClickProp}: Props) { - const { collapseClick } = useCollapseDrawer(); - - return ( - - - - ) -} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnUpload.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnUpload.tsx deleted file mode 100644 index 23df5ed5..00000000 --- a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateBtnUpload.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { useRef } from "react"; -import { Box, ButtonBase, Typography } from "@mui/material"; -import Iconify from "@/components/Iconify"; - -type Props = { - handleChangeInputProp: (event: any) => void -} - -export default function FormCreateBtnUpload ({handleChangeInputProp}: Props) { - const fileInput = useRef(null); - - return ( - fileInput.current?.click()}> - - - - Upload Result - - - handleChangeInputProp(event.target.files ? event.target.files[0] : {})} - accept="application/pdf" - /> - - ) -} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateFilesUpload.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateFilesUpload.tsx deleted file mode 100644 index 7ab9d7bd..00000000 --- a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateFilesUpload.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import Iconify from "@/components/Iconify"; -import { ArrowBackIosNew, InsertDriveFile } from '@mui/icons-material'; -import { Stack, Typography } from "@mui/material"; - -type Props = { - file: any, - handleRemoveFileProp: () => void, -} - -export default function FormCreateFilesUpload({ file, handleRemoveFileProp }: Props) { - return ( - - - - {file.name ? file.name : '-'} - - {handleRemoveFileProp()}} - sx={{cursor: 'pointer'}} - > - - ) -} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateListChoose.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateListChoose.tsx deleted file mode 100644 index 03c8d0b1..00000000 --- a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateListChoose.tsx +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Core - * ============================================ - */ -import { useEffect, useState } from 'react'; -import { Box, FormControlLabel, Grid, Checkbox, Typography, Card} from '@mui/material'; - -/** - * Components - * ============================================ -*/ -// - Global - -import Label from '@/components/Label'; -// - Local - - -/** - * Icon, Utils, Types, Functions, theme, hook - * ============================================ - */ -import { fDateTimesecond } from '@/utils/formatTime'; -import { MemberListType } from '../Model/Types'; -import palette from '@/theme/palette'; - -/** - * Props - * ===================================================== - */ -type Props = { - data: MemberListType, - ListChoosed: MemberListType[], - handleCheckedProp: (checked: boolean, data: MemberListType) => void, -}; - -export default function FormCreateListChoose({data, ListChoosed, handleCheckedProp}: Props) { - const [isChoosed, setIsChoosed] = useState(false) - - useEffect(() => { - setIsChoosed(false); - - ListChoosed.forEach(list => { - if (list.id == data.id) { - setIsChoosed(true); - } - }) - }, [ListChoosed]) - - return ( - - { - return isChoosed ? palette.light.primary.lighter : palette.light.background.default - } - }}> - - handleCheckedProp(checked, data)} />} - checked={isChoosed} - /> - - - - {data.name} - - - {data.member_id} - - - - - - - - ) -} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateSearch.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateSearch.tsx deleted file mode 100644 index 026b886b..00000000 --- a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormCreateSearch.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Core - * ============================================ - */ -import { useEffect } from 'react'; -import { useForm } from 'react-hook-form'; -import { Grid } from '@mui/material'; - -/** - * Components - * ============================================ -*/ -// - Global - -import { FormProvider, RHFTextField } from '@/components/hook-form'; -// - Local - - -/** - * Icon, Utils, Types, Functions - * ============================================ - */ -import { Search } from '@mui/icons-material'; -import { SearchType } from '../Model/Types'; - -type Props = { - onSubmit: (keyword: string) => void, - onEmpty: () => void, -}; - -const FormCreateSearch = ({ onSubmit, onEmpty }: Props) => { - const defaultValuesSearchForm = { - keyword: '' - }; - - const methodsSearchForm = useForm({ - defaultValues: defaultValuesSearchForm - }); - - const { handleSubmit, formState: { isDirty } } = methodsSearchForm; - - // search on submit - const onSubmitSearch = (data: SearchType ) => { - onSubmit(data.keyword); - } - - // search on empty - useEffect(() => { - if (isDirty === false) { - onEmpty() - } - },[isDirty]) - - return ( - - - - }} - sx={{ input: { paddingLeft: '14px' } }} - /> - - - - ) -} - -export default FormCreateSearch diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormEdit.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormEdit.tsx deleted file mode 100644 index faa95bf0..00000000 --- a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Components/FormEdit.tsx +++ /dev/null @@ -1,456 +0,0 @@ -import * as Yup from 'yup'; -import { useSnackbar } from 'notistack'; -import { useNavigate } from 'react-router-dom'; -import { yupResolver } from '@hookform/resolvers/yup'; -import { Controller, useForm } from 'react-hook-form'; -import React, { useRef, useEffect, useMemo, useState } from 'react'; -import axios from '../../../utils/axios'; -import { FormProvider, RHFTextField } from '../../../components/hook-form'; - -import { makeFormData } from '@/utils/jsonToFormData'; -import { - Autocomplete, - Button, - Grid, - Stack, - Table, - TableBody, - TableCell, - TableRow, - TextField, - Typography, - useTheme, - List, - ListItem, - IconButton, - ListItemAvatar, - Avatar, - ListItemText, - Card, - InputAdornment, - Divider, - ButtonBase, - Box, -} from '@mui/material'; -import Iconify from '../../../components/Iconify'; -import CalendarTodayIcon from '@mui/icons-material/CalendarToday'; -import { LoadingButton } from '@mui/lab'; -import { fCurrency } from '../../../utils/formatNumber'; -import MemberSelectDialog from '../../../components/dialogs/MemberSelectDialog'; -import { Add, ArrowBackIosNew, DeleteOutline } from '@mui/icons-material'; -import { ClaimRequest, Files } from '@/@types/claims'; -import { fDateTimesecond } from '@/utils/formatTime'; - -interface FormValuesProps extends Partial { - taxes: boolean; - inStock: boolean; -} - -type Props = { - isEdit: boolean; - currentClaim?: ClaimRequest; -}; - -export default function FormEdit({ isEdit, currentClaim }: Props) { - const navigate = useNavigate(); - - const { enqueueSnackbar } = useSnackbar(); - - const EditClaimSchema = Yup.object().shape({ - organization_id: Yup.string().required('Code Provider is required'), - }); - - const defaultValues = useMemo( - () => ({ - id: currentClaim?.id || '-', - code: currentClaim?.code || '-', - member_name: currentClaim?.member?.name || '-', - date: currentClaim?.submission_date ? fDateTimesecond(currentClaim?.submission_date) : '-', - claim_method: currentClaim?.payment_type || '-', - service_type: currentClaim?.service_code || '-', - organization_id: currentClaim?.organization?.code || '-', - }), - [currentClaim] - ); - - useEffect(() => { - if (isEdit && currentClaim) { - reset(defaultValues); - } - if (!isEdit) { - reset(defaultValues); - } - // setFileKondisis(currentClaim?.files_by_type?.claim_diagnosis); - // setFileDiagnosas(currentClaim?.files_by_type?.claim_diagnosis); - setFileHasilPenunjangCurrent(currentClaim?.files_by_type?.claim_result); - }, [isEdit, currentClaim]); - - - const methods = useForm({ - resolver: yupResolver(EditClaimSchema), - defaultValues, - }); - - const { - reset, - watch, - control, - setValue, - getValues, - setError, - handleSubmit, - formState: { isSubmitting }, - } = methods; - - const values = watch(); - - const [isCheckingLimit, setIsCheckingLimit] = useState(false); - const [isEligible, setIsEligible] = useState(false); - const [memberBenefits, setMemberBenefits] = useState([]); - const [diagnosisOption, setDiagnosisOption] = useState([]); - const [isMemberDialogOpen, setIsMemberDialogOpen] = useState(false); - const [member, setMember] = useState({}) - - // ---------------------------------------------------------------------- - - // Files Result Kondisi - const fileKondisiInput = useRef(null); - const [fileKondisis, setFileKondisis] = useState([]); - - const handleKondisiInputChange = (event) => { - if (event.target.files[0]) { - setFileKondisis([...fileKondisis, ...event.target.files]); - } else { - console.log('NO FILE'); - } - }; - const removeKondisiFiles = (filesState, index) => { - setFileKondisis( - filesState.filter((file, fileIndex) => { - return fileIndex != index; - }) - ); - }; - - // Files Result Diagnosa - const fileDiagnosaInput = useRef(null); - const [fileDiagnosas, setFileDiagnosas] = useState([]); - - const handleDiagnosaInputChange = (event) => { - if (event.target.files[0]) { - setFileDiagnosas([...fileDiagnosas, ...event.target.files]); - } else { - console.log('NO FILE'); - } - }; - const removeDiagnosaFiles = (filesState, index) => { - setFileDiagnosas( - filesState.filter((file, fileIndex) => { - return fileIndex != index; - }) - ); - }; - - // Files Result Hasil Penunjang - const fileHasilPenunjangInput = useRef(null); - const [fileHasilPenunjangs, setFileHasilPenunjangs] = useState([]); - const [fileHasilPenunjangsCurrent, setFileHasilPenunjangCurrent] = useState([]); - - const handleResultInputChange = (event) => { - if (event.target.files[0]) { - setFileHasilPenunjangs([...fileHasilPenunjangs, ...event.target.files]); - } else { - console.log('NO FILE'); - } - }; - const removeFiles = (filesState, index) => { - setFileHasilPenunjangs( - filesState.filter((file, fileIndex) => { - return fileIndex != index; - }) - ); - }; - - - const onSubmit = async (data: FormValuesProps) => { - try { - // const formData = new FormData(); - // formData.append('result_files', fileHasilPenunjangs); - // formData.append('diagnosa_files', fileDiagnosaInput); - // formData.append('kondisi_files', fileKondisiInput); - // formData.append('provider_code', data.organization_id); - // formData.append('_method', 'PUT'); - const formData = makeFormData({ - result_files: fileHasilPenunjangs, - diagnosa_files: fileDiagnosas, - kondisi_files: fileKondisis, - provider_code: data.organization_id, - _method: 'PUT' - }); - - const response = await axios.put(`/claim-requests/${data.id}`, formData); - - reset(); - enqueueSnackbar('Claim Request Updated Successfully!', { variant: 'success' }); - navigate('/claim-requests'); - } catch (error: any) { - if (error && error.response.status === 422) { - for (const [key, value] of Object.entries(error.response.data.errors)) { - // setError(key, { message: value[0] }); - enqueueSnackbar('Failed Processing Request', { variant: 'error' }); - } - } else { - enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' }); - } - } - }; - - - return ( - - - - navigate(`/claim-requests`)} > - - - - - {'Edit Claim Requests'} - - - - - - - - Code* - - - Name* - - - - - - - - {/* */} - - - - - - Date of Submission* - - - Claim Method* - - - Service Type* - - - Code Provider* - - - - - - - - ), }} - name="date" label="Date of Submission" disabled/> - - - - - - - - - - - - - {/* -------------------------------Upload Dokumen Kondisi------------------------------- */} - - - Condition Document - - - {fileKondisis && - fileKondisis.map((file, index) => ( - - {file.name} - { - removeKondisiFiles(fileKondisis, index); - }} - > - - ))} - - - fileKondisiInput.current?.click()}> - - - - Add File - - - - - - - {/* -------------------------------Upload Dokumen Diagnosa------------------------------- */} - - - Diagnosis Document - - - {fileDiagnosas && - fileDiagnosas.map((file, index) => ( - - {file.name} - { - removeDiagnosaFiles(fileDiagnosas, index); - }} - > - - ))} - - - fileDiagnosaInput.current?.click()}> - - - - Add Result - - - - - - - {/* -------------------------------Upload Result Hasil Penunjang------------------------------- */} - - - Supporting Result Document - - - {fileHasilPenunjangs && - fileHasilPenunjangs.map((file, index) => ( - - {file.name} - { - removeFiles(fileHasilPenunjangs, index); - }} - > - - ))} - - - fileHasilPenunjangInput.current?.click()}> - - - - Add Result - - - - - - - - - - - - - - - Update - - - - - - ); -} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/CreateUpdate.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/CreateUpdate.tsx deleted file mode 100644 index c710deaa..00000000 --- a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/CreateUpdate.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import * as Yup from 'yup'; -import { Box, IconButton } from '@mui/material'; -import { ArrowBackIosNew } from '@mui/icons-material'; -import { yupResolver } from '@hookform/resolvers/yup'; -import { Autocomplete, Button, Card, Collapse, Container, Divider, Grid, Stack, Table, TableBody, TableCell, TableRow, TextField, Typography } from '@mui/material'; -import { Controller, useForm } from 'react-hook-form'; -import { useParams } from 'react-router-dom'; -import HeaderBreadcrumbs from '../../components/HeaderBreadcrumbs'; -import { FormProvider, RHFCheckbox, RHFSelect, RHFTextField } from '../../components/hook-form'; -import Page from '../../components/Page'; -import useSettings from '../../hooks/useSettings'; -import { useEffect, useMemo, useRef, useState } from 'react'; -import MemberSelectDialog from '../../components/dialogs/MemberSelectDialog'; -import { styled } from '@mui/system'; -import axios from '../../utils/axios'; -import { enqueueSnackbar } from 'notistack'; -import { LoadingButton } from '@mui/lab'; -import { fCurrency } from '../../utils/formatNumber'; -import Iconify from '../../components/Iconify'; -import { ClaimRequest } from '@/@types/claims'; -import FormEdit from './Components/FormEdit'; -import FormCreate from './Components/FormCreate'; - -export default function ClaimsCreateUpdate() { - - const { themeStretch } = useSettings(); - const { id } = useParams(); - - const isEdit = id ? true : false; - - const [currentClaim, setCurrentClaim] = useState(); - - useEffect(() => { - if (isEdit) { - axios.get('/claim-requests/' + id).then((res) => { - console.log('Yeet', res.data); - setCurrentClaim(res.data.data); - }); - - console.log(currentClaim) - } - }, [id]); - - - return ( - - - { - id == undefined - ? - ( - - ) - : - ( - - ) - } - - - - ); -} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Detail.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Detail.tsx deleted file mode 100644 index 39aa66ab..00000000 --- a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Detail.tsx +++ /dev/null @@ -1,306 +0,0 @@ -// mui -import { Container, Grid, Stack, Typography, Card, TextField, Divider, ButtonBase, Box, IconButton } from '@mui/material'; -// components -import Page from '../../components/Page'; -// utils -import useSettings from '../../hooks/useSettings'; -// react -import { useNavigate, useParams, useLocation } from 'react-router-dom'; -import { useEffect, useState, useRef } from 'react'; -import axios from '../../utils/axios'; -// pages -import DetailTimeline from '../../pages/ClaimRequests/DetailTimeline'; -import DetailStepper from '../../pages/ClaimRequests/DetailStepper'; -import { format } from 'date-fns'; -import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; -import Button from '@mui/material/Button'; -import AddIcon from '@mui/icons-material/Add'; -import RemoveIcon from '@mui/icons-material/Remove'; -import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers'; -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; -import Iconify from '@/components/Iconify'; -import { fPostFormat } from '@/utils/formatTime'; -import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; -import DownloadIcon from '@mui/icons-material/Download'; -import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material'; -import CloseIcon from '@mui/icons-material/Close'; -import { fDateTimesecond } from '@/utils/formatTime'; -import { makeFormData } from '@/utils/jsonToFormData'; - -import { enqueueSnackbar } from 'notistack'; - -// ---------------------------------------------------------------------- - -export default function Detail() { - const location = useLocation(); - const queryParams = new URLSearchParams(location.search); - const code = queryParams.get('code'); - - const navigate = useNavigate(); - const { themeStretch } = useSettings(); - const [data, setData] = useState(); - const [dataDialog, setDataDialog] = useState(); - const [document, setDocument] = useState(null); - - const { id } = useParams(); - - useEffect(() => { - axios - .get('/claim-requests/detail/'+id) - .then((response) => { - setData(response.data); - setDataDialog(response.data.data.dialog_submits); - setDocument(response.data.data.documents); - - }) - .catch((error) => { - console.error(error); - }); - - }, []); - - const [isInvoiceVisible, setInvoiceVisibility] = useState(false); - - const handleInvoice = () => { - setInvoiceVisibility(!isInvoiceVisible); - } - const currentDate = new Date(); - const formattedCurrentDate = format(currentDate, 'dd MMM yyyy'); - const [dateInvoice, setDateInvoice] = useState(currentDate); - - const fileInvoiceInput = useRef(null); - const [fileInvoices, setFileInvoices] = useState([]); - - const handleInvoiceInputChange = (event) => { - if (event.target.files[0]) { - setFileInvoices([...fileInvoices, ...event.target.files]); - } else { - console.log('NO FILE'); - } - }; - const removeInvoiceFiles = (filesState, index) => { - setFileInvoices( - filesState.filter((file, fileIndex) => { - return fileIndex != index; - }) - ); - }; - const date = dateInvoice ? fPostFormat(dateInvoice, 'yyyy-MM-dd') : null; - - const [openDialogSubmit, setOpenDialogSubmit] = useState(false); - const handleCloseDialogSubmit = () => { - setOpenDialogSubmit(false); - } - const handleSubmitData = () => { - // if(fileInvoices.length > 0) - // { - //submit data - axios - .post('claim-requests/'+id+'/approve') - .then((response) => { - enqueueSnackbar('Success Submit Claim Request', { variant: 'success' }); - setOpenDialogSubmit(false); - }) - .catch(({ response }) => { - enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' }); - }); - //Upload file invoices - const formData = makeFormData({ - date:date, - invoice_files: fileInvoices, - }); - axios - .post('claim-requests/'+id+'/invoice-files', formData) - .then((response) => { - enqueueSnackbar(response.data.message ?? 'Success upload invoice', { variant: 'success' }); - }) - .catch(({ response }) => { - enqueueSnackbar(response.data.message ?? 'Something Went Wrong', { variant: 'error' }); - }); - // } - // else - // { - // enqueueSnackbar('Please upload file invoice, before submit', { variant: 'warning' }); - // } - - setTimeout(() => - { - window.location.reload(); - }, 5000); - - }; - - const check_invoice = document?.find((dataInvoice) => dataInvoice.type === 'claim-invoice'); - - return ( - - - - navigate(-1)} sx={{cursor:'pointer'}}/> - {(data && data.data) ? data.data.status.code : ''} - {data ? ( - - Submission Date - {(data && data.data) ? format(new Date(data.data.status.submission_date), "d MMM yyyy") : ''} - - ) : ''} - - {data ? ( - - - - - - - Format Claim - - - - {check_invoice ? ( - - - Request Claim - - - - ) : ''} - - - - - { - setDateInvoice(newValue); - }} - inputFormat="dd MMM yyyy" - renderInput={(params) => } - /> - - } - spacing={1} - sx={{ marginY: 2 }} - > - {fileInvoices && - fileInvoices.map((file, index) => ( - - - - {file.name ? file.name : '-'} - - { - removeInvoiceFiles(fileInvoices, index); - }} - sx={{cursor: 'pointer'}} - > - - ))} - - fileInvoiceInput.current?.click()}> - - - - Upload Invoice - - - - - - - - - - - - - {dataDialog && dataDialog.status === 'requested' ? ( - <> - - - - ) : ''} - {/* Dialog Submits */} - - - - - Confirmation - - - - - - - - {dataDialog ? ( - - Are you sure to submit this claim ? - - - Code - {dataDialog.code} - - - Name - {dataDialog.name} - - - Date Submission - {fDateTimesecond(dataDialog.submission_date)} - - - Claim Method - Service Type - - - Service Type - - {dataDialog.service_code === 'IP' ? 'Inpatient' : 'Outpatient'} - - - - - ) : ''} - - - - - - - - - - ) : ''} - - - ); -} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailStepper.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailStepper.tsx deleted file mode 100644 index b788e29f..00000000 --- a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailStepper.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import * as React from 'react'; -import Box from '@mui/material/Box'; -import Stepper from '@mui/material/Stepper'; -import Step from '@mui/material/Step'; -import StepLabel from '@mui/material/StepLabel'; -import { useEffect, useState } from 'react'; -import ClearIcon from '@mui/icons-material/Clear'; - -const steps = [ - 'Request', - 'Review', - 'Approval', - 'Decline', - ]; - - export default function HorizontalLinearAlternativeLabelStepper({data}) { - const [active, setActive] = useState(0); - const [status, SetStatus] = useState(null); - let updatedSteps = [...steps]; - useEffect(() => { - if (data && data.data) { - if (data.data.status.status === 'requested') { - setActive(1); - updatedSteps = updatedSteps.filter(step => step !== 'Decline'); - } - else if (data.data.status.status === 'reviewed') { - setActive(2); - updatedSteps = updatedSteps.filter(step => step !== 'Decline'); - } - else if (data.data.status.status === 'approved') - { - setActive(3); - updatedSteps = updatedSteps.filter(step => step !== 'Decline'); - } - else if(data.data.status.status === 'declined') - { - setActive(4) - updatedSteps = updatedSteps.filter(step => step !== 'Approval'); - } - } - SetStatus(updatedSteps); - }, [data]); - - - - - return ( - - - {status?.map((label) => ( - - : ''}>{label} - - ))} - - - ); -} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailTimeline.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailTimeline.tsx deleted file mode 100644 index f62a706d..00000000 --- a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/DetailTimeline.tsx +++ /dev/null @@ -1,426 +0,0 @@ -import * as React from 'react'; -import Timeline from '@mui/lab/Timeline'; -import TimelineItem, { timelineItemClasses } from '@mui/lab/TimelineItem'; -import TimelineSeparator from '@mui/lab/TimelineSeparator'; -import TimelineConnector from '@mui/lab/TimelineConnector'; -import TimelineContent from '@mui/lab/TimelineContent'; -import TimelineDot from '@mui/lab/TimelineDot'; -import {Typography, Card, Stack, ButtonBase, Box, Divider} from '@mui/material'; -import { styled } from '@mui/material/styles'; -import Paper from '@mui/material/Paper'; -import Button from '@mui/material/Button'; -import AddIcon from '@mui/icons-material/Add'; -import Iconify from '../../components/Iconify'; -import { useEffect, useState, useRef } from 'react'; -import { format } from 'date-fns'; -import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; -import DescriptionIcon from '@mui/icons-material/Description'; -import { LoadingButton } from '@mui/lab'; -import axios from '../../utils/axios'; -import { makeFormData } from '@/utils/jsonToFormData'; -import { enqueueSnackbar } from 'notistack'; -import { useParams} from 'react-router-dom'; - -const Item1 = styled(Paper)(({ theme }) => ({ - ...theme.typography.body2, - padding: theme.spacing(1), - textAlign: 'center', - backgroundColor: '#919EAB29', - color: '#637381', - width: 'fit-content', - marginRight: 'auto', -})); - -const Item2 = styled(Paper)(({ theme }) => ({ - backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff', - ...theme.typography.body2, - padding: theme.spacing(1), - textAlign: 'center', - color: theme.palette.text.secondary, - width: 'fit-content', - marginLeft: 'auto', -})); - -export default function NoOppositeContent({data}) { - const [timeline, setTimeline] = useState(null); - const [requestFile, setRequestFile] = useState(null); - const [document, setDocument] = useState(null); - useEffect(() => { - if (data && data.data) { - setTimeline(data.data.timeline); - setRequestFile(data.data.request_files); - setDocument(data.data.documents); - } - - }, [data]); - - // Diagnosis - const fileRequestDocumentInputDiagnosis = useRef(null); - const [fileDiagnosis, setFileDiagnosis] = useState([]); - const handleRequestDocumentInputChangeDiagnosis = (event) => { - if (event.target.files[0]) { - setFileDiagnosis([...fileDiagnosis, ...event.target.files]); - } - }; - const removeFileDiagnois = (filesState, index) => { - setFileDiagnosis( - filesState.filter((file, fileIndex) => { - return fileIndex != index; - }) - ); - }; - // Kondisi - const fileRequestDocumentInputKondisi = useRef(null); - const [fileKondisi, setFileKondisi] = useState([]); - const handleRequestDocumentInputChangeKondisi = (event) => { - if (event.target.files[0]) { - setFileKondisi([...fileKondisi, ...event.target.files]); - } - }; - const removeFileKondisi = (filesState, index) => { - setFileKondisi( - filesState.filter((file, fileIndex) => { - return fileIndex != index; - }) - ); - }; - // Result - const fileRequestDocumentInputResult = useRef(null); - const [fileResult, setFileResult] = useState([]); - const handleRequestDocumentInputChangeResult = (event) => { - if (event.target.files[0]) { - setFileResult([...fileResult, ...event.target.files]); - } - }; - const removeFileResult = (filesState, index) => { - setFileResult( - filesState.filter((file, fileIndex) => { - return fileIndex != index; - }) - ); - }; - const { id } = useParams(); - const [submitLoading, setSubmitLoading] = useState(false); - const submitRequestFiles = () => { - setSubmitLoading(true); - const formData = makeFormData({ - fileDiagnosis: fileDiagnosis, - fileKondisis: fileKondisi, - fileResults: fileResult - }); - axios - .post('claim-requests/'+id+'/request-files', formData) - .then((response) => { - window.location.reload(); - }) - .catch(({ response }) => { - enqueueSnackbar(response.data.message ?? 'Something Went Wrong', { variant: 'error' }); - }); - } - const submitButton = requestFile?.find((dataRequestFile) => dataRequestFile.check_files === null); - return ( - <> - {timeline?.map((dataTimeline, index) => ( - - {dataTimeline.date ? format(new Date(dataTimeline.date), "d MMM yyyy") : ''} - - - - - - - - - - {dataTimeline.date ? format(new Date(dataTimeline.date), "HH : mm") : ''} - {dataTimeline.txt_status} - - - Detail: - {dataTimeline.description} - - {dataTimeline.status === 'reviewed' && requestFile ? ( - <> - {submitButton ? ( - Request Document - ) : ( - Request Document Success Uploaded - )} - {/* Diagnosis */} - {requestFile?.map((dataRequestFile, index) => { - if(dataRequestFile.type !== 'claim-diagnosis' || dataRequestFile.check_files !== null){ - return null; - } - return ( - - - Diagnosis - - } - spacing={1} - sx={{ marginY: 2 }} - > - {fileDiagnosis && - fileDiagnosis.map((file, index) => ( - - - - {file.name ? file.name : '-'} - - { - removeFileDiagnois(fileDiagnosis, index); - }} - sx={{cursor: 'pointer'}} - > - - ))} - - fileRequestDocumentInputDiagnosis.current?.click()} - > - - - - Add Result - - - handleRequestDocumentInputChangeDiagnosis(event)} - accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf" - /> - - - ); - })} - {/* Kondisi */} - {requestFile?.map((dataRequestFile, index) => { - if(dataRequestFile.type !== 'claim-kondisi' || dataRequestFile.check_files !== null){ - return null; - } - return ( - - - Condition - - } - spacing={1} - sx={{ marginY: 2 }} - > - {fileKondisi && - fileKondisi.map((file, index) => ( - - - - {file.name ? file.name : '-'} - - { - removeFileKondisi(fileKondisi, index); - }} - sx={{cursor: 'pointer'}} - > - - ))} - - fileRequestDocumentInputKondisi.current?.click()} - > - - - - Add Result - - - handleRequestDocumentInputChangeKondisi(event)} - accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf" - /> - - - ); - })} - {/* Supporting Result */} - {requestFile?.map((dataRequestFile, index) => { - if(dataRequestFile.type !== 'claim-result' || dataRequestFile.check_files !== null){ - return null; - } - return ( - - - Supporting Result - - } - spacing={1} - sx={{ marginY: 2 }} - > - {fileResult && - fileResult.map((file, index) => ( - - - - {file.name ? file.name : '-'} - - { - removeFileResult(fileResult, index); - }} - sx={{cursor: 'pointer'}} - > - - ))} - - fileRequestDocumentInputResult.current?.click()} - > - - - - Add Result - - - handleRequestDocumentInputChangeResult(event)} - accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf" - /> - - - ); - })} - {submitButton ? ( - { - submitRequestFiles(); - }} - loading={submitLoading} - > - Submit - - ) : ''} - - ) : ''} - - - {dataTimeline.status === 'requested' ? ( - - - - - Documents - - - {document?.map((dataDocument, index) => ( - - - {dataDocument.type === 'claim-diagnosis' ? - 'Diagnosis' - : dataDocument.type === 'claim-kondisi' ? - 'Condition' - : dataDocument.type === 'claim-result' ? - 'Supporting Result' - : dataDocument.type === 'claim-invoice' ? - 'Invoice' - : ''} - - - - - {dataDocument.original_name ? dataDocument.original_name : '-'} - - - - ))} - - - - ) : ''} - - - - ))} - - ); -} diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Index.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Index.tsx index d26903b0..16298e5e 100644 --- a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Index.tsx +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Index.tsx @@ -7,7 +7,7 @@ import List from "./List"; export default function Claims() { - const pageTitle = 'Claim Request'; + const pageTitle = 'Inpatient Monitoring'; return ( @@ -16,8 +16,8 @@ export default function Claims() { links={[ { name: 'Dashboard', href: '/dashboard' }, { - name: 'Claim Request', - href: '/claim-requests', + name: 'Inpatient Monitoring', + href: '/inpatient_monitoring', }, ]} /> diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/List.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/List.tsx index 8bc34214..f734db68 100644 --- a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/List.tsx +++ b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/List.tsx @@ -49,7 +49,7 @@ import Label from '@/components/Label'; import TableMoreMenu from '@/components/table/TableMoreMenu'; import { Import } from '@/@types/claims'; -import { FinalLogType } from './Model/Types'; +import { FinalLogType } from '../../CustomerService/FinalLog/Model/Types'; // import LoadingButton from '@/theme/overrides/LoadingButton'; export default function List() { @@ -344,7 +344,7 @@ export default function List() { {open ? : } */ } - + {/* { // handleShowClaim(row); @@ -352,9 +352,9 @@ export default function List() { > {row.id} - + */} {row.code} - {row.member?.full_name} + {row.member_name} {row.service_name} {row.payment_type_name} @@ -370,11 +370,11 @@ export default function List() { - navigate(`/claim-requests/edit/${row.id}`)}> + {/* navigate(`/claim-requests/edit/${row.id}`)}> Edit - - navigate ('/claim-requests/detail/'+row.id+'')}> + */} + navigate ('/custormer-service/final-log/detail/'+row.id+'')}> Detail @@ -476,9 +476,9 @@ export default function List() { {/* */} - + {/* ID Request LOG - + */} Code diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Functions.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Functions.tsx deleted file mode 100644 index da72ff60..00000000 --- a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Functions.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import axios from '@/utils/axios'; -import { enqueueSnackbar } from 'notistack'; -import { MemberListType } from './Types'; -import { makeFormData } from '@/utils/jsonToFormData'; - -/** - * Listing Member - */ -export const getMemberList = async ( page: number, keyword: string ): Promise => { - const response = await axios.get(`/claim-requests/list-member?page=${page}&keyword=${keyword}`) - .then((res) =>{ - return res.data.data.member_list; - }) - .catch((res) => { - enqueueSnackbar("server error !", { - variant: 'error', - }); - - return []; - }); - - return response; -}; - -/** - * Add Claim Request - */ -export const addClaimRequest = async ( data: MemberListType[] ): Promise => { - // Mapping - const formData = new FormData(); - - data.map((row, index) => { - formData.append(`member_id[${index}]`, row.id.toString()); - formData.append(`service_code[${index}]`, row.patien_type??''); - - if (row.file_kondisi != undefined) { - row.file_kondisi.forEach((file, file_index) => { - console.log(file); - - formData.append(`file_kondisi[member_${row.id}][${file_index}]`, file); - }); - } - - if (row.file_diagnosa != undefined) { - row.file_diagnosa.forEach((file, file_index) => { - console.log(file); - - formData.append(`file_diagnosa[member_${row.id}][${file_index}]`, file); - }); - } - - if (row.file_penunjang != undefined) { - row.file_penunjang.forEach((file, file_index) => { - console.log(file); - - formData.append(`file_penunjang[member_${row.id}][${file_index}]`, file); - }); - } - }) - - // Axios - const response = await axios.post(`/claim-requests`, formData) - .then((res) =>{ - enqueueSnackbar("Berhasil membuat data !", { - variant: 'success', - }); - - return true; - }) - .catch((res) => { - enqueueSnackbar("server error !", { - variant: 'error', - }); - - return false; - }); - - return response; -}; diff --git a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Types.tsx b/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Types.tsx deleted file mode 100644 index e1d99d40..00000000 --- a/frontend/dashboard/src/pages/CaseManagement/InpatientMonitoring/Model/Types.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Member } from "@/@types/member" - -/** - * Search Type - */ -export type SearchType = { - keyword: string, -} - -/** - * Member List - */ -export type FinalLogType = { - id : number, - code : string, - member : Member, - submission_date : string, - service_name : string, - payment_type_name : string, - status_final_log : string, - status : string, - files_by_type : files_by_type, -} - -export type files_by_type = { - claim_diagnosis : file[], - claim_kondisi : file[], - claim_result : file[], -} - -export type file = { - name: string, - url: string[], -} - - diff --git a/frontend/dashboard/src/pages/CustomerService/Components/CardBenefit.tsx b/frontend/dashboard/src/pages/CustomerService/Components/CardBenefit.tsx new file mode 100644 index 00000000..65addbfe --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/Components/CardBenefit.tsx @@ -0,0 +1,214 @@ +import { Card, Grid, MenuItem, Typography } from "@mui/material"; +import { Stack } from '@mui/material'; +import { BenefitData, DetailFinalLogType } from "../FinalLog/Model/Types"; +import { useEffect, useState, useRef, useMemo } from 'react'; +import { Box } from "@mui/material"; + + +import { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime"; +import Label from '@/components/Label'; + +import AddIcon from '@mui/icons-material/Add'; +import { Button } from "@mui/material"; +import MoreMenu from "@/components/MoreMenu"; +import { Delete, EditOutlined } from "@mui/icons-material"; +import { fNumber } from "@/utils/formatNumber"; +import palette from "@/theme/palette"; +import DialogBenefit from "../FinalLog/Components/DialogBenefit"; +import DialogEditBenefit from "../FinalLog/Components/DialogEditBenefit"; +import DialogDelete from "../FinalLog/Components/DialogDelete"; + + + +type CardDetail = { + requestLog: DetailFinalLogType|undefined; +} + +const style1 = { + color: '#919EAB', + width: '30%' +} +const style2 = { + width: '70%' +} +const marginBottom1 = { + marginBottom: 1, +} +const marginBottom2 = { + marginBottom: 2, +} + +const [openDialogBenefit, setDialogBenefit] = useState(false); +// Handle Edit Detail Benefit +const [openDialogEditBenefit, setDialogEditBenefit] = useState(false) +const [BenefitConfigurationData, setBenefitConfigurationData] = useState(); + +// Handel Delete Detail Benefit +const [idBenefitData, setIdBenefitData] = useState(); +const [openDialogDeleteBenefit, setDialogDeleteBenefit] = useState(false) + + +export default function CardBenefit({requestLog} : CardDetail ) { + return ( + + + Benefit + + + + {requestLog?.benefit_data?.map((item, index) => ( + + + + + + + {item.benefit?.description} + + + + + { + setDialogEditBenefit(true) + setIdBenefitData(item.id) + setBenefitConfigurationData(item) + }} + > + + Edit + + { + setIdBenefitData(item.id) + setDialogDeleteBenefit(true) + }} + > + + Delete + + + } /> + + + + + + + + {/* Amount Incurred */} + + + + + Amount Incurred + + + + + {fNumber(item.amount_incurred)} + + + + + + {/* Amount Approved */} + + + + + Amount Approved + + + + + {fNumber(item.amount_approved)} + + + + + + {/* Amount Not Approved */} + + + + + Amount Not Approved + + + + + {fNumber(item.amount_not_approved)} + + + + + + {/* Excess Paid* */} + + + + + Excess Paid* + + + + + {fNumber(item.excess_paid)} + + + + + + {/* Keterangan* */} + + + + + Keterangan* + + + + + {item.keterangan} + + + + + + + + + + + + ))} + + {/* Dialog Edit */} + + + + {/* Dialog Delete */} + + + + ) + +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/Components/CardFile.tsx b/frontend/dashboard/src/pages/CustomerService/Components/CardFile.tsx new file mode 100644 index 00000000..9cb6efb4 --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/Components/CardFile.tsx @@ -0,0 +1,50 @@ +import { Card, Typography } from "@mui/material"; +import { Stack } from '@mui/material'; +import { DetailFinalLogType } from "../FinalLog/Model/Types"; +import { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime"; + + +type CardDetail = { + requestLog: DetailFinalLogType|undefined; +} + +const style1 = { + color: '#919EAB', + width: '30%' +} +const style2 = { + width: '70%' +} +const marginBottom1 = { + marginBottom: 1, +} +const marginBottom2 = { + marginBottom: 2, +} + + +export default function CardFile({requestLog} : CardDetail ) { + return ( + + + + Files History + {requestLog?.files?.map((documentType, index) => ( + + + + {documentType.original_name ? documentType.original_name : '-'} + + + + ))} + + + + ) + +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/Components/CardMedicine.tsx b/frontend/dashboard/src/pages/CustomerService/Components/CardMedicine.tsx new file mode 100644 index 00000000..4054024c --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/Components/CardMedicine.tsx @@ -0,0 +1,65 @@ +import { Card, Grid, Typography } from "@mui/material"; +import { Stack } from '@mui/material'; +import { DetailFinalLogType } from "../FinalLog/Model/Types"; +import { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime"; +import DialogMedicine from "../FinalLog/Components/DialogMedicine"; +import { fNumber } from "@/utils/formatNumber"; +import { Button } from '@mui/material'; +import AddIcon from '@mui/icons-material/Add'; +import { useState } from "react"; + +type CardDetail = { + requestLog: DetailFinalLogType|undefined; +} + +const style1 = { + color: '#919EAB', + width: '30%' +} +const style2 = { + width: '70%' +} +const marginBottom1 = { + marginBottom: 1, +} +const marginBottom2 = { + marginBottom: 2, +} + +const [openDialogMedicine, setDialogMedicine] = useState(false); + + +export default function CardMedicine({requestLog} : CardDetail ) { + return ( + + + Medicine + + + + {requestLog?.medicine.map((item, index) => ( + + {item.medicine} + Rp. {fNumber(item.price)} + + ))} + + {/* */} + + ) + +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/Components/DetailBenefit.tsx b/frontend/dashboard/src/pages/CustomerService/Components/DetailBenefit.tsx deleted file mode 100644 index de3371b2..00000000 --- a/frontend/dashboard/src/pages/CustomerService/Components/DetailBenefit.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { Card, Grid, Typography } from "@mui/material"; -import { Stack } from '@mui/material'; -import { DetailFinalLogType } from "../FinalLog/Model/Types"; -import { useEffect, useState, useRef, useMemo } from 'react'; -import { Box } from "@mui/material"; - - -import { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime"; -import Label from '@/components/Label'; - -import AddIcon from '@mui/icons-material/Add'; -import { Button } from "@mui/material"; - - - -type CardDetail = { - requestLog: DetailFinalLogType|undefined; -} - -const style1 = { - color: '#919EAB', - width: '30%' -} -const style2 = { - width: '70%' -} -const marginBottom1 = { - marginBottom: 1, -} -const marginBottom2 = { - marginBottom: 2, -} - - - -export default function DetailBenefit({requestLog} : CardDetail ) { - return ( - {requestLog.benefitData?.map((item, index) => ( - - - - - {item.description} - - - - - - - Amount Incurred* - - - - - - - - - - - - - Amount Approved* - - - - - - - - - - - - - Amount Not Approved* - - - - - - - - - - - - - Excess Paid* - - - - - - - - - - - - - Keterangan* - - - - - - - - - - ))} - ) - -} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogConfirmation.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogConfirmation.tsx index b53cc2f0..061739d0 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogConfirmation.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogConfirmation.tsx @@ -23,14 +23,15 @@ export default function DialogConfirmation({requestLog, setOpenDialog, openDialo const navigate = useNavigate(); const handleSubmit = () => { const formData = { - status : approve + status : approve, + id: requestLog?.id } axios - .put(`customer-service/request/${requestLog?.id}`, formData) + .post(`customer-service/request/final-log`, formData) .then((response) => { - enqueueSnackbar('Verification Request LOG Success', { variant: 'success' }); + enqueueSnackbar('Verification Final LOG Success', { variant: 'success' }); setOpenDialog(false); - navigate('/custormer-service/request') + navigate('/custormer-service/final-log') }) .catch(({ response }) => { enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' }); @@ -54,7 +55,7 @@ export default function DialogConfirmation({requestLog, setOpenDialog, openDialo const getContent = () => ( - Are you sure to {approve == 'approved' ? 'approve' : 'deciline'} this request ? + Are you sure to {approve == 'approved' ? 'approve' : 'deciline'} this final log ? diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogDelete.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogDelete.tsx index 1d493427..59669585 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogDelete.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogDelete.tsx @@ -66,4 +66,55 @@ export default function DialogDelete({id, setOpenDialog, openDialog,onSubmit} : maxWidth="xs" /> ); +} + +export function DialogDeleteMedicine({id, setOpenDialog, openDialog,onSubmit} : DialogDeleteType ) { + const handleSubmit = () => { + axios + .delete(`customer-service/request/medicine-data/${id}`) + .then((response) => { + enqueueSnackbar('Benefit Data has Deleted', { variant: 'success' }); + setOpenDialog(false); + window.location.reload() + }) + .catch(({ response }) => { + enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' }); + }); + } + + const style1 = { + color: '#919EAB', + width: '30%' + } + const style2 = { + width: '70%' + } + const marginBottom1 = { + marginBottom: 1, + } + + const handleCloseDialog = () => { + setOpenDialog(false); + } + + const getContent = () => ( + + Are you sure to delete this detail medicine ? + + + + + + ); + + + return ( + + ); } \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogDeleteMedicine.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogDeleteMedicine.tsx new file mode 100644 index 00000000..bd98ba42 --- /dev/null +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogDeleteMedicine.tsx @@ -0,0 +1,69 @@ +import MuiDialog from "@/components/MuiDialog"; +import { Button, Card, Checkbox, DialogActions, Grid, Typography } from "@mui/material"; +import { Paper } from "@mui/material"; +import { Stack } from '@mui/material'; +import React, { useState } from 'react'; +import { DetailFinalLogType } from "../Model/Types"; +import { fDateTimesecond, toTitleCase } from "@/utils/formatTime"; +import axios from "@/utils/axios"; +import { enqueueSnackbar } from "notistack"; +import { useNavigate } from "react-router"; + + +type DialogDeleteType = { + openDialog: boolean; + setOpenDialog: any; + onSubmit?: void; + id: number|undefined; +} + +export default function DialogDeleteMedicine({id, setOpenDialog, openDialog,onSubmit} : DialogDeleteType ) { + const handleSubmit = () => { + axios + .delete(`customer-service/request/medicine-data/${id}`) + .then((response) => { + enqueueSnackbar('Benefit Data has Deleted', { variant: 'success' }); + setOpenDialog(false); + window.location.reload() + }) + .catch(({ response }) => { + enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' }); + }); + } + + const style1 = { + color: '#919EAB', + width: '30%' + } + const style2 = { + width: '70%' + } + const marginBottom1 = { + marginBottom: 1, + } + + const handleCloseDialog = () => { + setOpenDialog(false); + } + + const getContent = () => ( + + Are you sure to delete this detail medicine ? + + + + + + ); + + + return ( + + ); +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogEditBenefit.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogEditBenefit.tsx index 50860d19..57063b87 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogEditBenefit.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogEditBenefit.tsx @@ -24,7 +24,7 @@ type DialogDeleteType = { setOpenDialog: any; onSubmit?: void; data: BenefitConfigurationListType|undefined; - id: number; + id: number|undefined; } export default function DialogEditBenefit({id, data, setOpenDialog, openDialog,onSubmit} : DialogDeleteType ) { diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogMedicine.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogMedicine.tsx index 53cd0ad8..0b9d01ed 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogMedicine.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Components/DialogMedicine.tsx @@ -1,9 +1,13 @@ +import * as Yup from 'yup'; +import { yupResolver } from '@hookform/resolvers/yup'; + import MuiDialog from "@/components/MuiDialog"; import { Button, Autocomplete, Card, Checkbox, DialogActions, Grid, Typography } from "@mui/material"; import { Paper } from "@mui/material"; import { Stack } from '@mui/material'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { DetailFinalLogType } from "../Model/Types"; +import { MedicineType } from "../Model/Types"; import { fDateTimesecond, toTitleCase } from "@/utils/formatTime"; import { useFieldArray, useForm } from 'react-hook-form'; import { FormProvider, RHFDatepicker, RHFSelect, RHFTextField } from '@/components/hook-form'; @@ -13,8 +17,10 @@ import { enqueueSnackbar } from "notistack"; import { useNavigate } from "react-router"; import { LoadingButton } from '@mui/lab'; import AddIcon from '@mui/icons-material/Add'; +import RemoveIcon from '@mui/icons-material/Remove'; import RHFTextFieldMoney from "@/components/hook-form/v2/RHFTextFieldMoney"; - +import { IconButton } from '@mui/material'; +import { postAddMedince } from '../Model/Functions'; type DialogConfirmationType = { openDialog: boolean; @@ -23,128 +29,133 @@ type DialogConfirmationType = { requestLog: DetailFinalLogType|undefined; } -export default function DialogHMedicine({requestLog, setOpenDialog, openDialog } : DialogConfirmationType ) { - - interface FormValuesProps extends Partial { - taxes: boolean; - inStock: boolean; - } - - const onSubmit = async (data: DetailFinalLogType) => { - - reset(); - } - +export default function DialogMedicine({requestLog, setOpenDialog, openDialog } : DialogConfirmationType ) { const handleCloseDialogMedicine = () => { - setOpenDialog(false) - setMedicines([]) + setOpenDialog(false); } - const [medicines, setMedicines] = useState([]); - const addMedicine = () => { - setMedicines((prevMedicines) => [...prevMedicines, { medicine: '', price: '' }]); - + const requestID = requestLog?.id + + const defaultValues: MedicineType = { + medicine : [{ + id: 0, + medicine_name: '', + medicine_price: 0, + request_log_id: requestID, + medicine: '', // input to database + price: 0, // input to database + }], }; - const handleDelete = (index) => { - // Update the medicines state to remove the medicine at the given index - setMedicines((prevMeds) => prevMeds.filter((med, medIndex) => medIndex !== index)); - }; + const validationSchema = Yup.object().shape({ + medicine: Yup.array().of( + Yup.object().shape({ + medicine_name : Yup.string().typeError('').required(''), + medicine_price : Yup.number().typeError('').required(''), + request_log_id : Yup.number().typeError('').required(''), + }) + ) + }) - const removeMedicene = (i:number) => { - const index = medicines.indexOf(i); - if (index > -1) { // only splice array when item is found - medicines.splice(index, 1); // 2nd parameter means remove one item only + const methods = useForm({ + resolver: yupResolver(validationSchema), + defaultValues + }); + + const {fields, append, remove} = useFieldArray({name: 'medicine',control: methods.control}) + + useEffect(() => { + let temp = fields.map((item, i) => { + return { + medicine_name: 'test', + medicine_price: 0, + request_log_id: 3, + } + }) + + reset({medicine: temp}) + }, []) + + + + const { handleSubmit, reset, watch, setValue, formState: { isDirty, isSubmitting, errors } } = methods; + // Submit Form + // ===================================== + const submitHandler = async (data: MedicineType) => { + const response = await postAddMedince(data); + + if (response == true) { + reset(); + // navigate('custormer-service/final-log/detail/'+requestLog?.id); + window.location.reload() } } - - - const methods = useForm(); - const { - reset, - watch, - control, - setValue, - getValues, - setError, - handleSubmit, - resetField, - formState: { isSubmitting }, - } = methods; - - const {fields, append, remove} = useFieldArray({name: "secondary_diagnosis_id", control}) const getContent = () => ( - + {/* Medicine */} Medicine* - - {/* Listing */} - - - - - - - {medicines.map((medicine, index) => ( - + {fields.map((field, index) => ( + - + - {/* - - */} + { + index != (fields.length-1) ? + ( + + remove(index)}> + + + + ) : null + } ))} + + + + + Add + + + ); - const getAction = () => ( - - - - - ); - + const getAction = () => null; return ( diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx index f1e97362..480fd05a 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Detail.tsx @@ -11,6 +11,7 @@ import { Collapse, AccordionSummary, AccordionDetails, + IconButton, } from '@mui/material'; // components import Page from '../../../components/Page'; @@ -37,19 +38,22 @@ import AddIcon from '@mui/icons-material/Add'; import CardDetail from '../Components/CardDetail'; import CardService from '../Components/CardService'; import CardExclusion from '../Components/CardExclusion'; +import CardBenefit from '../Components/CardBenefit'; // Import Dialog import DialogHospitalCare from './Components/DialogHospitalCare'; import DialogBenefit from './Components/DialogBenefit'; import DialogMedicine from './Components/DialogMedicine'; -import DetailBenefit from '../Components/DetailBenefit'; +import DialogDelete from './Components/DialogDelete'; import DialogEditBenefit from './Components/DialogEditBenefit'; +import { DialogDeleteMedicine } from './Components/DialogDelete'; import MoreMenu from '@/components/MoreMenu'; import { MenuItem } from '@mui/material'; import { fNumber } from '@/utils/formatNumber'; import palette from '@/theme/palette'; -import DialogDelete from './Components/DialogDelete'; +import CardMedicine from '../Components/CardMedicine'; +import CardFile from '../Components/CardFile'; // ---------------------------------------------------------------------- @@ -299,7 +303,13 @@ export default function Detail() { - + + {/* PR Buat pindahin ke componen */} + {/* + + */} Medicine - - + {requestLog?.medicine.map((item, index) => ( + + {item.medicine} + Rp. {fNumber(item.price)} + { + setIdBenefitData(item.id) + setDialogDeleteBenefit(true) + }}> + + + + + ))} + + + +
{/* File */} - - - - Files History - {requestLog?.files?.map((documentType, index) => ( - - - - {documentType.original_name ? documentType.original_name : '-'} - - - - ))} - - - + {requestLog?.status_final_log == 'requested' ? ( diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Functions.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Functions.tsx index c0831263..753fca55 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Functions.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Functions.tsx @@ -1,6 +1,6 @@ import axios from '@/utils/axios'; import { enqueueSnackbar } from 'notistack'; -import { MemberListType } from './Types'; +import { MedicineType, MemberListType } from './Types'; import { BenefitConfigurationListType } from './Types'; import { makeFormData } from '@/utils/jsonToFormData'; @@ -119,7 +119,7 @@ export const postAddBenefit = async (data: BenefitConfigurationListType):Promise /** * Edit Benefit */ -export const postEditBenefit = async (id:number, data: BenefitConfigurationListType):Promise => { +export const postEditBenefit = async (id:number|undefined, data: BenefitConfigurationListType):Promise => { const response = await axios.put(`customer-service/request/benefit_data/${id}`, { ...data }) @@ -151,3 +151,40 @@ export const postEditBenefit = async (id:number, data: BenefitConfigurationListT return response; } + +/** + * Add Medicine + */ + +export const postAddMedince = async (data: MedicineType):Promise => { + const response = await axios.post(`customer-service/request/medicine-data`, { + ...data + }) + .then((res) =>{ + enqueueSnackbar(res.data.message, { + variant: 'success', + }); + + return true; + }) + .catch((res) => { + if (res.response.status == 400) { + let arr_message = res.response.data.message; + + // for (const key in arr_message) { + enqueueSnackbar(arr_message, { + variant: 'warning', + }); + // } + } + else { + enqueueSnackbar("server error !", { + variant: 'error', + }); + } + + return false; + }); + + return response; +} diff --git a/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Types.tsx b/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Types.tsx index c89f0369..ad56d099 100644 --- a/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Types.tsx +++ b/frontend/dashboard/src/pages/CustomerService/FinalLog/Model/Types.tsx @@ -14,6 +14,7 @@ export type FinalLogType = { id : number, code : string, member : Member, + member_name : string, submission_date : string, service_name : string, payment_type_name : string, @@ -41,6 +42,7 @@ export type DetailFinalLogType = { benefit_data : BenefitData[], config_service : ConfigService, exclusion : Exclusion[], + medicine : Medicine[], files : file[], } @@ -51,9 +53,26 @@ export type BenefitData = { excess_paid : number, keterangan : string, benefit : Benefit, + request_log_id : number, + benefit_name : string, + description : string, id : number, } +export type BenefitConfigurationListType = { + request_log_id: number|undefined, + benefit_name: string, + benefit: { + description: string + }, + amount_incurred: number, + amount_approved: number, + amount_not_approved: number, + excess_paid: number, + keterangan: string, + description: string, +} + export type Benefit = { id: number, code: string, @@ -104,15 +123,17 @@ export type Rule = { } - -export type BenefitConfigurationListType = { - request_log_id: number|undefined, - benefit_name: string, - amount_incurred: number, - amount_approved: number, - amount_not_approved: number, - excess_paid: number, - keterangan: string, - description: string, +export type MedicineType = { + medicine: Medicine[], } +export type Medicine = { + id: number, + medicine_name: string, + medicine_price: number, + medicine: string, + price: number, + request_log_id: number|undefined, +} + + diff --git a/resources/views/pdf/guaranted_leter.blade.php b/resources/views/pdf/guaranted_leter.blade.php index 324614f5..8738d901 100644 --- a/resources/views/pdf/guaranted_leter.blade.php +++ b/resources/views/pdf/guaranted_leter.blade.php @@ -123,8 +123,8 @@
Date of Admission
- @if (isset($claimRequest)) -
{{ !empty($claimRequest->submission_date) ? \Carbon\Carbon::parse($claimRequest->submission_date)->format('d/m/Y') : now()->format('d/m/Y') }}
+ @if (isset($requestLog)) +
{{ !empty($requestLog->submission_date) ? \Carbon\Carbon::parse($requestLog->submission_date)->format('d/m/Y') : now()->format('d/m/Y') }}
@else
{{ $dateOfAdmission->format('d/m/Y') }}
@endif @@ -140,7 +140,7 @@ - + @@ -148,18 +148,34 @@ --}} + @if ($member->currentPlan) + @foreach ($member->currentPlan->corporateBenefits as $corporateBenefit) + + + + + + @endforeach + @endif +
Detail BenefitLimit
Medical Check Up As Charged
{{ @$corporateBenefit->benefit->description ?? '' }}
+ - @foreach ($member->currentPlan->corporateBenefits as $corporateBenefit) - - - {{ @$corporateBenefit->benefit->description ?? '' }} - @if($corporateBenefit->limit_amount == 999999999) - As Charged - @else - IDR {{ number_format($corporateBenefit->limit_amount, 0, ',', '.') ?? '' }} - @endif - - @endforeach +
+ + + + + + + @if ($member->currentPlan) + @foreach ($member->currentPlan->corporateBenefits as $corporateBenefit) + + + + + + @endforeach + @endif
Term on Condition
{{ @$corporateBenefit->benefit->description ?? '' }}
From 4defd4fa2f78b1d3181ce48cc96bbf988c4aca68 Mon Sep 17 00:00:00 2001 From: ivan-sim Date: Wed, 20 Dec 2023 16:27:57 +0700 Subject: [PATCH 3/3] Update Claim, Final LOG, Request LOG --- .../Http/Controllers/Api/AuthController.php | 3 +- .../Api/ClaimRequestController.php | 181 +++---- .../Http/Controllers/Api/MemberController.php | 62 ++- .../Controllers/Api/RequestLogController.php | 284 +++++++++++ Modules/HospitalPortal/Routes/api.php | 18 +- app/Models/ClaimRequest.php | 3 +- app/Models/File.php | 3 + app/Services/ClaimRequestService.php | 3 +- .../hospital-portal/public/image/en-US.json | 15 - .../hospital-portal/public/image/id-ID.json | 15 - .../hospital-portal/public/lang/en-US.json | 29 +- .../hospital-portal/public/lang/id-ID.json | 27 +- .../hospital-portal/src/components/Table.tsx | 14 +- .../layouts/dashboard/navbar/NavConfig.tsx | 5 +- .../layouts/dashboard/navbar/NavbarDocs.tsx | 2 +- frontend/hospital-portal/src/pages/Claim.tsx | 119 +++++ frontend/hospital-portal/src/routes/index.tsx | 22 + .../src/sections/claim/TableList.tsx | 365 +++++++++++++++ .../sections/dashboard/CardSearchMember.tsx | 8 +- .../sections/dashboard/DialogClaimSubmit.tsx | 164 +++++++ .../src/sections/dashboard/DialogFinalLog.tsx | 328 +++++++++++++ .../src/sections/dashboard/DialogMember.tsx | 107 +++-- .../src/sections/dashboard/FormRequestLog.tsx | 128 +++++ .../src/sections/dashboard/TableList.tsx | 222 +++++++-- .../sections/dashboard/TableListFinalLog.tsx | 441 ++++++++++++++++++ .../sections/dashboard/TableListReqLog.tsx | 425 +++++++++++++++++ resources/lang/en/Message.php | 1 + resources/lang/id/Message.php | 1 + 28 files changed, 2779 insertions(+), 216 deletions(-) create mode 100644 Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php delete mode 100644 frontend/hospital-portal/public/image/en-US.json delete mode 100644 frontend/hospital-portal/public/image/id-ID.json create mode 100644 frontend/hospital-portal/src/pages/Claim.tsx create mode 100644 frontend/hospital-portal/src/sections/claim/TableList.tsx create mode 100644 frontend/hospital-portal/src/sections/dashboard/DialogClaimSubmit.tsx create mode 100644 frontend/hospital-portal/src/sections/dashboard/DialogFinalLog.tsx create mode 100644 frontend/hospital-portal/src/sections/dashboard/FormRequestLog.tsx create mode 100644 frontend/hospital-portal/src/sections/dashboard/TableListFinalLog.tsx create mode 100644 frontend/hospital-portal/src/sections/dashboard/TableListReqLog.tsx 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.', ];