Merge branch 'staging' of https://dev.sismedika.online/febio/aso into staging

This commit is contained in:
Linksehat Staging Server
2023-12-20 16:44:47 +07:00
83 changed files with 6718 additions and 790 deletions

View File

@@ -18,6 +18,7 @@ use Modules\HospitalPortal\Transformers\ClaimRequestShowResource;
use PDF;
use Illuminate\Support\Facades\DB;
use Modules\HospitalPortal\Helpers\ApiResponse;
use Illuminate\Support\Facades\Validator;
class ClaimRequestController extends Controller
{
@@ -63,90 +64,93 @@ class ClaimRequestController extends Controller
*/
public function store(Request $request)
{
$request->validate([
$data = [
'request_logs_id' => $request->request_logs_id,
'member_id' => $request->member_id,
'service_code' => $request->service_code
];
$validator = Validator::make($request->all(), [
'request_logs_id' => 'required',
'member_id' => 'required',
'service_code' => 'required'
], [
'request_logs_id.required' => trans('Validation.required',['attribute' => 'Request Log ID']),
'member_id.required' => trans('Validation.required',['attribute' => 'Member ID']),
'service_code.required' => trans('Validation.required',['attribute' => 'Service Code'])
]);
$code = $this->getNextCode();
$member = Member::find($request->member_id);
$newClaimRequest = ClaimRequestService::storeClaimRequest(
row: [],
code: $code,
member: $member,
paymentType: 'reimbursement',
serviceCode: $request->service_code
);
ClaimRequested::dispatch($newClaimRequest);
// Log History
$newClaimRequest->histories()->create([
'title' => 'New Claim Requested',
'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})",
'type' => 'info',
'system_origin' => 'hospital-portal'
]);
// Claim Log
DB::table('claim_logs')
->insert([
'claim_request_id' => $newClaimRequest->id,
'status' => 'requested',
'date' => date('Y-m-d H:i:s'),
'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})",
'system_origin' => 'hospital-portal',
'created_by' => auth()->user()->id,
'created_at' => date('Y-m-d H:i:s'),
'updated_at'=> date('Y-m-d H:i:s'),
]);
if ($request->hasFile('result_files')) {
foreach ($request->result_files as $file) {
$pathFile = File::storeFile('claim-result', $newClaimRequest->id, $file);
$newClaimRequest->files()->updateOrCreate([
'type' => 'claim-result',
'name' => File::getFileName('claim-result', $newClaimRequest->id, $file),
'original_name' => $file->getClientOriginalName(),
'extension' => $file->getClientOriginalExtension(),
'path' => $pathFile,
'created_by' => auth()->user()->id,
'updated_by' => auth()->user()->id,
]);
}
if ($validator->fails())
{
return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400);
}
if ($request->hasFile('diagnosa_files')) {
foreach ($request->diagnosa_files as $file) {
$pathFile = File::storeFile('claim-diagnosis', $newClaimRequest->id, $file);
$newClaimRequest->files()->updateOrCreate([
'type' => 'claim-diagnosis',
'name' => File::getFileName('claim-diagnosis', $newClaimRequest->id, $file),
'original_name' => $file->getClientOriginalName(),
'extension' => $file->getClientOriginalExtension(),
'path' => $pathFile,
'created_by' => auth()->user()->id,
'updated_by' => auth()->user()->id,
]);
else
{
$check_claim_requests = DB::table('claim_requests')
->where('claim_requests.request_log_id', '=', $request->request_logs_id)
->first();
if(!$check_claim_requests)
{
try {
DB::beginTransaction();
$code = $this->getNextCode();
$member = Member::find($request->member_id);
$newClaimRequest = ClaimRequestService::storeClaimRequest(
row: [],
code: $code,
member: $member,
paymentType: 'reimbursement',
serviceCode: $request->service_code,
requestLogID: $request->request_logs_id,
);
// Log History
$newClaimRequest->histories()->create([
'title' => 'New Claim Requested',
'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})",
'type' => 'info',
'system_origin' => 'hospital-portal'
]);
// Claim Log
DB::table('claim_logs')
->insert([
'claim_request_id' => $newClaimRequest->id,
'status' => 'requested',
'date' => date('Y-m-d H:i:s'),
'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})",
'system_origin' => 'hospital-portal',
'created_by' => auth()->user()->id,
'created_at' => date('Y-m-d H:i:s'),
'updated_at'=> date('Y-m-d H:i:s'),
]);
if ($request->hasFile('additional_files')) {
foreach ($request->additional_files as $file) {
$pathFile = File::storeFile('additional-files', $newClaimRequest->id, $file);
$newClaimRequest->files()->updateOrCreate([
'type' => 'additional-files',
'name' => File::getFileName('additional-files', $newClaimRequest->id, $file),
'original_name' => $file->getClientOriginalName(),
'extension' => $file->getClientOriginalExtension(),
'path' => $pathFile,
'created_by' => auth()->user()->id,
'updated_by' => auth()->user()->id,
]);
}
}
DB::commit();
return ApiResponse::apiResponse('Success', $data, trans('Message.success'), 200);
}
catch (\Exception $e) {
DB::rollback();
return ApiResponse::apiResponse("Error", $data, $e->getMessage(), 500);
}
}
}
if ($request->hasFile('kondisi_files')) {
foreach ($request->kondisi_files as $file) {
$pathFile = File::storeFile('claim-kondisi', $newClaimRequest->id, $file);
$newClaimRequest->files()->updateOrCreate([
'type' => 'claim-kondisi',
'name' => File::getFileName('claim-kondisi', $newClaimRequest->id, $file),
'original_name' => $file->getClientOriginalName(),
'extension' => $file->getClientOriginalExtension(),
'path' => $pathFile,
'created_by' => auth()->user()->id,
'updated_by' => auth()->user()->id,
]);
else
{
return ApiResponse::apiResponse("Error", $data, trans('Message.already_exists'), 409);
}
}
return ApiResponse::apiResponse("Success", [], trans('message.success'), 200);
}
/**
@@ -253,12 +257,13 @@ class ClaimRequestController extends Controller
->leftJoin('corporate_divisions', 'corporate_employees.division_id', '=', 'corporate_divisions.id')
->when($request->input('search'), function ($query, $search) {
$query->where(function ($query) use ($search) {
$query->orWhere('claim_requests.code', 'like', "%" . $search . "%")
$query->orWhere('claim_requests.code', 'like', "%" . ($search == 'outpatient' || $search == 'Outpatient' ? 'OP' : 'IP') . "%")
->orWhere('members.member_id', 'like', "%" . $search . "%")
->orWhere('members.name', 'like', "%" . $search . "%")
->orWhere('corporate_divisions.name', 'like', "%" . $search . "%")
->orWhere('claim_requests.status', 'like', "%" . $search . "%")
->orWhere('claim_requests.submission_date', 'like', "%" . $search . "%");
->orWhere('claim_requests.submission_date', 'like', "%" . $search . "%")
->orWhere('claims.status', 'like', "%" . $search . "%");
});
})
->when($request->has('orderBy'), function ($query) use ($request) {
@@ -296,7 +301,12 @@ class ClaimRequestController extends Controller
});
})
->select('members.id', 'claim_requests.code','members.member_id', 'members.name as full_name', 'corporate_divisions.name AS division_name',
->select(
'members.id',
'claim_requests.code',
'members.member_id',
'members.name as full_name',
'corporate_divisions.name AS division_name',
DB::raw('
CASE
WHEN claim_requests.status = "requested" THEN "requested"
@@ -308,7 +318,16 @@ class ClaimRequestController extends Controller
ELSE ""
END AS status
'),
'claim_requests.id AS claim_request_id', 'claim_requests.submission_date')
'claim_requests.id AS claim_request_id',
'claim_requests.submission_date',
DB::raw('
CASE
WHEN service_code = "OP" THEN "Outpatient"
WHEN service_code = "IP" THEN "Inpatient"
ELSE ""
END AS service_type
')
)
->paginate($limit);
return response()->json(Helper::paginateResources($results));
}

View File

@@ -94,6 +94,8 @@ class MemberController extends Controller
$res_data['groupServices'] = $groupServices;
$res_data['type'] = $request->type;
return ApiResponse::apiResponse("Success", $res_data, trans('Message.success'), 200);
}

View File

@@ -8,6 +8,8 @@ use Illuminate\Support\Facades\Validator;
use Modules\HospitalPortal\Helpers\ApiResponse;
use Illuminate\Support\Facades\DB;
use Modules\Internal\Http\Controllers\Api\RequestLogController as primeCenterRequestLog;
use App\Helpers\Helper;
use App\Models\File;
class RequestLogController extends Controller
{
@@ -48,4 +50,235 @@ class RequestLogController extends Controller
}
}
}
public function getRequestLog(Request $request)
{
$limit = $request->has('per_page') ? $request->input('per_page') : 10;
$results = DB::table('request_logs')
->leftJoin('members', 'request_logs.member_id', '=', 'members.id')
->when($request->input('search'), function ($query, $search) {
$query->where(function ($query) use ($search) {
$query->orWhere('request_logs.code', 'like', "%" . $search . "%")
->orWhere('members.name', 'like', "%" . $search . "%")
->orWhere('request_logs.submission_date', 'like', "%" . $search . "%");
});
})
->when($request->has('orderBy'), function ($query) use ($request) {
$orderBy = $request->orderBy;
$direction = $request->order ?? 'asc';
$query->orderBy($orderBy, $direction);
})
->when($request->input('start_date') && !$request->input('end_date'), function ($query, $start_date) {
$query->where(function ($query) use ($start_date) {
$query->where('request_logs.submission_date', '<', $start_date);
});
})
->when($request->input('status'), function ($query, $status) {
$query->where(function ($query) use ($status) {
if ($status === 'requested') {
$query->where('request_logs.status', '=', 'requested');
}
if ($status === 'reviewed') {
$query->where('request_logs.status', '=', 'approved');
}
if ($status === 'approved') {
$query->where('request_logs.status', '=', 'approved');
}
if ($status === 'declined') {
$query->where('request_logs.status', '=', 'declined');
}
});
})
->select(
'request_logs.id',
'request_logs.final_log',
'request_logs.code',
'members.name as full_name',
'members.member_id as no_polis',
'members.birth_date',
DB::raw('
CASE
WHEN request_logs.status = "requested" THEN "requested"
WHEN request_logs.status = "approved" THEN "approved"
WHEN request_logs.status = "declined" THEN "declined"
WHEN request_logs.status = "reviewed" THEN "reviewed"
ELSE ""
END AS status
'),
'request_logs.submission_date')
->paginate($limit);
return response()->json(Helper::paginateResources($results));
}
public function getFinalLog(Request $request)
{
$limit = $request->has('per_page') ? $request->input('per_page') : 10;
$results = DB::table('request_logs')
->leftJoin('members', 'request_logs.member_id', '=', 'members.id')
->when($request->input('search'), function ($query, $search) {
$query->where(function ($query) use ($search) {
$query->orWhere('request_logs.code', 'like', "%" . $search . "%")
->orWhere('members.name', 'like', "%" . $search . "%")
->orWhere('request_logs.submission_date', 'like', "%" . $search . "%")
->orWhere('request_logs.service_code', 'like', "%" . ($search == 'outpatient' || $search == 'Outpatient' ? 'OP' : 'IP') . "%");
});
})
->when($request->has('orderBy'), function ($query) use ($request) {
$orderBy = $request->orderBy;
$direction = $request->order ?? 'asc';
$query->orderBy($orderBy, $direction);
})
->when($request->input('start_date') && !$request->input('end_date'), function ($query, $start_date) {
$query->where(function ($query) use ($start_date) {
$query->where('request_logs.submission_date', '<', $start_date);
});
})
->when($request->input('status'), function ($query, $status) {
$query->where(function ($query) use ($status) {
if ($status === 'requested') {
$query->where('request_logs.status_final_log', '=', 'requested');
}
if ($status === 'reviewed') {
$query->where('request_logs.status_final_log', '=', 'approved');
}
if ($status === 'approved') {
$query->where('request_logs.status_final_log', '=', 'approved');
}
if ($status === 'declined') {
$query->where('request_logs.status_final_log', '=', 'declined');
}
});
})
->where('request_logs.final_log', '=', 1)
->select(
'request_logs.id',
'request_logs.final_log',
'request_logs.code',
'members.name as full_name',
'members.member_id as no_polis',
'members.id AS member_id',
'request_logs.service_code',
'members.birth_date',
DB::raw('
CASE
WHEN request_logs.status_final_log = "requested" THEN "requested"
WHEN request_logs.status_final_log = "approved" THEN "approved"
WHEN request_logs.status_final_log = "declined" THEN "declined"
WHEN request_logs.status_final_log = "reviewed" THEN "reviewed"
ELSE ""
END AS status
'),
'request_logs.submission_date',
DB::raw('
CASE
WHEN service_code = "OP" THEN "Outpatient"
WHEN service_code = "IP" THEN "Inpatient"
ELSE ""
END AS service_type
'),
DB::raw('
(Select request_log_id FROM claim_requests WHERE claim_requests.request_log_id = request_logs.id LIMIT 1) AS check_claim
')
)
->paginate($limit);
return response()->json(Helper::paginateResources($results));
}
public function requestFinalLog(Request $request)
{
$data = [
'request_logs_id' => $request->request_logs_id
];
$validator = Validator::make($request->all(), [
'request_logs_id' => 'required'
], [
'request_logs_id.required' => trans('Validation.required',['attribute' => 'Request Logs ID'])
]);
if ($validator->fails())
{
return ApiResponse::apiResponse('Bad Request', $data, $validator->errors(), 400);
}
else
{
try {
DB::beginTransaction();
DB::table('request_logs')
->where('request_logs.id', '=', $request->request_logs_id)
->update([
'status_final_log' => 'requested',
'final_log' => 1
]);
if ($request->hasFile('result_files')) {
foreach ($request->result_files as $file) {
$pathFile = File::storeFile('final-log-result', $request->request_logs_id, $file);
File::updateOrCreate([
'fileable_type' => 'App\Models\RequestLog',
'fileable_id' => $request->request_logs_id,
'type' => 'final-log-result',
'name' => File::getFileName('final-log-result', $request->request_logs_id, $file),
'original_name' => $file->getClientOriginalName(),
'extension' => $file->getClientOriginalExtension(),
'path' => $pathFile,
'created_by' => auth()->user()->id,
'updated_by' => auth()->user()->id,
]);
}
}
if ($request->hasFile('diagnosa_files')) {
foreach ($request->diagnosa_files as $file) {
$pathFile = File::storeFile('final-log-diagnosis', $request->request_logs_id, $file);
File::updateOrCreate([
'fileable_type' => 'App\Models\RequestLog',
'fileable_id' => $request->request_logs_id,
'type' => 'final-log-diagnosis',
'name' => File::getFileName('final-log-diagnosis', $request->request_logs_id, $file),
'original_name' => $file->getClientOriginalName(),
'extension' => $file->getClientOriginalExtension(),
'path' => $pathFile,
'created_by' => auth()->user()->id,
'updated_by' => auth()->user()->id,
]);
}
}
if ($request->hasFile('kondisi_files')) {
foreach ($request->kondisi_files as $file) {
$pathFile = File::storeFile('final-log-kondisi', $request->request_logs_id, $file);
File::updateOrCreate([
'fileable_type' => 'App\Models\RequestLog',
'fileable_id' => $request->request_logs_id,
'type' => 'final-log-kondisi',
'name' => File::getFileName('final-log-kondisi', $request->request_logs_id, $file),
'original_name' => $file->getClientOriginalName(),
'extension' => $file->getClientOriginalExtension(),
'path' => $pathFile,
'created_by' => auth()->user()->id,
'updated_by' => auth()->user()->id,
]);
}
}
DB::commit();
return ApiResponse::apiResponse('Success', $data, trans('Message.success'), 200);
}
catch (\Exception $e) {
DB::rollback();
return ApiResponse::apiResponse("Error", $data, $e->getMessage(), 500);
}
}
}
}

View File

@@ -51,6 +51,9 @@ Route::prefix('v1')->group(function() {
// Request LOG
Route::controller(RequestLogController::class)->group(function () {
Route::post('request-log', 'requestLog');
Route::get('get-request-log', 'getRequestLog');
Route::get('get-final-log', 'getFinalLog');
Route::post('request-final-log', 'requestFinalLog');
});
//Notification
Route::controller(NotificationController::class)->group(function() {
@@ -60,8 +63,16 @@ Route::prefix('v1')->group(function() {
Route::post('set-read-notification', 'setReadNotification');
});
});
// Request Final LOG
Route::controller(RequestLogController::class)->group(function () {
Route::post('request-final-log', 'requestFinalLog');
});
// Claim Submit
Route::controller(ClaimRequestController::class)->group(function () {
Route::post('claim-requests', 'store');
});
Route::get('claim-requests', [ClaimRequestController::class, 'index'])->name('claim-requests.index');
Route::post('claim-requests', [ClaimRequestController::class, 'store'])->name('claim-requests.store');
// Route::post('claim-requests', [ClaimRequestController::class, 'store'])->name('claim-requests.store');
Route::get('claim-requests/{claim_request_id}/log', [ClaimRequestController::class, 'generateLog'])->name('claim-requests.generate-log');
Route::get('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show');
Route::get('get-claim-requests', [ClaimRequestController::class, 'get_claim_requests'])->name('claim-requests.get_claim_requests');

View File

@@ -34,7 +34,7 @@ class ClaimController extends Controller
*/
public function index(Request $request)
{
$serviceCode = 'IP';
// $serviceCode = 'IP';
$claims = Claim::with([
'member',
'member.currentCorporate',

View File

@@ -35,12 +35,15 @@ class DailyMonitoringController extends Controller
*/
public function GetMemberList()
{
$memberList = DB::table('claims')
->leftJoin('members', 'claims.member_id', '=', 'members.id')
->leftJoin('member_plans', 'members.id', '=', 'member_plans.id')
->select('members.member_id','members.name','member_plans.start AS startdate','member_plans.end AS enddate')
->groupBy('claims.member_id')
->orderBy('claims.created_at', 'desc')
$memberList = DB::table('request_logs')
->leftJoin('members', 'request_logs.member_id', '=', 'members.id')
->leftJoin('member_plans', 'request_logs.member_id', '=', 'member_plans.member_id')
->leftJoin('organizations', 'organizations.id', '=', 'request_logs.organization_id')
->select('members.member_id','members.name','member_plans.start AS startdate','member_plans.end AS enddate', 'request_logs.submission_date as addmision_date', 'organizations.name as provider' )
->where('request_logs.service_code', 'IP')
->where('request_logs.status_final_log', 'approved')
->groupBy('request_logs.member_id')
->orderBy('request_logs.created_at', 'desc')
->get();
return response()->json([
@@ -62,15 +65,14 @@ class DailyMonitoringController extends Controller
->where('member_id', $member_id)
->first();
$claimList = DB::table('claims')
->leftJoin('claim_requests', 'claims.claim_request_id', '=', 'claim_requests.id')
->leftJoin('claim_history_cares', 'claims.id', '=', 'claim_history_cares.claim_id')
->leftJoin('services', 'claim_requests.service_code', '=', 'services.code')
->leftJoin('members', 'claims.member_id', '=', 'members.id')
->select('claims.id AS claim_id','claim_history_cares.admission_date','claim_history_cares.discharge_date','claim_requests.code AS claim_code','services.name AS service_type','claims.status AS claim_status','members.member_id',)
->where("claims.member_id", "=", $memberDetail->id)
->where("claim_requests.claim_id", "!=",null)
->orderBy("claims.created_at", "desc")
$claimList = DB::table('request_logs')
->leftJoin('services', 'services.code', '=', 'request_logs.service_code')
->leftJoin('members', 'members.id', '=', 'request_logs.member_id')
->select('request_logs.id','request_logs.submission_date AS admission_date','request_logs.discharge_date','request_logs.code','services.name as service_name','request_logs.status','members.name',)
->where('request_logs.service_code', 'IP')
->where('request_logs.status_final_log', 'approved')
->where("request_logs.member_id", "=", $memberDetail->id)
->orderBy("request_logs.created_at", "desc")
->get();
return response()->json([

View File

@@ -0,0 +1,141 @@
<?php
namespace Modules\Internal\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Models\RequestLogBenefit;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\DB;
class RequestLogBenefitController extends Controller
{
public function index(Request $request)
{
}
/**
* Show the form for creating a new resource.
* @return Renderable
*/
public function create()
{
return view('internal::create');
}
/**
* Show the specified resource.
* @param int $id
* @return Renderable
*/
public function show($id)
{
}
/**
* Store a newly created resource in storage.
* @param Request $request
* @return Renderable
*/
public function store(Request $request)
{
$customMessages = [
'required' => '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();
}
}

View File

@@ -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,9 +299,21 @@ 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);
$status = $request->status ?? 'requested';
// Update Request LOG untuk lanjut ke Final LOG
$requestLog->final_log = 1;
$requestLog->status_final_log = $status;
$requestLog->save();
if ($request->hasFile('result_files')) {
foreach ($request->result_files as $file) {
@@ -335,7 +353,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 +363,7 @@ class RequestLogController extends Controller
return response()->json([
'error' => false,
'message' => 'Update succses',
'data' => $updateClaimRequest],
'data' => $requestLog],
200);
}

View File

@@ -0,0 +1,136 @@
<?php
namespace Modules\Internal\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Models\RequestLogMedicine;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\DB;
class RequestLogMedicineController extends Controller
{
public function index(Request $request)
{
}
/**
* Show the form for creating a new resource.
* @return Renderable
*/
public function create()
{
return view('internal::create');
}
/**
* Show the specified resource.
* @param int $id
* @return Renderable
*/
public function show($id)
{
}
/**
* Store a newly created resource in storage.
* @param Request $request
* @return Renderable
*/
public function store(Request $request)
{
$customMessages = [
'required' => 'Kolom :attribute wajib diisi.',
'numeric' => 'Kolom :attribute harus berupa angka.',
];
$validator = Validator::make($request->all(), [
'medicine' => 'required|array',
'medicine.*' => 'required',
], $customMessages);
if ($validator->fails()) {
return Helper::responseJson([],'error', 400, $validator->errors());
} else {
$medicine = $request->medicine;
if (count($medicine)>0){
// BeginTransaction
DB::beginTransaction();
foreach($medicine as $key => $value){
$data = [
'request_log_id' => $value['request_log_id'],
'medicine' => $value['medicine_name'],
'price' => $value['medicine_price'],
];
// Insert Data
try {
RequestLogMedicine::create($data);
} catch (\Throwable $th) {
DB::rollBack();
return Helper::responseJson(status: 'failed', statusCode: 500, message: $th->getMessage());
}
}
DB::commit();
return Helper::responseJson(status: 'success', statusCode: 201, message: 'success', data: $request->toArray());
};
}
$requestLogMedicine = RequestLogMedicine::insert($data);
return $requestLogMedicine;
}
/**
* Show the form for editing the specified resource.
* @param int $id
* @return Renderable
*/
public function edit($id)
{
return view('internal::edit');
}
/**
* Update the specified resource in storage.
* @param Request $request
* @param int $id
* @return Renderable
*/
public function update(Request $request, $id)
{
$requestLogBenefit = requestLogBenefit::findOrFail($id);
$requestLogBenefit->amount_approved = $request->amount_approved;
$requestLogBenefit->amount_incurred = $request->amount_incurred;
$requestLogBenefit->amount_not_approved = $request->amount_not_approved;
$requestLogBenefit->excess_paid = $request->excess_paid;
$requestLogBenefit->keterangan = $request->keterangan;
$requestLogBenefit->save();
return response()->json([
'error' => false,
'message' => 'Update succses',
'data' => $requestLogBenefit],
200);
}
/**
* Remove the specified resource from storage.
* @param int $id
* @return Renderable
*/
public function destroy($id)
{
$RequestLogMedicine = RequestLogMedicine::findOrFail($id);
$RequestLogMedicine->delete();
}
}

View File

@@ -7,8 +7,10 @@ use Modules\Internal\Http\Controllers\Api\AppointmentController;
use Modules\Internal\Http\Controllers\Api\BenefitController;
use Modules\Internal\Http\Controllers\Api\CityController;
use Modules\Internal\Http\Controllers\Api\ClaimController;
use Modules\Internal\Http\Controllers\Api\RequestLogController;
use Modules\Internal\Http\Controllers\Api\ClaimRequestController;
use Modules\Internal\Http\Controllers\Api\RequestLogController;
use Modules\Internal\Http\Controllers\Api\RequestLogBenefitController;
use Modules\Internal\Http\Controllers\Api\RequestLogMedicineController;
use Modules\Internal\Http\Controllers\Api\CorporateBenefitController;
use Modules\Internal\Http\Controllers\Api\CorporateController;
use Modules\Internal\Http\Controllers\Api\CorporateFormulariumController;
@@ -251,12 +253,23 @@ 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']);
// insert medicine
Route::post('customer-service/request/medicine-data', [RequestLogMedicineController::class, 'store']);
Route::delete('customer-service/request/medicine-data/{id}', [RequestLogMedicineController::class, 'destroy']);
Route::put('customer-service/request/medicine-data/{id}', [RequestLogMedicineController::class, 'update']);
Route::get('search-organizations', [OrganizationController::class, 'searchOrganization']);
Route::get('search-specialities', [SpecialityController::class, 'searchSpeciality']);
Route::resource('organizations', OrganizationController::class);

View File

@@ -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,

View File

@@ -0,0 +1,93 @@
<?php
namespace Modules\Internal\Transformers;
use App\Models\Benefit;
use App\Models\CorporateBenefit;
use App\Models\ClaimRequest;
use App\Models\CorporateService;
use App\Models\RequestLogBenefit;
use App\Models\RequestLogMedicine;
use App\Models\Exclusion;
use App\Models\Icd;
use App\Helpers\Helper;
use Illuminate\Http\Resources\Json\JsonResource;
class RequestLogShowResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
{
$requestLog = parent::toArray($request);
$corporateId = $requestLog['member']['current_plan']['corporate_id'] ?? 0;
$benefit = CorporateBenefit::with('benefit')->where('plan_id', $corporateId)->get()->toArray();
$benefitDetailLog = RequestLogBenefit::with('benefit')->where('request_log_id', $requestLog['id'])->get()->toArray();
$medicineDetailLog = RequestLogMedicine::where('request_log_id', $requestLog['id'])->get()->toArray();
$benefitData = [];
if (count($benefit)){
foreach($benefit as $data){
array_push($benefitData, $data['benefit']);
}
}
// Medicine
$medicineData = [];
if (count($medicineDetailLog)){
foreach($medicineDetailLog as $data){
array_push($medicineData, $data);
}
}
// Service Rule
$corporateService = CorporateService::query()
->where('corporate_id', $corporateId)
->where('service_code', $requestLog['service_code'])
->with(['configs'])
->first();
$config = [];
if ($corporateService) {
$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,
'medicine' => $medicineData,
'files' => $requestLog['files'],
];
return $data;
}
}

View File

@@ -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 [

View File

@@ -27,7 +27,8 @@ class ClaimRequest extends Model
'status',
'claim_id',
'organization_id',
'code'
'code',
'request_log_id'
];
protected $hidden = [

View File

@@ -19,6 +19,8 @@ class File extends Model
'original_name',
'extension',
'path',
'created_by',
'updated_by',
];
protected $hidden = [
@@ -44,7 +46,11 @@ 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/',
'additional-files' => 'additional-files/',
];
public function fileable()
@@ -54,7 +60,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)

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class OrganizationUser extends Model
{
use HasFactory;
protected $table = 'organization_user';
protected $connection = 'mysql';
protected $fillable = [
'organization_id',
];
public function organization(){
return $this->hasOne(Organization::class, 'id', 'organization_id');
}
}

View File

@@ -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',

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class RequestLogBenefit extends Model
{
use HasFactory;
protected $table = 'request_log_benefits';
public $fillable = [
'request_log_id',
'benefit_id',
'amount_incurred',
'amount_approved',
'amount_not_approved',
'excess_paid',
'keterangan',
];
public function benefit(){
return $this->belongsTo(Benefit::class, 'benefit_id', 'id');
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class RequestLogMedicine extends Model
{
use HasFactory;
public $fillable = [
'request_log_id',
'medicine',
'price',
];
protected $hidden = [
'created_at',
'updated_at',
'deleted_at',
'created_by',
'updated_by',
'deleted_by',
];
public function benefit(){
return $this->belongsTo(Benefit::class, 'benefit_id', 'id');
}
}

View File

@@ -105,4 +105,9 @@ class User extends Authenticatable
{
return $this->morphMany(NotificationToken::class, 'notifiabletoken');
}
public function getOrganization()
{
return $this->hasOne(OrganizationUser::class, 'user_id');
}
}

View File

@@ -20,7 +20,7 @@ use Str;
class ClaimRequestService{
public static function storeClaimRequest($row = null, $code, $member, $paymentType, $serviceCode, $submissionDate = null, $status = 'requested', $organization_code = null)
public static function storeClaimRequest($row = null, $code, $member, $paymentType, $serviceCode, $requestLogID, $submissionDate = null, $status = 'requested', $organization_code = null)
{
// try {
$organization = False;
@@ -38,6 +38,7 @@ class ClaimRequestService{
$claimRequestData = [
'code' => $code,
'request_log_id' => $requestLogID,
'member_id' => $member->id,
'submission_date' => $submissionDate ?? now(),
'status' => $status,

View File

@@ -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;
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->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');
});
}
};

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('request_logs', function (Blueprint $table) {
$table->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');
});
}
};

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('request_logs', function (Blueprint $table) {
$table->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');
});
}
};

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('organization_user', function (Blueprint $table) {
$table->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');
}
};

View File

@@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('request_log_benefits', function (Blueprint $table) {
$table->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');
}
};

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('request_log_medicines', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->foreignId('request_log_id');
$table->integer('price');
$table->string('medicine');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('request_log_medicines');
}
};

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('request_logs', function (Blueprint $table) {
$table->dateTime('discharge_date')->after('submission_date')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('request_logs', function (Blueprint $table) {
$table->dropColumn('discharge_date');
});
}
};

View File

@@ -13,9 +13,10 @@ return new class extends Migration
*/
public function up()
{
Schema::create('claim_daily_monitoring', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('claim_id');
Schema::create('request_log_daily_monitorings', function (Blueprint $table) {
$table->id();
$table->foreignId('request_log_id');
$table->timestamps();
$table->text('subject');
$table->decimal('body_temperature', 11, 2);
$table->decimal('respiration_rate', 11, 2);
@@ -23,7 +24,9 @@ return new class extends Migration
$table->decimal('diastole', 11, 2);
$table->text('analysis');
$table->text('complaints');
$table->timestamps();
$table->dateTime('lab_date')->nullable();
$table->string('provider')->nullable();
$table->string('examination')->nullable();
});
}
@@ -34,6 +37,6 @@ return new class extends Migration
*/
public function down()
{
Schema::dropIfExists('claim_daily_monitoring');
Schema::dropIfExists('request_log_daily_monitorings');
}
};

View File

@@ -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;

View File

@@ -22,4 +22,5 @@ export type Member = {
active: string,
current_plans: Plan,
current_corporate: Corporate,
full_name: string,
};

View File

@@ -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|null;
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
</IconButton>
</Stack>
</DialogTitle>
<DialogContent sx={{ backgroundColor: '#F9FAFB' }}>
{content ? content : 'Testing Content Dialog'}
</DialogContent>
{action ? (
<DialogActions> {action} </DialogActions>
) : ''}
</Dialog>
);
};

View File

@@ -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' },
],
},
{

View File

@@ -37,7 +37,7 @@ export default function ClaimListRow ({ ...props }: Props) {
<TableRow hover sx={{ '& > td': { borderBottom: '1' } }}>
<TableCell align="left" />
<TableCell align="left">
{props.row.admission_date == "0000-00-00 00:00:00" ?
{props.row.admission_date == null?
('-')
:
(
@@ -50,7 +50,7 @@ export default function ClaimListRow ({ ...props }: Props) {
)}
</TableCell>
<TableCell align="left">
{props.row.discharge_date == "0000-00-00 00:00:00" ?
{props.row.discharge_date == null ?
('-')
:
(
@@ -62,9 +62,29 @@ export default function ClaimListRow ({ ...props }: Props) {
</Label>
)}
</TableCell>
<TableCell align="left">{props.row.claim_code}</TableCell>
<TableCell align="left">{props.row.service_type}</TableCell>
<TableCell align="left">{props.row.claim_status}</TableCell>
<TableCell align="left">{props.row.code}</TableCell>
<TableCell align="left">{props.row.service_name}</TableCell>
<TableCell align="left">
{props.row.discharge_date == null ?
(
<Label
variant="ghost"
color="warning"
>
On Monitor
</Label>
) :
(
<Label
variant="ghost"
color="success"
>
Close Monitor
</Label>
)
}
</TableCell>
<TableCell align="right" onClick={(e) => e.stopPropagation()}>
<Stack direction="row" justifyContent="flex-end" spacing={1}>
<TableMoreMenu actions={

View File

@@ -52,6 +52,8 @@ export default function DailyMonitoringList() {
<TableCell style={TableHeadStyle} align="left" width={'*'}>Name</TableCell>
<TableCell style={TableHeadStyle} align="left" width={160}>Start Date</TableCell>
<TableCell style={TableHeadStyle} align="left" width={160}>End Date</TableCell>
<TableCell style={TableHeadStyle} align="left" width={160}>Admission Date</TableCell>
<TableCell style={TableHeadStyle} align="left" width={160}>Provider</TableCell>
<TableCell align="left" width={"10"} />
</TableRow>
</TableHead>

View File

@@ -53,6 +53,15 @@ export default function DailyMonitoringListRow ({ ...props }: Props) {
{fDate(props.row.enddate)}
</Label>
</TableCell>
<TableCell align="left">
<Label
variant="ghost"
color="default"
>
{fDate(props.row.addmision_date)}
</Label>
</TableCell>
<TableCell align="left">{props.row.provider}</TableCell>
<TableCell align="right" onClick={(e) => e.stopPropagation()}>
<Stack direction="row" justifyContent="flex-end" spacing={1}>
<TableMoreMenu actions={

View File

@@ -6,6 +6,8 @@ export type DailyMonitoringListType = {
name : string,
startdate : string,
enddate : string,
addmision_date : string,
provider : string
}
/**

View File

@@ -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 = 'Inpatient Monitoring';
return (
<Page title={ pageTitle } sx={{ mx: 2}}>
<HeaderBreadcrumbs
heading={ pageTitle }
links={[
{ name: 'Dashboard', href: '/dashboard' },
{
name: 'Inpatient Monitoring',
href: '/inpatient_monitoring',
},
]}
/>
{/* <Stack> */}
<List />
{/* </Stack> */}
</Page>
);
}

View File

@@ -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 '../../CustomerService/FinalLog/Model/Types';
// import LoadingButton from '@/theme/overrides/LoadingButton';
export default function List() {
const { themeColorPresets } = useSettings();
const [searchParams, setSearchParams] = useSearchParams();
const [importResult, setImportResult] = useState<Import>(null);
const navigate = useNavigate()
function SearchInput(props: any) {
// SEARCH
const searchInput = useRef<HTMLInputElement>(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 (
<form onSubmit={handleSearchSubmit} style={{ width: '100%' }}>
<TextField
id="search-input"
ref={searchInput}
label="Search"
variant="outlined"
fullWidth
onChange={handleSearchChange}
value={searchText}
placeholder='Search Code or Name...'
/>
</form>
);
}
function ImportForm(props: any) {
// IMPORT
// Create Button Menu
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const createMenu = Boolean(anchorEl);
const importForm = useRef<HTMLInputElement>(null);
const [currentImportFileName, setCurrentImportFileName] = useState(null);
const [importLoading, setImportLoading] = useState(false);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
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 (
<div>
<input
type="file"
id="file"
ref={importForm}
style={{ display: 'none' }}
onChange={handleImportChange}
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain"
/>
{!currentImportFileName && (
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
<SearchInput onSearch={applyFilter} />
<Button
variant="outlined"
startIcon={<UploadIcon />}
sx={{ p: 1.8 }}
onClick={handleClick}
>
Import
</Button>
<Menu
id="import-button"
anchorEl={anchorEl}
open={createMenu}
onClose={handleClose}
MenuListProps={{
'aria-labelledby': 'basic-button',
}}
>
<MenuItem onClick={handleImportButton}>Import</MenuItem>
<MenuItem onClick={() => {handleGetTemplate('claim-request')}}>Download Template</MenuItem>
<MenuItem onClick={() => {handleGetData('data-plan-benefit')}}>Download Claim Request</MenuItem>
</Menu>
{/* <Button
variant="contained"
startIcon={<AddIcon />}
sx={{ p: 1.8 }}
onClick={() => {
navigate('/claim-requests/create');
}}
>
Create
</Button> */}
</Stack>
)}
{currentImportFileName && (
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
<ButtonGroup variant="outlined" aria-label="outlined button group" fullWidth>
<Button onClick={handleImportButton} fullWidth>
{currentImportFileName ?? 'No File Selected'}
</Button>
<Button
onClick={handleCancelImportButton}
size="small"
fullWidth={false}
sx={{ p: 1.8 }}
>
<CancelIcon color="error" />
</Button>
</ButtonGroup>
<LoadingButton
id="upload-button"
variant="outlined"
startIcon={<UploadIcon />}
sx={{ p: 1.8 }}
onClick={handleUpload}
loading={importLoading}
>
Upload
</LoadingButton>
</Stack>
)}
{importResult && (
<Stack direction={'row'} sx={{ px: 2, pb: 2 }}>
<Box sx={{ color: 'text.secondary' }}>
Last Import Result Report :{' '}
<a href={importResult.result_file?.url ?? '#'}>
{importResult.result_file?.name ?? '-'}
</a>
</Box>
</Stack>
)}
</div>
);
}
// Dummy Default Data
const [dataTableIsLoading, setDataTableLoading] = useState(true);
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>(
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<typeof createData> }) {
const { row } = props;
const [open, setOpen] = React.useState(false);
const [loadingApprove, setLoadingApprove] = React.useState(false);
return (
<React.Fragment>
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
{/* <TableCell>
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
</IconButton>
</TableCell> */ }
{/* <TableCell align="left">
<Typography
// onClick={() => {
// handleShowClaim(row);
// }}
>
{row.id}
</Typography>
</TableCell> */}
<TableCell align="left">{row.code}</TableCell>
<TableCell align="left">{row.member_name}</TableCell>
<TableCell align="left"><Label>{fDateTimesecond(row.submission_date)}</Label></TableCell>
<TableCell align="left">{row.service_name}</TableCell>
<TableCell align="left">{row.payment_type_name}</TableCell>
<TableCell align="left">
{ row.status_final_log == "requested" ?
(<Label variant='ghost' color='primary'>{capitalizeFirstLetter(row.status_final_log)}</Label>) :
row.status_final_log == "declined" ?
(<Label color='error'> {capitalizeFirstLetter(row.status_final_log)}</Label>)
:
(<Label color='success'> {capitalizeFirstLetter(row.status_final_log)}</Label>)
}
</TableCell>
<TableCell align="right">
<TableMoreMenu actions={
<>
{/* <MenuItem onClick={() => navigate(`/claim-requests/edit/${row.id}`)}>
<EditOutlinedIcon />
Edit
</MenuItem> */}
<MenuItem onClick={() => navigate ('/custormer-service/final-log/detail/'+row.id+'')}>
<FindInPageOutlinedIcon />
Detail
</MenuItem>
</>
} />
</TableCell>
{/* <TableCell>
<IconButton
onClick={() => {
handleShowClaim(row);
}}
>
<Iconify icon="eva:eye-fill" />
</IconButton>
</TableCell> */}
</TableRow>
{/* COLLAPSIBLE ROW */}
<TableRow>
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={99}>
<Collapse in={open} timeout="auto" unmountOnExit>
<Box sx={{ borderBottom: 1 }}>
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2 }}
>
<Box>
<Typography fontWeight={600}>Berkas Hasil Penunjang</Typography>
{/* {row.files_by_type?.claim_kondisi &&
row.files_by_type?.claim_kondisi.map((file, index) => (
<Stack direction="row" key={index}>
<Typography sx={{ marginRight: 2 }}>-</Typography>{' '}
<a href={file.url} target="_blank">
{file.name}
</a>
</Stack>
))} */}
{row.files_by_type?.claim_kondisi && (
<>
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Kondisi</Typography>
{row.files_by_type?.claim_kondisi.map((file, index) => (
<Stack direction="row" key={index}>
<a href={file.url} target="_blank">
{file.name}
</a>
</Stack>
))}
</>
)}
{row.files_by_type?.claim_diagnosis && (
<>
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Diagnosa</Typography>
{row.files_by_type?.claim_diagnosis.map((file, index) => (
<Stack direction="row" key={index}>
<a href={file.url} target="_blank">
{file.name}
</a>
</Stack>
))}
</>
)}
{row.files_by_type?.claim_result && (
<>
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Hasil</Typography>
{row.files_by_type?.claim_result.map((file, index) => (
<Stack direction="row" key={index}>
<a href={file.url} target="_blank">
{file.name}
</a>
</Stack>
))}
</>
)}
{(!row.files_by_type?.claim_result && !row.files_by_type?.claim_diagnosis && !row.files_by_type?.claim_kondisi)&& <Typography>Tidak ada berkas</Typography>}
</Box>
</Stack>
</Box>
</Collapse>
</TableCell>
</TableRow>
</React.Fragment>
);
}
{
/* ------------------ END TABLE ROW ------------------ */
}
function TableContent() {
return (
<Table aria-label="collapsible table">
{/* ------------------ TABLE HEADER ------------------ */}
<TableHead>
<TableRow>
{/* <TableCell style={headStyle} align="left" /> */}
{/* <TableCell style={headStyle} align="left">
ID Request LOG
</TableCell> */}
<TableCell style={headStyle} align="left">
Code
</TableCell>
<TableCell style={headStyle} align="left">
Name
</TableCell>
<TableCell style={headStyle} align="left">
Date of Submission
</TableCell>
<TableCell style={headStyle} align="left">
Service Type
</TableCell>
<TableCell style={headStyle} align="left">
Claim Method
</TableCell>
<TableCell style={headStyle} align="left">
Status
</TableCell>
<TableCell style={headStyle} align="right"></TableCell>
</TableRow>
</TableHead>
{/* ------------------ END TABLE HEADER ------------------ */}
{/* ------------------ TABLE ROW ------------------ */}
{dataTableIsLoading ? (
<TableBody>
<TableRow>
<TableCell colSpan={8} align="center">
Loading
</TableCell>
</TableRow>
</TableBody>
) : dataTableData.data.length === 0 ? (
<TableBody>
<TableRow>
<TableCell colSpan={8} align="center">
No Data
</TableCell>
</TableRow>
</TableBody>
) : (
<TableBody>
{dataTableData.data.map((row) => (
<Row key={row.id} row={row} />
))}
</TableBody>
)}
{/* ------------------ END TABLE ROW ------------------ */}
</Table>
);
}
// ---------------------------------------------------------
// 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 (
<Grid container>
<Grid item sm={12}>
<ImportForm />
</Grid>
<Grid item sm={12}>
<DataTable
isLoading={dataTableIsLoading}
lastRequest={0}
data={dataTableData}
handlePageChange={handlePageChange}
TableContent={<TableContent />}
/>
</Grid>
<Grid item sm={12}>
<DialogDetailClaim
openDialog={openDialogDetailClaim}
setOpenDialog={setOpenDialogDetailClaim}
title={{ name: 'Claim Request Detail' }}
data={{ claim: currentClaim, isLoading: loadingClaimDetail, handleDownloadLog }}
></DialogDetailClaim>
</Grid>
</Grid>
);
}

View File

@@ -687,7 +687,7 @@ export default function List(props: any) {
</Grid>
<Grid item xs={3}>
<Typography variant="body1" component="div" color={'GrayText'}>
Play :
Plan :
</Typography>
</Grid>
<Grid item xs={9} sx={{display: 'flex', gap: 1}}>

View File

@@ -0,0 +1,214 @@
import { Card, Grid, MenuItem, Typography } from "@mui/material";
import { Stack } from '@mui/material';
import { BenefitData, DetailFinalLogType } from "../FinalLog/Model/Types";
import { useEffect, useState, useRef, useMemo } from 'react';
import { Box } from "@mui/material";
import { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime";
import Label from '@/components/Label';
import AddIcon from '@mui/icons-material/Add';
import { Button } from "@mui/material";
import MoreMenu from "@/components/MoreMenu";
import { Delete, EditOutlined } from "@mui/icons-material";
import { fNumber } from "@/utils/formatNumber";
import palette from "@/theme/palette";
import DialogBenefit from "../FinalLog/Components/DialogBenefit";
import DialogEditBenefit from "../FinalLog/Components/DialogEditBenefit";
import DialogDelete from "../FinalLog/Components/DialogDelete";
type CardDetail = {
requestLog: DetailFinalLogType|undefined;
}
const style1 = {
color: '#919EAB',
width: '30%'
}
const style2 = {
width: '70%'
}
const marginBottom1 = {
marginBottom: 1,
}
const marginBottom2 = {
marginBottom: 2,
}
const [openDialogBenefit, setDialogBenefit] = useState(false);
// Handle Edit Detail Benefit
const [openDialogEditBenefit, setDialogEditBenefit] = useState(false)
const [BenefitConfigurationData, setBenefitConfigurationData] = useState<BenefitData>();
// Handel Delete Detail Benefit
const [idBenefitData, setIdBenefitData] = useState<number>();
const [openDialogDeleteBenefit, setDialogDeleteBenefit] = useState(false)
export default function CardBenefit({requestLog} : CardDetail ) {
return (
<Card sx={{padding:2}} >
<Stack direction="row" alignItems="center" sx={{marginBottom: 4}}>
<Typography variant='subtitle1' sx={{color: '#19BBBB'}} gutterBottom>Benefit</Typography>
<Button variant="outlined" startIcon={<AddIcon/>} sx={{marginLeft: 'auto'}} onClick={() => {
setDialogBenefit(true);
}} >
<Typography variant="button" display="block">Benefit</Typography>
</Button>
</Stack>
{requestLog?.benefit_data?.map((item, index) => (
<Box key={index} sx={{ border: '1px solid rgba(0,0,0,0.125)', px: '24px', py: '20px', marginBottom: '24px', borderRadius: '12px'}}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={6}>
<Typography variant="body2" sx={{ fontWeight: 'bold'}}>
{item.benefit?.description}
</Typography>
</Grid>
<Grid item xs={6} sx={{ display: 'flex', placeContent: 'end' }}>
<MoreMenu actions={
<>
<MenuItem onClick={() => {
setDialogEditBenefit(true)
setIdBenefitData(item.id)
setBenefitConfigurationData(item)
}}
>
<EditOutlined />
Edit
</MenuItem>
<MenuItem onClick={() => {
setIdBenefitData(item.id)
setDialogDeleteBenefit(true)
}}
>
<Delete color='error'/>
Delete
</MenuItem>
</>
} />
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Box sx={{ py: '8px', px: '12px', background: palette.light.grey[50012], borderRadius: '6px'}}>
<Grid container spacing={1}>
{/* Amount Incurred */}
<Grid item xs={2}>
<Grid container sx={{ borderRight: `0.5px solid ${palette.light.grey[400]}` }}>
<Grid item xs={12}>
<Typography variant="caption">
Amount Incurred
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
{fNumber(item.amount_incurred)}
</Typography>
</Grid>
</Grid>
</Grid>
{/* Amount Approved */}
<Grid item xs={2}>
<Grid container sx={{ borderRight: `0.5px solid ${palette.light.grey[400]}` }}>
<Grid item xs={12}>
<Typography variant="caption">
Amount Approved
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
{fNumber(item.amount_approved)}
</Typography>
</Grid>
</Grid>
</Grid>
{/* Amount Not Approved */}
<Grid item xs={3}>
<Grid container sx={{ borderRight: `0.5px solid ${palette.light.grey[400]}` }}>
<Grid item xs={12}>
<Typography variant="caption">
Amount Not Approved
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
{fNumber(item.amount_not_approved)}
</Typography>
</Grid>
</Grid>
</Grid>
{/* Excess Paid* */}
<Grid item xs={2}>
<Grid container sx={{ borderRight: `0.5px solid ${palette.light.grey[400]}` }}>
<Grid item xs={12}>
<Typography variant="caption">
Excess Paid*
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
{fNumber(item.excess_paid)}
</Typography>
</Grid>
</Grid>
</Grid>
{/* Keterangan* */}
<Grid item xs={3}>
<Grid container>
<Grid item xs={12}>
<Typography variant="caption">
Keterangan*
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
{item.keterangan}
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Box>
</Grid>
</Grid>
</Box>
))}
<DialogBenefit
requestLog={requestLog}
openDialog={openDialogBenefit}
setOpenDialog={setDialogBenefit}
/>
{/* Dialog Edit */}
<DialogEditBenefit
id={idBenefitData}
data={BenefitConfigurationData}
openDialog={openDialogEditBenefit}
setOpenDialog={setDialogEditBenefit}
>
</DialogEditBenefit>
{/* Dialog Delete */}
<DialogDelete
id={idBenefitData}
openDialog={openDialogDeleteBenefit}
setOpenDialog={setDialogDeleteBenefit}
/>
</Card>
)
}

View File

@@ -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 (
<Card sx={{padding:2}} >
<Typography variant='subtitle1' sx={{color: '#19BBBB', marginBottom: 4}} gutterBottom>Detail</Typography>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Member ID</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.member_id}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Policy Number</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.policy_number}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Name</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.name}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Date Of Birth</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.date_of_birth ? fDate(requestLog?.date_of_birth) : '-'}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Marital Status</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.marital_status}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Submission Date</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : '-'}</Typography>
</Stack>
</Card>
)
}

View File

@@ -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 (
<Card sx={{padding:2}} >
<Typography variant='subtitle1' sx={{color: '#19BBBB', marginBottom: 4}} gutterBottom>Exclusion</Typography>
{requestLog?.exclusion?.length > 0 ? requestLog?.exclusion.map((r, index) => (
<Accordion>
<AccordionSummary
expandIcon={<ExpandMore />}
aria-controls='panelia-content'
id='panel1a-header'
>
<Typography variant='subtitle1'>{r.exclusionable.code}</Typography>
<Typography variant='subtitle1' sx={{marginLeft:3}}>{r.exclusionable.name}</Typography>
</AccordionSummary>
<AccordionDetails>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>MSC</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>
{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 (
<Label key={j} sx={{marginLeft:1}}>{labelMSC}</Label>
);
})
: null;
})}
</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Gender</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>
{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 (
<Label key={j} sx={{marginLeft:1}}>{labelGender}</Label>
);
})
: null;
})}
</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Min Age</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>
{r.rules.length > 0 && r?.rules?.map((text, i) => {
return text.name === 'min_age' ?
<Typography variant='subtitle1'> {text.values} </Typography> : null
})}
</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Max Age</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>
{r.rules.length > 0 && r?.rules?.map((text, i) => {
return text.name === 'max_age' ?
<Typography variant='subtitle1'> {text.values} </Typography> : null
})}
</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Plan</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>
{r.rules.length > 0 && r?.rules?.map((text, i) => {
return text.name === 'plan' ?
<Typography variant='subtitle1'> {text.values} </Typography> : null
})}
</Typography>
</Stack>
</AccordionDetails>
</Accordion>
)) : null}
</Card>
)
}

