Update customer service

This commit is contained in:
2023-12-19 08:56:18 +07:00
parent e76c480ce9
commit 40371bd53a
42 changed files with 1027 additions and 2328 deletions

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

@@ -306,10 +306,12 @@ class RequestLogController extends Controller
{
$id = $request->id;
$requestLog = RequestLog::findOrFail($id);
$status = $request->status ?? 'requested';
// Update Request LOG untuk lanjut ke Final LOG
$requestLog->final_log = 1;
$requestLog->status_final_log = 'requested';
$requestLog->status_final_log = $status;
$requestLog->save();

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,9 +7,10 @@ use Modules\Internal\Http\Controllers\Api\AppointmentController;
use Modules\Internal\Http\Controllers\Api\BenefitController;
use Modules\Internal\Http\Controllers\Api\CityController;
use Modules\Internal\Http\Controllers\Api\ClaimController;
use Modules\Internal\Http\Controllers\Api\ClaimRequestController;
use Modules\Internal\Http\Controllers\Api\RequestLogController;
use Modules\Internal\Http\Controllers\Api\RequestLogBenefitController;
use Modules\Internal\Http\Controllers\Api\ClaimRequestController;
use Modules\Internal\Http\Controllers\Api\RequestLogMedicineController;
use Modules\Internal\Http\Controllers\Api\CorporateBenefitController;
use Modules\Internal\Http\Controllers\Api\CorporateController;
use Modules\Internal\Http\Controllers\Api\CorporateFormulariumController;
@@ -258,12 +259,17 @@ Route::prefix('internal')->group(function () {
Route::get('customer-service/request/data', [RequestLogController::class, 'generateDataRequestLogExcel']);
Route::post('customer-service/request/final-log', [RequestLogController::class, 'updateFinalLog']);
// insert benefit
Route::post('customer-service/request/insert-benefit', [RequestLogBenefitController::class, 'store']);
Route::delete('customer-service/request/benefit_data/{id}', [RequestLogBenefitController::class, 'destroy']);
Route::put('customer-service/request/benefit_data/{id}', [RequestLogBenefitController::class, 'update']);
// insert medicine
Route::post('customer-service/request/medicine-data', [RequestLogMedicineController::class, 'store']);
Route::delete('customer-service/request/medicine-data/{id}', [RequestLogMedicineController::class, 'destroy']);
Route::put('customer-service/request/medicine-data/{id}', [RequestLogMedicineController::class, 'update']);
Route::get('search-organizations', [OrganizationController::class, 'searchOrganization']);
Route::get('search-specialities', [SpecialityController::class, 'searchSpeciality']);
Route::resource('organizations', OrganizationController::class);

View File

@@ -7,6 +7,7 @@ use App\Models\CorporateBenefit;
use App\Models\ClaimRequest;
use App\Models\CorporateService;
use App\Models\RequestLogBenefit;
use App\Models\RequestLogMedicine;
use App\Models\Exclusion;
use App\Models\Icd;
use App\Helpers\Helper;
@@ -26,6 +27,7 @@ class RequestLogShowResource extends JsonResource
$corporateId = $requestLog['member']['current_plan']['corporate_id'] ?? 0;
$benefit = CorporateBenefit::with('benefit')->where('plan_id', $corporateId)->get()->toArray();
$benefitDetailLog = RequestLogBenefit::with('benefit')->where('request_log_id', $requestLog['id'])->get()->toArray();
$medicineDetailLog = RequestLogMedicine::where('request_log_id', $requestLog['id'])->get()->toArray();
$benefitData = [];
if (count($benefit)){
foreach($benefit as $data){
@@ -33,13 +35,23 @@ class RequestLogShowResource extends JsonResource
}
}
// Medicine
$medicineData = [];
if (count($medicineDetailLog)){
foreach($medicineDetailLog as $data){
array_push($medicineData, $data);
}
}
// Service Rule
$corporateService = CorporateService::query()
->where('corporate_id', $corporateId)
->where('service_code', $requestLog['service_code'])
->with(['configs'])
->first();
$config = $corporateService->configs->pluck('value', 'name')->toArray();
$config = [];
if ($corporateService) {
$config = $corporateService->configs->pluck('value', 'name')->toArray();
}
// Exclusion Service or diagnosis
$exclusions = Exclusion::query()
@@ -70,6 +82,7 @@ class RequestLogShowResource extends JsonResource
'benefit_data' => $benefitDetailLog,
'config_service' => $config,
'exclusion' => $exclusions,
'medicine' => $medicineData,
'files' => $requestLog['files'],

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

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

@@ -13,7 +13,7 @@ type MuiDialogProps = {
openDialog: boolean;
setOpenDialog: Function;
content?: ReactElement;
action?: ReactElement;
action?: ReactElement|null;
maxWidth?: string;
};

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

@@ -1,355 +0,0 @@
/**
* Core
* ============================================
*/
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router';
import { Box, FormControlLabel, Grid, Checkbox, Typography, CircularProgress , Button, styled, Stack, IconButton, Card} from '@mui/material';
import { LoadingButton } from '@mui/lab';
/**
* Components
* ============================================
*/
// - Global -
import Label from '@/components/Label';
// - Local -
import FormCreateSearch from './FormCreateSearch';
import FormCreateListChoose from './FormCreateListChoose';
import FormCreateBtnUpload from './FormCreateBtnUpload';
/**
* Icon, Utils, Types, Functions, theme, hook
* ============================================
*/
import { ArrowBackIosNew } from '@mui/icons-material';
import { fDateTimesecond } from '@/utils/formatTime';
import { MemberListType } from '../Model/Types';
import { addClaimRequest, getMemberList } from '../Model/Functions';
import palette from '@/theme/palette';
import FormCreateFilesUpload from './FormCreateFilesUpload';
import useLoadOnScroll from '@/hooks/useLoadOnScroll';
import useCollapseDrawer from '@/hooks/useCollapseDrawer';
import FormCreateBtnChoose from './FormCreateBtnChoose';
import axios from '../../../utils/axios';
export default function FormCreate() {
const navigate = useNavigate()
const defaultListChoosed:MemberListType[] = [];
// State
// -------------------------
const [keyword, setKeyword] = useState<string>('');
const [listChoosed, setListChoosed] = useState<MemberListType[]>([]);
const [isChoosed, setIsChoosed] = useState<boolean>(false);
const [formIsLoading, setFormIsLoading] = useState<boolean>(false);
// List Choose - auto Scroll
// -------------------------
const fetchFunction = async (page: number): Promise<MemberListType[]> => getMemberList(page, keyword)
const {data: MemberList, isLoading: scrollIsLoading, setData, resetLastPage, refetchData} = useLoadOnScroll<MemberListType>(fetchFunction);
// List Choose - Search
// -------------------------
const handleSearch = (keyword: string) => {
setData([])
resetLastPage()
setKeyword(keyword)
refetchData()
}
// Function - Clear Form
// -----------------------------
const clearForm = () => {
setListChoosed(defaultListChoosed);
setIsChoosed(false);
}
// Function - Choose Patien Type
// -----------------------------
const handleChoosePatienType = (data: MemberListType, type: string) => {
let newListChoosed = listChoosed.map((list) => {
if (data.id == list.id) {
list.patien_type = type
}
return list;
})
setListChoosed(newListChoosed)
}
// Function - Handle Btn Upload
// -----------------------------
const handleChangeInput = (data: MemberListType, type_file: 'kondisi'|'diagnosa'|'penunjang', file: any) => {
let newListChoosed = listChoosed.map((list) => {
if (data.id == list.id) {
if (type_file == 'kondisi') {
if (list.file_kondisi == undefined) {
list.file_kondisi = [file];
}
else {
list.file_kondisi.push(file);
}
}
if (type_file == 'diagnosa') {
if (list.file_diagnosa == undefined) {
list.file_diagnosa = [file];
}
else {
list.file_diagnosa.push(file);
}
}
if (type_file == 'penunjang') {
if (list.file_penunjang == undefined) {
list.file_penunjang = [file];
}
else {
list.file_penunjang.push(file);
}
}
}
return list;
})
setListChoosed(newListChoosed)
}
// Function - Handle Remove Fle
// -----------------------------
const handleRemoveFile = (data: MemberListType, type_file: 'kondisi'|'diagnosa'|'penunjang', target_index: number) => {
let newListChoosed = listChoosed.map((list) => {
if (data.id == list.id) {
if (type_file == 'kondisi') {
list.file_kondisi = list.file_kondisi?.filter((file: any, index: number) =>{
if (target_index !== index) {
return file;
}
});
}
if (type_file == 'diagnosa') {
list.file_diagnosa = list.file_diagnosa?.filter((file: any, index: number) =>{
if (target_index !== index) {
return file;
}
});
}
if (type_file == 'penunjang') {
list.file_penunjang = list.file_penunjang?.filter((file: any, index: number) =>{
if (target_index !== index) {
return file;
}
});
}
}
return list;
})
setListChoosed(newListChoosed)
}
// Function - Handle Submit Form
// -----------------------------
const handleSubmit = async () => {
setFormIsLoading(true)
let response = await addClaimRequest(listChoosed)
setFormIsLoading(false)
if (response == true) {
clearForm()
}
}
let isDirty = listChoosed.some((row) => {
if (row.patien_type == undefined) {
return true
}
})
return (
<Box>
{/* Back Button */}
<Box sx={{ display: 'flex', alignItems: 'center', mb: 5}}>
<IconButton size='large' color='inherit' onClick={() => isChoosed==false ? navigate(`/claim-requests`) : setIsChoosed(false)} >
<ArrowBackIosNew/>
</IconButton>
<Typography variant="h5" sx={{ marginLeft: '24px' }}>
{'Create Claim Requests'}
</Typography>
</Box>
{/* Choose Section */}
<Grid container spacing={4} sx={{ px: 2, position: 'relative', display: isChoosed==false ? 'inherit' : 'none' }}>
{/* Search */}
<Grid item xs={12}>
<FormCreateSearch onEmpty={() => handleSearch('')} onSubmit={(keyword) => handleSearch(keyword)} />
</Grid>
<Grid item xs={12}>
<Grid container spacing={2}>
{/* List */}
<Grid item xs={12}>
<Grid container spacing={2}>
{
MemberList.map((row, index) => {
return (
<FormCreateListChoose
key={index}
data={row}
ListChoosed={listChoosed}
handleCheckedProp={(checked, data) => {
checked ? setListChoosed((prevData) => [...prevData, data]) : setListChoosed((items) => items.filter(item => item.id != data.id))
}}
/>
)
})
}
</Grid>
</Grid>
{/* Loading */}
<Grid item xs={12} sx={{ display: scrollIsLoading === false ? 'none' : 'flex', justifyContent: 'center', marginTop: '40px' }}>
<CircularProgress />
</Grid>
{/* Submit List */}
<Grid item xs={12}>
<FormCreateBtnChoose disabled={listChoosed.length==0} title={`Create Number Batch (${listChoosed.length})`} handleClickProp={() => setIsChoosed(true)} />
</Grid>
</Grid>
</Grid>
</Grid>
{/* Input Section */}
<Grid container spacing={10} sx={{ px: 2, display: isChoosed==true ? 'inherit' : 'none' }}>
{
listChoosed.map((row, index) => {
return (
<Grid key={index} item xs={12}>
<Grid container spacing={6}>
{/* Patien Name */}
<Grid item xs={12}>
<Card sx={{ border: '1px solid rgba(0,0,0,0.05)', display: 'flex', justifyContent: 'space-between', borderRadius: '12px', px: '24px', py: '16px' }}>
<Box>
<Typography variant="body2" sx={{ fontWeight: 600 }}>
{row.name}
</Typography>
<Typography variant="caption" color={palette.light.grey[500]} sx={{ fontWeight: 600 }}>
{row.member_id}
</Typography>
</Box>
<Label variant="ghost" color="default">
{fDateTimesecond(new Date())}
</Label>
</Card>
</Grid>
{/* Patien Type */}
<Grid item xs={12}>
<Grid container spacing={2}>
{row.service_type.map((r,i) => {
const code = r.code
return (
<Grid item xs={6}>
<Button
sx={{ padding: 2, width: '100%',border: row.patien_type === code ? '1px solid #19BBBB' : '1px solid #919EAB52' }}
variant="outlined"
color={row.patien_type === code ? 'primary' : 'inherit'}
onClick={() => {
handleChoosePatienType(row, code)
}}
>
{r.name}
</Button>
</Grid>
)
})}
</Grid>
</Grid>
{/* File Kondisi */}
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="h6">Condition Document</Typography>
</Grid>
{row.file_kondisi && row.file_kondisi.map((file, index) => (
<Grid item xs={12} key={index}>
<FormCreateFilesUpload file={file} handleRemoveFileProp={() => handleRemoveFile(row, 'kondisi', index)} />
</Grid>
))}
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<FormCreateBtnUpload handleChangeInputProp={(file) => handleChangeInput(row, 'kondisi', file)} />
</Grid>
</Grid>
</Grid>
{/* File Diagnosa */}
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="h6">Diagnosis Document</Typography>
</Grid>
{row.file_diagnosa && row.file_diagnosa.map((file, index) => (
<Grid item xs={12} key={index}>
<FormCreateFilesUpload file={file} handleRemoveFileProp={() => handleRemoveFile(row, 'diagnosa', index)} />
</Grid>
))}
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<FormCreateBtnUpload handleChangeInputProp={(file) => handleChangeInput(row, 'diagnosa', file)} />
</Grid>
</Grid>
</Grid>
{/* File Penunjang */}
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="h6">Supporting Result Document</Typography>
</Grid>
{row.file_penunjang && row.file_penunjang.map((file, index) => (
<Grid item xs={12} key={index}>
<FormCreateFilesUpload file={file} handleRemoveFileProp={() => handleRemoveFile(row, 'penunjang', index)} />
</Grid>
))}
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<FormCreateBtnUpload handleChangeInputProp={(file) => handleChangeInput(row, 'penunjang', file)} />
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
)
})
}
<Grid item xs={12} sx={{ display: 'flex', justifyContent: 'flex-end' }}>
<Box display="flex" gap={1}>
<Button variant="outlined" color="inherit" onClick={() => clearForm()}>
Cancel
</Button>
<LoadingButton disabled={isDirty} type="submit" variant="contained" loading={formIsLoading} onClick={() => handleSubmit()}>
Save Changes
</LoadingButton>
</Box>
</Grid>
</Grid>
</Box>
)
}

View File

@@ -1,39 +0,0 @@
import { styled, Button } from "@mui/material";
import useCollapseDrawer from "@/hooks/useCollapseDrawer";
/**
* Custom Style
* ============================================
*/
const DivCustom1 = styled('div')(({ theme }) => ({
background: 'white',
position: 'fixed',
left: '350px',
right: 0,
bottom: 0,
paddingLeft: '32px',
paddingRight: '32px',
paddingTop: '32px',
paddingBottom: '48px',
[theme.breakpoints.between('sm', 'lg')]: {
left: '0px',
},
}));
type Props = {
disabled: boolean,
title : string,
handleClickProp: () => void
}
export default function FormCreateBtnChoose ({disabled, title, handleClickProp}: Props) {
const { collapseClick } = useCollapseDrawer();
return (
<DivCustom1 sx={{ left: collapseClick ? '80px' : '350px' }}>
<Button variant="contained" color="primary" disabled={disabled} sx={{ width: '100%', p: '11px' }} onClick={handleClickProp}>
{title}
</Button>
</DivCustom1>
)
}

View File

@@ -1,39 +0,0 @@
import { useRef } from "react";
import { Box, ButtonBase, Typography } from "@mui/material";
import Iconify from "@/components/Iconify";
type Props = {
handleChangeInputProp: (event: any) => void
}
export default function FormCreateBtnUpload ({handleChangeInputProp}: Props) {
const fileInput = useRef<HTMLInputElement>(null);
return (
<ButtonBase sx={{ py: 5, border: '2px dashed #F9FAFB',bgcolor: '#919EAB52',borderRadius: '8px',width: '100%', height: '60px'}} onClick={() => fileInput.current?.click()}>
<Box
sx={{
display: 'flex',
placeItems: 'center',
gap: 1,
placeContent: 'center',
py:'11px'
}}
>
<Iconify icon="icon-park-outline:upload-one" fontSize="1.5em" />
<Typography variant="body1" fontWeight="bold" fontSize={'15px'}>
Upload Result
</Typography>
</Box>
<input
type="file"
id="file"
ref={fileInput}
style={{ display: 'none' }}
multiple
onChange={(event) => handleChangeInputProp(event.target.files ? event.target.files[0] : {})}
accept="application/pdf"
/>
</ButtonBase>
)
}

View File

@@ -1,25 +0,0 @@
import Iconify from "@/components/Iconify";
import { ArrowBackIosNew, InsertDriveFile } from '@mui/icons-material';
import { Stack, Typography } from "@mui/material";
type Props = {
file: any,
handleRemoveFileProp: () => void,
}
export default function FormCreateFilesUpload({ file, handleRemoveFileProp }: Props) {
return (
<Stack direction="row" justifyContent={'space-between'} sx={{ mb: '16px' }}>
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
<InsertDriveFile />
<Typography variant="body2" gutterBottom>{file.name ? file.name : '-'}</Typography>
</Stack>
<Iconify
icon="eva:trash-2-outline"
color={'darkred'}
onClick={() => {handleRemoveFileProp()}}
sx={{cursor: 'pointer'}}
></Iconify>
</Stack>
)
}

View File

@@ -1,78 +0,0 @@
/**
* Core
* ============================================
*/
import { useEffect, useState } from 'react';
import { Box, FormControlLabel, Grid, Checkbox, Typography, Card} from '@mui/material';
/**
* Components
* ============================================
*/
// - Global -
import Label from '@/components/Label';
// - Local -
/**
* Icon, Utils, Types, Functions, theme, hook
* ============================================
*/
import { fDateTimesecond } from '@/utils/formatTime';
import { MemberListType } from '../Model/Types';
import palette from '@/theme/palette';
/**
* Props
* =====================================================
*/
type Props = {
data: MemberListType,
ListChoosed: MemberListType[],
handleCheckedProp: (checked: boolean, data: MemberListType) => void,
};
export default function FormCreateListChoose({data, ListChoosed, handleCheckedProp}: Props) {
const [isChoosed, setIsChoosed] = useState<boolean>(false)
useEffect(() => {
setIsChoosed(false);
ListChoosed.forEach(list => {
if (list.id == data.id) {
setIsChoosed(true);
}
})
}, [ListChoosed])
return (
<Grid item xs={12}>
<Card sx={{
border: '0px solid rgba(0,0,0,0.125)', px: '24px', py: '16px', borderRadius: '12px', display: 'flex', justifyContent: 'space-between',
bgcolor: (theme) => {
return isChoosed ? palette.light.primary.lighter : palette.light.background.default
}
}}>
<Box sx={{ display: 'flex', alignItems: 'center', px: '8px'}}>
<FormControlLabel
label=""
control={<Checkbox onChange={(event, checked) => handleCheckedProp(checked, data)} />}
checked={isChoosed}
/>
<Box>
<Typography variant="body2" sx={{ fontWeight: 600 }}>
{data.name}
</Typography>
<Typography variant="caption" color={palette.light.grey[500]} sx={{ fontWeight: 600 }}>
{data.member_id}
</Typography>
</Box>
</Box>
<Label variant="ghost" color="default">
{fDateTimesecond(new Date())}
</Label>
</Card>
</Grid>
)
}

View File

@@ -1,70 +0,0 @@
/**
* Core
* ============================================
*/
import { useEffect } from 'react';
import { useForm } from 'react-hook-form';
import { Grid } from '@mui/material';
/**
* Components
* ============================================
*/
// - Global -
import { FormProvider, RHFTextField } from '@/components/hook-form';
// - Local -
/**
* Icon, Utils, Types, Functions
* ============================================
*/
import { Search } from '@mui/icons-material';
import { SearchType } from '../Model/Types';
type Props = {
onSubmit: (keyword: string) => void,
onEmpty: () => void,
};
const FormCreateSearch = ({ onSubmit, onEmpty }: Props) => {
const defaultValuesSearchForm = {
keyword: ''
};
const methodsSearchForm = useForm<SearchType>({
defaultValues: defaultValuesSearchForm
});
const { handleSubmit, formState: { isDirty } } = methodsSearchForm;
// search on submit
const onSubmitSearch = (data: SearchType ) => {
onSubmit(data.keyword);
}
// search on empty
useEffect(() => {
if (isDirty === false) {
onEmpty()
}
},[isDirty])
return (
<FormProvider methods={methodsSearchForm} onSubmit={handleSubmit(onSubmitSearch)}>
<Grid container direction={"row"}>
<Grid item xs={12}>
<RHFTextField
name="keyword"
placeholder="Search..."
autoComplete='off'
fullWidth
InputProps={{ startAdornment: <Search /> }}
sx={{ input: { paddingLeft: '14px' } }}
/>
</Grid>
</Grid>
</FormProvider>
)
}
export default FormCreateSearch

View File

@@ -1,456 +0,0 @@
import * as Yup from 'yup';
import { useSnackbar } from 'notistack';
import { useNavigate } from 'react-router-dom';
import { yupResolver } from '@hookform/resolvers/yup';
import { Controller, useForm } from 'react-hook-form';
import React, { useRef, useEffect, useMemo, useState } from 'react';
import axios from '../../../utils/axios';
import { FormProvider, RHFTextField } from '../../../components/hook-form';
import { makeFormData } from '@/utils/jsonToFormData';
import {
Autocomplete,
Button,
Grid,
Stack,
Table,
TableBody,
TableCell,
TableRow,
TextField,
Typography,
useTheme,
List,
ListItem,
IconButton,
ListItemAvatar,
Avatar,
ListItemText,
Card,
InputAdornment,
Divider,
ButtonBase,
Box,
} from '@mui/material';
import Iconify from '../../../components/Iconify';
import CalendarTodayIcon from '@mui/icons-material/CalendarToday';
import { LoadingButton } from '@mui/lab';
import { fCurrency } from '../../../utils/formatNumber';
import MemberSelectDialog from '../../../components/dialogs/MemberSelectDialog';
import { Add, ArrowBackIosNew, DeleteOutline } from '@mui/icons-material';
import { ClaimRequest, Files } from '@/@types/claims';
import { fDateTimesecond } from '@/utils/formatTime';
interface FormValuesProps extends Partial<ClaimRequest> {
taxes: boolean;
inStock: boolean;
}
type Props = {
isEdit: boolean;
currentClaim?: ClaimRequest;
};
export default function FormEdit({ isEdit, currentClaim }: Props) {
const navigate = useNavigate();
const { enqueueSnackbar } = useSnackbar();
const EditClaimSchema = Yup.object().shape({
organization_id: Yup.string().required('Code Provider is required'),
});
const defaultValues = useMemo(
() => ({
id: currentClaim?.id || '-',
code: currentClaim?.code || '-',
member_name: currentClaim?.member?.name || '-',
date: currentClaim?.submission_date ? fDateTimesecond(currentClaim?.submission_date) : '-',
claim_method: currentClaim?.payment_type || '-',
service_type: currentClaim?.service_code || '-',
organization_id: currentClaim?.organization?.code || '-',
}),
[currentClaim]
);
useEffect(() => {
if (isEdit && currentClaim) {
reset(defaultValues);
}
if (!isEdit) {
reset(defaultValues);
}
// setFileKondisis(currentClaim?.files_by_type?.claim_diagnosis);
// setFileDiagnosas(currentClaim?.files_by_type?.claim_diagnosis);
setFileHasilPenunjangCurrent(currentClaim?.files_by_type?.claim_result);
}, [isEdit, currentClaim]);
const methods = useForm<FormValuesProps>({
resolver: yupResolver(EditClaimSchema),
defaultValues,
});
const {
reset,
watch,
control,
setValue,
getValues,
setError,
handleSubmit,
formState: { isSubmitting },
} = methods;
const values = watch();
const [isCheckingLimit, setIsCheckingLimit] = useState(false);
const [isEligible, setIsEligible] = useState(false);
const [memberBenefits, setMemberBenefits] = useState([]);
const [diagnosisOption, setDiagnosisOption] = useState([]);
const [isMemberDialogOpen, setIsMemberDialogOpen] = useState(false);
const [member, setMember] = useState({})
// ----------------------------------------------------------------------
// Files Result Kondisi
const fileKondisiInput = useRef<HTMLInputElement>(null);
const [fileKondisis, setFileKondisis] = useState<Files>([]);
const handleKondisiInputChange = (event) => {
if (event.target.files[0]) {
setFileKondisis([...fileKondisis, ...event.target.files]);
} else {
console.log('NO FILE');
}
};
const removeKondisiFiles = (filesState, index) => {
setFileKondisis(
filesState.filter((file, fileIndex) => {
return fileIndex != index;
})
);
};
// Files Result Diagnosa
const fileDiagnosaInput = useRef<HTMLInputElement>(null);
const [fileDiagnosas, setFileDiagnosas] = useState([]);
const handleDiagnosaInputChange = (event) => {
if (event.target.files[0]) {
setFileDiagnosas([...fileDiagnosas, ...event.target.files]);
} else {
console.log('NO FILE');
}
};
const removeDiagnosaFiles = (filesState, index) => {
setFileDiagnosas(
filesState.filter((file, fileIndex) => {
return fileIndex != index;
})
);
};
// Files Result Hasil Penunjang
const fileHasilPenunjangInput = useRef<HTMLInputElement>(null);
const [fileHasilPenunjangs, setFileHasilPenunjangs] = useState([]);
const [fileHasilPenunjangsCurrent, setFileHasilPenunjangCurrent] = useState([]);
const handleResultInputChange = (event) => {
if (event.target.files[0]) {
setFileHasilPenunjangs([...fileHasilPenunjangs, ...event.target.files]);
} else {
console.log('NO FILE');
}
};
const removeFiles = (filesState, index) => {
setFileHasilPenunjangs(
filesState.filter((file, fileIndex) => {
return fileIndex != index;
})
);
};
const onSubmit = async (data: FormValuesProps) => {
try {
// const formData = new FormData();
// formData.append('result_files', fileHasilPenunjangs);
// formData.append('diagnosa_files', fileDiagnosaInput);
// formData.append('kondisi_files', fileKondisiInput);
// formData.append('provider_code', data.organization_id);
// formData.append('_method', 'PUT');
const formData = makeFormData({
result_files: fileHasilPenunjangs,
diagnosa_files: fileDiagnosas,
kondisi_files: fileKondisis,
provider_code: data.organization_id,
_method: 'PUT'
});
const response = await axios.put(`/claim-requests/${data.id}`, formData);
reset();
enqueueSnackbar('Claim Request Updated Successfully!', { variant: 'success' });
navigate('/claim-requests');
} catch (error: any) {
if (error && error.response.status === 422) {
for (const [key, value] of Object.entries(error.response.data.errors)) {
// setError(key, { message: value[0] });
enqueueSnackbar('Failed Processing Request', { variant: 'error' });
}
} else {
enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' });
}
}
};
return (
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
<Stack direction="row" alignItems="center" sx={{ mb: 5 }}>
<Box sx={{ display: 'flex', alignItems: 'center'}}>
<IconButton size='large' color='inherit' onClick={() => navigate(`/claim-requests`)} >
<ArrowBackIosNew/>
</IconButton>
<Typography variant="h5" sx={{ marginLeft: '24px' }}>
{'Edit Claim Requests'}
</Typography>
</Box>
</Stack>
<Card sx={{paddingX:2, paddingY:2}}>
<Grid container spacing={2}>
<Grid item xs={5}>
<Typography variant="subtitle1">Code*</Typography>
</Grid>
<Grid item xs={7}>
<Typography variant="subtitle1">Name*</Typography>
</Grid>
<Grid item xs={5}>
<RHFTextField name="code" label="Code" disabled/>
</Grid>
<Grid item xs={7}>
<RHFTextField name="member_name" label="Name" disabled/>
</Grid>
{/* <input type="hidden" name="id"/> */}
<Grid item xs={12}></Grid>
<Grid item xs={3}>
<Typography variant="subtitle1">Date of Submission*</Typography>
</Grid>
<Grid item xs={3}>
<Typography variant="subtitle1">Claim Method*</Typography>
</Grid>
<Grid item xs={3}>
<Typography variant="subtitle1">Service Type*</Typography>
</Grid>
<Grid item xs={3}>
<Typography variant="subtitle1">Code Provider*</Typography>
</Grid>
<Grid item xs={3}>
<RHFTextField InputProps={{endAdornment: (
<InputAdornment position="end">
<CalendarTodayIcon />
</InputAdornment>
), }}
name="date" label="Date of Submission" disabled/>
</Grid>
<Grid item xs={3}>
<RHFTextField name="claim_method" label="Claim Method" disabled/>
</Grid>
<Grid item xs={3}>
<RHFTextField name="service_type" label="Service Type*" disabled/>
</Grid>
<Grid item xs={3}>
<RHFTextField name="organization_id" label="Code Provider*"/>
</Grid>
{/* -------------------------------Upload Dokumen Kondisi------------------------------- */}
<React.Fragment>
<Grid item xs={12}>
<Typography variant='h6'> Condition Document</Typography>
</Grid>
<Grid item xs={12}>
{fileKondisis &&
fileKondisis.map((file, index) => (
<Stack sx={{marginTop: 2}} 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>
))}
</Grid>
<Grid item xs={12}>
<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">
Add File
</Typography>
</Box>
<input
type="file"
id="file"
ref={fileKondisiInput}
style={{ display: 'none' }}
multiple
onChange={handleKondisiInputChange}
accept="application/pdf"
/>
</ButtonBase>
</Grid>
</React.Fragment>
{/* -------------------------------Upload Dokumen Diagnosa------------------------------- */}
<React.Fragment>
<Grid item xs={12}>
<Typography variant='h6'> Diagnosis Document</Typography>
</Grid>
<Grid item xs={12}>
{fileDiagnosas &&
fileDiagnosas.map((file, index) => (
<Stack sx={{marginTop: 2}} 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>
))}
</Grid>
<Grid item xs={12}>
<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">
Add Result
</Typography>
</Box>
<input
type="file"
id="file"
ref={fileDiagnosaInput}
style={{ display: 'none' }}
multiple
onChange={handleDiagnosaInputChange}
accept="application/pdf"
/>
</ButtonBase>
</Grid>
</React.Fragment>
{/* -------------------------------Upload Result Hasil Penunjang------------------------------- */}
<React.Fragment>
<Grid item xs={12}>
<Typography variant='h6'> Supporting Result Document</Typography>
</Grid>
<Grid item xs={12}>
{fileHasilPenunjangs &&
fileHasilPenunjangs.map((file, index) => (
<Stack sx={{marginTop: 2}} 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>
))}
</Grid>
<Grid item xs={12}>
<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">
Add Result
</Typography>
</Box>
<input
type="file"
id="file"
ref={fileHasilPenunjangInput}
style={{ display: 'none' }}
multiple
onChange={handleResultInputChange}
accept="application/pdf"
/>
</ButtonBase>
</Grid>
</React.Fragment>
</Grid>
</Card>
<Grid container marginTop={3}>
<Grid item xs={12} md={12} >
<Stack direction="row" alignItems="center" justifyContent="flex-end">
<Button
sx={{
margin: 1
}}
type="submit"
variant="contained"
size="large"
color='inherit'
onClick={() => navigate(`/claim-requests`)}
>
Cancel
</Button>
<LoadingButton
type="submit"
variant="contained"
size="large"
loading={isSubmitting}
>
Update
</LoadingButton>
</Stack>
</Grid>
</Grid>
</FormProvider>
);
}

View File

@@ -1,63 +0,0 @@
import * as Yup from 'yup';
import { Box, IconButton } from '@mui/material';
import { ArrowBackIosNew } from '@mui/icons-material';
import { yupResolver } from '@hookform/resolvers/yup';
import { Autocomplete, Button, Card, Collapse, Container, Divider, Grid, Stack, Table, TableBody, TableCell, TableRow, TextField, Typography } from '@mui/material';
import { Controller, useForm } from 'react-hook-form';
import { useParams } from 'react-router-dom';
import HeaderBreadcrumbs from '../../components/HeaderBreadcrumbs';
import { FormProvider, RHFCheckbox, RHFSelect, RHFTextField } from '../../components/hook-form';
import Page from '../../components/Page';
import useSettings from '../../hooks/useSettings';
import { useEffect, useMemo, useRef, useState } from 'react';
import MemberSelectDialog from '../../components/dialogs/MemberSelectDialog';
import { styled } from '@mui/system';
import axios from '../../utils/axios';
import { enqueueSnackbar } from 'notistack';
import { LoadingButton } from '@mui/lab';
import { fCurrency } from '../../utils/formatNumber';
import Iconify from '../../components/Iconify';
import { ClaimRequest } from '@/@types/claims';
import FormEdit from './Components/FormEdit';
import FormCreate from './Components/FormCreate';
export default function ClaimsCreateUpdate() {
const { themeStretch } = useSettings();
const { id } = useParams();
const isEdit = id ? true : false;
const [currentClaim, setCurrentClaim] = useState<ClaimRequest>();
useEffect(() => {
if (isEdit) {
axios.get('/claim-requests/' + id).then((res) => {
console.log('Yeet', res.data);
setCurrentClaim(res.data.data);
});
console.log(currentClaim)
}
}, [id]);
return (
<Page title={isEdit ? `Edit Claim Request` : "Create New Claim"}>
<Container maxWidth={themeStretch ? false : 'xl'}>
{
id == undefined
?
(
<FormCreate />
)
:
(
<FormEdit isEdit={isEdit} currentClaim={currentClaim} />
)
}
</Container>
</Page>
);
}

View File

@@ -1,306 +0,0 @@
// mui
import { Container, Grid, Stack, Typography, Card, TextField, Divider, ButtonBase, Box, IconButton } from '@mui/material';
// components
import Page from '../../components/Page';
// utils
import useSettings from '../../hooks/useSettings';
// react
import { useNavigate, useParams, useLocation } from 'react-router-dom';
import { useEffect, useState, useRef } from 'react';
import axios from '../../utils/axios';
// pages
import DetailTimeline from '../../pages/ClaimRequests/DetailTimeline';
import DetailStepper from '../../pages/ClaimRequests/DetailStepper';
import { format } from 'date-fns';
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
import Button from '@mui/material/Button';
import AddIcon from '@mui/icons-material/Add';
import RemoveIcon from '@mui/icons-material/Remove';
import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import Iconify from '@/components/Iconify';
import { fPostFormat } from '@/utils/formatTime';
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
import DownloadIcon from '@mui/icons-material/Download';
import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
import { fDateTimesecond } from '@/utils/formatTime';
import { makeFormData } from '@/utils/jsonToFormData';
import { enqueueSnackbar } from 'notistack';
// ----------------------------------------------------------------------
export default function Detail() {
const location = useLocation();
const queryParams = new URLSearchParams(location.search);
const code = queryParams.get('code');
const navigate = useNavigate();
const { themeStretch } = useSettings();
const [data, setData] = useState();
const [dataDialog, setDataDialog] = useState();
const [document, setDocument] = useState(null);
const { id } = useParams();
useEffect(() => {
axios
.get('/claim-requests/detail/'+id)
.then((response) => {
setData(response.data);
setDataDialog(response.data.data.dialog_submits);
setDocument(response.data.data.documents);
})
.catch((error) => {
console.error(error);
});
}, []);
const [isInvoiceVisible, setInvoiceVisibility] = useState(false);
const handleInvoice = () => {
setInvoiceVisibility(!isInvoiceVisible);
}
const currentDate = new Date();
const formattedCurrentDate = format(currentDate, 'dd MMM yyyy');
const [dateInvoice, setDateInvoice] = useState(currentDate);
const fileInvoiceInput = useRef<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;
const [openDialogSubmit, setOpenDialogSubmit] = useState(false);
const handleCloseDialogSubmit = () => {
setOpenDialogSubmit(false);
}
const handleSubmitData = () => {
// if(fileInvoices.length > 0)
// {
//submit data
axios
.post('claim-requests/'+id+'/approve')
.then((response) => {
enqueueSnackbar('Success Submit Claim Request', { variant: 'success' });
setOpenDialogSubmit(false);
})
.catch(({ response }) => {
enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' });
});
//Upload file invoices
const formData = makeFormData({
date:date,
invoice_files: fileInvoices,
});
axios
.post('claim-requests/'+id+'/invoice-files', formData)
.then((response) => {
enqueueSnackbar(response.data.message ?? 'Success upload invoice', { variant: 'success' });
})
.catch(({ response }) => {
enqueueSnackbar(response.data.message ?? 'Something Went Wrong', { variant: 'error' });
});
// }
// else
// {
// enqueueSnackbar('Please upload file invoice, before submit', { variant: 'warning' });
// }
setTimeout(() =>
{
window.location.reload();
}, 5000);
};
const check_invoice = document?.find((dataInvoice) => dataInvoice.type === 'claim-invoice');
return (
<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>
</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>
</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>
</Card>
</Grid>
<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'}
</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>
</Stack>
</Grid>
</Grid>
) : ''}
</Container>
</Page>
);
}

View File

@@ -1,58 +0,0 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Stepper from '@mui/material/Stepper';
import Step from '@mui/material/Step';
import StepLabel from '@mui/material/StepLabel';
import { useEffect, useState } from 'react';
import ClearIcon from '@mui/icons-material/Clear';
const steps = [
'Request',
'Review',
'Approval',
'Decline',
];
export default function HorizontalLinearAlternativeLabelStepper({data}) {
const [active, setActive] = useState(0);
const [status, SetStatus] = useState(null);
let updatedSteps = [...steps];
useEffect(() => {
if (data && data.data) {
if (data.data.status.status === 'requested') {
setActive(1);
updatedSteps = updatedSteps.filter(step => step !== 'Decline');
}
else if (data.data.status.status === 'reviewed') {
setActive(2);
updatedSteps = updatedSteps.filter(step => step !== 'Decline');
}
else if (data.data.status.status === 'approved')
{
setActive(3);
updatedSteps = updatedSteps.filter(step => step !== 'Decline');
}
else if(data.data.status.status === 'declined')
{
setActive(4)
updatedSteps = updatedSteps.filter(step => step !== 'Approval');
}
}
SetStatus(updatedSteps);
}, [data]);
return (
<Box sx={{ width: '100%', marginBottom: 2 }}>
<Stepper activeStep={active} alternativeLabel>
{status?.map((label) => (
<Step key={label}>
<StepLabel icon={label==='Decline' ? <ClearIcon sx={{ color: 'white', backgroundColor: 'red', borderRadius: '50%' }} /> : ''}>{label}</StepLabel>
</Step>
))}
</Stepper>
</Box>
);
}

View File

@@ -1,426 +0,0 @@
import * as React from 'react';
import Timeline from '@mui/lab/Timeline';
import TimelineItem, { timelineItemClasses } from '@mui/lab/TimelineItem';
import TimelineSeparator from '@mui/lab/TimelineSeparator';
import TimelineConnector from '@mui/lab/TimelineConnector';
import TimelineContent from '@mui/lab/TimelineContent';
import TimelineDot from '@mui/lab/TimelineDot';
import {Typography, Card, Stack, ButtonBase, Box, Divider} from '@mui/material';
import { styled } from '@mui/material/styles';
import Paper from '@mui/material/Paper';
import Button from '@mui/material/Button';
import AddIcon from '@mui/icons-material/Add';
import Iconify from '../../components/Iconify';
import { useEffect, useState, useRef } from 'react';
import { format } from 'date-fns';
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
import DescriptionIcon from '@mui/icons-material/Description';
import { LoadingButton } from '@mui/lab';
import axios from '../../utils/axios';
import { makeFormData } from '@/utils/jsonToFormData';
import { enqueueSnackbar } from 'notistack';
import { useParams} from 'react-router-dom';
const Item1 = styled(Paper)(({ theme }) => ({
...theme.typography.body2,
padding: theme.spacing(1),
textAlign: 'center',
backgroundColor: '#919EAB29',
color: '#637381',
width: 'fit-content',
marginRight: 'auto',
}));
const Item2 = styled(Paper)(({ theme }) => ({
backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
...theme.typography.body2,
padding: theme.spacing(1),
textAlign: 'center',
color: theme.palette.text.secondary,
width: 'fit-content',
marginLeft: 'auto',
}));
export default function NoOppositeContent({data}) {
const [timeline, setTimeline] = useState(null);
const [requestFile, setRequestFile] = useState(null);
const [document, setDocument] = useState(null);
useEffect(() => {
if (data && data.data) {
setTimeline(data.data.timeline);
setRequestFile(data.data.request_files);
setDocument(data.data.documents);
}
}, [data]);
// Diagnosis
const fileRequestDocumentInputDiagnosis = useRef<HTMLInputElement>(null);
const [fileDiagnosis, setFileDiagnosis] = useState([]);
const handleRequestDocumentInputChangeDiagnosis = (event) => {
if (event.target.files[0]) {
setFileDiagnosis([...fileDiagnosis, ...event.target.files]);
}
};
const removeFileDiagnois = (filesState, index) => {
setFileDiagnosis(
filesState.filter((file, fileIndex) => {
return fileIndex != index;
})
);
};
// Kondisi
const fileRequestDocumentInputKondisi = useRef<HTMLInputElement>(null);
const [fileKondisi, setFileKondisi] = useState([]);
const handleRequestDocumentInputChangeKondisi = (event) => {
if (event.target.files[0]) {
setFileKondisi([...fileKondisi, ...event.target.files]);
}
};
const removeFileKondisi = (filesState, index) => {
setFileKondisi(
filesState.filter((file, fileIndex) => {
return fileIndex != index;
})
);
};
// Result
const fileRequestDocumentInputResult = useRef<HTMLInputElement>(null);
const [fileResult, setFileResult] = useState([]);
const handleRequestDocumentInputChangeResult = (event) => {
if (event.target.files[0]) {
setFileResult([...fileResult, ...event.target.files]);
}
};
const removeFileResult = (filesState, index) => {
setFileResult(
filesState.filter((file, fileIndex) => {
return fileIndex != index;
})
);
};
const { id } = useParams();
const [submitLoading, setSubmitLoading] = useState(false);
const submitRequestFiles = () => {
setSubmitLoading(true);
const formData = makeFormData({
fileDiagnosis: fileDiagnosis,
fileKondisis: fileKondisi,
fileResults: fileResult
});
axios
.post('claim-requests/'+id+'/request-files', formData)
.then((response) => {
window.location.reload();
})
.catch(({ response }) => {
enqueueSnackbar(response.data.message ?? 'Something Went Wrong', { variant: 'error' });
});
}
const submitButton = requestFile?.find((dataRequestFile) => dataRequestFile.check_files === null);
return (
<>
{timeline?.map((dataTimeline, index) => (
<Timeline
sx={{
[`& .${timelineItemClasses.root}:before`]: {
flex: 0,
padding: 0,
},
}}
key={index}
>
<Typography variant="body2" gutterBottom fontWeight="bold">{dataTimeline.date ? format(new Date(dataTimeline.date), "d MMM yyyy") : ''}</Typography>
<TimelineItem>
<TimelineSeparator>
<TimelineDot />
<TimelineConnector />
</TimelineSeparator>
<TimelineContent spacing={3}>
<Card sx={{ borderRadius: '6px', paddingY: 2 }}>
<Stack sx={{marginLeft: 2, marginRight: 2, marginTop: 2 }}>
<Stack direction="row" sx={{marginBottom: 2, paddingBottom: 2, borderBottom: '1px solid #919EAB52' }}>
<Item1>{dataTimeline.date ? format(new Date(dataTimeline.date), "HH : mm") : ''}</Item1>
<Item2 sx={{backgroundColor: dataTimeline.txt_status_backgroundColor, color: dataTimeline.txt_status_color}}>{dataTimeline.txt_status}</Item2>
</Stack>
<Stack direction="row" spacing={2} sx={{marginBottom: 2}}>
<Typography variant="body2" gutterBottom>Detail:</Typography>
<Typography variant="body2" gutterBottom>{dataTimeline.description}</Typography>
</Stack>
{dataTimeline.status === 'reviewed' && requestFile ? (
<>
{submitButton ? (
<Typography variant="body2" gutterBottom>Request Document</Typography>
) : (
<Typography sx={{color: '#19BBBB'}} variant="body2" gutterBottom>Request Document Success Uploaded</Typography>
)}
{/* Diagnosis */}
{requestFile?.map((dataRequestFile, index) => {
if(dataRequestFile.type !== 'claim-diagnosis' || dataRequestFile.check_files !== null){
return null;
}
return (
<Stack spacing={2} sx={{marginBottom: 2}} key={index}>
<Typography variant="body2" gutterBottom fontWeight="bold">
Diagnosis
</Typography>
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2 }}
>
{fileDiagnosis &&
fileDiagnosis.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={() => {
removeFileDiagnois(fileDiagnosis, index);
}}
sx={{cursor: 'pointer'}}
></Iconify>
</Stack>
))}
</Stack>
<ButtonBase
sx={{
p: 4,
border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
width: '100%',
height: '60px',
}}
onClick={() => fileRequestDocumentInputDiagnosis.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">
Add Result
</Typography>
</Box>
<input
type="file"
id={`file-${index}`}
ref={fileRequestDocumentInputDiagnosis}
style={{ display: 'none' }}
multiple
onChange={(event) => handleRequestDocumentInputChangeDiagnosis(event)}
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf"
/>
</ButtonBase>
</Stack>
);
})}
{/* Kondisi */}
{requestFile?.map((dataRequestFile, index) => {
if(dataRequestFile.type !== 'claim-kondisi' || dataRequestFile.check_files !== null){
return null;
}
return (
<Stack spacing={2} sx={{marginBottom: 2}} key={index}>
<Typography variant="body2" gutterBottom fontWeight="bold">
Condition
</Typography>
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2 }}
>
{fileKondisi &&
fileKondisi.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={() => {
removeFileKondisi(fileKondisi, index);
}}
sx={{cursor: 'pointer'}}
></Iconify>
</Stack>
))}
</Stack>
<ButtonBase
sx={{
p: 4,
border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
width: '100%',
height: '60px',
}}
onClick={() => fileRequestDocumentInputKondisi.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">
Add Result
</Typography>
</Box>
<input
type="file"
id={`file-${index}`}
ref={fileRequestDocumentInputKondisi}
style={{ display: 'none' }}
multiple
onChange={(event) => handleRequestDocumentInputChangeKondisi(event)}
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf"
/>
</ButtonBase>
</Stack>
);
})}
{/* Supporting Result */}
{requestFile?.map((dataRequestFile, index) => {
if(dataRequestFile.type !== 'claim-result' || dataRequestFile.check_files !== null){
return null;
}
return (
<Stack spacing={2} sx={{marginBottom: 2}} key={index}>
<Typography variant="body2" gutterBottom fontWeight="bold">
Supporting Result
</Typography>
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2 }}
>
{fileResult &&
fileResult.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={() => {
removeFileResult(fileResult, index);
}}
sx={{cursor: 'pointer'}}
></Iconify>
</Stack>
))}
</Stack>
<ButtonBase
sx={{
p: 4,
border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
width: '100%',
height: '60px',
}}
onClick={() => fileRequestDocumentInputResult.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">
Add Result
</Typography>
</Box>
<input
type="file"
id={`file-${index}`}
ref={fileRequestDocumentInputResult}
style={{ display: 'none' }}
multiple
onChange={(event) => handleRequestDocumentInputChangeResult(event)}
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf"
/>
</ButtonBase>
</Stack>
);
})}
{submitButton ? (
<LoadingButton
variant="contained"
sx={{ marginTop: 2, p: 2, backgroundColor: '#19BBBB' }}
onClick={() => {
submitRequestFiles();
}}
loading={submitLoading}
>
Submit
</LoadingButton>
) : ''}
</>
) : ''}
</Stack>
</Card>
{dataTimeline.status === 'requested' ? (
<Card sx={{marginTop: 2 }}>
<Stack sx={{marginLeft: 2, marginRight: 2, marginTop: 2 }}>
<Stack direction="row" spacing={2} sx={{marginBottom: 2, paddingBottom: 2, borderBottom: '1px solid #919EAB52' }} alignItems="center">
<DescriptionIcon />
<Typography variant="Subtitle2" sx={{fontWeight: 'bold'}}>Documents</Typography>
</Stack>
<Stack direction="column" spacing={2} sx={{marginBottom: 2}}>
{document?.map((dataDocument, index) => (
<Stack direction="column" spacing={2} key={index}>
<Typography variant="Subtitle2" gutterBottom>
{dataDocument.type === 'claim-diagnosis' ?
'Diagnosis'
: dataDocument.type === 'claim-kondisi' ?
'Condition'
: dataDocument.type === 'claim-result' ?
'Supporting Result'
: dataDocument.type === 'claim-invoice' ?
'Invoice'
: ''}
</Typography>
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
<InsertDriveFileIcon />
<a
href={dataDocument.path}
style={{ cursor: 'pointer', textDecoration: 'underline', color: '#19BBBB' }}
target="_blank"
>
<Typography variant="body2" gutterBottom>{dataDocument.original_name ? dataDocument.original_name : '-'}</Typography>
</a>
</Stack>
</Stack>
))}
</Stack>
</Stack>
</Card>
) : ''}
</TimelineContent>
</TimelineItem>
</Timeline>
))}
</>
);
}

