diff --git a/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php b/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php index a3d8ea35..a347a99b 100644 --- a/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php +++ b/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php @@ -10,6 +10,8 @@ use Illuminate\Support\Facades\DB; use Modules\Internal\Http\Controllers\Api\RequestLogController as primeCenterRequestLog; use App\Helpers\Helper; use App\Models\File; +use Dompdf\Dompdf; +use Dompdf\Options; class RequestLogController extends Controller { @@ -99,6 +101,7 @@ class RequestLogController extends Controller }) ->select( 'request_logs.id', + 'request_logs.member_id', 'request_logs.final_log', 'request_logs.code', 'members.name as full_name', @@ -281,4 +284,97 @@ class RequestLogController extends Controller } } } + + public function downlodLog($request_log_id) + { + $dataRequestLog = DB::table('request_logs') + ->where('request_logs.id', '=', $request_log_id) + ->first(); + $dataMember = DB::table('members') + ->where('members.id', '=', $dataRequestLog->member_id) + ->select( + 'members.principal_id', + 'members.name', + 'members.birth_date', + 'members.member_id', + 'members.gender', + DB::raw(' + (Select persons.nik FROM persons WHERE persons.id = members.person_id LIMIT 1) AS nik + '), + DB::raw(' + "Link Sehat" AS penjamin + '), + DB::raw(' + (Select corporates.name FROM corporates + INNER JOIN corporate_employees ON corporate_employees.corporate_id = corporates.id + WHERE corporate_employees.member_id = members.id LIMIT 1) AS nama_perusahaan + '), + DB::raw(' + (Select member_policies.policy_id FROM member_policies WHERE member_policies.member_id = members.member_id LIMIT 1) AS no_polis + '), + DB::raw(' + (Select member_policies.status FROM member_policies WHERE member_policies.member_id = members.member_id LIMIT 1) AS status_polis + '), + DB::raw(' + (Select plans.code FROM member_plans + INNER JOIN plans ON plans.id = member_plans.plan_id + WHERE member_plans.member_id = members.id LIMIT 1) AS code_plan + '), + DB::raw(' + (Select plans.limit_rules FROM member_plans + INNER JOIN plans ON plans.id = member_plans.plan_id + WHERE member_plans.member_id = members.id LIMIT 1) AS limit_rules + '), + DB::raw(' + "IDR" AS mata_uang + '), + 'members.members_effective_date AS mulai', + 'members.members_expire_date AS akhir' + ) + ->first(); + $data['namaKaryawan'] = ''; + if($dataMember->principal_id) + { + $dataNamaKaryawan = DB::table('members') + ->where('members.member_id', '=', $dataMember->principal_id) + ->select('members.name') + ->limit(1) + ->first(); + $data['namaKaryawan'] = $dataNamaKaryawan->name; + } + else{ + $data['namaKaryawan'] = $dataMember->name; + } + + $data['dataMember'] = $dataMember; + + $data['request_logs'] = $dataRequestLog; + + $pdf = new Dompdf(); + + $options = new Options(); + $options->set('isHtml5ParserEnabled', true); + $options->set('isPhpEnabled', true); + $options->set(['isRemoteEnabled' => true]); + $pdf->setOptions($options); + + // Halaman 1 + $html1 = view('pdf.req_log_page_1', $data); + + // Halaman 2 + $html2 = view('pdf.req_log_page_2', $data); + + // Gabung konten HTML dari dua tampilan + $htmlCombined = $html1 . $html2; + + $pdf->loadHtml($htmlCombined); + $pdf->render(); + + $headers = [ + 'Content-Type' => 'application/pdf', + 'Content-Disposition' => 'inline; filename="file.pdf"', + ]; + + return response($pdf->output(), 200, $headers); + } } diff --git a/Modules/HospitalPortal/Routes/api.php b/Modules/HospitalPortal/Routes/api.php index fabf81c9..f0717cc0 100644 --- a/Modules/HospitalPortal/Routes/api.php +++ b/Modules/HospitalPortal/Routes/api.php @@ -54,6 +54,7 @@ Route::prefix('v1')->group(function() { Route::get('get-request-log', 'getRequestLog'); Route::get('get-final-log', 'getFinalLog'); Route::post('request-final-log', 'requestFinalLog'); + Route::get('download-log/{request_log_id}', 'downlodLog'); }); //Notification Route::controller(NotificationController::class)->group(function() { diff --git a/Modules/Internal/Http/Controllers/Api/CorporateMemberController.php b/Modules/Internal/Http/Controllers/Api/CorporateMemberController.php index 19fc5583..9acc2340 100644 --- a/Modules/Internal/Http/Controllers/Api/CorporateMemberController.php +++ b/Modules/Internal/Http/Controllers/Api/CorporateMemberController.php @@ -20,6 +20,8 @@ use Modules\Internal\Services\MemberEnrollmentService; use PDF; use Illuminate\Support\Facades\DB; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Support\Facades\File; +use Spatie\Browsershot\Browsershot; class CorporateMemberController extends Controller { @@ -393,4 +395,70 @@ class CorporateMemberController extends Controller "file_url" => url('files/CorporateMembershipList.xlsx') ]); } + + public function sendAllECard(Request $request, $corporate_id){ + $members = Member::with([ + 'currentPlan', + 'currentPolicy', + 'currentCorporate', + // 'currentPlan.corporateBenefits.benefit' + ])->whereHas('currentCorporate', function ($query) use ($corporate_id) { + $query->where('corporate_id', $corporate_id); + })->get(); + $data = []; + $countSuccesSend = 0; + foreach($members as $member){ + // Simpan file PDF ke direktori yang diinginkan + $pdfPath = storage_path('app/pdf/ecards/E-card-' . $member->name. '.pdf'); + // Cek apakah file sudah ada + if (!File::exists($pdfPath)) { + $pdf = PDF::loadView('pdf.ecard', compact('member'))->setPaper('A5', 'portrait'); + $pdf->save($pdfPath); + } + + $dataEmail = [ + // 'email' => $member->email, + 'email' => 'tbfajri', + 'name' => $member->name, + 'subject' => 'Digital E Card '. $member->name, + 'body' => '

Hi ' . $member->name . '


ini adalah uji coba kirim e-card' , + 'attach' => $pdfPath, + ]; + $sendEmail = Helper::sendEmailattachData($dataEmail); + + if ($sendEmail === true){ + $countSuccesSend ++; + + File::delete($pdfPath); + } else { + $dataFaild = [ + 'email' => $member->email, + 'name' => $member->name, + 'message' => $sendEmail + ]; + array_push($data, $dataFaild); + } + } + $response = [ + 'data_fail_send' => count($data), + 'message' => $data, + 'data_succes_send' => $countSuccesSend, + ]; + + return response()->json($response); + } + + public function viewECard(Request $request, $member_id){ + $member = Member::with([ + 'currentPlan', + 'currentPolicy', + 'currentCorporate', + // 'currentPlan.corporateBenefits.benefit' + ])->find($member_id); + + $pdf = PDF::loadView('pdf.ecard', compact('member'))->setPaper('A5', 'portrait'); + return $pdf->download('Ecard - '.$member->full_name.'.pdf'); + + } + } diff --git a/Modules/Internal/Http/Controllers/Api/DailyMonitoringController.php b/Modules/Internal/Http/Controllers/Api/DailyMonitoringController.php index 09347128..d5da9d0f 100644 --- a/Modules/Internal/Http/Controllers/Api/DailyMonitoringController.php +++ b/Modules/Internal/Http/Controllers/Api/DailyMonitoringController.php @@ -3,12 +3,14 @@ namespace Modules\Internal\Http\Controllers\Api; use App\Models\DailyMonitoring; +use App\Models\RequestDailyMonitoring; use App\Models\MedicalPlan; use DB; use Exception; use Illuminate\Http\Request; use Illuminate\Routing\Controller; use Illuminate\Support\Facades\Validator; +use App\Models\File; /** * Bagaskoro BSD 27-10-2023 @@ -17,6 +19,7 @@ use Illuminate\Support\Facades\Validator; */ class DailyMonitoringController extends Controller { + protected $path_for_store = 'public/lab_result'; protected function messages() { return [ @@ -68,7 +71,7 @@ class DailyMonitoringController extends Controller $claimList = DB::table('request_logs') ->leftJoin('services', 'services.code', '=', 'request_logs.service_code') ->leftJoin('members', 'members.id', '=', 'request_logs.member_id') - ->select('request_logs.id','request_logs.submission_date AS admission_date','request_logs.discharge_date','request_logs.code','services.name as service_name','request_logs.status','members.name',) + ->select('request_logs.id','request_logs.submission_date AS admission_date','request_logs.discharge_date','request_logs.code','services.name as service_name','request_logs.status','members.name', 'members.member_id') ->where('request_logs.service_code', 'IP') ->where('request_logs.status_final_log', 'approved') ->where("request_logs.member_id", "=", $memberDetail->id) @@ -88,21 +91,17 @@ class DailyMonitoringController extends Controller /** * Detail Monitoring List - by claim_code */ - public function GetDetailMonitoringList(Request $request, $claim_code) + public function GetDetailMonitoringList(Request $request, $request_code) { - // get claim request - $claim_request = DB::table('claim_requests') + // get id request log + $request_logs = DB::table('request_logs') ->select('id') - ->where('code', $claim_code) + ->where('code', $request_code) ->first(); - // get claim - $claim = DB::table('claims') - ->select('id') - ->where('claim_request_id', empty($claim_request)==false ? $claim_request->id : '') - ->first(); - - $detail_list = DailyMonitoring::where('claim_id', empty($claim) == false ? $claim->id : '')->orderBy("created_at", "desc")->get()->makeHidden(['updated_at']); + $detail_list = RequestDailyMonitoring::where('request_log_id', empty($request_logs) == false ? $request_logs->id : '') + ->orderBy("created_at", "desc") + ->get(); return response()->json([ 'error' => false, @@ -213,4 +212,194 @@ class DailyMonitoringController extends Controller ],500); } } + + /** + * Add Detail Request LOG LIST + */ + public function AddDetailMonitoringListRequestLog(Request $request, $request_code) + { + $request->merge(['request_code' => $request_code]); + + // validation rule + $validator = Validator::make($request->all(),[ + 'request_code' => 'required|exists:request_logs,code', + 'subject' => 'required', + 'body_temperature' => 'required|numeric', + 'sistole' => 'required|numeric', + 'diastole' => 'required|numeric', + 'respiration_rate' => 'required|numeric', + 'analysis' => 'required', + 'medical_plan' => 'required', + 'non_medikamentosa_plan' => 'required', + ],$this->messages()); + + // validation error + if ($validator->fails()) { + return response()->json([ + 'error' => true, + 'message' => $validator->getMessageBag() + ],400); + } + + // get claim request + $request_log = DB::table('request_logs') + ->select('id') + ->where('code', $request_code) + ->first(); + DB::beginTransaction(); + try { + // insert claim daily monitoring + $db_response = RequestDailyMonitoring::create([ + 'request_log_id' => $request_log->id, + 'subject' => $request->subject, + 'sistole' => $request->sistole, + 'diastole' => $request->diastole, + 'body_temperature' => $request->body_temperature, + 'respiration_rate' => $request->respiration_rate, + 'analysis' => $request->analysis, + 'lab_date' => $request->lab_date, + 'provider' => $request->provider, + 'examination' => $request->examination, + ]); + + + // cek medical plan + $num_medical_plan = 0; + foreach ($request->medical_plan as $row) { + if ($row['medical_plan_str']) { + $num_medical_plan++; + } + } + + if ($num_medical_plan == 0) { + DB::rollBack(); + return response()->json([ + 'error' => true, + 'message' => [ + 'medical_plan' => ['medical plan harus diisi'] + ], + 'data' => [] + ],400); + } + + // insert medical plan + foreach ($request->medical_plan as $row) { + DB::table('request_log_medical_plan')->insert([ + 'request_log_daily_monitoring_id' => $db_response->id, + 'plan' => $row['medical_plan_str'], + 'type' => 1, + 'created_at' => date('Y-m-d'), + ]); + } + + // insert non medical plan + foreach ($request->non_medikamentosa_plan as $row) { + DB::table('request_log_medical_plan')->insert([ + 'request_log_daily_monitoring_id' => $db_response->id, + 'plan' => $row['non_medikamentosa_plan_str'], + 'type' => 2, + 'created_at' => date('Y-m-d'), + ]); + } + + // insert file result + if ($request->confirmation_medical_leter){ + foreach ($request->confirmation_medical_leter as $file) { + $name = 'labresult-' . uniqid(); + $extension= $file->getClientOriginalExtension(); + $fileName = $name . '.' . $extension; + $path = $file->storeAs($this->path_for_store, $fileName); + File::create([ + 'fileable_type' => 'App\Models\LaboratoriumResult', + 'fileable_id' => $db_response->id, + 'type' => 'confirmation-medical-letter', + 'name' => $name, + 'original_name' => $fileName, + 'extension' => $extension, + 'path' => $path, + ]); + + } + } + if ($request->medical_action_letter){ + foreach ($request->medical_action_letter as $file) { + $name = 'labresult-' . uniqid(); + $extension= $file->getClientOriginalExtension(); + $fileName = $name . '.' . $extension; + $path = $file->storeAs($this->path_for_store, $fileName); + File::create([ + 'fileable_type' => 'App\Models\LaboratoriumResult', + 'fileable_id' => $db_response->id, + 'type' => 'medical-action-letter', + 'name' => $name, + 'original_name' => $fileName, + 'extension' => $extension, + 'path' => $path, + ]); + + // $file->storeAs($this->path_for_store, $fileName); + } + } + if ($request->result){ + foreach ($request->result as $file) { + $name = 'labresult-' . uniqid(); + $extension= $file->getClientOriginalExtension(); + $fileName = $name . '.' . $extension; + $path = $file->storeAs($this->path_for_store, $fileName); + File::create([ + 'fileable_type' => 'App\Models\LaboratoriumResult', + 'fileable_id' => $db_response->id, + 'type' => 'laboratorium-result', + 'name' => $name, + 'original_name' => $fileName, + 'extension' => $extension, + 'path' => $path, + ]); + + // $file->storeAs($this->path_for_store, $fileName); + } + } + + + DB::commit(); + + return response()->json([ + 'error' => false, + 'message' => "success", + 'data' => [] + ],200); + } + catch (Exception $e) { + DB::rollBack(); + return response()->json([ + 'error' => true, + 'message' => $e->getMessage(), + 'data' => [] + ],500); + } + } + + /** + * Update Status Request LOG + */ + public function UpdateListRequestLog(Request $request, $request_code) + { + // get claim request + $request_log = DB::table('request_logs') + ->where('code', $request_code) + ->update(['discharge_date' => now()]); + if ($request_log) { + return response()->json([ + 'error' => false, + 'message' => "success", + 'data' => [] + ], 200); + } else { + return response()->json([ + 'error' => true, + 'message' => $e->getMessage(), + 'data' => [] + ],500); + } + } } diff --git a/Modules/Internal/Routes/api.php b/Modules/Internal/Routes/api.php index c97454bd..a4b86bba 100644 --- a/Modules/Internal/Routes/api.php +++ b/Modules/Internal/Routes/api.php @@ -170,6 +170,8 @@ Route::prefix('internal')->group(function () { Route::prefix('daily_monitoring')->group(function () { Route::get('detail/{claim_code}/list', [DailyMonitoringController::class, 'GetDetailMonitoringList']); Route::post('detail/{claim_code}/add', [DailyMonitoringController::class, 'AddDetailMonitoringList']); + Route::post('detail/{claim_code}/add-request', [DailyMonitoringController::class, 'AddDetailMonitoringListRequestLog']); + Route::post('detail/{claim_code}/update-status', [DailyMonitoringController::class, 'UpdateListRequestLog']); }); // Laboratorium Result @@ -284,6 +286,9 @@ Route::prefix('internal')->group(function () { Route::resource('doctors', DoctorController::class); Route::post('generate-log/{member_id}', [CorporateMemberController::class, 'generateLog']); + + Route::get('send_card/{corporate_id}', [CorporateMemberController::class, 'sendAllECard']); + Route::get('view_card/{member_id}', [CorporateMemberController::class, 'viewECard']); Route::controller(ClaimRequestController::class)->group(function () { Route::post('files-mcu', 'filesMcu'); }); diff --git a/Modules/Internal/Services/MemberEnrollmentService.php b/Modules/Internal/Services/MemberEnrollmentService.php index 84227525..a771d61f 100644 --- a/Modules/Internal/Services/MemberEnrollmentService.php +++ b/Modules/Internal/Services/MemberEnrollmentService.php @@ -324,6 +324,12 @@ class MemberEnrollmentService // "Ingestion Status", ]; + public $doc_headers_send_email = [ + "Name", + "Email", + "Message" + ]; + public function __construct(Member $member) { app()->setLocale('en'); diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 5ce5c9a4..12eb9f96 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -317,7 +317,6 @@ class Helper { // Buat instance PHPMailer $mail = new PHPMailer(true); - try { // Server settings $mail->isSMTP(); @@ -341,8 +340,46 @@ class Helper // Kirim email $mail->send(); return true; + } catch (\Exception $e) { - //var_dump($mail->ErrorInfo);die(); + dd($e); + return ($mail->ErrorInfo); + return false; + } + } + + public static function sendEmailattachData($data = array()) + { + // Buat instance PHPMailer + $mail = new PHPMailer(true); + try { + // Server settings + $mail->isSMTP(); + $mail->Host = 'smtp.gmail.com'; + $mail->SMTPAuth = true; + $mail->Username = env('EMAIL'); + $mail->Password = env('PW_EMAIL'); + $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; + $mail->Port = 465; + $mail->SMTPSecure = "ssl"; + + // Penerima email + $mail->setFrom(env('EMAIL'), env('NAME_EMAIL')); + $mail->addAddress($data['email'], $data['name']); + + // Konten email + $mail->isHTML(true); + $mail->Subject = $data['subject']; + $mail->Body = $data['body']; + $mail->addAttachment($data['attach'], 'e-card.pdf'); + + // Kirim email + $mail->send(); + return true; + + } catch (\Exception $e) { + dd($mail->ErrorInfo); + return ($mail->ErrorInfo); return false; } } diff --git a/app/Models/Member.php b/app/Models/Member.php index 1d0435a3..ef95adb6 100644 --- a/app/Models/Member.php +++ b/app/Models/Member.php @@ -255,19 +255,46 @@ class Member extends Model ); } - protected function birthDate(): Attribute + // protected function birthDate(): Attribute + // { + // // $date = $this->person->birth_date ?? ($this->birth_date ?? null); + // $date = $this->birth_date ?? ($this->person->birth_date ?? null); + // return Attribute::make( + // get: fn () => !empty($date) ? Carbon::parse($date)->format('Y-m-d') : null + // ); + // } + + protected function birthDateeCard(): Attribute { // $date = $this->person->birth_date ?? ($this->birth_date ?? null); - $date = $this->person->birth_date ?? ($this->birth_date ?? null); + $date = $this->birth_date ?? ($this->birth_date ?? this->person->birth_date); return Attribute::make( - get: fn () => !empty($date) ? Carbon::parse($date)->format('Y-m-d') : null + get: fn () => !empty($date) ? Carbon::parse($date)->format('d / M / Y') : null + ); + } + + protected function startDate(): Attribute + { + // $date = $this->person->birth_date ?? ($this->birth_date ?? null); + $date = $this->members_effective_date; + return Attribute::make( + get: fn () => !empty($date) ? Carbon::parse($date)->format('d / M / Y') : null + ); + } + + protected function endDate(): Attribute + { + // $date = $this->person->birth_date ?? ($this->birth_date ?? null); + $date = $this->members_expire_date; + return Attribute::make( + get: fn () => !empty($date) ? Carbon::parse($date)->format('d / M / Y') : null ); } protected function gender(): Attribute { return Attribute::make( - get: fn () => $this->person->gender ?? null + get: fn () => ucfirst($this->person->gender) ?? null ); } diff --git a/app/Models/RequestDailyMonitoring.php b/app/Models/RequestDailyMonitoring.php new file mode 100644 index 00000000..6eb1aa77 --- /dev/null +++ b/app/Models/RequestDailyMonitoring.php @@ -0,0 +1,99 @@ +attributes['body_temperature'], 0); + } + + public function getSistoleAttribute() + { + return round($this->attributes['sistole'], 0); + } + + public function getDiastoleAttribute() + { + return round($this->attributes['diastole'], 0); + } + + public function getRespirationRateAttribute() + { + return round($this->attributes['respiration_rate'], 0); + } + + public function getMedicalPlanAttribute() + { + $arr_medical_plan = []; + $medical_plan = DB::table('request_log_medical_plan')->where(['request_log_daily_monitoring_id' => $this->attributes['id'], 'type' => 1])->get(); + + foreach ($medical_plan as $row) { + $arr_medical_plan[] = [ + 'medical_plan_str' => $row->plan + ]; + } + + return $arr_medical_plan; + } + + public function getNonMedikamentosaPlanAttribute() + { + $arr_non_medikamentosa_plan = []; + $non_medikamentosa_plan = DB::table('request_log_medical_plan')->where(['request_log_daily_monitoring_id' => $this->attributes['id'], 'type' => 2])->get(); + + foreach ($non_medikamentosa_plan as $row) { + $arr_non_medikamentosa_plan[] = [ + 'non_medikamentosa_plan_str' => $row->plan + ]; + } + + return $arr_non_medikamentosa_plan; + } + + public function getDocumentAttribute() + { + $arr_document = []; + $document = DB::table('files')->where(['fileable_type' => 'App\Models\LaboratoriumResult', 'fileable_id' => $this->attributes['id']])->get(); + + foreach ($document as $row) { + $arr_document[] = [ + 'file_name' => $row->original_name, + 'path' => env('APP_URL') . '/storage/lab_result/' . $row->original_name, + 'type' => $row->type, + ]; + } + + return $arr_document; + } + + public function getDischargeDateAttribute() + { + return $discharge_date = DB::table('request_logs')->where('id', $this->attributes['request_log_id'])->select('discharge_date')->first(); + } + +} diff --git a/database/migrations/2023_12_27_141340_create_request_log_daily_monitoring.php b/database/migrations/2023_12_27_141340_create_request_log_daily_monitoring.php new file mode 100644 index 00000000..aa6f74e9 --- /dev/null +++ b/database/migrations/2023_12_27_141340_create_request_log_daily_monitoring.php @@ -0,0 +1,33 @@ +id(); + $table->foreignId('request_log_daily_monitoring_id'); + $table->string('plan'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('request_log_medical_plan'); + } +}; diff --git a/database/migrations/2023_12_27_163050_add_column_to_request_log_medical_plan.php b/database/migrations/2023_12_27_163050_add_column_to_request_log_medical_plan.php new file mode 100644 index 00000000..9e3115f5 --- /dev/null +++ b/database/migrations/2023_12_27_163050_add_column_to_request_log_medical_plan.php @@ -0,0 +1,32 @@ +integer('type')->after('plan'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('request_log_medical_plan', function (Blueprint $table) { + $table->dropColumn('type'); + }); + } +}; diff --git a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/ClaimListRow.tsx b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/ClaimListRow.tsx index 67e46a89..e08b4db5 100644 --- a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/ClaimListRow.tsx +++ b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/ClaimListRow.tsx @@ -22,6 +22,8 @@ import TableMoreMenu from '@/components/table/TableMoreMenu'; */ import { fDate } from "@/utils/formatTime"; import { ClaimListType } from "../Model/Types"; +import { ClearOutlined, LoopOutlined } from "@mui/icons-material"; +import DialogConfirmation from "./DialogConfirmation"; type Props = { row: ClaimListType, @@ -30,6 +32,14 @@ type Props = { export default function ClaimListRow ({ ...props }: Props) { const navigate = useNavigate() + const [openDialogSubmit, setOpenDialogSubmit] = useState(false); + const [code, setCode] = useState(''); + const [member_id, setMemberId] = useState(''); + const handleUpdate = (code: string, member_id: string) => { + setOpenDialogSubmit(true) + setMemberId(member_id) + setCode(code) + } return ( @@ -87,21 +97,45 @@ export default function ClaimListRow ({ ...props }: Props) { e.stopPropagation()}> - - navigate(`/case_management/daily_monitoring/${props.row.member_id}/claims/${props.row.claim_code}/list_monitoring`)}> - - View - - navigate(`/case_management/daily_monitoring/${props.row.member_id}/claims/${props.row.claim_code}/add_monitoring`)}> - - Daily Monitoring - - - } /> + {props.row.discharge_date == null ? + ( + + navigate(`/case_management/daily_monitoring/${props.row.member_id}/claims/${props.row.code}/list_monitoring`)}> + + View + + navigate(`/case_management/daily_monitoring/${props.row.member_id}/claims/${props.row.code}/add_monitoring`)}> + + Daily Monitoring + + handleUpdate(props.row.code, props.row.member_id)}> + + Update Status + + + } /> + ) : + ( + + navigate(`/case_management/daily_monitoring/${props.row.member_id}/claims/${props.row.code}/list_monitoring`)}> + + View + + + } /> + ) + } + + ); diff --git a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DetailMonitoringForm.tsx b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DetailMonitoringForm.tsx index b06b9721..0960b7ab 100644 --- a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DetailMonitoringForm.tsx +++ b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DetailMonitoringForm.tsx @@ -4,7 +4,7 @@ */ import { useFieldArray, useForm } from 'react-hook-form'; import { useNavigate, useParams } from 'react-router-dom'; -import { Box, IconButton, Typography, Grid, Card, Button } from '@mui/material'; +import { Box, IconButton, Typography, Grid, Card, Button, ButtonBase, Stack } from '@mui/material'; import { LoadingButton } from "@mui/lab"; /** @@ -13,6 +13,7 @@ import { LoadingButton } from "@mui/lab"; */ import Page from '@/components/Page'; import { FormProvider, RHFTextField } from '@/components/hook-form'; +import RHFDatePickerV2 from '@/components/hook-form/RHFDatePickerV2'; /** * Icon @@ -21,6 +22,7 @@ import { FormProvider, RHFTextField } from '@/components/hook-form'; import ArrowBackIosNew from '@mui/icons-material/ArrowBackIosNew'; import AddIcon from '@mui/icons-material/Add'; import RemoveIcon from '@mui/icons-material/Remove'; +import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; /** * Utils, Types, Functions @@ -28,11 +30,18 @@ import RemoveIcon from '@mui/icons-material/Remove'; */ import { AddMonitoringDetail } from '../Model/Functions'; import { DetailMonitoringListType} from '../Model/Types'; +import FormCreateFilesUpload from '@/pages/CustomerService/FinalLog/Components/FormCreateFilesUpload'; +import MultiFilePreview from '@/components/upload/MultiFilePreview'; +import Iconify from '@/components/Iconify'; +import { useRef } from 'react'; export default function DetailMonitoringList() { const { member_id, claim_code } = useParams(); const navigate = useNavigate() const pageTitle = claim_code??'_ _ _ _'; + const fileInput1 = useRef(null); + const fileInput2 = useRef(null); + const fileInput3 = useRef(null); // setup form // ==================================== @@ -50,16 +59,99 @@ export default function DetailMonitoringList() { medical_plan : [{ medical_plan_str: '' }], - created_at : '' + non_medikamentosa_plan : [{ + non_medikamentosa_plan_str: '' + }], + confirmation_medical_leter : [], + medical_action_letter : [], + result : [], + created_at : '', + lab_date : '', + provider : '', + examination : '', }; const methods = useForm({ defaultValues }); - const {fields, append, remove} = useFieldArray({name: 'medical_plan',control: methods.control}) + const {fields: fields1, append: append1, remove: remove1} = useFieldArray({name: 'medical_plan',control: methods.control}) + const {fields: fields2, append: append2, remove: remove2} = useFieldArray({name: 'non_medikamentosa_plan',control: methods.control}) - const { handleSubmit, reset, formState: { isDirty, isSubmitting } } = methods; + const { handleSubmit, reset, watch, setValue, formState: { isDirty, isSubmitting } } = methods; + const formValues = watch(); + // Handle File Input + // ===================================== + const handleInputChangeConfirmationMedicalLeter = (event: any) => { + if (event.target.files[0]) { + + let arr_confirmation_medical_leter_file = formValues.confirmation_medical_leter; + arr_confirmation_medical_leter_file.push(event.target.files[0]); + + setValue('confirmation_medical_leter', arr_confirmation_medical_leter_file); + } + else { + console.log('NO FILE'); + } + }; + const handleInputChangeMedicalActionLetter = (event: any) => { + if (event.target.files[0]) { + + let arr_medical_action_letter = formValues.medical_action_letter; + arr_medical_action_letter.push(event.target.files[0]); + + setValue('medical_action_letter', arr_medical_action_letter) + console.log('test2') + } + else { + console.log('NO FILE'); + } + }; + + const handleInputChangeResult = (event: any) => { + if (event.target.files[0]) { + + let arr_result = formValues.result; + arr_result.push(event.target.files[0]); + + setValue('result', arr_result) + console.log('test3') + } + else { + console.log('NO FILE'); + } + }; + + + // Handle Remove File + // ===================================== + const handleRemoveFileConfirmationMedicalLeter = (target_index: number) => { + let arr_confirmation_medical_leter_file = formValues.confirmation_medical_leter.filter((file: any, index: number) =>{ + if (target_index !== index) { + return file; + } + }); + + setValue('confirmation_medical_leter', arr_confirmation_medical_leter_file) + }; + const handleRemoveFileMedicalActionLetter = (target_index: number) => { + let arr_medical_action_letter = formValues.medical_action_letter.filter((file: any, index: number) =>{ + if (target_index !== index) { + return file; + } + }); + + setValue('medical_action_letter', arr_medical_action_letter) + }; + const handleRemoveFileResult = (target_index: number) => { + let arr_result = formValues.result.filter((file: any, index: number) =>{ + if (target_index !== index) { + return file; + } + }); + + setValue('result', arr_result) + }; // Submit Form // ===================================== @@ -70,8 +162,8 @@ export default function DetailMonitoringList() { if (response == true) { reset(); - navigate('case_management/daily_monitoring/'+claim_code+'claims'); - window.location.reload() + navigate('/case_management/daily_monitoring/'+member_id+'/claims', { replace: true }); + // window.location.reload() } } @@ -197,7 +289,7 @@ export default function DetailMonitoringList() { {/* Complaints */} - + {/* @@ -212,7 +304,7 @@ export default function DetailMonitoringList() { /> - + */} {/* Analysis */} @@ -242,7 +334,7 @@ export default function DetailMonitoringList() { { - fields.map((field,index) => { + fields1.map((field,index) => { return ( @@ -253,10 +345,10 @@ export default function DetailMonitoringList() { /> { - index == (fields.length-1) ? + index == (fields1.length-1) ? ( - append({medical_plan_str: ''})}> + append1({medical_plan_str: ''})}> @@ -264,7 +356,7 @@ export default function DetailMonitoringList() { : ( - remove(index)}> + remove1(index)}> @@ -278,7 +370,268 @@ export default function DetailMonitoringList() { - {/* Button Cancle & Save */} + {/* Non Medikamentosa Plan* */} + + + + + Non Medikamentosa Plan* : + + + + { + fields2.map((field,index) => { + return ( + + + + + { + index == (fields2.length-1) ? + ( + + append2({non_medikamentosa_plan_str: ''})}> + + + + ) + : + ( + + remove2(index)}> + + + + ) + } + + ) + }) + } + + + + + {/* Confirmation Medical Letter */} + + + + + Confirmation Medical Letter* + + + + { + formValues.confirmation_medical_leter.map((file: any, index: number) => ( + + + + {file.name ? file.name : '-'} + + handleRemoveFileConfirmationMedicalLeter(index)} + sx={{cursor: 'pointer'}} + > + + )) + } + + + fileInput1.current?.click()}> + + + + Upload File + + + handleInputChangeConfirmationMedicalLeter(e)} + accept="application/pdf" + /> + + + + + + + {/* Medical Action Letter */} + + + + + Medical Action Letter* + + + + { + formValues.medical_action_letter.map((file: any, index: number) => ( + + + + {file.name ? file.name : '-'} + + handleRemoveFileMedicalActionLetter(index)} + sx={{cursor: 'pointer'}} + > + + )) + } + + + fileInput2.current?.click()}> + + + + Upload File + + + + + + + + + + + {/* Laboratorium */} + + + + + Laboratorium Result* + + + + + Date* + + + + + Provider* + + + + + + + + + + + + Examination* + + + + + + + + Laboratorium Result* + + + + { + formValues.result.map((file: any, index: number) => ( + + + + {file.name ? file.name : '-'} + + handleRemoveFileResult(index)} + sx={{cursor: 'pointer'}} + > + + )) + } + + + fileInput3.current?.click()}> + + + + Upload File + + + + + + + + + + + {/* Button Cancel & Save */} @@ -286,7 +639,7 @@ export default function DetailMonitoringList() { Cancel - Save Changes + Add diff --git a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DetailMonitoringList.tsx b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DetailMonitoringList.tsx index da31d37d..3c96fa02 100644 --- a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DetailMonitoringList.tsx +++ b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DetailMonitoringList.tsx @@ -27,7 +27,7 @@ import FiberManualRecord from '@mui/icons-material/FiberManualRecord'; * Utils, Types, Functions * ============================================ */ -import { fDate } from "@/utils/formatTime"; +import { fDate, fDateOnly } from '@/utils/formatTime'; import { getMonitoringDetailList } from '../Model/Functions'; import { DetailMonitoringListType } from '../Model/Types'; @@ -87,6 +87,22 @@ export default function DetailMonitoringList() { > {row.created_at ? fDate(row.created_at) : '-'} + + {row.discharge_date.discharge_date ? + () : ()} + {/* card body */} @@ -160,21 +176,6 @@ export default function DetailMonitoringList() { - - - - - Subject : - - - - - {row.subject} - - - - - @@ -190,21 +191,6 @@ export default function DetailMonitoringList() { - - - - - Complaints : - - - - - {row.complaints} - - - - - @@ -215,7 +201,7 @@ export default function DetailMonitoringList() { { - row.medical_plan.map((data, index) => { + row.medical_plan?.map((data, index) => { return ( {data.medical_plan_str} @@ -227,6 +213,164 @@ export default function DetailMonitoringList() { + + + + + + Non Medikamentosa Plan : + + + + + { + row.non_medikamentosa_plan?.map((data, index) => { + return ( + + {data.non_medikamentosa_plan_str} + + ) + }) + } + + + + + + + + + + Laboratorium Result : + + + + + + Date + + + + + { row.lab_date != null ? fDate(row.lab_date) : '-'} + + + + + + + Location + + + + + {row.provider} + + + + + + + Examination + + + + + {row.examination} + + + + + + + + + + + Document Confirmation Medical Letter: + + + + + {row.document?.map((data, index) => ( + + {data.type === 'confirmation-medical-letter' ? ( + <> + + + {data.file_name} + + + ) : null} + + ))} + + + + + + + + + Document Medical Action Letter: + + + + + {row.document?.map((data, index) => ( + + {data.type === 'medical-action-letter' ? ( + <> + + + {data.file_name} + + + ) : null} + + ))} + + + + + + + + + Document Laboratorium Result: + + + + + {row.document?.map((data, index) => ( + + {data.type === 'laboratorium-result' ? ( + <> + + + {data.file_name} + + + ) : null} + + ))} + + + + + diff --git a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DialogConfirmation.tsx b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DialogConfirmation.tsx new file mode 100644 index 00000000..d391a9ad --- /dev/null +++ b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Components/DialogConfirmation.tsx @@ -0,0 +1,92 @@ +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 { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime"; +import axios from "@/utils/axios"; +import { enqueueSnackbar } from "notistack"; +import { useNavigate } from "react-router"; +import { replace } from "lodash"; +import { ClaimListType } from "../Model/Types"; +import Label from "@/components/Label"; + + +type DialogConfirmationType = { + openDialog: boolean; + setOpenDialog: any; + onSubmit?: void; + row: ClaimListType; +} + +export default function DialogConfirmation({ setOpenDialog, openDialog, row} : DialogConfirmationType ) { + + const navigate = useNavigate(); + const handleSubmit = () => { + axios + .post(`case_management/daily_monitoring/detail/${row.code}/update-status`) + .then((response) => { + enqueueSnackbar('Close Monitoring Success', { variant: 'success' }); + setOpenDialog(false); + navigate(`/case_management/daily_monitoring/${row.member_id}/claims`, { replace: true }) + 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 closed this monitoring ? + + + + Name + {row.name} + + + Code + {row.code} + + + Admision Date + + + + + + + + + + + + ); + + + return ( + + ); +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Model/Functions.ts b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Model/Functions.ts index 05ace34d..fd68763e 100644 --- a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Model/Functions.ts +++ b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Model/Functions.ts @@ -1,6 +1,8 @@ import axios from '@/utils/axios'; +import { makeFormData } from '@/utils/jsonToFormData'; import { enqueueSnackbar } from 'notistack'; import { DailyMonitoringListType, DetailMonitoringListType, ResponseListingClaimType } from "./Types"; +import { fDate, fDateOnly } from '@/utils/formatTime'; /** * Listing Daily Monitoring @@ -44,9 +46,11 @@ export const getClaimList = async ( member_id: string ): Promise => { - const response = await axios.post(`/case_management/daily_monitoring/detail/${claim_code}/add`, { - ...data - }) + data.lab_date = data.lab_date != '' && data.lab_date != null ? fDateOnly(data.lab_date) : ''; + + const formData = makeFormData({...data}); + + const response = await axios.post(`/case_management/daily_monitoring/detail/${claim_code}/add-request`, formData) .then((res) =>{ enqueueSnackbar(res.data.message, { variant: 'success', diff --git a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Model/Types.ts b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Model/Types.ts index 216c89e0..3e4706c5 100644 --- a/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Model/Types.ts +++ b/frontend/dashboard/src/pages/CaseManagement/DailyMonitoring/Model/Types.ts @@ -35,6 +35,9 @@ export type ClaimListType = { admission_date : string, discharge_date : string, claim_code : string, + name : string, + code : string, + service_name : string, claim_status : string, service_type : string, member_id : string @@ -54,10 +57,32 @@ export type DetailMonitoringListType = { diastole : string analysis : string, complaints : string, + lab_date : string, + provider : string, + examination : string, medical_plan : MedicalPlanStrType[], + non_medikamentosa_plan : NonMedikamentosaPlanType[], + confirmation_medical_leter : files[], + medical_action_letter : files[], + result : files[], + document : document[], created_at : string|null } export type MedicalPlanStrType = { medical_plan_str: string } + +export type NonMedikamentosaPlanType = { + non_medikamentosa_plan_str: string +} + +export type files = { + file: string +} + +export type document = { + file_name: string, + path: string, + type: string +} diff --git a/frontend/dashboard/src/pages/Corporates/Member/List.tsx b/frontend/dashboard/src/pages/Corporates/Member/List.tsx index b2e0c17e..b6030f4f 100644 --- a/frontend/dashboard/src/pages/Corporates/Member/List.tsx +++ b/frontend/dashboard/src/pages/Corporates/Member/List.tsx @@ -94,6 +94,7 @@ export default function CorporatePlanList({handleSubmitSuccess}) { const { corporate_id } = useParams(); const [searchParams, setSearchParams] = useSearchParams(); const [importResult, setImportResult] = useState(null); + const [sendResult, setSendResult] = useState(null); const [openDialog, setOpenDialog] = useState(false); const [isDialog, setIsDialog] = useState(''); @@ -267,6 +268,25 @@ export default function CorporatePlanList({handleSubmitSuccess}) { }); } + const handleSendAllEcard = () => { + setImportLoading(true); + setDataTableLoading(true); + axios + .get(`send_card/${corporate_id}`) + .then((response) => { + loadDataTableData(); + }) + + .catch((response) => { + enqueueSnackbar( + 'Looks like something went wrong. Please check your data and try again.', + { variant: 'error' } + ); + setImportLoading(false); + loadDataTableData(); + }); + } + const handleCancelImportButton = () => { importPlan.current.value = ''; importPlan.current.dispatchEvent(new Event('change', { bubbles: true })); @@ -363,6 +383,9 @@ export default function CorporatePlanList({handleSubmitSuccess}) { Download Member + + Send All Ecard + )} @@ -413,6 +436,7 @@ export default function CorporatePlanList({handleSubmitSuccess}) { )} + ); } @@ -470,6 +494,21 @@ export default function CorporatePlanList({handleSubmitSuccess}) { const style1 = { color: '#637381' } + + + const handleDownloadEcard = (id: number) => { + axios + .get(`view_card/${id}`, { + responseType: 'blob', + }) + .then((response) => { + window.open(URL.createObjectURL(response.data)); + }) + .catch((response) => { + enqueueSnackbar(response.message, { variant: 'error' }); + }); + } + return ( @@ -527,6 +566,10 @@ export default function CorporatePlanList({handleSubmitSuccess}) { Update Status + handleDownloadEcard(row.id)}> + + Download E-card + navigate ('/corporates/'+corporate_id+'/members/'+row.id+'/history')}> History diff --git a/frontend/hospital-portal/src/routes/index.tsx b/frontend/hospital-portal/src/routes/index.tsx index b3006919..a0165145 100644 --- a/frontend/hospital-portal/src/routes/index.tsx +++ b/frontend/hospital-portal/src/routes/index.tsx @@ -98,8 +98,8 @@ export default function Router() { element: , }, { - path: '/detail/:id', - element: , + path: '/claim/detail/:id', + element: , }, ], }, @@ -126,3 +126,4 @@ const Claim = Loadable(lazy(() => import('@/pages/Claim'))); const NotFound = Loadable(lazy(() => import('@/pages/Page404'))); const DetailClaimReport = Loadable(lazy(()=> import('@/sections/dashboard/Detail'))); +const DetailClaim = Loadable(lazy(()=> import('@/sections/claim/Detail'))); diff --git a/frontend/hospital-portal/src/sections/claim/Detail.tsx b/frontend/hospital-portal/src/sections/claim/Detail.tsx new file mode 100644 index 00000000..9c1ed9b8 --- /dev/null +++ b/frontend/hospital-portal/src/sections/claim/Detail.tsx @@ -0,0 +1,69 @@ +// mui +import { Container, Grid, Stack, Typography } from '@mui/material'; +// components +import Page from '../../components/Page'; +// utils +import useSettings from '../../hooks/useSettings'; +// section +import CardFamilyInformation from '../../sections/alarm-center/user-profile/CardFamilyInformation'; +// react +import { useNavigate, useParams } from 'react-router-dom'; +import ButtonBack from '../../components/ButtonBack'; +import { useEffect, useState, useContext } from 'react'; +import axios from '../../utils/axios'; +// pages +import DetailTimeline from '../../sections/dashboard/DetailTimeline'; +import DetailStepper from '../../sections/dashboard/DetailStepper'; +import { format } from 'date-fns'; +import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; +import { LanguageContext } from '@/contexts/LanguageContext'; + +// ---------------------------------------------------------------------- + +export default function Detail() { + const { localeData }: any = useContext(LanguageContext); + const navigate = useNavigate(); + const { themeStretch } = useSettings(); + const [data, setData] = useState(); + + const { id } = useParams(); + + useEffect(() => { + axios + .get('/detail-claim-requests/' + id) + .then((response) => { + setData(response.data); + }) + .catch((error) => { + console.error(error); + }); + + }, []); + + return ( + + + + navigate(-1)} sx={{cursor:'pointer'}}/> + Detail + {data ? ( + + {localeData.txtDialogMember5} + {(data && data.data) ? format(new Date(data.data.status.submission_date), "d MMM yyyy") : ''} + + ) : ''} + + {data ? ( + + + + + + + + + ) : ''} + + + ); +} \ No newline at end of file diff --git a/frontend/hospital-portal/src/sections/claim/DetailStepper.tsx b/frontend/hospital-portal/src/sections/claim/DetailStepper.tsx new file mode 100644 index 00000000..18dc959a --- /dev/null +++ b/frontend/hospital-portal/src/sections/claim/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/hospital-portal/src/sections/claim/DetailTimeline.tsx b/frontend/hospital-portal/src/sections/claim/DetailTimeline.tsx new file mode 100644 index 00000000..9d8b7b7f --- /dev/null +++ b/frontend/hospital-portal/src/sections/claim/DetailTimeline.tsx @@ -0,0 +1,386 @@ +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 { LoadingButton } from '@mui/lab'; +import axios from '../../utils/axios'; +import { makeFormData } from '@/utils/jsonToFormData'; +import { enqueueSnackbar } from 'notistack'; +import { useParams} from 'react-router-dom'; +import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; + +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); + useEffect(() => { + if (data && data.data) { + setTimeline(data.data.timeline); + setRequestFile(data.data.request_files); + } + + }, [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 + + ) : ''} + + ) : ''} + + + + + + ))} + + ); +} diff --git a/frontend/hospital-portal/src/sections/claim/TableList.tsx b/frontend/hospital-portal/src/sections/claim/TableList.tsx index 513ea292..61badfaf 100644 --- a/frontend/hospital-portal/src/sections/claim/TableList.tsx +++ b/frontend/hospital-portal/src/sections/claim/TableList.tsx @@ -313,7 +313,7 @@ export default function TableList() { action: - + navigate ('/claim/detail/'+obj.claim_request_id)}> View diff --git a/frontend/hospital-portal/src/sections/dashboard/FormRequestLog.tsx b/frontend/hospital-portal/src/sections/dashboard/FormRequestLog.tsx index 9110d837..1f6433c2 100644 --- a/frontend/hospital-portal/src/sections/dashboard/FormRequestLog.tsx +++ b/frontend/hospital-portal/src/sections/dashboard/FormRequestLog.tsx @@ -44,7 +44,6 @@ export default function FormRequestClaim({ member, handleSubmitSuccess }: FormRe axios .post('/request-log', formData) .then((response) => { - console.log(response); if (response && response.data && response.data.meta) { enqueueSnackbar(response.data.meta.message, { variant: 'success' }); handleSubmitSuccess(); diff --git a/frontend/hospital-portal/src/sections/dashboard/TableList.tsx b/frontend/hospital-portal/src/sections/dashboard/TableList.tsx index b1575b08..b3f95ca0 100644 --- a/frontend/hospital-portal/src/sections/dashboard/TableList.tsx +++ b/frontend/hospital-portal/src/sections/dashboard/TableList.tsx @@ -51,23 +51,16 @@ function handleChangeTab(event: React.SyntheticEvent, newValue: string) { const [data, setData] = useState([]); // Download LOG - async function handleDownloadLog(claimRequest:any) { + async function handleDownloadLog(request_log_id:any) { return axios - .get(`claim-requests/${claimRequest}/log`, { + .get(`download-log/${request_log_id}`, { responseType: 'blob', }) .then((response) => { - window.open(URL.createObjectURL(response.data)); - // setLoadingLog(false); + window.open(URL.createObjectURL(response.data), '_blank'); }) - // .then((blobFile) => { - // new File([blobFile], 'asdads.pdf', { type: blobFile.type }) - // setLoadingLog(false); - // }) .catch((response) => { - console.log(response); enqueueSnackbar(response.message, { variant: 'error' }); - // setLoadingLog(false); }); } @@ -357,13 +350,13 @@ function handleChangeTab(event: React.SyntheticEvent, newValue: string) { View - {obj.status === 'approved' ? ( - handleDownloadLog(obj.claim_request_id)}> + {/* {obj.status === 'approved' ? ( */} + handleDownloadLog(obj.id)}> Download LOG - ):''} - {obj.final_log === 0 ? ( + {/* ):''} */} + {obj.final_log === 0 && obj.status === 'approved' ? ( handleRequestFinalLog(obj.id, obj.full_name, obj.no_polis, obj.submission_date) }> Request Final LOG diff --git a/frontend/hospital-portal/src/sections/dashboard/TableListFinalLog.tsx b/frontend/hospital-portal/src/sections/dashboard/TableListFinalLog.tsx index 06dc44d8..4a71e61d 100644 --- a/frontend/hospital-portal/src/sections/dashboard/TableListFinalLog.tsx +++ b/frontend/hospital-portal/src/sections/dashboard/TableListFinalLog.tsx @@ -355,7 +355,7 @@ export default function TableListFinalLog() { Download LOG ):''} - {!obj.check_claim ? ( + {!obj.check_claim && obj.status === 'approved' ? ( handleRequestClaimSubmit(obj.member_id, obj.service_code, obj.id, obj.full_name, obj.no_polis, obj.submission_date) }> Submit Claim diff --git a/public/files/Benefit Usage Report.xlsx b/public/files/Benefit Usage Report.xlsx index 50ec0245..e80910f3 100644 Binary files a/public/files/Benefit Usage Report.xlsx and b/public/files/Benefit Usage Report.xlsx differ diff --git a/public/files/Corporate Plan & Benefit Import2.xlsx b/public/files/Corporate Plan & Benefit Import2.xlsx new file mode 100644 index 00000000..5d092aed Binary files /dev/null and b/public/files/Corporate Plan & Benefit Import2.xlsx differ diff --git a/public/files/TemplateFormulariumList.xlsx b/public/files/TemplateFormulariumList.xlsx index 65cec25b..d0d36f09 100644 Binary files a/public/files/TemplateFormulariumList.xlsx and b/public/files/TemplateFormulariumList.xlsx differ diff --git a/public/images/background-vale.png b/public/images/background-vale.png new file mode 100644 index 00000000..e41e2fa3 Binary files /dev/null and b/public/images/background-vale.png differ diff --git a/public/images/logo-default.png b/public/images/logo-default.png new file mode 100644 index 00000000..267e2e13 Binary files /dev/null and b/public/images/logo-default.png differ diff --git a/resources/views/pdf/ecard.blade.php b/resources/views/pdf/ecard.blade.php new file mode 100644 index 00000000..99c30f7e --- /dev/null +++ b/resources/views/pdf/ecard.blade.php @@ -0,0 +1,122 @@ + + + + + + {{-- --}} + + + + +



+
+
+ Member Name +

{{ $member->fullName }}

+ + Member ID +

{{ $member->member_id }}

+ + Policy Holder +

{{ $member->currentCorporate->name }}

+ + Policy Number +

{{ $member->currentPolicy->code }}

+ + Date of Birth +

{{ $member->birthDateeCard }}

+ + Gender +

{{ $member->gender }}

+ + Start Date +

{{ $member->startDate }}

+ +
+ +
+ + + + + + 08114123962 + + + Valid until: {{ $member->endDate }} +
+ +
+ + + + \ No newline at end of file diff --git a/resources/views/pdf/req_log_page_1.blade.php b/resources/views/pdf/req_log_page_1.blade.php new file mode 100644 index 00000000..768e27dd --- /dev/null +++ b/resources/views/pdf/req_log_page_1.blade.php @@ -0,0 +1,268 @@ + + + + + + + + +
+
+
+
+ The Future Of Healthcare At Your Fingertips +
+ +
+
+ SURAT JAMINAN +
+
+ (SURAT JAMINAN INI HARUS DITANDATANGANI OLEH PASIEN) +
+
+ + + + + + + + + + + + + + + + + +
No. Klaim:{{$request_logs->code}}Tanggal:{{ \Carbon\Carbon::parse($request_logs->submission_date)->format('d M Y') }}
Kepada:{{ $dataMember->name }}Plan Polis:{{ $dataMember->code_plan }}
+
+ (HOT LINE LINK SEHAT) +
+
+ Link Sehat bertindak mewakili perusahaan asuransi/penanggung untuk mengeluarkan Surat Jaminan Awal untuk peserta dibawah ini : +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Jenis Surat Jaminan:SURAT JAMINAN AWALPenjamin:{{ $dataMember->penjamin }}
Nama Peserta:{{ $dataMember->name }}Nama Perusahaan:{{ $dataMember->nama_perusahaan }}
Nama Karyawan:{{ $namaKaryawan }}No. Polis:{{ $dataMember->code_plan }}
Tanggal Lahir:{{ \Carbon\Carbon::parse($dataMember->birth_date)->format('d M Y') }}Produk:{{ $dataMember->no_polis }}
Jenis Kelamin:{{ $dataMember->gender == 'male' ? 'Laki-Laki' : 'Perempuan' }}Tipe:{{ $dataMember->limit_rules == '999999999' ? 'As Charge' : 'Max Amount, Rp '.number_format($dataMember->limit_rules, 2, ',', '.') }}
Member ID:{{ $dataMember->member_id }}Status Polis:{{ $dataMember->status_polis == 'active' ? 'Aktif' : 'Tidak Aktif' }}
Identitas Peserta:{{ $dataMember->nik }}Tanggal Mulai Akhir:{{ \Carbon\Carbon::parse($dataMember->mulai)->format('d M Y') }} - {{ \Carbon\Carbon::parse($dataMember->akhir)->format('d M Y') }}
Hak Kamar Pasien:Mata Uang:{{ $dataMember->mata_uang }}
Tanggal Pembayaran:Rumah Sakit:
Alamat:
+
+ Surat Jaminan ini dinyatakan berlaku apabila disertai surat jaminan akhir dengan nominal yang tertera pada akhir perawatan. +
+
+ The Future Of Healthcare At Your Fingertips +
+
+ PT Link Medis Sehat
+ Primaya Hospital Corporate
+ Graha Cempaka Mas Blok D5-6
+ Jl. Let. Jend. Suprapto, Jakarta Pusat 10640, Indonesia
+ Telp (021) 4217746/47 +
+
+ + \ No newline at end of file diff --git a/resources/views/pdf/req_log_page_2.blade.php b/resources/views/pdf/req_log_page_2.blade.php new file mode 100644 index 00000000..ea7a1425 --- /dev/null +++ b/resources/views/pdf/req_log_page_2.blade.php @@ -0,0 +1,254 @@ + + + + + + + + +
+
+
+
+ The Future Of Healthcare At Your Fingertips +
+ +
+
SYARAT DAN KETENTUAN
+ + + + + + + + + + + + + + + + + + + + + + + + + +
1. Surat jaminan ini hanya berlaku untuk diagnosa yang tercantum diatas. + Apabila ditemukan adanya perubahan atau penambahan diagnosa, maka Link Sehat berhak membatalkan surat jaminan. + Mohon untuk menghubungi Link Sehat apabila ada perubahan diagnosa dan diagnosa tambahan.
2. Surat jaminan ini dinyatakan berlaku apabila disertai surat jaminan akhir dengan + nominal yang tertera pada kolom diatas.
3. Surat jaminan ini tidak berlaku untuk biaya diluar medis seperti makan/minum + diluar ketentuan, tagihan telepon, binatu, dan lain-lain. Mohon ditagihkan langsung kepeserta.
4. Rumah sakit harap segera menghubungi Link Sehat apabila biaya rumah sakit melebihi batas tertanggung diatas.
5. Rumah sakit wajib menghubungi Link Sehat sebelum pasien meninggalkan rumah sakit + dapat menghubungi biaya apa saja yang dijamin oleh Link Sehat. Jika peserta meninggalkan rumah sakit sebelum mengkonfirmasikan ke Link Sehat, + maka Link Sehat tidak bertanggung jawab atas biaya yang tidak dijamin oleh pihak asuransi.
6. Peserta bertanggung jawab untuk menyelesaikan secara langsung kepada pihak rumah sakit dan penyedia jasa medis + apabila terjadi selisih biaya (ekses) atas seluruh biaya perawatan, biaya medis, dan yang lain yang telah terjadi sehubungan + dengan rawat inap, maupun atas perihal perawatan medis yang tidak tercakup dalam polis asuransi dikarenakan karena alasan apapun. + Apabila biaya-biaya tersebut telah dijamin oleh Link Sehat atas nama nasabah, maka peserta akan membayar kembali ke pihak Link Sehat + secara penuh termasuk biaya berhubungan dengan penagihan (apabila ada) yang terjadi ke pihak Link Sehat atas biaya yang tidak termasuk dalam manfaat polis.
7. Dengan ini perserta menyatakan mengetahui dan menyetujui ketentuan selisih biaya yang telah disebutkan diatas.
8. Dalam hal surat jaminan ini tidak ditandatangani oleh peserta yang bersangkutan maka rumah sakit berkewajiban untuk menyampaikan keadaan tersebut + kepada Link Sehat dalam kurun waktu paling lambat 1x24 jam, dalam hal tidak ada perubahan dalam jangka waktu yang telah ditentukan tersebut + maka dianggap peserta yang bersangkutan telah setuju dengan ketentuan yang terdapat dalam surat jaminan ini.
+
+ +
+ Hormat Kami,
+ Acknowledged, +
+
+ [..................................................] +
+
+ [{{ $dataMember->name }}] +
+
+ The Future Of Healthcare At Your Fingertip +
+
+ PT Link Medis Sehat
+ Primaya Hospital Corporate
+ Graha Cempaka Mas Blok D5-6
+ Jl. Let. Jend. Suprapto, Jakarta Pusat 10640, Indonesia
+ Telp (021) 4217746/47 +
+
+ + \ No newline at end of file diff --git a/resources/views/pdf/view.blade.php b/resources/views/pdf/view.blade.php new file mode 100644 index 00000000..dd2e4a16 --- /dev/null +++ b/resources/views/pdf/view.blade.php @@ -0,0 +1,37 @@ + + + + + + + + Ivan Julian + + + + + + + +

Hello, {{ $key }}

+

This is a simple example for generating PDF in Laravel using Dompdf.

+ +