View File

@@ -0,0 +1,50 @@
import { Card, Typography } from "@mui/material";
import { Stack } from '@mui/material';
import { DetailFinalLogType } from "../FinalLog/Model/Types";
import { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime";
type CardDetail = {
requestLog: DetailFinalLogType|undefined;
}
const style1 = {
color: '#919EAB',
width: '30%'
}
const style2 = {
width: '70%'
}
const marginBottom1 = {
marginBottom: 1,
}
const marginBottom2 = {
marginBottom: 2,
}
export default function CardFile({requestLog} : CardDetail ) {
return (
<Card sx={{padding:2}} >
<Stack direction="row" alignItems="center" sx={{marginBottom: 4}}>
<Stack direction="column" spacing={2} sx={{marginBottom: 2}}>
<Typography variant='subtitle1' sx={{color: '#19BBBB'}} gutterBottom>Files History</Typography>
{requestLog?.files?.map((documentType, index) => (
<Stack direction="column" spacing={2} key={index}>
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
<a
href={documentType.url}
style={{ cursor: 'pointer', textDecoration: 'none', color: '#19BBBB' }}
target="_blank"
>
<Typography variant="body2" gutterBottom>{documentType.original_name ? documentType.original_name : '-'}</Typography>
</a>
</Stack>
</Stack>
))}
</Stack>
</Stack>
</Card>
)
}

View File

@@ -0,0 +1,65 @@
import { Card, Grid, Typography } from "@mui/material";
import { Stack } from '@mui/material';
import { DetailFinalLogType } from "../FinalLog/Model/Types";
import { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime";
import DialogMedicine from "../FinalLog/Components/DialogMedicine";
import { fNumber } from "@/utils/formatNumber";
import { Button } from '@mui/material';
import AddIcon from '@mui/icons-material/Add';
import { useState } from "react";
type CardDetail = {
requestLog: DetailFinalLogType|undefined;
}
const style1 = {
color: '#919EAB',
width: '30%'
}
const style2 = {
width: '70%'
}
const marginBottom1 = {
marginBottom: 1,
}
const marginBottom2 = {
marginBottom: 2,
}
const [openDialogMedicine, setDialogMedicine] = useState(false);
export default function CardMedicine({requestLog} : CardDetail ) {
return (
<Card sx={{padding:2}} >
<Stack direction="row" alignItems="center" sx={{marginBottom: 4}}>
<Typography variant='subtitle1' sx={{color: '#19BBBB'}} gutterBottom>Medicine</Typography>
<Button variant="outlined" startIcon={<AddIcon/>} sx={{marginLeft: 'auto'}} onClick={() => {
setDialogMedicine(true)
}} >
<Typography variant="button" display="block">Medicine</Typography>
</Button>
</Stack>
{requestLog?.medicine.map((item, index) => (
<Grid
container
direction="row"
alignItems="center"
justifyContent="space-between" // Menempatkan item ke sebelah kiri dan kanan
sx={{ marginBottom: 2 }}
>
<Typography variant='subtitle1'>{item.medicine}</Typography>
<Typography variant="subtitle1">Rp. {fNumber(item.price)}</Typography>
</Grid>
))}
{/* <DialogMedicine
requestLog={requestLog}
openDialog={openDialogMedicine}
setOpenDialog={setDialogMedicine}
/> */}
</Card>
)
}

View File

@@ -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 (
<Card sx={{padding:2}} >
<Typography variant='subtitle1' sx={{color: '#19BBBB', marginBottom: 4}} gutterBottom>Service</Typography>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Service Type</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.service_type}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Claim Method</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{toTitleCase(requestLog?.claim_method ?? '-')}</Typography>
</Stack>
{/* <Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={{width:'35%', color: '#919EAB'}} gutterBottom>Benefit</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>
<ul>
{requestLog?.benefit.length > 0 ? requestLog?.benefit.map((r, index) => (
<li key={index}>{r.code } - {r.description}</li>
)) : <li>-</li>}
</ul>
</Typography>
</Stack> */}
{/* General Practitioner */}
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>General Practitioner</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>External Doctor :
{requestLog?.config_service?.gp_external_doctor_online == '1' ? (<Label sx={{marginLeft:2}}> Online</Label>) : '-'}
{requestLog?.config_service?.gp_external_doctor_offline == '1' ? (<Label sx={{marginLeft:1}}> Offfline</Label>) : '-'}
</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom></Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>Internal Doctor :
{requestLog?.config_service?.gp_internal_doctor_online == '1' ? (<Label sx={{marginLeft:2}}> Online</Label>) : '-'}
{requestLog?.config_service?.gp_internal_doctor_offline == '1' ? (<Label sx={{marginLeft:1}}> Offfline</Label>) : '-'}
</Typography>
</Stack>
{/* Specialist Practitioner */}
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Specialist Practitioner</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>External Doctor :
{requestLog?.config_service?.sp_external_doctor_online == '1' ? (<Label sx={{marginLeft:2}}> Online</Label>) : '-'}
{requestLog?.config_service?.sp_external_doctor_offline == '1' ? (<Label sx={{marginLeft:1}}> Offfline</Label>) : '-'}
</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom></Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>Internal Doctor :
{requestLog?.config_service?.gp_internal_doctor_online == '1' ? (<Label sx={{marginLeft:2}}> Online</Label>) : '-'}
{requestLog?.config_service?.gp_internal_doctor_offline == '1' ? (<Label sx={{marginLeft:1}}> Offfline</Label>) : '-'}
</Typography>
</Stack>
{/* Medicine */}
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={{width:'35%', color: '#919EAB'}} gutterBottom>Medicine</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>
<ul>
{requestLog?.config_service?.vitamins == '1' ? (<li>Suplemen</li>) : (<li>-</li>)}
{requestLog?.config_service?.delivery_fee == '1' ? (<li>Delivery Fee</li>) : (<li>-</li>)}
</ul>
</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Admin Fee</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>
{requestLog?.config_service?.general_practitioner_fee == '1' ? (<Label sx={{marginLeft:2}}> General Practitioner</Label>) : '-'}
{requestLog?.config_service?.specialist_practitioner_fee == '1' ? (<Label sx={{marginLeft:1}}> Specialist Practitioner</Label>) : '-'}
</Typography>
</Stack>
</Card>
)
}