View File

@@ -7,7 +7,7 @@ import List from "./List";
export default function Claims() {
const pageTitle = 'Claim Request';
const pageTitle = 'Inpatient Monitoring';
return (
<Page title={ pageTitle } sx={{ mx: 2}}>
@@ -16,8 +16,8 @@ export default function Claims() {
links={[
{ name: 'Dashboard', href: '/dashboard' },
{
name: 'Claim Request',
href: '/claim-requests',
name: 'Inpatient Monitoring',
href: '/inpatient_monitoring',
},
]}
/>

View File

@@ -49,7 +49,7 @@ import Label from '@/components/Label';
import TableMoreMenu from '@/components/table/TableMoreMenu';
import { Import } from '@/@types/claims';
import { FinalLogType } from './Model/Types';
import { FinalLogType } from '../../CustomerService/FinalLog/Model/Types';
// import LoadingButton from '@/theme/overrides/LoadingButton';
export default function List() {
@@ -344,7 +344,7 @@ export default function List() {
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
</IconButton>
</TableCell> */ }
<TableCell align="left">
{/* <TableCell align="left">
<Typography
// onClick={() => {
// handleShowClaim(row);
@@ -352,9 +352,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>
@@ -370,11 +370,11 @@ export default function List() {
<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>
@@ -476,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,79 +0,0 @@
import axios from '@/utils/axios';
import { enqueueSnackbar } from 'notistack';
import { MemberListType } from './Types';
import { makeFormData } from '@/utils/jsonToFormData';
/**
* Listing Member
*/
export const getMemberList = async ( page: number, keyword: string ): Promise<MemberListType[]> => {
const response = await axios.get(`/claim-requests/list-member?page=${page}&keyword=${keyword}`)
.then((res) =>{
return res.data.data.member_list;
})
.catch((res) => {
enqueueSnackbar("server error !", {
variant: 'error',
});
return [];
});
return response;
};
/**
* Add Claim Request
*/
export const addClaimRequest = async ( data: MemberListType[] ): Promise<boolean> => {
// Mapping
const formData = new FormData();
data.map((row, index) => {
formData.append(`member_id[${index}]`, row.id.toString());
formData.append(`service_code[${index}]`, row.patien_type??'');
if (row.file_kondisi != undefined) {
row.file_kondisi.forEach((file, file_index) => {
console.log(file);
formData.append(`file_kondisi[member_${row.id}][${file_index}]`, file);
});
}
if (row.file_diagnosa != undefined) {
row.file_diagnosa.forEach((file, file_index) => {
console.log(file);
formData.append(`file_diagnosa[member_${row.id}][${file_index}]`, file);
});
}
if (row.file_penunjang != undefined) {
row.file_penunjang.forEach((file, file_index) => {
console.log(file);
formData.append(`file_penunjang[member_${row.id}][${file_index}]`, file);
});
}
})
// Axios
const response = await axios.post(`/claim-requests`, formData)
.then((res) =>{
enqueueSnackbar("Berhasil membuat data !", {
variant: 'success',
});
return true;
})
.catch((res) => {
enqueueSnackbar("server error !", {
variant: 'error',
});
return false;
});
return response;
};

View File

@@ -1,36 +0,0 @@
import { Member } from "@/@types/member"
/**
* Search Type
*/
export type SearchType = {
keyword: string,
}
/**
* Member List
*/
export type FinalLogType = {
id : number,
code : string,
member : Member,
submission_date : string,
service_name : string,
payment_type_name : string,
status_final_log : string,
status : string,
files_by_type : files_by_type,
}
export type files_by_type = {
claim_diagnosis : file[],
claim_kondisi : file[],
claim_result : file[],
}
export type file = {
name: string,
url: string[],
}

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

@@ -1,115 +0,0 @@
import { Card, Grid, Typography } from "@mui/material";
import { Stack } from '@mui/material';
import { DetailFinalLogType } from "../FinalLog/Model/Types";
import { useEffect, useState, useRef, useMemo } from 'react';
import { Box } from "@mui/material";
import { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime";
import Label from '@/components/Label';
import AddIcon from '@mui/icons-material/Add';
import { Button } from "@mui/material";
type CardDetail = {
requestLog: DetailFinalLogType|undefined;
}
const style1 = {
color: '#919EAB',
width: '30%'
}
const style2 = {
width: '70%'
}
const marginBottom1 = {
marginBottom: 1,
}
const marginBottom2 = {
marginBottom: 2,
}
export default function DetailBenefit({requestLog} : CardDetail ) {
return (
{requestLog.benefitData?.map((item, index) => (
<Box sx={{ marginTop:'10px', marginBottom:'10px', py: '8px', px: '12px', border:'1px solid #919EAB52', borderRadius: '6px'}}>
<Grid 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}}>
</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}}>
</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}}>
</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}}>
</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}}>
</Grid>
</Grid>
</Grid>
</Grid>
</Box>
))}
)
}

