From e76c480ce9e44e69f9788ad29c84dc51b7a1eaf7 Mon Sep 17 00:00:00 2001 From: Tb Fajri Date: Tue, 12 Dec 2023 14:35:12 +0700 Subject: [PATCH] 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(); + }); +}