View File

@@ -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<BenefitSelected[]>([]);
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<any>({
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 ? (
<Stack spacing={2} sx={{marginTop: 2, padding: 2}} direction="column">
<Stack direction="row" spacing={2}>
<Stack spacing={2} sx={{width:'100%'}}>
<Typography variant='subtitle1'>Benefit Name*</Typography>
<FormControl>
<InputLabel htmlFor="benefit_name">
Benefit Name
</InputLabel>
<Select
id="benefit_name"
value={valBenefitNames}
fullWidth
label="Benefit Name"
error={!!valBenefitNameError}
onChange={(e) => {
setValBenefitNameError(!valBenefitNames ? 'At least one item must be selected' : '');
}}
renderValue={(selected) => selected.map(value => {
const selectedOption = benefitNameData?.find(option => String(option.id) === value);
return selectedOption ? selectedOption.description : '';
}).join(', ')}
>
{benefitNameData?.map((item, index) => (
<FormGroup key={index} sx={{ marginLeft: 2 }}>
<FormControlLabel
control={
<Checkbox
checked={valBenefitNames.includes(String(item.id))}
onChange={handleConditionChangeService}
value={String(item.id)}
/>
}
label={item.description}
/>
</FormGroup>
))}
</Select>
<FormHelperText style={{ color: 'red' }}>{valBenefitNameError}</FormHelperText>
</FormControl>
</Stack>
</Stack>
</Stack>
) :
(
<FormProvider methods={methods} onSubmit={handleSubmit(submitHandler)}>
<Stack paddingX={2} paddingY={4}>
{/* <Card sx={{padding:2}}> */}
{fields?.map((item, index) =>
(
<Box sx={{ marginTop:'10px', marginBottom:'10px', py: '8px', px: '12px', border:'1px solid #919EAB52', borderRadius: '6px'}}>
<Grid key={item.id} container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" sx={{ fontWeight: 'bold'}}>
{item.description}
</Typography>
</Grid>
<Grid item xs={2.5}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Amount Incurred*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
key={item.id}
id='amount_incurred'
name={`benefit_data.${index}.amount_incurred`}
placeholder='Amount Incurred'
required
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={2.5}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Amount Approved*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
// onChange={() => append({amount_approved: ''}) }
id='amount_approved'
key={item.id}
name={`benefit_data.${index}.amount_approved`}
placeholder='Amount Approved'
required
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={2.5}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Amount Not Approved*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
// onChange={() => append({amount_not_approved: ''}) }
id='amount_not_approved'
key={item.id}
name={`benefit_data.${index}.amount_not_approved`}
placeholder='Amount Not Approved'
required
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={2.5}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Excess Paid*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
// onChange={() => append({excess_paid: ''}) }
id='excess_paid'
key={item.id}
name={`benefit_data.${index}.excess_paid`}
placeholder='Excess Paid'
required
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={2}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Keterangan*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextField
// onChange={() => append({keterangan: ''}) }
id='keterangan'
key={item.id}
name={`benefit_data.${index}.keterangan`}
placeholder='Keterangan'
required
/>
</Grid>
</Grid>
</Grid>
</Grid>
</Box>
))}
{/* </Card> */}
<DialogActions>
<Stack direction="row" sx={{marginTop:3}} alignItems="center" justifyContent="space-between" spacing={2}>
<Button variant="outlined" onClick={handleCloseDialogBenefit}><Typography>Cancel</Typography></Button>
<LoadingButton disabled={!addBenefit} type="submit" variant="contained" loading={isSubmitting}>
Save
</LoadingButton>
</Stack>
</DialogActions>
</Stack>
</FormProvider>
);
const getAction = () => !addBenefit ? (
<Stack direction="row" alignItems="center" justifyContent="space-between" spacing={2}>
<Button variant="outlined" onClick={handleCloseDialogBenefit}><Typography>Cancel</Typography></Button>
<Button variant="contained" onClick={handleAddDialogBenefit}><Typography>Add</Typography></Button>
</Stack>
) : null;
return (
<MuiDialog
title={{name: "Add Benefit"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
action={getAction()}
maxWidth="xl"
/>
);
}

View File

@@ -0,0 +1,110 @@
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,
id: requestLog?.id
}
axios
.post(`customer-service/request/final-log`, formData)
.then((response) => {
enqueueSnackbar('Verification Final LOG Success', { variant: 'success' });
setOpenDialog(false);
navigate('/custormer-service/final-log')
})
.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 = () => (
<Stack spacing={1} marginTop={2}>
<Typography variant="subtitle2">Are you sure to {approve == 'approved' ? 'approve' : 'deciline'} this final log ?</Typography>
<Grid item xs={12} md={12} marginTop={4}>
<Card sx={{padding:2, marginTop:2}} >
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Member ID</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.member_id}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Policy Number</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.policy_number}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Name</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.name}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Submission Date</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : '-'}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Claim Method</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.claim_method ? toTitleCase(requestLog?.claim_method) : '-'}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Service Type</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.service_type}</Typography>
</Stack>
</Card>
</Grid>
<DialogActions>
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialog}>Cancel</Button>
{approve == 'approved' ? (
<Button color="primary" variant="contained" onClick={handleSubmit}>Approve</Button>
) : (
<Button color="error" variant="contained" onClick={handleSubmit}>Decline</Button>
) }
</DialogActions>
</Stack>
);
return (
<MuiDialog
title={{name: "Confirmation"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
maxWidth="xl"
/>
);
}

View File

@@ -0,0 +1,120 @@
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 = () => (
<Stack spacing={1} marginTop={2}>
<Typography variant="subtitle2">Are you sure to delete this detail benefit ?</Typography>
<DialogActions>
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialog}>Cancel</Button>
<Button color="error" variant="contained" onClick={handleSubmit}>Delete</Button>
</DialogActions>
</Stack>
);
return (
<MuiDialog
title={{name: "Delete Benefit"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
maxWidth="xs"
/>
);
}
export function DialogDeleteMedicine({id, setOpenDialog, openDialog,onSubmit} : DialogDeleteType ) {
const handleSubmit = () => {
axios
.delete(`customer-service/request/medicine-data/${id}`)
.then((response) => {
enqueueSnackbar('Benefit Data has Deleted', { variant: 'success' });
setOpenDialog(false);
window.location.reload()
})
.catch(({ response }) => {
enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' });
});
}
const style1 = {
color: '#919EAB',
width: '30%'
}
const style2 = {
width: '70%'
}
const marginBottom1 = {
marginBottom: 1,
}
const handleCloseDialog = () => {
setOpenDialog(false);
}
const getContent = () => (
<Stack spacing={1} marginTop={2}>
<Typography variant="subtitle2">Are you sure to delete this detail medicine ?</Typography>
<DialogActions>
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialog}>Cancel</Button>
<Button color="error" variant="contained" onClick={handleSubmit}>Delete</Button>
</DialogActions>
</Stack>
);
return (
<MuiDialog
title={{name: "Delete Medicine"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
maxWidth="xs"
/>
);
}

View File

@@ -0,0 +1,69 @@
import MuiDialog from "@/components/MuiDialog";
import { Button, Card, Checkbox, DialogActions, Grid, Typography } from "@mui/material";
import { Paper } from "@mui/material";
import { Stack } from '@mui/material';
import React, { useState } from 'react';
import { DetailFinalLogType } from "../Model/Types";
import { fDateTimesecond, toTitleCase } from "@/utils/formatTime";
import axios from "@/utils/axios";
import { enqueueSnackbar } from "notistack";
import { useNavigate } from "react-router";
type DialogDeleteType = {
openDialog: boolean;
setOpenDialog: any;
onSubmit?: void;
id: number|undefined;
}
export default function DialogDeleteMedicine({id, setOpenDialog, openDialog,onSubmit} : DialogDeleteType ) {
const handleSubmit = () => {
axios
.delete(`customer-service/request/medicine-data/${id}`)
.then((response) => {
enqueueSnackbar('Benefit Data has Deleted', { variant: 'success' });
setOpenDialog(false);
window.location.reload()
})
.catch(({ response }) => {
enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' });
});
}
const style1 = {
color: '#919EAB',
width: '30%'
}
const style2 = {
width: '70%'
}
const marginBottom1 = {
marginBottom: 1,
}
const handleCloseDialog = () => {
setOpenDialog(false);
}
const getContent = () => (
<Stack spacing={1} marginTop={2}>
<Typography variant="subtitle2">Are you sure to delete this detail medicine ?</Typography>
<DialogActions>
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialog}>Cancel</Button>
<Button color="error" variant="contained" onClick={handleSubmit}>Delete</Button>
</DialogActions>
</Stack>
);
return (
<MuiDialog
title={{name: "Delete Medicine"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
maxWidth="xs"
/>
);
}

View File

@@ -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|undefined;
}
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<any>({
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 = () => (
<FormProvider methods={methods} onSubmit={handleSubmit(submitHandler)}>
<Stack paddingX={2} paddingY={4}>
{/* <Card sx={{padding:2}}> */}
<Box sx={{ marginTop:'10px', marginBottom:'10px', py: '8px', px: '12px', border:'1px solid #919EAB52', borderRadius: '6px'}}>
<Grid key={id} container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" sx={{ fontWeight: 'bold'}}>
{data?.benefit?.description}
</Typography>
</Grid>
<Grid item xs={2.5}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Amount Incurred*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
key={id}
id='amount_incurred'
name={`amount_incurred`}
placeholder='Amount Incurred'
required
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={2.5}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Amount Approved*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
// onChange={() => append({amount_approved: ''}) }
id='amount_approved'
key={id}
name={`amount_approved`}
placeholder='Amount Approved'
required
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={2.5}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Amount Not Approved*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
// onChange={() => append({amount_not_approved: ''}) }
id='amount_not_approved'
key={id}
name={`amount_not_approved`}
placeholder='Amount Not Approved'
required
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={2.5}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Excess Paid*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
// onChange={() => append({excess_paid: ''}) }
id='excess_paid'
key={id}
name={`excess_paid`}
placeholder='Excess Paid'
required
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={2}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Keterangan*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextField
// onChange={() => append({keterangan: ''}) }
id='keterangan'
key={id}
name={`keterangan`}
placeholder='Keterangan'
required
/>
</Grid>
</Grid>
</Grid>
</Grid>
</Box>
{/* </Card> */}
<DialogActions>
<Stack direction="row" sx={{marginTop:3}} alignItems="center" justifyContent="space-between" spacing={2}>
<Button variant="outlined" onClick={handleCloseDialog}><Typography>Cancel</Typography></Button>
<LoadingButton type="submit" variant="contained" loading={isSubmitting}>
Save
</LoadingButton>
</Stack>
</DialogActions>
</Stack>
</FormProvider>
);
return (
<MuiDialog
title={{name: "Edit Detail Benefit"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
maxWidth="xl"
/>
);
}

View File

@@ -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<DetailFinalLogType> {
taxes: boolean;
inStock: boolean;
}
const onSubmit = async (data: DetailFinalLogType) => {
reset();
}
const methods = useForm<DetailFinalLogType>();
const {
reset,
watch,
control,
setValue,
getValues,
setError,
handleSubmit,
resetField,
formState: { isSubmitting },
} = methods;
const {fields, append, remove} = useFieldArray<FormValuesProps>({name: "secondary_diagnosis_id", control})
const getContent = () => (
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
<Stack spacing={2} sx={{marginTop: 2, padding: 2}}>
<Grid container spacing={2}>
{/* Location */}
<Grid item xs={12}>
<Typography variant='subtitle1' marginBottom={1}>Location*</Typography>
<RHFTextField name="location" label="Location" required placeholder='Location' />
</Grid>
{/* Dokter */}
<Grid item xs={12}>
<Typography variant='subtitle1' marginBottom={1}>Doctor*</Typography>
<RHFTextField name="doctor" label="Doctor" required placeholder='Doctor' />
</Grid>
<Grid item xs={12}>
<Typography variant='subtitle1' marginBottom={1}>Medical Record Number*</Typography>
<RHFTextField name="medical_record_number" label="Medical Record Number" required placeholder='Medical Record Number' />
</Grid>
<Grid item xs={12}>
<Typography variant='subtitle1' marginBottom={1}>Symptoms*</Typography>
<RHFTextField name="symptoms" label="Symptoms" placeholder='Symptoms' required/>
</Grid>
<Grid item xs={12}>
<Typography variant='subtitle1' marginBottom={1}>Sign*</Typography>
<RHFTextField name="sign" label="Sign" placeholder='Sign' required />
</Grid>
<Grid item xs={10.8}>
<Typography variant='subtitle1'>Diagnosis*</Typography>
</Grid>
<Grid item xs={1} justifyContent={'flex-end'}>
{/* <Button variant="outlined" startIcon={<AddIcon/>} sx={{marginLeft: 'auto'}} onClick={() => handleAddSecondaryDiagnosis()}> */}
<Button variant="outlined" startIcon={<AddIcon/>} sx={{marginLeft: 'auto'}} onClick={() => append({value: {name: "", value: 0}})}>
<Typography variant="button" display="block">Diagnosis</Typography>
</Button>
</Grid>
<Grid item xs={12}>
<RHFTextField name="Diagnosis" label="Diagnosis" placeholder='Diagnosis' required />
</Grid>
<Grid item xs={10.7}>
<Typography variant='subtitle1'>Examination and Result*</Typography>
</Grid>
<Grid item xs={1} justifyContent={'flex-end'}>
{/* <Button variant="outlined" startIcon={<AddIcon/>} sx={{marginLeft: 'auto'}} onClick={() => handleAddSecondaryDiagnosis()}> */}
<Button variant="outlined" startIcon={<AddIcon/>} sx={{marginLeft: 'auto'}} onClick={() => append({value: {name: "", value: 0}})}>
<Typography variant="button" display="block">Examination</Typography>
</Button>
</Grid>
<Grid item xs={6}>
<RHFTextField name="examination" label="Examination" placeholder='Examination' required />
</Grid>
<Grid item xs={6}>
<RHFTextField name="result" label="Result" placeholder='Result' required />
</Grid>
<Grid item xs={12}>
<Typography variant='subtitle1' marginBottom={1}>Invoice*</Typography>
<RHFTextField name="invoice" label="Invoice" placeholder='Invoice' required/>
</Grid>
</Grid>
</Stack>
<Stack direction="row" spacing={2}>
<Grid container item xs={12} md={12} justifyContent="flex-end">
<Button variant="outlined" color='primary' >Cancel</Button>
<LoadingButton
type="submit"
variant="contained"
size="medium"
loading={isSubmitting}
sx={{marginLeft:2}}
>
<Typography variant="subtitle2"> Save</Typography>
</LoadingButton>
</Grid>
</Stack>
</FormProvider>
);
return (
<MuiDialog
title={{name: "Add History of Hospital Care"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
maxWidth="xl"
/>
);
}

View File

@@ -0,0 +1,171 @@
import * as Yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
import MuiDialog from "@/components/MuiDialog";
import { Button, Autocomplete, Card, Checkbox, DialogActions, Grid, Typography } from "@mui/material";
import { Paper } from "@mui/material";
import { Stack } from '@mui/material';
import React, { useEffect, useState } from 'react';
import { DetailFinalLogType } from "../Model/Types";
import { MedicineType } from "../Model/Types";
import { fDateTimesecond, toTitleCase } from "@/utils/formatTime";
import { useFieldArray, useForm } from 'react-hook-form';
import { FormProvider, RHFDatepicker, RHFSelect, RHFTextField } from '@/components/hook-form';
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 RemoveIcon from '@mui/icons-material/Remove';
import RHFTextFieldMoney from "@/components/hook-form/v2/RHFTextFieldMoney";
import { IconButton } from '@mui/material';
import { postAddMedince } from '../Model/Functions';
type DialogConfirmationType = {
openDialog: boolean;
setOpenDialog: any;
onSubmit?: void;
requestLog: DetailFinalLogType|undefined;
}
export default function DialogMedicine({requestLog, setOpenDialog, openDialog } : DialogConfirmationType ) {
const handleCloseDialogMedicine = () => {
setOpenDialog(false);
}
const requestID = requestLog?.id
const defaultValues: MedicineType = {
medicine : [{
id: 0,
medicine_name: '',
medicine_price: 0,
request_log_id: requestID,
medicine: '', // input to database
price: 0, // input to database
}],
};
const validationSchema = Yup.object().shape({
medicine: Yup.array().of(
Yup.object().shape({
medicine_name : Yup.string().typeError('').required(''),
medicine_price : Yup.number().typeError('').required(''),
request_log_id : Yup.number().typeError('').required(''),
})
)
})
const methods = useForm<any>({
resolver: yupResolver(validationSchema),
defaultValues
});
const {fields, append, remove} = useFieldArray({name: 'medicine',control: methods.control})
useEffect(() => {
let temp = fields.map((item, i) => {
return {
medicine_name: 'test',
medicine_price: 0,
request_log_id: 3,
}
})
reset({medicine: temp})
}, [])
const { handleSubmit, reset, watch, setValue, formState: { isDirty, isSubmitting, errors } } = methods;
// Submit Form
// =====================================
const submitHandler = async (data: MedicineType) => {
const response = await postAddMedince(data);
if (response == true) {
reset();
// navigate('custormer-service/final-log/detail/'+requestLog?.id);
window.location.reload()
}
}
const getContent = () => (
<FormProvider methods={methods} onSubmit={handleSubmit(submitHandler)}>
<Stack spacing={2} sx={{marginTop: 2, padding: 2}}>
<Grid container spacing={2}>
{/* Medicine */}
<Grid item xs={12}>
<Stack direction="row" alignItems="center" sx={{marginBottom: 4}}>
<Typography variant='subtitle1' gutterBottom>Medicine*</Typography>
<Button color="inherit" variant="outlined" startIcon={<AddIcon/>} sx={{marginLeft: 'auto'}} onClick={() => append({medicine_name: '', medicine_price: 0, request_log_id: requestLog?.id })}>
<Typography variant="button" display="block">Medicine</Typography>
</Button>
</Stack>
</Grid>
{fields.map((field, index) => (
<React.Fragment key={index}>
<Grid item xs={6}>
<RHFTextField
id='medicine_name'
key={field.id}
name={`medicine.${index}.medicine_name`}
label="Medicine"
required
placeholder="Medicine"
/>
</Grid>
<Grid item xs={5}>
<RHFTextFieldMoney
id='medicine_price'
key={field.id}
name={`medicine.${index}.medicine_price`}
label="Price"
required
placeholder="Price"
/>
</Grid>
{
index != (fields.length-1) ?
(
<Grid item xs={1} sx={{ textAlign: 'center' }}>
<IconButton size='large' color='error' onClick={() => remove(index)}>
<RemoveIcon />
</IconButton>
</Grid>
) : null
}
</React.Fragment>
))}
</Grid>
</Stack>
<DialogActions>
<Stack direction="row" alignItems="center" justifyContent="space-between" spacing={2}>
<Button color="inherit" variant="outlined" onClick={handleCloseDialogMedicine}><Typography>Cancel</Typography></Button>
<LoadingButton disabled={!isDirty} type="submit" variant="contained" loading={isSubmitting}>
Add
</LoadingButton>
</Stack>
</DialogActions>
</FormProvider>
);
const getAction = () => null;
return (
<MuiDialog
title={{name: "Medicine"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
action={getAction()}
content={getContent()}
maxWidth="xl"
/>
);
}

View File

@@ -1,305 +1,430 @@
// 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,
IconButton,
} 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 CardBenefit from '../Components/CardBenefit';
// Import Dialog
import DialogHospitalCare from './Components/DialogHospitalCare';
import DialogBenefit from './Components/DialogBenefit';
import DialogMedicine from './Components/DialogMedicine';
import DialogDelete from './Components/DialogDelete';
import DialogEditBenefit from './Components/DialogEditBenefit';
import { DialogDeleteMedicine } from './Components/DialogDelete';
import MoreMenu from '@/components/MoreMenu';
import { MenuItem } from '@mui/material';
import { fNumber } from '@/utils/formatNumber';
import palette from '@/theme/palette';
import CardMedicine from '../Components/CardMedicine';
import CardFile from '../Components/CardFile';
// ----------------------------------------------------------------------
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<DetailFinalLogType>();
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<HTMLInputElement>(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<number>();
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<BenefitData>();
return (
<Page title='Detail'>
<Container maxWidth={themeStretch ? false : 'xl'}>
<Stack direction="row" alignItems="center" sx={{ marginBottom: 3 }}>
<ArrowBackIosIcon onClick={() => navigate(-1)} sx={{cursor:'pointer'}}/>
<Typography variant="h5" sx={{marginLeft:2}}>{(data && data.data) ? data.data.status.code : ''}</Typography>
{data ? (
<Stack direction="row" spacing={2} ml="auto">
<Typography variant="body2" sx={{color: '#757575'}}>Submission Date</Typography>
<Typography variant="body2" fontWeight="bold">{(data && data.data) ? format(new Date(data.data.status.submission_date), "d MMM yyyy") : ''}</Typography>
<Typography variant="h5" sx={{marginLeft:2}}>{(requestLog && requestLog.code ? requestLog.code : '')}</Typography>
</Stack>
) : ''}
</Stack>
{data ? (
<Grid container spacing={2}>
{/* Detail */}
<Grid item xs={12} md={12}>
<DetailStepper data={data}/>
<CardDetail
requestLog={requestLog}
>
</CardDetail>
</Grid>
<Grid item xs={12} md={12}>
<Stack direction="row" alignItems="center">
<Typography variant="subtitle1">Format Claim</Typography>
<Button variant="outlined" color="primary" startIcon={< DownloadIcon/>} sx={{marginLeft: 'auto'}}>
<Typography variant="button" display="block">Import</Typography>
</Button>
</Stack>
{/* Service */}
<Grid item xs={12} md={12} marginTop={2}>
<CardService
requestLog={requestLog}
isFinalLog={true}
>
</CardService>
</Grid>
{/* Exclusion */}
<Grid item xs={12} md={12} marginTop={2}>
<CardExclusion
requestLog={requestLog}
>
</CardExclusion>
</Grid>
{check_invoice ? (
<Grid item xs={12} md={12}>
<Stack direction="row" alignItems="center">
<Typography variant="subtitle1">Request Claim</Typography>
<Button variant="outlined" color="primary" startIcon={ isInvoiceVisible ? < RemoveIcon/> : < AddIcon/>} sx={{marginLeft: 'auto'}} onClick={() => handleInvoice()}>
<Typography variant="button" display="block">Invoice</Typography>
</Button>
</Stack>
</Grid>
) : ''}
<Grid item xs={12} md={12} sx={{display : isInvoiceVisible ? '' : 'none',}}>
<Card sx={{padding: 2}}>
<Stack direction="column" spacing={2}>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DatePicker
label="Invoice Date"
value={dateInvoice}
onChange={(newValue) => {
setDateInvoice(newValue);
}}
inputFormat="dd MMM yyyy"
renderInput={(params) => <TextField sx={{width:'40%'}} {...params} defaultValue={formattedCurrentDate} required/>}
/>
</LocalizationProvider>
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2 }}
>
{fileInvoices &&
fileInvoices.map((file, index) => (
<Stack direction="row" justifyContent={'space-between'} key={index}>
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
<InsertDriveFileIcon />
<Typography variant="body2" gutterBottom>{file.name ? file.name : '-'}</Typography>
</Stack>
<Iconify
icon="eva:trash-2-outline"
color={'darkred'}
onClick={() => {
removeInvoiceFiles(fileInvoices, index);
}}
sx={{cursor: 'pointer'}}
></Iconify>
</Stack>
))}
</Stack>
<ButtonBase sx={{ p: 4, border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
width: '100%', height: '60px'}} onClick={() => fileInvoiceInput.current?.click()}>
<Box
sx={{
display: 'flex',
placeItems: 'center',
gap: 1,
placeContent: 'center',
}}
>
<Iconify icon="icon-park-outline:upload-one" fontSize="3em" />
<Typography variant="body1" fontWeight="bold">
Upload Invoice
</Typography>
</Box>
<input
type="file"
id="file"
ref={fileInvoiceInput}
style={{ display: 'none' }}
multiple
onChange={handleInvoiceInputChange}
accept="application/pdf"
/>
</ButtonBase>
{/* Hospital Care */}
{/* <Grid item xs={12} md={12}>
<Card sx={{padding:2}} >
<Stack direction="row" alignItems="center" sx={{marginBottom: 4}}>
<Typography variant='subtitle1' sx={{color: '#19BBBB'}} gutterBottom>History of Hospital Care</Typography>
<Button variant="outlined" startIcon={<AddIcon/>} sx={{marginLeft: 'auto'}} onClick={() => {
setDialogHospital(true);
}} >
<Typography variant="button" display="block">History</Typography>
</Button>
</Stack>
</Card>
</Grid>
<DialogHospitalCare
requestLog={requestLog}
openDialog={openDialogHospital}
setOpenDialog={setDialogHospital}
>
</DialogHospitalCare>
</Grid> */}
{/* Benefit */}
<Grid item xs={12} md={12}>
<DetailTimeline data={data}/>
</Grid>
<Grid item xs={12} md={12}>
<Stack direction="row" padding={4}>
{dataDialog && dataDialog.status === 'requested' ? (
<>
<Button variant="outlined" sx={{color: '#212B36', marginLeft: 'auto', borderColor: '#919EAB52'}} >Cancel</Button>
<Button sx={{backgroundColor: '#19BBBB', marginLeft: 1}} variant="contained" onClick={()=> setOpenDialogSubmit(true)}>Submit</Button>
</>
) : ''}
{/* Dialog Submits */}
<Dialog open={openDialogSubmit} onClose={handleCloseDialogSubmit} fullWidth={true}>
<DialogTitle sx={{ backgroundColor: '#19BBBB', color: '#FFF', padding: 2 }}>
<Stack direction="row" alignItems="center" justifyContent="space-between">
<Stack direction="row" alignItems='center' spacing={1}>
<Typography variant="h6">Confirmation</Typography>
</Stack>
<IconButton sx={{ color: '#FFF' }} onClick={handleCloseDialogSubmit}>
<CloseIcon />
</IconButton>
</Stack>
</DialogTitle>
<DialogContent>
{dataDialog ? (
<Stack spacing={2} padding={2}>
<Typography variant='body1'>Are you sure to submit this claim ?</Typography>
<Card sx={{padding:2}} >
<Stack direction='row' spacing={2}>
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Code</Typography>
<Typography variant='subtitle2' sx={{width: '70%'}}>{dataDialog.code}</Typography>
</Stack>
<Stack direction='row' spacing={2}>
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Name</Typography>
<Typography variant='subtitle2' sx={{width: '70%'}}>{dataDialog.name}</Typography>
</Stack>
<Stack direction='row' spacing={2}>
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Date Submission</Typography>
<Typography variant='subtitle2' sx={{width: '70%'}}>{fDateTimesecond(dataDialog.submission_date)}</Typography>
</Stack>
<Stack direction='row' spacing={2}>
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Claim Method</Typography>
<Typography variant='subtitle2' sx={{width: '70%'}}>Service Type</Typography>
</Stack>
<Stack direction='row' spacing={2}>
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Service Type</Typography>
<Typography variant='subtitle2' sx={{width: '70%'}}>
{dataDialog.service_code === 'IP' ? 'Inpatient' : 'Outpatient'}
<Card sx={{padding:2}} >
<Stack direction="row" alignItems="center" sx={{marginBottom: 4}}>
<Typography variant='subtitle1' sx={{color: '#19BBBB'}} gutterBottom>Benefit</Typography>
<Button variant="outlined" startIcon={<AddIcon/>} sx={{marginLeft: 'auto'}} onClick={() => {
setDialogBenefit(true);
}} >
<Typography variant="button" display="block">Benefit</Typography>
</Button>
</Stack>
{requestLog?.benefit_data?.map((item, index) => (
<Box key={index} sx={{ border: '1px solid rgba(0,0,0,0.125)', px: '24px', py: '20px', marginBottom: '24px', borderRadius: '12px'}}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={6}>
<Typography variant="body2" sx={{ fontWeight: 'bold'}}>
{item.benefit?.description}
</Typography>
</Stack>
</Card>
</Stack>
) : ''}
</DialogContent>
<DialogActions>
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialogSubmit}>Cancel</Button>
<Button sx={{backgroundColor: '#19BBBB'}} onClick={handleSubmitData} variant="contained">Submit</Button>
</DialogActions>
</Dialog>
</Grid>
<Grid item xs={6} sx={{ display: 'flex', placeContent: 'end' }}>
<MoreMenu actions={
<>
<MenuItem onClick={() => {
setDialogEditBenefit(true)
setIdBenefitData(item.id)
setBenefitConfigurationData(item)
}}
>
<EditOutlined />
Edit
</MenuItem>
<MenuItem onClick={() => {
setIdBenefitData(item.id)
setDialogDeleteBenefit(true)
}}
>
<Delete color='error'/>
Delete
</MenuItem>
</>
} />
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Box sx={{ py: '8px', px: '12px', background: palette.light.grey[50012], borderRadius: '6px'}}>
<Grid container spacing={1}>
{/* Amount Incurred */}
<Grid item xs={2}>
<Grid container sx={{ borderRight: `0.5px solid ${palette.light.grey[400]}` }}>
<Grid item xs={12}>
<Typography variant="caption">
Amount Incurred
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
{fNumber(item.amount_incurred)}
</Typography>
</Grid>
</Grid>
</Grid>
{/* Amount Approved */}
<Grid item xs={2}>
<Grid container sx={{ borderRight: `0.5px solid ${palette.light.grey[400]}` }}>
<Grid item xs={12}>
<Typography variant="caption">
Amount Approved
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
{fNumber(item.amount_approved)}
</Typography>
</Grid>
</Grid>
</Grid>
{/* Amount Not Approved */}
<Grid item xs={3}>
<Grid container sx={{ borderRight: `0.5px solid ${palette.light.grey[400]}` }}>
<Grid item xs={12}>
<Typography variant="caption">
Amount Not Approved
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
{fNumber(item.amount_not_approved)}
</Typography>
</Grid>
</Grid>
</Grid>
{/* Excess Paid* */}
<Grid item xs={2}>
<Grid container sx={{ borderRight: `0.5px solid ${palette.light.grey[400]}` }}>
<Grid item xs={12}>
<Typography variant="caption">
Excess Paid*
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
{fNumber(item.excess_paid)}
</Typography>
</Grid>
</Grid>
</Grid>
{/* Keterangan* */}
<Grid item xs={3}>
<Grid container>
<Grid item xs={12}>
<Typography variant="caption">
Keterangan*
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
{item.keterangan}
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Box>
</Grid>
</Grid>
</Box>
))}
</Card>
{/* PR Buat pindahin ke componen */}
{/* <CardBenefit
requestLog={requestLog}
>
</CardBenefit> */}
<DialogBenefit
requestLog={requestLog}
openDialog={openDialogBenefit}
setOpenDialog={setDialogBenefit}
/>
{/* Dialog Edit */}
<DialogEditBenefit
id={idBenefitData}
data={BenefitConfigurationData}
openDialog={openDialogEditBenefit}
setOpenDialog={setDialogEditBenefit}
>
</DialogEditBenefit>
{/* Dialog Delete */}
<DialogDelete
id={idBenefitData}
openDialog={openDialogDeleteBenefit}
setOpenDialog={setDialogDeleteBenefit}
/>
</Grid>
{/* Medicine */}
<Grid item xs={12} md={12}>
<Card sx={{padding:2}} >
<Stack direction="row" alignItems="center" sx={{marginBottom: 4}}>
<Typography variant='subtitle1' sx={{color: '#19BBBB'}} gutterBottom>Medicine</Typography>
<Button variant="outlined" startIcon={<AddIcon/>} sx={{marginLeft: 'auto'}} onClick={() => {
setDialogMedicine(true)
}} >
<Typography variant="button" display="block">Medicine</Typography>
</Button>
</Stack>
{requestLog?.medicine.map((item, index) => (
<Grid
container
direction="row"
alignItems="center"
justifyContent="space-between" // Menempatkan item ke sebelah kiri dan kanan
sx={{ marginBottom: 2 }}
>
<Typography variant='subtitle1'>{item.medicine}</Typography>
<Typography variant="subtitle1">Rp. {fNumber(item.price)}
<IconButton size='large' color='error' onClick={() => {
setIdBenefitData(item.id)
setDialogDeleteBenefit(true)
}}>
<Delete color='error'/>
</IconButton>
</Typography>
</Grid>
))}
<DialogMedicine
requestLog={requestLog}
openDialog={openDialogMedicine}
setOpenDialog={setDialogMedicine}
/>
<DialogDeleteMedicine
id={idBenefitData}
openDialog={openDialogDeleteBenefit}
setOpenDialog={setDialogDeleteBenefit}
/>
</Card>
</Grid>
{/* File */}
<Grid item xs={12} md={12}>
<CardFile
requestLog={requestLog}
/>
</Grid>
{requestLog?.status_final_log == 'requested' ? (
<Grid item xs={12} md={12}>
<Stack direction="row" padding={4} sx={{ justifyContent: 'space-between' }}>
<>
<div>
<Button
variant="outlined"
sx={{ color: '#FF4842', borderColor: '#FF4842' }}
onClick={() => {
setOpenDialogSubmit(true);
setApprove('declined');
}}
>
Decline
</Button>
</div>
<div>
<Button
variant="contained"
onClick={() => {
setOpenDialogSubmit(true);
setApprove('approved');
}}
>
Approve
</Button>
</div>
</>
<DialogConfirmation
setOpenDialog={setOpenDialogSubmit}
requestLog={requestLog}
openDialog={openDialogSubmit}
approve={approve}
></DialogConfirmation>
</Stack>
</Grid>
) : null}
</Grid>
) : ''}
</Container>
</Page>
);

View File

@@ -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() {
<MenuItem onClick={() => {handleGetTemplate('claim-request')}}>Download Template</MenuItem>
<MenuItem onClick={() => {handleGetData('data-plan-benefit')}}>Download Claim Request</MenuItem>
</Menu>
<Button
{/* <Button
variant="contained"
startIcon={<AddIcon />}
sx={{ p: 1.8 }}
@@ -226,7 +228,7 @@ export default function List() {
}}
>
Create
</Button>
</Button> */}
</Stack>
)}
@@ -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 ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
</IconButton>
</TableCell> */ }
<TableCell align="left">
{/* <TableCell align="left">
<Typography
// onClick={() => {
// handleShowClaim(row);
@@ -350,26 +352,29 @@ export default function List() {
>
{row.id}
</Typography>
</TableCell>
<TableCell align="left">{row.member?.code}</TableCell>
</TableCell> */}
<TableCell align="left">{row.code}</TableCell>
<TableCell align="left">{row.member?.full_name}</TableCell>
<TableCell align="left"><Label>{fDateTimesecond(row.submission_date)}</Label></TableCell>
<TableCell align="left">{row.service_name}</TableCell>
<TableCell align="left">{row.payment_type_name}</TableCell>
<TableCell align="left">
{ row.status == "requested" ?
(<Label variant='ghost' color='primary'>{capitalizeFirstLetter(row.status)}</Label>) :
(<Label color='success'> {capitalizeFirstLetter(row.status)}</Label>)
}
{ row.status_final_log == "requested" ?
(<Label variant='ghost' color='primary'>{capitalizeFirstLetter(row.status_final_log)}</Label>) :
row.status_final_log == "declined" ?
(<Label color='error'> {capitalizeFirstLetter(row.status_final_log)}</Label>)
:
(<Label color='success'> {capitalizeFirstLetter(row.status_final_log)}</Label>)
}
</TableCell>
<TableCell align="right">
<TableMoreMenu actions={
<>
<MenuItem onClick={() => navigate(`/claim-requests/edit/${row.id}`)}>
{/* <MenuItem onClick={() => navigate(`/claim-requests/edit/${row.id}`)}>
<EditOutlinedIcon />
Edit
</MenuItem>
<MenuItem onClick={() => navigate ('/claim-requests/detail/'+row.id+'')}>
</MenuItem> */}
<MenuItem onClick={() => navigate ('/custormer-service/final-log/detail/'+row.id+'')}>
<FindInPageOutlinedIcon />
Detail
</MenuItem>
@@ -471,9 +476,9 @@ export default function List() {
<TableHead>
<TableRow>
{/* <TableCell style={headStyle} align="left" /> */}
<TableCell style={headStyle} align="left">
{/* <TableCell style={headStyle} align="left">
ID Request LOG
</TableCell>
</TableCell> */}
<TableCell style={headStyle} align="left">
Code
</TableCell>

View File

@@ -1,6 +1,7 @@
import axios from '@/utils/axios';
import { enqueueSnackbar } from 'notistack';
import { MemberListType } from './Types';
import { MedicineType, MemberListType } from './Types';
import { BenefitConfigurationListType } from './Types';
import { makeFormData } from '@/utils/jsonToFormData';
/**
@@ -77,3 +78,113 @@ export const addClaimRequest = async ( data: MemberListType[] ): Promise<boolean
return response;
};
/**
* Add Benefit
*/
export const postAddBenefit = async (data: BenefitConfigurationListType):Promise<boolean> => {
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|undefined, data: BenefitConfigurationListType):Promise<boolean> => {
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;
}
/**
* Add Medicine
*/
export const postAddMedince = async (data: MedicineType):Promise<boolean> => {
const response = await axios.post(`customer-service/request/medicine-data`, {
...data
})
.then((res) =>{
enqueueSnackbar(res.data.message, {
variant: 'success',
});
return true;
})
.catch((res) => {
if (res.response.status == 400) {
let arr_message = res.response.data.message;
// for (const key in arr_message) {
enqueueSnackbar(arr_message, {
variant: 'warning',
});
// }
}
else {
enqueueSnackbar("server error !", {
variant: 'error',
});
}
return false;
});
return response;
}

View File

@@ -1,3 +1,5 @@
import { Member } from "@/@types/member"
/**
* Search Type
*/
@@ -8,18 +10,130 @@ 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,
member_name : string,
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[],
medicine : Medicine[],
files : file[],
}
export type BenefitData = {
amount_incurred : number,
amount_approved : number,
amount_not_approved : number,
excess_paid : number,
keterangan : string,
benefit : Benefit,
request_log_id : number,
benefit_name : string,
description : string,
id : number,
}
export type BenefitConfigurationListType = {
request_log_id: number|undefined,
benefit_name: string,
benefit: {
description: string
},
amount_incurred: number,
amount_approved: number,
amount_not_approved: number,
excess_paid: number,
keterangan: string,
description: string,
}
export type Benefit = {
id: number,
code: string,
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 MedicineType = {
medicine: Medicine[],
}
export type Medicine = {
id: number,
medicine_name: string,
medicine_price: number,
medicine: string,
price: number,
request_log_id: number|undefined,
}

View File

@@ -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 = () => (
<Stack spacing={1} marginTop={2}>
<Typography variant="subtitle2">Are you sure to {approve == 'approved' ? 'approve' : 'deciline'} this request ?</Typography>
<Grid item xs={12} md={12} marginTop={4}>
<Card sx={{padding:2, marginTop:2}} >
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Member ID</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.member_id}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Policy Number</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.policy_number}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Name</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.name}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Submission Date</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : '-'}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Claim Method</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.claim_method ? toTitleCase(requestLog?.claim_method) : '-'}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Service Type</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.service_type}</Typography>
</Stack>
</Card>
</Grid>
<DialogActions>
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialog}>Cancel</Button>
{approve == 'approved' ? (
<Button color="primary" variant="contained" onClick={handleSubmit}>Approve</Button>
) : (
<Button color="error" variant="contained" onClick={handleSubmit}>Decline</Button>
) }
</DialogActions>
</Stack>
);
return (
<MuiDialog
title={{name: "Confirmation"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
maxWidth="xl"
/>
);
}

View File

@@ -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<DetailRequestLogType>();
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<HTMLInputElement>(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 (
<Page title='Detail'>
<Container maxWidth={themeStretch ? false : 'xl'}>
<Stack direction="row" alignItems="center" sx={{ marginBottom: 3 }}>
<ArrowBackIosIcon onClick={() => navigate(-1)} sx={{cursor:'pointer'}}/>
<Typography variant="h5" sx={{marginLeft:2}}>{(data && data.data) ? data.data.status.code : ''}</Typography>
{data ? (
<Stack direction="row" spacing={2} ml="auto">
<Typography variant="body2" sx={{color: '#757575'}}>Submission Date</Typography>
<Typography variant="body2" fontWeight="bold">{(data && data.data) ? format(new Date(data.data.status.submission_date), "d MMM yyyy") : ''}</Typography>
<Typography variant="h5" sx={{marginLeft:2}}>{(requestLog && requestLog.code ? requestLog.code : '')}</Typography>
</Stack>
) : ''}
</Stack>
{data ? (
<Grid container spacing={2}>
<Grid item xs={12} md={12}>
<DetailStepper data={data}/>
</Grid>
<Grid item xs={12} md={12}>
<Stack direction="row" alignItems="center">
<Typography variant="subtitle1">Format Claim</Typography>
<Button variant="outlined" color="primary" startIcon={< DownloadIcon/>} sx={{marginLeft: 'auto'}}>
<Typography variant="button" display="block">Import</Typography>
</Button>
</Stack>
</Grid>
{check_invoice ? (
<Grid item xs={12} md={12}>
<Stack direction="row" alignItems="center">
<Typography variant="subtitle1">Request Claim</Typography>
<Button variant="outlined" color="primary" startIcon={ isInvoiceVisible ? < RemoveIcon/> : < AddIcon/>} sx={{marginLeft: 'auto'}} onClick={() => handleInvoice()}>
<Typography variant="button" display="block">Invoice</Typography>
</Button>
<Card sx={{padding:2}} >
<Typography variant='subtitle1' sx={{color: '#19BBBB', marginBottom: 4}} gutterBottom>Detail</Typography>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Member ID</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.member_id}</Typography>
</Stack>
</Grid>
) : ''}
<Grid item xs={12} md={12} sx={{display : isInvoiceVisible ? '' : 'none',}}>
<Card sx={{padding: 2}}>
<Stack direction="column" spacing={2}>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DatePicker
label="Invoice Date"
value={dateInvoice}
onChange={(newValue) => {
setDateInvoice(newValue);
}}
inputFormat="dd MMM yyyy"
renderInput={(params) => <TextField sx={{width:'40%'}} {...params} defaultValue={formattedCurrentDate} required/>}
/>
</LocalizationProvider>
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2 }}
>
{fileInvoices &&
fileInvoices.map((file, index) => (
<Stack direction="row" justifyContent={'space-between'} key={index}>
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
<InsertDriveFileIcon />
<Typography variant="body2" gutterBottom>{file.name ? file.name : '-'}</Typography>
</Stack>
<Iconify
icon="eva:trash-2-outline"
color={'darkred'}
onClick={() => {
removeInvoiceFiles(fileInvoices, index);
}}
sx={{cursor: 'pointer'}}
></Iconify>
</Stack>
))}
</Stack>
<ButtonBase sx={{ p: 4, border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
width: '100%', height: '60px'}} onClick={() => fileInvoiceInput.current?.click()}>
<Box
sx={{
display: 'flex',
placeItems: 'center',
gap: 1,
placeContent: 'center',
}}
>
<Iconify icon="icon-park-outline:upload-one" fontSize="3em" />
<Typography variant="body1" fontWeight="bold">
Upload Invoice
</Typography>
</Box>
<input
type="file"
id="file"
ref={fileInvoiceInput}
style={{ display: 'none' }}
multiple
onChange={handleInvoiceInputChange}
accept="application/pdf"
/>
</ButtonBase>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Policy Number</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.policy_number}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Name</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.name}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Date Of Birth</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.date_of_birth ? fDate(requestLog?.date_of_birth) : '-'}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Marital Status</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.marital_status}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Submission Date</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : '-'}</Typography>
</Stack>
</Card>
</Grid>
<Grid item xs={12} md={12}>
<DetailTimeline data={data}/>
<Grid item xs={12} md={12} marginTop={2}>
<Card sx={{padding:2}} >
<Typography variant='subtitle1' sx={{color: '#19BBBB', marginBottom: 4}} gutterBottom>Service</Typography>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Service Type</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.service_type}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Claim Method</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{toTitleCase(requestLog?.claim_method ?? '-')}</Typography>
</Stack>
{/* <Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={{width:'35%', color: '#919EAB'}} gutterBottom>Benefit</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>
<ul>
{requestLog?.benefit.length > 0 ? requestLog?.benefit.map((r, index) => (
<li key={index}>{r.code } - {r.description}</li>
)) : <li>-</li>}
</ul>
</Typography>
</Stack> */}
</Card>
</Grid>
<Grid item xs={12} md={12}>
<Stack direction="row" padding={4}>
{dataDialog && dataDialog.status === 'requested' ? (
<>
<Button variant="outlined" sx={{color: '#212B36', marginLeft: 'auto', borderColor: '#919EAB52'}} >Cancel</Button>
<Button sx={{backgroundColor: '#19BBBB', marginLeft: 1}} variant="contained" onClick={()=> setOpenDialogSubmit(true)}>Submit</Button>
</>
) : ''}
{/* Dialog Submits */}
<Dialog open={openDialogSubmit} onClose={handleCloseDialogSubmit} fullWidth={true}>
<DialogTitle sx={{ backgroundColor: '#19BBBB', color: '#FFF', padding: 2 }}>
<Stack direction="row" alignItems="center" justifyContent="space-between">
<Stack direction="row" alignItems='center' spacing={1}>
<Typography variant="h6">Confirmation</Typography>
</Stack>
<IconButton sx={{ color: '#FFF' }} onClick={handleCloseDialogSubmit}>
<CloseIcon />
</IconButton>
</Stack>
</DialogTitle>
<DialogContent>
{dataDialog ? (
<Stack spacing={2} padding={2}>
<Typography variant='body1'>Are you sure to submit this claim ?</Typography>
<Card sx={{padding:2}} >
<Stack direction='row' spacing={2}>
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Code</Typography>
<Typography variant='subtitle2' sx={{width: '70%'}}>{dataDialog.code}</Typography>
</Stack>
<Stack direction='row' spacing={2}>
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Name</Typography>
<Typography variant='subtitle2' sx={{width: '70%'}}>{dataDialog.name}</Typography>
</Stack>
<Stack direction='row' spacing={2}>
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Date Submission</Typography>
<Typography variant='subtitle2' sx={{width: '70%'}}>{fDateTimesecond(dataDialog.submission_date)}</Typography>
</Stack>
<Stack direction='row' spacing={2}>
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Claim Method</Typography>
<Typography variant='subtitle2' sx={{width: '70%'}}>Service Type</Typography>
</Stack>
<Stack direction='row' spacing={2}>
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Service Type</Typography>
<Typography variant='subtitle2' sx={{width: '70%'}}>
{dataDialog.service_code === 'IP' ? 'Inpatient' : 'Outpatient'}
</Typography>
</Stack>
</Card>
</Stack>
) : ''}
</DialogContent>
<DialogActions>
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialogSubmit}>Cancel</Button>
<Button sx={{backgroundColor: '#19BBBB'}} onClick={handleSubmitData} variant="contained">Submit</Button>
</DialogActions>
</Dialog>
{requestLog?.status == 'requested' ? (
<Grid item xs={12} md={12}>
<Stack direction="row" padding={4} sx={{ justifyContent: 'space-between' }}>
<>
<div>
<Button
variant="outlined"
sx={{ color: '#FF4842', borderColor: '#FF4842' }}
onClick={() => {
setOpenDialogSubmit(true);
setApprove('declined');
}}
>
Decline
</Button>
</div>
<div>
<Button
variant="outlined"
sx={{ color: '#19BBBB', borderColor: '#19BBBB' }}
onClick={() => {
setOpenDialogSubmit(true);
setApprove('approved');
}}
>
Approve
</Button>
</div>
</>
<DialogConfirmation
setOpenDialog={setOpenDialogSubmit}
requestLog={requestLog}
openDialog={openDialogSubmit}
approve={approve}
></DialogConfirmation>
</Stack>
</Grid>
) : null}
</Grid>
) : ''}
</Container>
</Page>
);