View File

@@ -23,14 +23,15 @@ export default function DialogConfirmation({requestLog, setOpenDialog, openDialo
const navigate = useNavigate();
const handleSubmit = () => {
const formData = {
status : approve
status : approve,
id: requestLog?.id
}
axios
.put(`customer-service/request/${requestLog?.id}`, formData)
.post(`customer-service/request/final-log`, formData)
.then((response) => {
enqueueSnackbar('Verification Request LOG Success', { variant: 'success' });
enqueueSnackbar('Verification Final LOG Success', { variant: 'success' });
setOpenDialog(false);
navigate('/custormer-service/request')
navigate('/custormer-service/final-log')
})
.catch(({ response }) => {
enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' });
@@ -54,7 +55,7 @@ export default function DialogConfirmation({requestLog, setOpenDialog, openDialo
const getContent = () => (
<Stack spacing={1} marginTop={2}>
<Typography variant="subtitle2">Are you sure to {approve == 'approved' ? 'approve' : 'deciline'} this request ?</Typography>
<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}>

View File

@@ -66,4 +66,55 @@ export default function DialogDelete({id, setOpenDialog, openDialog,onSubmit} :
maxWidth="xs"
/>
);
}
export function DialogDeleteMedicine({id, setOpenDialog, openDialog,onSubmit} : DialogDeleteType ) {
const handleSubmit = () => {
axios
.delete(`customer-service/request/medicine-data/${id}`)
.then((response) => {
enqueueSnackbar('Benefit Data has Deleted', { variant: 'success' });
setOpenDialog(false);
window.location.reload()
})
.catch(({ response }) => {
enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' });
});
}
const style1 = {
color: '#919EAB',
width: '30%'
}
const style2 = {
width: '70%'
}
const marginBottom1 = {
marginBottom: 1,
}
const handleCloseDialog = () => {
setOpenDialog(false);
}
const getContent = () => (
<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

@@ -24,7 +24,7 @@ type DialogDeleteType = {
setOpenDialog: any;
onSubmit?: void;
data: BenefitConfigurationListType|undefined;
id: number;
id: number|undefined;
}
export default function DialogEditBenefit({id, data, setOpenDialog, openDialog,onSubmit} : DialogDeleteType ) {

View File

@@ -1,9 +1,13 @@
import * as Yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
import MuiDialog from "@/components/MuiDialog";
import { Button, Autocomplete, Card, Checkbox, DialogActions, Grid, Typography } from "@mui/material";
import { Paper } from "@mui/material";
import { Stack } from '@mui/material';
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { DetailFinalLogType } from "../Model/Types";
import { MedicineType } from "../Model/Types";
import { fDateTimesecond, toTitleCase } from "@/utils/formatTime";
import { useFieldArray, useForm } from 'react-hook-form';
import { FormProvider, RHFDatepicker, RHFSelect, RHFTextField } from '@/components/hook-form';
@@ -13,8 +17,10 @@ import { enqueueSnackbar } from "notistack";
import { useNavigate } from "react-router";
import { LoadingButton } from '@mui/lab';
import AddIcon from '@mui/icons-material/Add';
import RemoveIcon from '@mui/icons-material/Remove';
import RHFTextFieldMoney from "@/components/hook-form/v2/RHFTextFieldMoney";
import { IconButton } from '@mui/material';
import { postAddMedince } from '../Model/Functions';
type DialogConfirmationType = {
openDialog: boolean;
@@ -23,128 +29,133 @@ type DialogConfirmationType = {
requestLog: DetailFinalLogType|undefined;
}
export default function DialogHMedicine({requestLog, setOpenDialog, openDialog } : DialogConfirmationType ) {
interface FormValuesProps extends Partial<DetailFinalLogType> {
taxes: boolean;
inStock: boolean;
}
const onSubmit = async (data: DetailFinalLogType) => {
reset();
}
export default function DialogMedicine({requestLog, setOpenDialog, openDialog } : DialogConfirmationType ) {
const handleCloseDialogMedicine = () => {
setOpenDialog(false)
setMedicines([])
setOpenDialog(false);
}
const [medicines, setMedicines] = useState([]);
const addMedicine = () => {
setMedicines((prevMedicines) => [...prevMedicines, { medicine: '', price: '' }]);
const requestID = requestLog?.id
const defaultValues: MedicineType = {
medicine : [{
id: 0,
medicine_name: '',
medicine_price: 0,
request_log_id: requestID,
medicine: '', // input to database
price: 0, // input to database
}],
};
const handleDelete = (index) => {
// Update the medicines state to remove the medicine at the given index
setMedicines((prevMeds) => prevMeds.filter((med, medIndex) => medIndex !== index));
};
const validationSchema = Yup.object().shape({
medicine: Yup.array().of(
Yup.object().shape({
medicine_name : Yup.string().typeError('').required(''),
medicine_price : Yup.number().typeError('').required(''),
request_log_id : Yup.number().typeError('').required(''),
})
)
})
const removeMedicene = (i:number) => {
const index = medicines.indexOf(i);
if (index > -1) { // only splice array when item is found
medicines.splice(index, 1); // 2nd parameter means remove one item only
const methods = useForm<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 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)}>
<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={addMedicine}>
<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>
{/* Listing */}
<Grid item xs={6}>
<RHFTextField
name={`medicine[0].name`}
label="Medicine"
required
placeholder="Medicine"
/>
</Grid>
<Grid item xs={6}>
<RHFTextFieldMoney
name={`medicine[0].price`}
label="Price"
required
placeholder="Price"
/>
</Grid>
{medicines.map((medicine, index) => (
<React.Fragment key={index+1}>
{fields.map((field, index) => (
<React.Fragment key={index}>
<Grid item xs={6}>
<RHFTextField
name={`medicine[${index+1}].name`}
id='medicine_name'
key={field.id}
name={`medicine.${index}.medicine_name`}
label="Medicine"
required
placeholder="Medicine"
/>
</Grid>
<Grid item xs={6}>
<Grid item xs={5}>
<RHFTextFieldMoney
name={`medicine[${index+1}].price`}
id='medicine_price'
key={field.id}
name={`medicine.${index}.medicine_price`}
label="Price"
required
placeholder="Price"
/>
</Grid>
{/* <Grid item xs={1}>
<Button variant="contained" color="error" onClick={() => handleDelete(index)}>
Delete
</Button>
</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 = () => (
<Stack direction="row" alignItems="center" justifyContent="space-between" spacing={2}>
<Button color="inherit" variant="outlined" onClick={handleCloseDialogMedicine}><Typography>Cancel</Typography></Button>
<Button variant="contained"><Typography>Add</Typography></Button>
</Stack>
);
const getAction = () => null;
return (

View File

@@ -11,6 +11,7 @@ import {
Collapse,
AccordionSummary,
AccordionDetails,
IconButton,
} from '@mui/material';
// components
import Page from '../../../components/Page';
@@ -37,19 +38,22 @@ import AddIcon from '@mui/icons-material/Add';
import CardDetail from '../Components/CardDetail';
import CardService from '../Components/CardService';
import CardExclusion from '../Components/CardExclusion';
import CardBenefit from '../Components/CardBenefit';
// Import Dialog
import DialogHospitalCare from './Components/DialogHospitalCare';
import DialogBenefit from './Components/DialogBenefit';
import DialogMedicine from './Components/DialogMedicine';
import DetailBenefit from '../Components/DetailBenefit';
import DialogDelete from './Components/DialogDelete';
import DialogEditBenefit from './Components/DialogEditBenefit';
import { DialogDeleteMedicine } from './Components/DialogDelete';
import MoreMenu from '@/components/MoreMenu';
import { MenuItem } from '@mui/material';
import { fNumber } from '@/utils/formatNumber';
import palette from '@/theme/palette';
import DialogDelete from './Components/DialogDelete';
import CardMedicine from '../Components/CardMedicine';
import CardFile from '../Components/CardFile';
// ----------------------------------------------------------------------
@@ -299,7 +303,13 @@ export default function Detail() {
</Card>
{/* PR Buat pindahin ke componen */}
{/* <CardBenefit
requestLog={requestLog}
>
</CardBenefit> */}
<DialogBenefit
requestLog={requestLog}
@@ -335,37 +345,45 @@ export default function Detail() {
<Typography variant="button" display="block">Medicine</Typography>
</Button>
</Stack>
</Card>
<DialogMedicine
requestLog={requestLog}
openDialog={openDialogMedicine}
setOpenDialog={setDialogMedicine}
/>
{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}>
<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>
<CardFile
requestLog={requestLog}
/>
</Grid>
{requestLog?.status_final_log == 'requested' ? (

View File

@@ -1,6 +1,6 @@
import axios from '@/utils/axios';
import { enqueueSnackbar } from 'notistack';
import { MemberListType } from './Types';
import { MedicineType, MemberListType } from './Types';
import { BenefitConfigurationListType } from './Types';
import { makeFormData } from '@/utils/jsonToFormData';
@@ -119,7 +119,7 @@ export const postAddBenefit = async (data: BenefitConfigurationListType):Promise
/**
* Edit Benefit
*/
export const postEditBenefit = async (id:number, data: BenefitConfigurationListType):Promise<boolean> => {
export const postEditBenefit = async (id:number|undefined, data: BenefitConfigurationListType):Promise<boolean> => {
const response = await axios.put(`customer-service/request/benefit_data/${id}`, {
...data
})
@@ -151,3 +151,40 @@ export const postEditBenefit = async (id:number, data: BenefitConfigurationListT
return response;
}
/**
* Add Medicine
*/
export const postAddMedince = async (data: MedicineType):Promise<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

@@ -14,6 +14,7 @@ export type FinalLogType = {
id : number,
code : string,
member : Member,
member_name : string,
submission_date : string,
service_name : string,
payment_type_name : string,
@@ -41,6 +42,7 @@ export type DetailFinalLogType = {
benefit_data : BenefitData[],
config_service : ConfigService,
exclusion : Exclusion[],
medicine : Medicine[],
files : file[],
}
@@ -51,9 +53,26 @@ export type BenefitData = {
excess_paid : number,
keterangan : string,
benefit : Benefit,
request_log_id : number,
benefit_name : string,
description : string,
id : number,
}
export type BenefitConfigurationListType = {
request_log_id: number|undefined,
benefit_name: string,
benefit: {
description: string
},
amount_incurred: number,
amount_approved: number,
amount_not_approved: number,
excess_paid: number,
keterangan: string,
description: string,
}
export type Benefit = {
id: number,
code: string,
@@ -104,15 +123,17 @@ export type Rule = {
}
export type BenefitConfigurationListType = {
request_log_id: number|undefined,
benefit_name: string,
amount_incurred: number,
amount_approved: number,
amount_not_approved: number,
excess_paid: number,
keterangan: string,
description: string,
export type MedicineType = {
medicine: Medicine[],
}
export type Medicine = {
id: number,
medicine_name: string,
medicine_price: number,
medicine: string,
price: number,
request_log_id: number|undefined,
}

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>