View File

@@ -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 ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
</IconButton>
</TableCell> */ }
<TableCell align="left">
{/* <TableCell align="left">
<Typography
// onClick={() => {
// handleShowClaim(row);
@@ -353,9 +355,9 @@ export default function List() {
>
{row.id}
</Typography>
</TableCell>
</TableCell> */}
<TableCell align="left">{row.code}</TableCell>
<TableCell align="left">{row.member?.full_name}</TableCell>
<TableCell align="left">{row.member_name}</TableCell>
<TableCell align="left"><Label>{fDateTimesecond(row.submission_date)}</Label></TableCell>
<TableCell align="left">{row.service_name}</TableCell>
<TableCell align="left">{row.payment_type_name}</TableCell>
@@ -371,19 +373,11 @@ export default function List() {
<TableCell align="right">
<TableMoreMenu actions={
<>
<MenuItem onClick={() => navigate ('/claim-requests/detail/'+row.id+'')}>
<MenuItem onClick={() => navigate ('/custormer-service/request/detail/'+row.id+'')}>
<FindInPageOutlinedIcon />
Detail
</MenuItem>
<MenuItem onClick={() => navigate ('/claim-requests/detail/'+row.id+'')}>
<SvgIcon>
{/* credit: plus icon from https://heroicons.com/ */}
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.5 10.25C12.5 10.0511 12.579 9.86032 12.7197 9.71967C12.8603 9.57902 13.0511 9.5 13.25 9.5H16.75C16.9489 9.5 17.1397 9.57902 17.2803 9.71967C17.421 9.86032 17.5 10.0511 17.5 10.25C17.5 10.4489 17.421 10.6397 17.2803 10.7803C17.1397 10.921 16.9489 11 16.75 11H13.25C13.0511 11 12.8603 10.921 12.7197 10.7803C12.579 10.6397 12.5 10.4489 12.5 10.25ZM13.25 15C13.0511 15 12.8603 15.079 12.7197 15.2197C12.579 15.3603 12.5 15.5511 12.5 15.75C12.5 15.9489 12.579 16.1397 12.7197 16.2803C12.8603 16.421 13.0511 16.5 13.25 16.5H16.75C16.9489 16.5 17.1397 16.421 17.2803 16.2803C17.421 16.1397 17.5 15.9489 17.5 15.75C17.5 15.5511 17.421 15.3603 17.2803 15.2197C17.1397 15.079 16.9489 15 16.75 15H13.25ZM10.78 9.78C10.8537 9.71134 10.9128 9.62854 10.9538 9.53654C10.9948 9.44454 11.0168 9.34522 11.0186 9.24452C11.0204 9.14382 11.0018 9.04379 10.9641 8.9504C10.9264 8.85701 10.8703 8.77218 10.799 8.70096C10.7278 8.62974 10.643 8.5736 10.5496 8.53588C10.4562 8.49816 10.3562 8.47963 10.2555 8.48141C10.1548 8.48318 10.0555 8.50523 9.96346 8.54622C9.87146 8.58721 9.78866 8.64631 9.72 8.72L8.25 10.19L7.78 9.72C7.63783 9.58752 7.44978 9.5154 7.25548 9.51882C7.06118 9.52225 6.87579 9.60097 6.73838 9.73838C6.60097 9.87579 6.52225 10.0612 6.51883 10.2555C6.5154 10.4498 6.58752 10.6378 6.72 10.78L7.72 11.78C7.86063 11.9205 8.05125 11.9993 8.25 11.9993C8.44875 11.9993 8.63937 11.9205 8.78 11.78L10.78 9.78ZM10.78 14.22C10.9205 14.3606 10.9993 14.5512 10.9993 14.75C10.9993 14.9488 10.9205 15.1394 10.78 15.28L8.78 17.28C8.63937 17.4205 8.44875 17.4993 8.25 17.4993C8.05125 17.4993 7.86063 17.4205 7.72 17.28L6.72 16.28C6.64631 16.2113 6.58721 16.1285 6.54622 16.0365C6.50523 15.9445 6.48319 15.8452 6.48141 15.7445C6.47963 15.6438 6.49816 15.5438 6.53588 15.4504C6.5736 15.357 6.62974 15.2722 6.70096 15.201C6.77218 15.1297 6.85701 15.0736 6.9504 15.0359C7.04379 14.9982 7.14382 14.9796 7.24452 14.9814C7.34523 14.9832 7.44454 15.0052 7.53654 15.0462C7.62854 15.0872 7.71134 15.1463 7.78 15.22L8.25 15.69L9.72 14.22C9.86063 14.0795 10.0512 14.0007 10.25 14.0007C10.4488 14.0007 10.6394 14.0795 10.78 14.22ZM15.994 4.084C15.9521 3.51752 15.6975 2.98786 15.2813 2.60132C14.865 2.21478 14.318 1.99997 13.75 2H10.25C9.69656 2.00002 9.16255 2.20401 8.75004 2.57297C8.33754 2.94194 8.07549 3.44999 8.014 4H6.25C5.65326 4 5.08097 4.23705 4.65901 4.65901C4.23705 5.08097 4 5.65326 4 6.25V19.75C4 20.3467 4.23705 20.919 4.65901 21.341C5.08097 21.7629 5.65326 22 6.25 22H17.75C18.0455 22 18.3381 21.9418 18.611 21.8287C18.884 21.7157 19.1321 21.5499 19.341 21.341C19.5499 21.1321 19.7157 20.884 19.8287 20.611C19.9418 20.3381 20 20.0455 20 19.75V6.25C20 5.95453 19.9418 5.66194 19.8287 5.38896C19.7157 5.11598 19.5499 4.86794 19.341 4.65901C19.1321 4.45008 18.884 4.28434 18.611 4.17127C18.3381 4.0582 18.0455 4 17.75 4H15.986L15.994 4.084ZM15.994 4.096L16 4.25C16 4.198 15.997 4.147 15.994 4.096ZM10.25 6.5H13.75C14.53 6.5 15.217 6.103 15.621 5.5H17.75C17.9489 5.5 18.1397 5.57902 18.2803 5.71967C18.421 5.86032 18.5 6.05109 18.5 6.25V19.75C18.5 19.9489 18.421 20.1397 18.2803 20.2803C18.1397 20.421 17.9489 20.5 17.75 20.5H6.25C6.05109 20.5 5.86032 20.421 5.71967 20.2803C5.57902 20.1397 5.5 19.9489 5.5 19.75V6.25C5.5 6.05109 5.57902 5.86032 5.71967 5.71967C5.86032 5.57902 6.05109 5.5 6.25 5.5H8.379C8.783 6.103 9.47 6.5 10.25 6.5ZM10.25 3.5H13.75C13.9489 3.5 14.1397 3.57902 14.2803 3.71967C14.421 3.86032 14.5 4.05109 14.5 4.25C14.5 4.44891 14.421 4.63968 14.2803 4.78033C14.1397 4.92098 13.9489 5 13.75 5H10.25C10.0511 5 9.86032 4.92098 9.71967 4.78033C9.57902 4.63968 9.5 4.44891 9.5 4.25C9.5 4.05109 9.57902 3.86032 9.71967 3.71967C9.86032 3.57902 10.0511 3.5 10.25 3.5Z" fill="black"/>
</svg>
</SvgIcon>
Konfirmasi
</MenuItem>
</>
} />
</TableCell>
@@ -482,9 +476,9 @@ export default function List() {
<TableHead>
<TableRow>
{/* <TableCell style={headStyle} align="left" /> */}
<TableCell style={headStyle} align="left">
{/* <TableCell style={headStyle} align="left">
ID Request LOG
</TableCell>
</TableCell> */}
<TableCell style={headStyle} align="left">
Code
</TableCell>

View File

@@ -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
}

View File

@@ -252,6 +252,10 @@ export default function Router() {
path: 'laboratorium_result/:member_id/claims/:claim_code/list_lab_result',
element: <DetailLabResultList />
},
{
path: 'inpatient_monitoring', // Inpatient Monitoring
element: <InpatientMonitoring />
},
]
},
{
@@ -475,9 +479,17 @@ export default function Router() {
element: <RequestLog />,
},
{
path: 'custormer-service/final-request',
path: 'custormer-service/request/detail/:id',
element: <RequestLogDetail />,
},
{
path: 'custormer-service/final-log',
element: <FinalLog />,
},
{
path: 'custormer-service/final-log/detail/:id',
element: <FinalLogDetail />,
},
],
},
// {
@@ -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')));

View File

@@ -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();
});
}

View File

@@ -1,15 +0,0 @@
{
"greeting": "Hello",
"buttonText": "Click Me",
"infoLogin": "Enter the registered account",
"txtLogin1" : "Sign in to Hospital Portal",
"txtLogin2" : "Enter your details below",
"txtCardSearchMember1" : "Guarantee Submission",
"txtCardSearchMember2" : "Find Member",
"txtCardSearchMember3" : "Date Birth",
"txtCardSearchMember4" : "Member ID",
"txtCardSearchMember5" : "Member",
"txtDialogMember1" : "Benefit Summary",
"txtDialogMember2" : "Request LOG",
"txtDialogMember3" : "Member Detail"
}

View File

@@ -1,15 +0,0 @@
{
"greeting": "Halo",
"buttonText": "Klik Saya",
"infoLogin": "Masukan akun yang telah terdaftar",
"txtLogin1" : "Masuk ke Hospital Portal",
"txtLogin2" : "Masukkan detail Anda di bawah ini",
"txtCardSearchMember1" : "Pengajuan Jaminan",
"txtCardSearchMember2" : "Cari Anggota",
"txtCardSearchMember3" : "Tanggal Lahir",
"txtCardSearchMember4" : "Member ID",
"txtCardSearchMember5" : "Member",
"txtDialogMember1" : "Ringkasan Manfaat",
"txtDialogMember2" : "Request LOG",
"txtDialogMember3" : "Detail Member"
}

View File

@@ -6,7 +6,7 @@
"txtLogin2" : "Enter your details below",
"txtCardSearchMember1" : "Membership Query",
"txtCardSearchMember2" : "Search Member",
"txtCardSearchMember3" : "Date Birth",
"txtCardSearchMember3" : "Date of Birth",
"txtCardSearchMember4" : "Member ID",
"txtCardSearchMember5" : "Member",
"txtDialogMember1" : "Services",
@@ -18,5 +18,21 @@
"txtGender" : "Gender",
"txtMaritalStatus" : "Marital Status",
"txtLanguage" : "Language",
"txtRelationship" : "Relationship"
"txtRelationship" : "Relationship",
"txtRequestDate" : "Request Date",
"txtMemberID" : "Member ID",
"txtClaimCode" : "Claim Code",
"txtRequestCode" : "Request Code",
"txtName" : "Name",
"txtStatus" : "Status",
"txtSearch" : "Search Name or Member ID...",
"txtAll" : "All",
"txtSubmissionDate" : "Submission Date",
"txtDataNotFound" : "Data Not Found",
"txtConditionDocument" : "Condition Document",
"txtDiagnosisDokument" : "Diagnosis Dokument",
"txtSupportingResultDocument" : "Supporting Result Document",
"txtAddResult" : "Add Result",
"txtServiceType" : "Service Type",
"txtAdditionalDocuments" : "Additional Documents"
}

View File

@@ -18,5 +18,21 @@
"txtGender" : "Jenis Kelamin",
"txtMaritalStatus" : "Status Perkawinan",
"txtLanguage" : "Bahasa",
"txtRelationship" : "Hubungan"
"txtRelationship" : "Hubungan",
"txtRequestDate" : "Tanggal Permintaan",
"txtMemberID" : "ID Anggota",
"txtClaimCode" : "Kode Klaim",
"txtRequestCode" : "Kode Pengajuan",
"txtName" : "Nama",
"txtStatus" : "Status",
"txtSearch" : "Cari Nama atau ID Anggota...",
"txtAll" : "Semua",
"txtSubmissionDate" : "Tanggal Pengajuan",
"txtDataNotFound" : "Data Tidak Ditemukan",
"txtConditionDocument" : "Dokumen Kondisi",
"txtDiagnosisDokument" : "Dokumen Diagnosa",
"txtSupportingResultDocument" : "Dokumen Hasil Pendukung",
"txtAddResult" : "Tambah Hasil",
"txtServiceType" : "Tipe Layanan",
"txtAdditionalDocuments" : "Dokumen Tambahan"
}

View File

@@ -42,6 +42,8 @@ import { Download, Search as SearchIcon, Upload } from '@mui/icons-material';
import { DivisionDataProps, Order, PaginationTableProps, TableListProps } from '../@types/table';
import { InputAdornment } from '@mui/material';
import GetAppIcon from '@mui/icons-material/GetApp';
import { LanguageContext } from '@/contexts/LanguageContext';
/* --------------------------------- styled --------------------------------- */
const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({
height: 10,
@@ -83,6 +85,8 @@ export default function Table<T>({
]);
params.setAppliedParams(parameters);
};
const { localeData }: any = useContext(LanguageContext);
/* -------------------------------------------------------------------------- */
/* -------------------------- enchanced table head -------------------------- */
@@ -219,7 +223,7 @@ export default function Table<T>({
</InputAdornment>
),
}}
placeholder="Search Name or Member ID... "
placeholder={localeData.txtSearch}
/>
</form>
</Grid>
@@ -239,7 +243,7 @@ export default function Table<T>({
</InputAdornment>
),
}}
placeholder="Search Name or Member ID... "
placeholder={localeData.txtSearch}
/>
</form>
</Grid>
@@ -299,7 +303,7 @@ export default function Table<T>({
label="Status"
onChange={filterStatus.config.handleStatusChange}
>
<MenuItem value="all">All</MenuItem>
<MenuItem value="all">{localeData.txtAll}</MenuItem>
{filterStatus.config.filterData.map((row: StatusDataProps, index) => (
<MenuItem key={index} value={row.id}>
{row.name}
@@ -336,7 +340,7 @@ export default function Table<T>({
{/* End Table Header */}
{/* Table Body */}
<TableBody>
{loadings.isLoading && rows.length >= 1 ? (
{loadings.isLoading ? (
<TableRow>
<TableCell colSpan={headCells?.length} align="center">
Loading . . .
@@ -358,7 +362,7 @@ export default function Table<T>({
) : (
<TableRow>
<TableCell colSpan={6} align="center">
No Data Found
{localeData.txtDataNotFound}
</TableCell>
</TableRow>
)}

View File

@@ -12,7 +12,7 @@ const ICONS = {
ecommerce: getIcon('ic_ecommerce'),
analytics: getIcon('ic_analytics'),
dashboard: getIcon('ic_dashboard'),
hospital: getIcon('ic_banking'),
ic_booking: getIcon('ic_booking'),
};
const navConfig = [
@@ -21,6 +21,9 @@ const navConfig = [
{
items: [{ title: 'Dashboard', path: '/dashboard', icon: ICONS.dashboard }],
},
{
items: [{ title: 'Claim', path: '/claim', icon: ICONS.ic_booking }],
},
// Membership
// ----------------------------------------------------------------------

View File

@@ -25,7 +25,7 @@ export default function NavbarDocs() {
</div>
<Button variant="contained">Documentation</Button>
<Typography variant='body2'>Hak Cipta © 2023 - 2024 Link Sehat</Typography>
<Typography variant='body2'>Hak Cipta © 2023 - 2024 Link Medis Sehat</Typography>
</Stack>
</>
);

View File

@@ -0,0 +1,119 @@
// @mui
import { Typography, Container, Grid, Card } from '@mui/material';
// hooks
import useSettings from '@/hooks/useSettings';
// components
import Page from '@/components/Page';
// theme
import CardNotification from '@/sections/dashboard/CardNotification';
import CardSearchMember from '@/sections/dashboard/CardSearchMember'
import { useContext, useEffect, useState } from 'react';
import axios from '@/utils/axios';
import { Stack } from '@mui/system';
import { Input } from '@mui/material';
//sections
import TableList from '@/sections/claim/TableList';
import { fDate } from '@/utils/formatTime';
import DialogDetailClaim from '@/components/dialogs/DialogDetailClaim';
import HeaderBreadcrumbs from "@/components/HeaderBreadcrumbs";
// ----------------------------------------------------------------------
// const [notifications, setNotifications] = useState([])
const itemList = [
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '08:00 WIB' },
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '09:00 WIB' },
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '10:00 WIB' },
{ info: 'Mohon lengkapi dokumen Mahen sadarsa', date: 'Selasa, 20 April 22', time: '11:00 WIB' },
];
// ----------------------------------------------------------------------
/* ---------------------------------- types --------------------------------- */
type PolicyProps = {
myLimit: {
balance: number;
total: number;
percentage: number;
};
lockLimit: {
balance: number;
percentage: number;
};
};
/* -------------------------------------------------------------------------- */
/* ------------------------------ default data ------------------------------ */
const defaultPolicyData = {
myLimit: {
balance: 0,
total: 0,
percentage: 0,
},
lockLimit: {
balance: 0,
percentage: 0,
},
};
/* -------------------------------------------------------------------------- */
export default function Claim() {
const { themeStretch } = useSettings();
// const [tableData, setTableData] = useState([]);
const [policyData, setPolicyData] = useState<PolicyProps>(defaultPolicyData);
// TODO Remove This
//const [itemList, setItemList] = useState([]);
function handleDataLoaded(dataTable:any) {
let dummyData = [];
dataTable.map(function(data:any) {
if (data.status == 'approved') {
dummyData.push({
info: `LOG Approved for member ${data.member.full_name}`,
date: fDate(data.created_at, "dd MMMM"),
time: fDate(data.created_at, "HH:mm")
})
}
})
//setItemList(dummyData);
}
return (
<Page title="Claim">
<Container maxWidth={themeStretch ? false : 'xl'}>
<Grid container spacing={2}>
{/* <Grid item xs={12} lg={12} md={12}>
<CardSearchMember/>
</Grid> */}
{/*<Grid item xs={12} lg={6} md={6}>
<CardNotification data={itemList} />
</Grid>*/}
<Grid item xs={12} lg={12} md={12}>
<HeaderBreadcrumbs
heading={'Claim'}
links={[
{
name: 'Dashboard',
href: '/dashboard',
},
{
name: 'Claim',
href: '/claim',
},
]}
/>
<Card>
<TableList/>
</Card>
</Grid>
</Grid>
</Container>
</Page>
);
}

View File

@@ -82,6 +82,27 @@ export default function Router() {
},
],
},
{
path: '/',
element: (
<AuthProvider>
<AuthGuard>
<DashboardLayout />
</AuthGuard>
</AuthProvider>
),
children: [
{ element: <Navigate to="/claim" replace />, index: true },
{
path: 'claim',
element: <Claim />,
},
{
path: '/detail/:id',
element: <DetailClaimReport />,
},
],
},
{
path: '*',
@@ -101,6 +122,7 @@ const ForgetPassword = Loadable(lazy(() => import('@/pages/auth/ForgetPassword')
// Dashboard
const Dashboard = Loadable(lazy(() => import('@/pages/Dashboard')));
const Claim = Loadable(lazy(() => import('@/pages/Claim')));
const NotFound = Loadable(lazy(() => import('@/pages/Page404')));
const DetailClaimReport = Loadable(lazy(()=> import('@/sections/dashboard/Detail')));

View File

@@ -0,0 +1,365 @@
/* ---------------------------------- @mui ---------------------------------- */
import { Stack, Button, MenuItem, SelectChangeEvent, Tab, Tabs, Card, Box } from '@mui/material';
/* ---------------------------------- axios --------------------------------- */
// import axios from 'axios';
import axios from '../../utils/axios';
import { styled } from '@mui/material/styles';
/* ---------------------------------- react --------------------------------- */
import { useContext, useEffect, useState } from 'react';
/* -------------------------------- component ------------------------------- */
import Iconify from '../../components/Iconify';
import TableComponent from '../../components/Table';
/* ---------------------------------- theme --------------------------------- */
import palette from '../../theme/palette';
//import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate';
import { HeadCell, Order, PaginationTableProps } from '../../@types/table';
import { useSearchParams, useNavigate } from 'react-router-dom';
import { fDate, fDateSuffix } from '../../utils/formatTime';
import Typography from '@mui/material/Typography';
import { format } from 'date-fns';
import TableMoreMenu from '../../components/table/TableMoreMenu';
import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
import HistoryIcon from '@mui/icons-material/History';
import SearchIcon from '@mui/icons-material/Search';
import Label from '../../components/Label';
import { enqueueSnackbar } from 'notistack';
import { LoadingButton, TabPanel } from "@mui/lab";
import { LanguageContext } from '@/contexts/LanguageContext';
import MuiDialog from '@/components/MuiDialog';
import DialogMember from '@/sections/dashboard/DialogMember';
import DialogClaimSubmit from '@/sections/dashboard/DialogClaimSubmit';
import { fPostFormat } from '@/utils/formatTime';
export default function TableList() {
const navigate = useNavigate();
const { localeData }: any = useContext(LanguageContext);
const [data, setData] = useState([]);
// Download LOG
async function handleDownloadLog(claimRequest:any) {
return axios
.get(`claim-requests/${claimRequest}/log`, {
responseType: 'blob',
})
.then((response) => {
window.open(URL.createObjectURL(response.data));
// setLoadingLog(false);
})
// .then((blobFile) => {
// new File([blobFile], 'asdads.pdf', { type: blobFile.type })
// setLoadingLog(false);
// })
.catch((response) => {
console.log(response);
enqueueSnackbar(response.message, { variant: 'error' });
// setLoadingLog(false);
});
}
/* -------------------------------------------------------------------------- */
/* setting up for the table */
/* -------------------------------------------------------------------------- */
const [isLoading, setIsLoading] = useState(true);
const loadings = {
isLoading: isLoading,
setIsLoading: setIsLoading,
};
/* ------------------------------ handle params ----------------------------- */
const [searchParams, setSearchParams] = useSearchParams();
const [appliedParams, setAppliedParams] = useState({});
const params = {
searchParams: searchParams,
setSearchParams: setSearchParams,
appliedParams: appliedParams,
setAppliedParams: setAppliedParams,
};
/* -------------------------------------------------------------------------- */
/* ------------------------------ handle order ------------------------------ */
const [order, setOrder] = useState<Order>('desc');
const [orderBy, setOrderBy] = useState('submission_date');
const orders = {
order: order,
setOrder: setOrder,
orderBy: orderBy,
setOrderBy: setOrderBy,
};
/* -------------------------------------------------------------------------- */
/* ---------------------------- handle pagination --------------------------- */
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10);
const [paginationTable, setPaginationTable] = useState<PaginationTableProps>({
current_page: 0,
from: 0,
last_page: 0,
links: [],
path: '',
per_page: 0,
to: 0,
total: 0,
});
const paginations = {
page: page,
setPage: setPage,
rowsPerPage: rowsPerPage,
setRowsPerPage: setRowsPerPage,
paginationTable: paginationTable,
setPaginationTable: setPaginationTable,
};
/* -------------------------------------------------------------------------- */
/* ------------------------------ handle search ----------------------------- */
const [searchText, setSearchText] = useState('');
const handleSearchSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (searchText === '') {
searchParams.delete('search');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([...searchParams.entries(), ['search', searchText]]);
setAppliedParams(params);
}
};
const searchs = {
useSearchs: true,
searchText: searchText,
setSearchText: setSearchText,
handleSearchSubmit: handleSearchSubmit,
};
/* ------------------------------ handle filter ----------------------------- */
const [statusValue, setStatusValue] = useState('all');
const [filterData, setStatusData] = useState([]);
// handle status
const handleStatusChanges = (event: SelectChangeEvent) => {
setStatusValue(event.target.value as string);
if (event.target.value === 'all') {
searchParams.delete('status');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([
...searchParams.entries(),
['status', event.target.value as string],
]);
setAppliedParams(params);
}
};
const filterStatus = {
useFilter: true,
config: {
label: 'Status',
statusValue: statusValue,
filterData: filterData,
handleStatusChange: handleStatusChanges,
},
};
// handle start date
const [startDateValue, setStartDateValue] = useState('');
const handleStartDateChanges = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const newStartDateValue = event.currentTarget.elements['date-input'].value;
setStartDateValue(newStartDateValue);
if (newStartDateValue === '') {
searchParams.delete('start_date');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([...searchParams.entries(), ['start_date', newStartDateValue]]);
setAppliedParams(params);
}
};
const filterStartDate = {
useFilter: true,
startDate: startDateValue,
setStartDate: setStartDateValue,
handleStartDateChange: handleStartDateChanges,
};
// handle end date
const [endDateValue, setEndDateValue] = useState('');
const handleEndDateChanges = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const newEndDateValue = event.currentTarget.elements['date-input'].value;
setEndDateValue(newEndDateValue);
if (newEndDateValue === '') {
searchParams.delete('end_date');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([...searchParams.entries(), ['end_date', newEndDateValue]]);
setAppliedParams(params);
}
};
const filterEndDate = {
useFilter: true,
endDate: endDateValue,
setEndDate: setEndDateValue,
handleEndDateChange: handleEndDateChanges,
};
/* -------------------------------- headCell Claim -------------------------------- */
const headCells: HeadCell<never>[] = [
{
id: 'code',
align: 'left',
label: localeData.txtRequestCode,
isSort: true,
},
{
id: 'full_name',
align: 'left',
label: localeData.txtName,
isSort: true,
},
{
id: 'submission_date',
align: 'center',
label: localeData.txtSubmissionDate,
isSort: true,
},
{
id: 'service_type',
align: 'center',
label: localeData.txtServiceType,
isSort: true,
},
{
id: 'status',
align: 'center',
label: localeData.txtStatus,
isSort: true,
},
{
id: 'action',
align: 'right',
label: '',
isSort: false,
},
];
useEffect(() => {
getData();
}, [appliedParams, searchParams, order, orderBy, setSearchParams]);
function getData()
{
(async () => {
setIsLoading(true);
await new Promise((resolve) => setTimeout(resolve, 250));
const parameters =
Object.keys(appliedParams).length !== 0
? appliedParams
: Object.fromEntries([...searchParams.entries(), ['order', order], ['orderBy', orderBy]]);
const response = await axios.get(`/get-claim-requests`, {
params: { ...parameters, type: 'final-log' },
});
setData(
response.data.data.map((obj: any) => ({
...obj,
status:
obj.status === 'requested' ? (
<Label color='primary'>
Request
</Label>
) : obj.status === 'approved' ? (
<Label color='success' >
Approval
</Label>
) : obj.status === 'declined' ? (
<Label color='error'>
Decline
</Label>
) : obj.status === 'reviewed' ? (
<Label color='info'>
Review
</Label>
) : (
<Label color='primary'>
Pending
</Label>
),
submission_date:
<Label>
{obj.submission_date ? fDateSuffix(obj.submission_date) : ''}
</Label>
,
action:
<TableMoreMenu actions={
<>
<MenuItem>
<Iconify icon="eva:eye-fill" />
View
</MenuItem>
</>
} />
}))
);
setPaginationTable(response.data);
setRowsPerPage(response.data.per_page);
if (searchParams.get('page')) {
//@ts-ignore
const currentPage = parseInt(searchParams.get('page')) - 1;
paginationTable.current_page = currentPage;
setPage(currentPage);
}
const status:any = [
{"id": "requested", "name": "Request" },
{"id": "reviewed", "name": "Review" },
{"id": "approved", "name": "Approval" },
{"id": "declined", "name": "Decline" },
];
setStatusData(status)
setIsLoading(false);
})();
}
return (
<>
<TableComponent
headCells={headCells}
rows={data}
orders={orders}
paginations={paginations}
loadings={loadings}
params={params}
searchs={searchs}
filterStatus={filterStatus}
// filterStartDate={filterStartDate}
// filterEndDate={filterEndDate}
/>
</>
);
}

View File

@@ -0,0 +1,164 @@
import { styled } from '@mui/material/styles';
import Iconify from '@/components/Iconify';
import { fCurrency } from '@/utils/formatNumber';
import { LoadingButton } from '@mui/lab';
import { Avatar, Button, Divider, LinearProgress, linearProgressClasses, ButtonBase, Box } from '@mui/material';
import { Card } from '@mui/material';
import { Stack, Typography } from '@mui/material';
import { fPostFormat } from '@/utils/formatTime';
import axios from '@/utils/axios';
import { enqueueSnackbar } from 'notistack';
import { useRef, useState, useContext } from 'react';
import { makeFormData } from '@/utils/jsonToFormData';
import { format } from 'date-fns';
import { LanguageContext } from '@/contexts/LanguageContext';
export default function DialogClaimSubmit({ member, getData, onClose, handleSubmitSuccess }: any) {
const { localeData }: any = useContext(LanguageContext);
// ----------------------------------------------------------------------
// Files Result Tambahan
const fileAdditionalInput = useRef<HTMLInputElement>(null);
const [fileAdditionals, setFileAdditionals] = useState<any>([]);
const handleKondisiInputChange = (event:any) => {
if (event.target.files[0]) {
setFileAdditionals([...fileAdditionals, ...event.target.files]);
} else {
console.log('NO FILE');
}
};
const removeKondisiFiles = (filesState:any, index:any) => {
setFileAdditionals(
filesState.filter((file:any, fileIndex:any) => {
return fileIndex != index;
})
);
};
// --------------------------------------------------------------
// Submit Form
const [submitLoading, setSubmitLoading] = useState(false);
function submitRequestClaim() {
setSubmitLoading(true);
const formData = makeFormData({
request_logs_id: member.id,
service_code: member.service_code,
member_id: member.member_id,
additional_files: fileAdditionals
});
axios
.post('/claim-requests', formData)
.then((response) => {
enqueueSnackbar(response.data.meta.message ?? 'Berhasil membuat data', { variant: 'success' });
handleSubmitSuccess();
onClose({ someData: 'example data' }, getData);
})
.catch(({ response }) => {
enqueueSnackbar(response.data.meta.message ?? 'Something Went Wrong', { variant: 'error' });
})
.then(() => {
setSubmitLoading(false);
});
}
return (
<Stack>
<Stack direction="row" justifyContent={'end'} sx={{ marginBottom: 2, marginTop: 2 }} spacing={2}>
<Typography variant='body2' sx={{color: '#757575'}}>
{localeData.txtDialogMember5}
</Typography>
<Typography variant='body2' sx={{fontWeight:'bold'}}>{format(member?.submission_date ? new Date(member.submission_date) : new Date(), "d MMM yyyy")}</Typography>
</Stack>
<Card sx={{ p: 1, background: '#f4f6f8'}}>
<Stack direction="row">
<Avatar
src="https://minimal-assets-api.vercel.app/assets/images/avatars/avatar_5.jpg"
alt={member?.full_name ?? ''}
sx={{ marginTop: 1, width: 48, height: 48 }}
/>
<Stack sx={{ p: 1 }}>
<Typography variant="body2">{member?.full_name ?? ''}</Typography>
<Typography variant="body2" sx={{color:'#637381'}}>{member?.no_polis ?? ''}</Typography>
</Stack>
</Stack>
</Card>
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={4}
sx={{ marginY: 2, marginBottom: 6 }}
>
{/* -------------------------------Upload Dokumen Tambahan------------------------------- */}
<Stack sx={{ marginTop: 2 }}>
<Typography variant="body1" sx={{fontWeight:'bold'}}>
{localeData.txtAdditionalDocuments}
</Typography>
{/* <Typography variant="body2">Hasil Lab, </Typography> */}
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2 }}
>
{fileAdditionals &&
fileAdditionals.map((file:any, index:any) => (
<Stack direction="row" justifyContent={'space-between'} key={index}>
<Typography sx={{ color: "text.secondary" }}>{file.name}</Typography>
<Iconify
icon="eva:trash-2-outline"
color={'darkred'}
onClick={() => {
removeKondisiFiles(fileAdditionals, index);
}}
></Iconify>
</Stack>
))}
</Stack>
<ButtonBase sx={{ p: 4, border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
width: '100%', height: '60px'}} onClick={() => fileAdditionalInput.current?.click()}>
<Box
sx={{
display: 'flex',
placeItems: 'center',
gap: 1,
placeContent: 'center',
}}
>
<Iconify icon="icon-park-outline:upload-one" fontSize="3em" />
<Typography variant="body1" fontWeight="bold">
{localeData.txtAddResult}
</Typography>
</Box>
<input
type="file"
id="file"
ref={fileAdditionalInput}
style={{ display: 'none' }}
multiple
onChange={handleKondisiInputChange}
accept="application/pdf"
/>
</ButtonBase>
</Stack>
</Stack>
<LoadingButton
variant="contained"
sx={{ marginTop: 2, p: 2, backgroundColor: '#19BBBB' }}
onClick={() => {
submitRequestClaim();
}}
loading={submitLoading}
>
Submit Claim
</LoadingButton>
</Stack>
);
}

View File

@@ -0,0 +1,328 @@
import { styled } from '@mui/material/styles';
import Iconify from '@/components/Iconify';
import { fCurrency } from '@/utils/formatNumber';
import { LoadingButton } from '@mui/lab';
import { Avatar, Button, Divider, LinearProgress, linearProgressClasses, ButtonBase, Box } from '@mui/material';
import { Card } from '@mui/material';
import { Stack, Typography } from '@mui/material';
import { fPostFormat } from '@/utils/formatTime';
import axios from '@/utils/axios';
import { enqueueSnackbar } from 'notistack';
import { useRef, useState, useContext } from 'react';
import { makeFormData } from '@/utils/jsonToFormData';
import { format } from 'date-fns';
import { LanguageContext } from '@/contexts/LanguageContext';
export default function DialogFinalLog({ member, getData, onClose, handleSubmitSuccess }: any) {
const { localeData }: any = useContext(LanguageContext);
// ----------------------------------------------------------------------
// Files Diagnosa
const fileDiagnosaInput = useRef<HTMLInputElement>(null);
const [fileDiagnosas, setFileDiagnosas] = useState<any>([]);
const handleDiagnosaInputChange = (event:any) => {
if (event.target.files[0]) {
setFileDiagnosas([...fileDiagnosas, ...event.target.files]);
} else {
console.log('NO FILE');
}
};
const removeDiagnosaFiles = (filesState:any, index:any) => {
setFileDiagnosas(
filesState.filter((file:any, fileIndex:any) => {
return fileIndex != index;
})
);
};
// ----------------------------------------------------------------------
// Files Result Kondisi
const fileKondisiInput = useRef<HTMLInputElement>(null);
const [fileKondisis, setFileKondisis] = useState<any>([]);
const handleKondisiInputChange = (event:any) => {
if (event.target.files[0]) {
setFileKondisis([...fileKondisis, ...event.target.files]);
} else {
console.log('NO FILE');
}
};
const removeKondisiFiles = (filesState:any, index:any) => {
setFileKondisis(
filesState.filter((file:any, fileIndex:any) => {
return fileIndex != index;
})
);
};
// ----------------------------------------------------------------------
// Files Result Hasil Penunjang
const fileHasilPenunjangInput = useRef<HTMLInputElement>(null);
const [fileHasilPenunjangs, setFileHasilPenunjangs] = useState<any>([]);
const handleResultInputChange = (event:any) => {
if (event.target.files[0]) {
setFileHasilPenunjangs([...fileHasilPenunjangs, ...event.target.files]);
} else {
console.log('NO FILE');
}
};
const removeFiles = (filesState:any, index:any) => {
setFileHasilPenunjangs(
filesState.filter((file:any, fileIndex:any) => {
return fileIndex != index;
})
);
};
// --------------------------------------------------------------
// Submit Form
const [submitLoading, setSubmitLoading] = useState(false);
function submitRequestFinalLog() {
setSubmitLoading(true);
const formData = makeFormData({
request_logs_id: member.id,
result_files: fileHasilPenunjangs,
diagnosa_files: fileDiagnosas,
kondisi_files: fileKondisis
});
axios
.post('/request-final-log', formData)
.then((response) => {
enqueueSnackbar(response.data.meta.message ?? 'Berhasil membuat data', { variant: 'success' });
handleSubmitSuccess();
onClose({ someData: 'example data' }, getData);
})
.catch(({ response }) => {
enqueueSnackbar(response.data.meta.message ?? 'Something Went Wrong', { variant: 'error' });
})
.then(() => {
setSubmitLoading(false);
});
}
return (
<Stack>
<Stack direction="row" justifyContent={'end'} sx={{ marginBottom: 2, marginTop: 2 }} spacing={2}>
<Typography variant='body2' sx={{color: '#757575'}}>
{localeData.txtDialogMember5}
</Typography>
<Typography variant='body2' sx={{fontWeight:'bold'}}>{format(member?.submission_date ? new Date(member.submission_date) : new Date(), "d MMM yyyy")}</Typography>
</Stack>
<Card sx={{ p: 1, background: '#f4f6f8'}}>
<Stack direction="row">
<Avatar
src="https://minimal-assets-api.vercel.app/assets/images/avatars/avatar_5.jpg"
alt={member?.full_name ?? ''}
sx={{ marginTop: 1, width: 48, height: 48 }}
/>
<Stack sx={{ p: 1 }}>
<Typography variant="body2">{member?.full_name ?? ''}</Typography>
<Typography variant="body2" sx={{color:'#637381'}}>{member?.no_polis ?? ''}</Typography>
</Stack>
</Stack>
</Card>
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={4}
sx={{ marginY: 2, marginBottom: 6 }}
>
{/* -------------------------------Upload Dokumen Kondisi------------------------------- */}
<Stack sx={{ marginTop: 2 }}>
<Typography variant="body1" sx={{fontWeight:'bold'}}>
{localeData.txtConditionDocument}
</Typography>
{/* <Typography variant="body2">Hasil Lab, </Typography> */}
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2 }}
>
{fileKondisis &&
fileKondisis.map((file:any, index:any) => (
<Stack direction="row" justifyContent={'space-between'} key={index}>
<Typography sx={{ color: "text.secondary" }}>{file.name}</Typography>
<Iconify
icon="eva:trash-2-outline"
color={'darkred'}
onClick={() => {
removeKondisiFiles(fileKondisis, index);
}}
></Iconify>
</Stack>
))}
</Stack>
<ButtonBase sx={{ p: 4, border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
width: '100%', height: '60px'}} onClick={() => fileKondisiInput.current?.click()}>
<Box
sx={{
display: 'flex',
placeItems: 'center',
gap: 1,
placeContent: 'center',
}}
>
<Iconify icon="icon-park-outline:upload-one" fontSize="3em" />
<Typography variant="body1" fontWeight="bold">
{localeData.txtAddResult}
</Typography>
</Box>
<input
type="file"
id="file"
ref={fileKondisiInput}
style={{ display: 'none' }}
multiple
onChange={handleKondisiInputChange}
accept="application/pdf"
/>
</ButtonBase>
</Stack>
{/* -------------------------------Upload Dokumen Diagnosa------------------------------- */}
<Stack sx={{ marginTop: 2 }}>
<Typography variant="body1" sx={{fontWeight:'bold'}}>
{localeData.txtDiagnosisDokument}
</Typography>
{/* <Typography variant="body2">Hasil Lab, </Typography> */}
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2 }}
>
{fileDiagnosas &&
fileDiagnosas.map((file:any, index:any) => (
<Stack direction="row" justifyContent={'space-between'} key={index}>
<Typography sx={{ color: "text.secondary" }}>{file.name}</Typography>
<Iconify
icon="eva:trash-2-outline"
color={'darkred'}
onClick={() => {
removeDiagnosaFiles(fileDiagnosas, index);
}}
></Iconify>
</Stack>
))}
{/* <Stack direction="row" justifyContent={'space-between'}>
<Typography>Nama File .pdf</Typography>
<Iconify icon="eva:trash-2-outline" color={'darkred'}></Iconify>
</Stack> */}
</Stack>
{/* { JSON.stringify(filesResult) } */}
<ButtonBase sx={{ p: 4, border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
width: '100%', height: '60px'}} onClick={() => fileDiagnosaInput.current?.click()}>
<Box
sx={{
display: 'flex',
placeItems: 'center',
gap: 1,
placeContent: 'center',
}}
>
<Iconify icon="icon-park-outline:upload-one" fontSize="3em" />
<Typography variant="body1" fontWeight="bold">
{localeData.txtAddResult}
</Typography>
</Box>
<input
type="file"
id="file"
ref={fileDiagnosaInput}
style={{ display: 'none' }}
multiple
onChange={handleDiagnosaInputChange}
accept="application/pdf"
/>
</ButtonBase>
</Stack>
{/* -------------------------------Upload Dokumen Hasil Penunjang------------------------------- */}
<Stack sx={{ marginTop: 2 }}>
<Typography variant="body1" sx={{fontWeight:'bold'}}>
{localeData.txtSupportingResultDocument}
</Typography>
{/* <Typography variant="body2">Hasil Lab, </Typography> */}
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2 }}
>
{fileHasilPenunjangs &&
fileHasilPenunjangs.map((file:any, index:any) => (
<Stack direction="row" justifyContent={'space-between'} key={index}>
<Typography sx={{ color: "text.secondary" }}>{file.name}</Typography>
<Iconify
icon="eva:trash-2-outline"
color={'darkred'}
onClick={() => {
removeFiles(fileHasilPenunjangs, index);
}}
></Iconify>
</Stack>
))}
{/* <Stack direction="row" justifyContent={'space-between'}>
<Typography>Nama File .pdf</Typography>
<Iconify icon="eva:trash-2-outline" color={'darkred'}></Iconify>
</Stack> */}
</Stack>
{/* { JSON.stringify(filesResult) } */}
<ButtonBase sx={{ p: 4, border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
width: '100%', height: '60px'}} onClick={() => fileHasilPenunjangInput.current?.click()}>
<Box
sx={{
display: 'flex',
placeItems: 'center',
gap: 1,
placeContent: 'center',
}}
>
<Iconify icon="icon-park-outline:upload-one" fontSize="3em" />
<Typography variant="body1" fontWeight="bold">
{localeData.txtAddResult}
</Typography>
</Box>
<input
type="file"
id="file"
ref={fileHasilPenunjangInput}
style={{ display: 'none' }}
multiple
onChange={handleResultInputChange}
accept="application/pdf"
/>
</ButtonBase>
</Stack>
</Stack>
<LoadingButton
variant="contained"
sx={{ marginTop: 2, p: 2, backgroundColor: '#19BBBB' }}
onClick={() => {
submitRequestFinalLog();
}}
loading={submitLoading}
>
Request Final LOG
</LoadingButton>
</Stack>
);
}

View File

@@ -33,7 +33,7 @@ import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
export default function DialogMember(member:any, handleSubmitSuccess:() => void) {
const { localeData }: any = useContext(LanguageContext);
const [currentTab, setCurrentTab] = useState('request')
const [currentTab, setCurrentTab] = useState('request');
// ----------------------------------------------------------------------
@@ -97,7 +97,9 @@ export default function DialogMember(member:any, handleSubmitSuccess:() => void)
>
<Tab value="detail" label={localeData.txtDialogMember3} />
<Tab value="service" label={localeData.txtDialogMember1} />
<Tab value="request" label={localeData.txtDialogMember2} />
{member?.type !== 'view' ? (
<Tab value="request" label={localeData.txtDialogMember2} />
) : ''}
</Tabs>
<TabPanel value={currentTab} index={'detail'}>

View File

@@ -1,8 +1,9 @@
/* ---------------------------------- @mui ---------------------------------- */
import { Stack, Button, MenuItem, SelectChangeEvent } from '@mui/material';
import { Stack, Button, MenuItem, SelectChangeEvent, Tab, Tabs, Card, Box } from '@mui/material';
/* ---------------------------------- axios --------------------------------- */
// import axios from 'axios';
import axios from '../../utils/axios';
import { styled } from '@mui/material/styles';
/* ---------------------------------- react --------------------------------- */
import { useContext, useEffect, useState } from 'react';
@@ -23,9 +24,26 @@ import HistoryIcon from '@mui/icons-material/History';
import SearchIcon from '@mui/icons-material/Search';
import Label from '../../components/Label';
import { enqueueSnackbar } from 'notistack';
import { LoadingButton, TabPanel } from "@mui/lab";
import { LanguageContext } from '@/contexts/LanguageContext';
import MuiDialog from '@/components/MuiDialog';
import DialogMember from './DialogMember';
import DialogFinalLog from './DialogFinalLog';
import { fPostFormat } from '@/utils/formatTime';
import TableListFinalLog from './TableListFinalLog';
export default function TableList2() {
export default function TableList() {
const navigate = useNavigate();
const { localeData }: any = useContext(LanguageContext);
const [currentTab, setCurrentTab] = useState<string>('request_log');
useEffect(() => {
setCurrentTab('request_log')
}, [])
function handleChangeTab(event: React.SyntheticEvent, newValue: string) {
setCurrentTab(newValue)
}
//const { corporateValue } = useContext(UserCurrentCorporateContext);
//const { corporateValue } = useContext(null);
@@ -33,7 +51,7 @@ export default function TableList2() {
const [data, setData] = useState([]);
// Download LOG
async function handleDownloadLog(claimRequest) {
async function handleDownloadLog(claimRequest:any) {
return axios
.get(`claim-requests/${claimRequest}/log`, {
responseType: 'blob',
@@ -215,36 +233,30 @@ export default function TableList2() {
handleEndDateChange: handleEndDateChanges,
};
/* -------------------------------- headCell -------------------------------- */
/* -------------------------------- headCell Request LOG -------------------------------- */
const headCells: HeadCell<never>[] = [
{
id: 'submission_date',
align: 'center',
label: 'Request Date',
isSort: true,
},
{
id: 'member_id',
align: 'left',
label: 'Member ID',
isSort: true,
},
{
id: 'code',
align: 'left',
label: 'Claim Code',
label: localeData.txtRequestCode,
isSort: true,
},
{
id: 'full_name',
align: 'left',
label: 'Name',
label: localeData.txtName,
isSort: true,
},
{
id: 'submission_date',
align: 'center',
label: localeData.txtSubmissionDate,
isSort: true,
},
{
id: 'status',
align: 'center',
label: 'Status',
label: localeData.txtStatus,
isSort: true,
},
{
@@ -254,8 +266,47 @@ export default function TableList2() {
isSort: false,
},
];
function handleSearchMember(noPolis:any, birthDate:any) {
setLoadingClaim(false)
axios.post('/search-member', {
no_polis: noPolis,
birth_date: birthDate ? fPostFormat(birthDate, 'yyyy-MM-dd') : null,
type: 'view'
})
.then((response) => {
setOpenDialogBenefit(true)
setCurrentMember(response.data.data)
setNameMember(response.data.data.members.name);
})
.catch(({response}) => {
enqueueSnackbar(response.data.errors ? response.data.errors[0] : (response.data ? response.data.meta.message : 'Opps, Something went Wrong!'), {variant : "error"})
})
.then(() => {
});
}
function handleRequestFinalLog(id:any, full_name:any, no_polis:any, submission_date:any)
{
setOpenDialogFinalLog(true);
const datas_view = {
'id' : id,
'full_name' : full_name,
'no_polis' : no_polis,
'submission_date' : submission_date
};
setDataViewFinalDialog(datas_view);
}
useEffect(() => {
getData();
}, [appliedParams, searchParams, order, orderBy, setSearchParams]);
function getData()
{
(async () => {
setIsLoading(true);
@@ -266,10 +317,9 @@ export default function TableList2() {
? appliedParams
: Object.fromEntries([...searchParams.entries(), ['order', order], ['orderBy', orderBy]]);
const response = await axios.get(`/get-claim-requests`, {
params: { ...parameters, type: 'claim-request' },
const response = await axios.get(`/get-request-log`, {
params: { ...parameters, type: 'request-log' },
});
setData(
response.data.data.map((obj: any) => ({
...obj,
@@ -303,14 +353,22 @@ export default function TableList2() {
action:
<TableMoreMenu actions={
<>
<MenuItem onClick={() => navigate ('/detail/'+obj.claim_request_id)}>
<MenuItem onClick={() => handleSearchMember(obj.no_polis, obj.birth_date) }>
<Iconify icon="eva:eye-fill" />
View
</MenuItem>
{obj.status === 'approved' ? (
<MenuItem onClick={() => handleDownloadLog(obj.claim_request_id)}>
<Iconify icon="eva:download-fill" />
Download LOG
</MenuItem>
):''}
{obj.final_log === 0 ? (
<MenuItem onClick={() => handleRequestFinalLog(obj.id, obj.full_name, obj.no_polis, obj.submission_date) }>
<Iconify icon="fa:file-text" />
Request Final LOG
</MenuItem>
):''}
</>
} />
}))
@@ -327,32 +385,116 @@ export default function TableList2() {
setPage(currentPage);
}
const status = [
const status:any = [
{"id": "requested", "name": "Request" },
{"id": "reviewed", "name": "Review" },
{"id": "approved", "name": "Approval" },
{"id": "declined", "name": "Decline" },
]
];
setStatusData(status)
setIsLoading(false);
})();
}, [appliedParams, searchParams, order, orderBy, setSearchParams]);
}
const RootNotificationStyle = styled(Card)(({ theme }) => ({
boxShadow: 'none',
padding: '1rem 0.5rem',
color: 'black',
borderRadius: 0,
backgroundColor: theme.palette.grey[200],
// maxHeight: '240px',
}));
function TabPanel(props:any) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && (
<Box sx={{ p: 3 }}>
<div>{children}</div>
</Box>
)}
</div>
);
}
// const [noPolis, setNoPolis] = useState('AW001-01');
//const [birthDate, setBirthDate] = useState('1991-01-10');
const [loadingBenefit, setLoadingBenefit] = useState(false);
const [loadingClaim, setLoadingClaim] = useState(false);
const [openDialogBenefit, setOpenDialogBenefit] = useState(false);
const [openDialogFinalLog, setOpenDialogFinalLog] = useState(false);
const [openDialogClaim, setOpenDialogClaim] = useState(false);
const [currentMember, setCurrentMember] = useState(null);
const [nameMember, setNameMember] = useState('');
const [setIsRequestFinalLog, isRequestFinalLog] = useState(false);
const [dataViewFinalDialog, setDataViewFinalDialog] = useState<any>(null);
return (
<Stack>
<TableComponent
headCells={headCells}
rows={data}
orders={orders}
paginations={paginations}
loadings={loadings}
params={params}
searchs={searchs}
filterStatus={filterStatus}
// filterStartDate={filterStartDate}
// filterEndDate={filterEndDate}
/>
</Stack>
<Card>
<RootNotificationStyle sx={{ p: 2, height: 'auto' }}>
<Tabs
value={currentTab}
onChange={handleChangeTab}
aria-label="wrapped label tabs example"
>
<Tab value="request_log" label= "Request LOG" />
<Tab value="final_log" label= "Final LOG" />
</Tabs>
</RootNotificationStyle>
<TabPanel value={currentTab} index={'request_log'}>
<TableComponent
headCells={headCells}
rows={data}
orders={orders}
paginations={paginations}
loadings={loadings}
params={params}
searchs={searchs}
filterStatus={filterStatus}
// filterStartDate={filterStartDate}
// filterEndDate={filterEndDate}
/>
</TabPanel>
<TabPanel value={currentTab} index={'final_log'}>
<TableListFinalLog/>
</TabPanel>
<MuiDialog
title={{name: nameMember}}
openDialog={openDialogBenefit}
setOpenDialog={setOpenDialogBenefit}
content={
DialogMember(currentMember, () => setOpenDialogBenefit(false))
}
maxWidth="sm"
/>
<MuiDialog
title={{name: dataViewFinalDialog?.full_name}}
openDialog={openDialogFinalLog}
setOpenDialog={setOpenDialogFinalLog}
content={
<DialogFinalLog
member={dataViewFinalDialog}
getData={getData}
onClose={(data:any, getData:any) => {
console.log('Data returned:', data);
getData();
setOpenDialogFinalLog(false);
}}
handleSubmitSuccess={() => {
}}
/>
}
maxWidth="sm"
/>
</Card>
);
}

View File

@@ -0,0 +1,441 @@
/* ---------------------------------- @mui ---------------------------------- */
import { Stack, Button, MenuItem, SelectChangeEvent, Tab, Tabs, Card, Box } from '@mui/material';
/* ---------------------------------- axios --------------------------------- */
// import axios from 'axios';
import axios from '../../utils/axios';
import { styled } from '@mui/material/styles';
/* ---------------------------------- react --------------------------------- */
import { useContext, useEffect, useState } from 'react';
/* -------------------------------- component ------------------------------- */
import Iconify from '../../components/Iconify';
import TableComponent from '../../components/Table';
/* ---------------------------------- theme --------------------------------- */
import palette from '../../theme/palette';
//import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate';
import { HeadCell, Order, PaginationTableProps } from '../../@types/table';
import { useSearchParams, useNavigate } from 'react-router-dom';
import { fDate, fDateSuffix } from '../../utils/formatTime';
import Typography from '@mui/material/Typography';
import { format } from 'date-fns';
import TableMoreMenu from '../../components/table/TableMoreMenu';
import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
import HistoryIcon from '@mui/icons-material/History';
import SearchIcon from '@mui/icons-material/Search';
import Label from '../../components/Label';
import { enqueueSnackbar } from 'notistack';
import { LoadingButton, TabPanel } from "@mui/lab";
import { LanguageContext } from '@/contexts/LanguageContext';
import MuiDialog from '@/components/MuiDialog';
import DialogMember from './DialogMember';
import DialogClaimSubmit from './DialogClaimSubmit';
import { fPostFormat } from '@/utils/formatTime';
export default function TableListFinalLog() {
const navigate = useNavigate();
const { localeData }: any = useContext(LanguageContext);
const [data, setData] = useState([]);
// Download LOG
async function handleDownloadLog(claimRequest:any) {
return axios
.get(`claim-requests/${claimRequest}/log`, {
responseType: 'blob',
})
.then((response) => {
window.open(URL.createObjectURL(response.data));
// setLoadingLog(false);
})
// .then((blobFile) => {
// new File([blobFile], 'asdads.pdf', { type: blobFile.type })
// setLoadingLog(false);
// })
.catch((response) => {
console.log(response);
enqueueSnackbar(response.message, { variant: 'error' });
// setLoadingLog(false);
});
}
/* -------------------------------------------------------------------------- */
/* setting up for the table */
/* -------------------------------------------------------------------------- */
const [isLoading, setIsLoading] = useState(true);
const loadings = {
isLoading: isLoading,
setIsLoading: setIsLoading,
};
/* ------------------------------ handle params ----------------------------- */
const [searchParams, setSearchParams] = useSearchParams();
const [appliedParams, setAppliedParams] = useState({});
const params = {
searchParams: searchParams,
setSearchParams: setSearchParams,
appliedParams: appliedParams,
setAppliedParams: setAppliedParams,
};
/* -------------------------------------------------------------------------- */
/* ------------------------------ handle order ------------------------------ */
const [order, setOrder] = useState<Order>('desc');
const [orderBy, setOrderBy] = useState('submission_date');
const orders = {
order: order,
setOrder: setOrder,
orderBy: orderBy,
setOrderBy: setOrderBy,
};
/* -------------------------------------------------------------------------- */
/* ---------------------------- handle pagination --------------------------- */
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10);
const [paginationTable, setPaginationTable] = useState<PaginationTableProps>({
current_page: 0,
from: 0,
last_page: 0,
links: [],
path: '',
per_page: 0,
to: 0,
total: 0,
});
const paginations = {
page: page,
setPage: setPage,
rowsPerPage: rowsPerPage,
setRowsPerPage: setRowsPerPage,
paginationTable: paginationTable,
setPaginationTable: setPaginationTable,
};
/* -------------------------------------------------------------------------- */
/* ------------------------------ handle search ----------------------------- */
const [searchText, setSearchText] = useState('');
const handleSearchSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (searchText === '') {
searchParams.delete('search');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([...searchParams.entries(), ['search', searchText]]);
setAppliedParams(params);
}
};
const searchs = {
useSearchs: true,
searchText: searchText,
setSearchText: setSearchText,
handleSearchSubmit: handleSearchSubmit,
};
/* ------------------------------ handle filter ----------------------------- */
const [statusValue, setStatusValue] = useState('all');
const [filterData, setStatusData] = useState([]);
// handle status
const handleStatusChanges = (event: SelectChangeEvent) => {
setStatusValue(event.target.value as string);
if (event.target.value === 'all') {
searchParams.delete('status');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([
...searchParams.entries(),
['status', event.target.value as string],
]);
setAppliedParams(params);
}
};
const filterStatus = {
useFilter: true,
config: {
label: 'Status',
statusValue: statusValue,
filterData: filterData,
handleStatusChange: handleStatusChanges,
},
};
// handle start date
const [startDateValue, setStartDateValue] = useState('');
const handleStartDateChanges = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const newStartDateValue = event.currentTarget.elements['date-input'].value;
setStartDateValue(newStartDateValue);
if (newStartDateValue === '') {
searchParams.delete('start_date');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([...searchParams.entries(), ['start_date', newStartDateValue]]);
setAppliedParams(params);
}
};
const filterStartDate = {
useFilter: true,
startDate: startDateValue,
setStartDate: setStartDateValue,
handleStartDateChange: handleStartDateChanges,
};
// handle end date
const [endDateValue, setEndDateValue] = useState('');
const handleEndDateChanges = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const newEndDateValue = event.currentTarget.elements['date-input'].value;
setEndDateValue(newEndDateValue);
if (newEndDateValue === '') {
searchParams.delete('end_date');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([...searchParams.entries(), ['end_date', newEndDateValue]]);
setAppliedParams(params);
}
};
const filterEndDate = {
useFilter: true,
endDate: endDateValue,
setEndDate: setEndDateValue,
handleEndDateChange: handleEndDateChanges,
};
/* -------------------------------- headCell Final LOG -------------------------------- */
const headCells: HeadCell<never>[] = [
{
id: 'code',
align: 'left',
label: localeData.txtRequestCode,
isSort: true,
},
{
id: 'full_name',
align: 'left',
label: localeData.txtName,
isSort: true,
},
{
id: 'submission_date',
align: 'center',
label: localeData.txtSubmissionDate,
isSort: true,
},
{
id: 'service_type',
align: 'center',
label: localeData.txtServiceType,
isSort: true,
},
{
id: 'status',
align: 'center',
label: localeData.txtStatus,
isSort: true,
},
{
id: 'action',
align: 'right',
label: '',
isSort: false,
},
];
function handleSearchMember(noPolis:any, birthDate:any) {
setLoadingClaim(false)
axios.post('/search-member', {
no_polis: noPolis,
birth_date: birthDate ? fPostFormat(birthDate, 'yyyy-MM-dd') : null,
type: 'view'
})
.then((response) => {
setOpenDialogBenefit(true)
setCurrentMember(response.data.data)
setNameMember(response.data.data.members.name);
})
.catch(({response}) => {
enqueueSnackbar(response.data.errors ? response.data.errors[0] : (response.data ? response.data.meta.message : 'Opps, Something went Wrong!'), {variant : "error"})
})
.then(() => {
});
}
const [openDialogClaimSubmit, setOpenDialogClaimSubmit] = useState(false);
const [dataViewClaimSubmit, setDataViewClaimSubmit] = useState<any>(null);
function handleRequestClaimSubmit(member_id:any, service_code:any, id:any, full_name:any, no_polis:any, submission_date:any)
{
setOpenDialogClaimSubmit(true);
const datas_view = {
'member_id' : member_id,
'service_code' : service_code,
'id' : id,
'full_name' : full_name,
'no_polis' : no_polis,
'submission_date' : submission_date
};
setDataViewClaimSubmit(datas_view);
}
useEffect(() => {
getData();
}, [appliedParams, searchParams, order, orderBy, setSearchParams]);
function getData()
{
(async () => {
setIsLoading(true);
await new Promise((resolve) => setTimeout(resolve, 250));
const parameters =
Object.keys(appliedParams).length !== 0
? appliedParams
: Object.fromEntries([...searchParams.entries(), ['order', order], ['orderBy', orderBy]]);
const response = await axios.get(`/get-final-log`, {
params: { ...parameters, type: 'final-log' },
});
setData(
response.data.data.map((obj: any) => ({
...obj,
status:
obj.status === 'requested' ? (
<Label color='primary'>
Request
</Label>
) : obj.status === 'approved' ? (
<Label color='success' >
Approval
</Label>
) : obj.status === 'declined' ? (
<Label color='error'>
Decline
</Label>
) : obj.status === 'reviewed' ? (
<Label color='info'>
Review
</Label>
) : (
<Label color='primary'>
Pending
</Label>
),
submission_date:
<Label>
{obj.submission_date ? fDateSuffix(obj.submission_date) : ''}
</Label>
,
action:
<TableMoreMenu actions={
<>
<MenuItem onClick={() => handleSearchMember(obj.no_polis, obj.birth_date) }>
<Iconify icon="eva:eye-fill" />
View
</MenuItem>
{obj.status === 'approved' ? (
<MenuItem onClick={() => handleDownloadLog(obj.claim_request_id)}>
<Iconify icon="eva:download-fill" />
Download LOG
</MenuItem>
):''}
{!obj.check_claim ? (
<MenuItem onClick={() => handleRequestClaimSubmit(obj.member_id, obj.service_code, obj.id, obj.full_name, obj.no_polis, obj.submission_date) }>
<Iconify icon="fa:file-text" />
Submit Claim
</MenuItem>
):''}
</>
} />
}))
);
setPaginationTable(response.data);
setRowsPerPage(response.data.per_page);
if (searchParams.get('page')) {
//@ts-ignore
const currentPage = parseInt(searchParams.get('page')) - 1;
paginationTable.current_page = currentPage;
setPage(currentPage);
}
const status:any = [
{"id": "requested", "name": "Request" },
{"id": "reviewed", "name": "Review" },
{"id": "approved", "name": "Approval" },
{"id": "declined", "name": "Decline" },
];
setStatusData(status)
setIsLoading(false);
})();
}
const [loadingClaim, setLoadingClaim] = useState(false);
const [openDialogBenefit, setOpenDialogBenefit] = useState(false);
const [currentMember, setCurrentMember] = useState(null);
const [nameMember, setNameMember] = useState('');
return (
<>
<TableComponent
headCells={headCells}
rows={data}
orders={orders}
paginations={paginations}
loadings={loadings}
params={params}
searchs={searchs}
filterStatus={filterStatus}
// filterStartDate={filterStartDate}
// filterEndDate={filterEndDate}
/>
<MuiDialog
title={{name: nameMember}}
openDialog={openDialogBenefit}
setOpenDialog={setOpenDialogBenefit}
content={
DialogMember(currentMember, () => setOpenDialogBenefit(false))
}
maxWidth="sm"
/>
<MuiDialog
title={{name: dataViewClaimSubmit?.full_name}}
openDialog={openDialogClaimSubmit}
setOpenDialog={setOpenDialogClaimSubmit}
content={
<DialogClaimSubmit
member={dataViewClaimSubmit}
getData={getData}
onClose={(data:any, getData:any) => {
console.log('Data returned:', data);
getData();
setOpenDialogClaimSubmit(false);
}}
handleSubmitSuccess={() => {
}}
/>
}
maxWidth="sm"
/>
</>
);
}

View File

@@ -0,0 +1,425 @@
/* ---------------------------------- @mui ---------------------------------- */
import { Stack, Button, MenuItem, SelectChangeEvent, Tab, Tabs, Card, Box } from '@mui/material';
/* ---------------------------------- axios --------------------------------- */
// import axios from 'axios';
import axios from '../../utils/axios';
import { styled } from '@mui/material/styles';
/* ---------------------------------- react --------------------------------- */
import { useContext, useEffect, useState } from 'react';
/* -------------------------------- component ------------------------------- */
import Iconify from '../../components/Iconify';
import TableComponent from '../../components/Table';
/* ---------------------------------- theme --------------------------------- */
import palette from '../../theme/palette';
//import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate';
import { HeadCell, Order, PaginationTableProps } from '../../@types/table';
import { useSearchParams, useNavigate } from 'react-router-dom';
import { fDate, fDateSuffix } from '../../utils/formatTime';
import Typography from '@mui/material/Typography';
import { format } from 'date-fns';
import TableMoreMenu from '../../components/table/TableMoreMenu';
import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
import HistoryIcon from '@mui/icons-material/History';
import SearchIcon from '@mui/icons-material/Search';
import Label from '../../components/Label';
import { enqueueSnackbar } from 'notistack';
import { LoadingButton, TabPanel } from "@mui/lab";
import { LanguageContext } from '@/contexts/LanguageContext';
export default function TableList() {
const navigate = useNavigate();
const { localeData }: any = useContext(LanguageContext);
const [currentTab, setCurrentTab] = useState<string>('request_log');
useEffect(() => {
setCurrentTab('request_log')
}, [])
function handleChangeTab(event: React.SyntheticEvent, newValue: string) {
setCurrentTab(newValue)
}
//const { corporateValue } = useContext(UserCurrentCorporateContext);
//const { corporateValue } = useContext(null);
const [data, setData] = useState([]);
// Download LOG
async function handleDownloadLog(claimRequest) {
return axios
.get(`claim-requests/${claimRequest}/log`, {
responseType: 'blob',
})
.then((response) => {
window.open(URL.createObjectURL(response.data));
// setLoadingLog(false);
})
// .then((blobFile) => {
// new File([blobFile], 'asdads.pdf', { type: blobFile.type })
// setLoadingLog(false);
// })
.catch((response) => {
console.log(response);
enqueueSnackbar(response.message, { variant: 'error' });
// setLoadingLog(false);
});
}
/* -------------------------------------------------------------------------- */
/* setting up for the table */
/* -------------------------------------------------------------------------- */
const [isLoading, setIsLoading] = useState(true);
const loadings = {
isLoading: isLoading,
setIsLoading: setIsLoading,
};
/* ------------------------------ handle params ----------------------------- */
const [searchParams, setSearchParams] = useSearchParams();
const [appliedParams, setAppliedParams] = useState({});
const params = {
searchParams: searchParams,
setSearchParams: setSearchParams,
appliedParams: appliedParams,
setAppliedParams: setAppliedParams,
};
/* -------------------------------------------------------------------------- */
/* ------------------------------ handle order ------------------------------ */
const [order, setOrder] = useState<Order>('desc');
const [orderBy, setOrderBy] = useState('submission_date');
const orders = {
order: order,
setOrder: setOrder,
orderBy: orderBy,
setOrderBy: setOrderBy,
};
/* -------------------------------------------------------------------------- */
/* ---------------------------- handle pagination --------------------------- */
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10);
const [paginationTable, setPaginationTable] = useState<PaginationTableProps>({
current_page: 0,
from: 0,
last_page: 0,
links: [],
path: '',
per_page: 0,
to: 0,
total: 0,
});
const paginations = {
page: page,
setPage: setPage,
rowsPerPage: rowsPerPage,
setRowsPerPage: setRowsPerPage,
paginationTable: paginationTable,
setPaginationTable: setPaginationTable,
};
/* -------------------------------------------------------------------------- */
/* ------------------------------ handle search ----------------------------- */
const [searchText, setSearchText] = useState('');
const handleSearchSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (searchText === '') {
searchParams.delete('search');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([...searchParams.entries(), ['search', searchText]]);
setAppliedParams(params);
}
};
const searchs = {
useSearchs: true,
searchText: searchText,
setSearchText: setSearchText,
handleSearchSubmit: handleSearchSubmit,
};
/* ------------------------------ handle filter ----------------------------- */
const [statusValue, setStatusValue] = useState('all');
const [filterData, setStatusData] = useState([]);
// handle status
const handleStatusChanges = (event: SelectChangeEvent) => {
setStatusValue(event.target.value as string);
if (event.target.value === 'all') {
searchParams.delete('status');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([
...searchParams.entries(),
['status', event.target.value as string],
]);
setAppliedParams(params);
}
};
const filterStatus = {
useFilter: true,
config: {
label: 'Status',
statusValue: statusValue,
filterData: filterData,
handleStatusChange: handleStatusChanges,
},
};
// handle start date
const [startDateValue, setStartDateValue] = useState('');
const handleStartDateChanges = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const newStartDateValue = event.currentTarget.elements['date-input'].value;
setStartDateValue(newStartDateValue);
if (newStartDateValue === '') {
searchParams.delete('start_date');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([...searchParams.entries(), ['start_date', newStartDateValue]]);
setAppliedParams(params);
}
};
const filterStartDate = {
useFilter: true,
startDate: startDateValue,
setStartDate: setStartDateValue,
handleStartDateChange: handleStartDateChanges,
};
// handle end date
const [endDateValue, setEndDateValue] = useState('');
const handleEndDateChanges = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const newEndDateValue = event.currentTarget.elements['date-input'].value;
setEndDateValue(newEndDateValue);
if (newEndDateValue === '') {
searchParams.delete('end_date');
const params = Object.fromEntries([...searchParams.entries()]);
setAppliedParams(params);
} else {
const params = Object.fromEntries([...searchParams.entries(), ['end_date', newEndDateValue]]);
setAppliedParams(params);
}
};
const filterEndDate = {
useFilter: true,
endDate: endDateValue,
setEndDate: setEndDateValue,
handleEndDateChange: handleEndDateChanges,
};
/* -------------------------------- headCell -------------------------------- */
const headCells: HeadCell<never>[] = [
{
id: 'submission_date',
align: 'center',
label: localeData.txtRequestDate,
isSort: true,
},
{
id: 'member_id',
align: 'left',
label: localeData.txtMemberID,
isSort: true,
},
{
id: 'code',
align: 'left',
label: localeData.txtClaimCode,
isSort: true,
},
{
id: 'full_name',
align: 'left',
label: localeData.txtName,
isSort: true,
},
{
id: 'status',
align: 'center',
label: localeData.txtStatus,
isSort: true,
},
{
id: 'action',
align: 'right',
label: '',
isSort: false,
},
];
useEffect(() => {
(async () => {
setIsLoading(true);
await new Promise((resolve) => setTimeout(resolve, 250));
const parameters =
Object.keys(appliedParams).length !== 0
? appliedParams
: Object.fromEntries([...searchParams.entries(), ['order', order], ['orderBy', orderBy]]);
const response = await axios.get(`/get-claim-requests`, {
params: { ...parameters, type: 'claim-request' },
});
setData(
response.data.data.map((obj: any) => ({
...obj,
status:
obj.status === 'requested' ? (
<Label color='primary'>
Request
</Label>
) : obj.status === 'approved' ? (
<Label color='success' >
Approval
</Label>
) : obj.status === 'declined' ? (
<Label color='error'>
Decline
</Label>
) : obj.status === 'reviewed' ? (
<Label color='info'>
Review
</Label>
) : (
<Label color='primary'>
Pending
</Label>
),
submission_date:
<Label>
{obj.submission_date ? fDateSuffix(obj.submission_date) : ''}
</Label>
,
action:
<TableMoreMenu actions={
<>
<MenuItem onClick={() => navigate ('/detail/'+obj.claim_request_id)}>
<Iconify icon="eva:eye-fill" />
View
</MenuItem>
<MenuItem onClick={() => handleDownloadLog(obj.claim_request_id)}>
<Iconify icon="eva:download-fill" />
Download LOG
</MenuItem>
</>
} />
}))
);
setPaginationTable(response.data);
setRowsPerPage(response.data.per_page);
if (searchParams.get('page')) {
//@ts-ignore
const currentPage = parseInt(searchParams.get('page')) - 1;
paginationTable.current_page = currentPage;
setPage(currentPage);
}
const status = [
{"id": "requested", "name": "Request" },
{"id": "reviewed", "name": "Review" },
{"id": "approved", "name": "Approval" },
{"id": "declined", "name": "Decline" },
]
setStatusData(status)
setIsLoading(false);
})();
}, [appliedParams, searchParams, order, orderBy, setSearchParams]);
const RootNotificationStyle = styled(Card)(({ theme }) => ({
boxShadow: 'none',
padding: '1rem 0.5rem',
color: 'black',
borderRadius: 0,
backgroundColor: theme.palette.grey[200],
// maxHeight: '240px',
}));
function TabPanel(props:any) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && (
<Box sx={{ p: 3 }}>
<div>{children}</div>
</Box>
)}
</div>
);
}
return (
<Card>
<RootNotificationStyle sx={{ p: 2, height: 'auto' }}>
<Tabs
value={currentTab}
onChange={handleChangeTab}
aria-label="wrapped label tabs example"
>
<Tab value="request_log" label= "Request LOG" />
<Tab value="final_log" label= "Final LOG" />
</Tabs>
</RootNotificationStyle>
<TabPanel value={currentTab} index={'request_log'}>
<TableComponent
headCells={headCells}
rows={data}
orders={orders}
paginations={paginations}
loadings={loadings}
params={params}
searchs={searchs}
filterStatus={filterStatus}
// filterStartDate={filterStartDate}
// filterEndDate={filterEndDate}
/>
</TabPanel>
<TabPanel value={currentTab} index={'request_log'}>
<TableComponent
headCells={headCells}
rows={data}
orders={orders}
paginations={paginations}
loadings={loadings}
params={params}
searchs={searchs}
filterStatus={filterStatus}
// filterStartDate={filterStartDate}
// filterEndDate={filterEndDate}
/>
</TabPanel>
</Card>
);
}

View File

@@ -6,4 +6,5 @@ return [
'not_found' => 'Data not found',
'password' => 'Password wrong. Please try again.',
'read_notification' => 'Notification has been read.',
'already_exists' => 'Data already exists.',
];

View File

@@ -6,4 +6,5 @@ return [
'not_found' => 'Data tidak ditemukan.',
'password' => 'Password salah. Silakan coba lagi.',
'read_notification' => 'Notifikasi telah dibaca.',
'already_exists' => 'Data sudah ada.',
];

View File

@@ -123,8 +123,8 @@
<tr>
<td>
<div class="text-sm text-gray">Date of Admission</div>
@if (isset($claimRequest))
<div class="text-md">{{ !empty($claimRequest->submission_date) ? \Carbon\Carbon::parse($claimRequest->submission_date)->format('d/m/Y') : now()->format('d/m/Y') }}</div>
@if (isset($requestLog))
<div class="text-md">{{ !empty($requestLog->submission_date) ? \Carbon\Carbon::parse($requestLog->submission_date)->format('d/m/Y') : now()->format('d/m/Y') }}</div>
@else
<div class="text-md">{{ $dateOfAdmission->format('d/m/Y') }}</div>
@endif
@@ -140,7 +140,7 @@
<table id="benefit-table">
<tr>
<th class="text-lg" style="font-weight: 600">Detail Benefit</th>
<th class="text-lg" style="font-weight: 600">Limit</th>
<!-- <th class="text-lg" style="font-weight: 600">Limit</th> -->
</tr>
@@ -148,18 +148,34 @@
<td class="text-lg">Medical Check Up</td>
<td class="text-lg">As Charged</td>
</tr> --}}
@if ($member->currentPlan)
@foreach ($member->currentPlan->corporateBenefits as $corporateBenefit)
<tr>
<td>{{ @$corporateBenefit->benefit->description ?? '' }}</td>
</tr>
@endforeach
@endif
</table>
</div>
@foreach ($member->currentPlan->corporateBenefits as $corporateBenefit)
<tr>
<td>{{ @$corporateBenefit->benefit->description ?? '' }}</td>
@if($corporateBenefit->limit_amount == 999999999)
<td style="align-right">As Charged</td>
@else
<td style="align-right">IDR {{ number_format($corporateBenefit->limit_amount, 0, ',', '.') ?? '' }}</td>
@endif
</tr>
@endforeach
<div class="benefit-table-wrapper" style="margin-top: 20px; width: 100%;">
<table id="benefit-table">
<tr>
<th class="text-lg" style="font-weight: 600">Term on Condition</th>
<!-- <th class="text-lg" style="font-weight: 600">Limit</th> -->
</tr>
@if ($member->currentPlan)
@foreach ($member->currentPlan->corporateBenefits as $corporateBenefit)
<tr>
<td>{{ @$corporateBenefit->benefit->description ?? '' }}</td>
</tr>
@endforeach
@endif
</table>
</div>