Merge branch 'feature/daily-monitoring' into staging

This commit is contained in:
korospace
2023-10-27 15:30:08 +07:00
20 changed files with 1542 additions and 10 deletions

View File

@@ -0,0 +1,192 @@
<?php
namespace Modules\Internal\Http\Controllers\Api;
use App\Models\ClaimDailyMonitoring;
use App\Models\MedicalPlan;
use DB;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Validator;
/**
* Bagaskoro BSD 27-10-2023
*
* Controller untuk daily monitoring
*/
class DailyMonitoringController extends Controller
{
protected function messages()
{
return [
'required' => ':attribute harus diisi',
'integer' => ':attribute harus angka',
'unique' => ':attribute (:input) sudah ada',
'max' => ':attribute maximal :max karakter',
'exists' => ':attribute (:input) tidak ditemukan',
'numeric' => ':attribute harus angka',
'digits_between'=> ':attribute maximal :max digit minimal :min digit'
];
}
/**
* Member List
*/
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')
->get();
return response()->json([
'error' => false,
'message' => "success",
'data' => [
'member_list'=> $memberList,
]
],200);
}
/**
* Claim List - by member id
*/
public function GetClaimList(Request $request, $member_id)
{
$memberDetail = DB::table('members')
->select('id','member_id','name')
->where('member_id', $member_id)
->first();
$claimList = DB::table('claims')
->leftJoin('claim_requests', 'claims.claim_request_id', '=', 'claim_requests.id')
->leftJoin('services', 'claim_requests.service_code', '=', 'services.code')
->leftJoin('members', 'claims.member_id', '=', 'members.id')
->select('claims.id AS claim_id','claims.admission_dates','claims.discharge_dates','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)
->get();
return response()->json([
'error' => false,
'message' => "success",
'data' => [
'member_detail'=> $memberDetail,
'claim_list' => $claimList,
]
],200);
}
/**
* Detail Monitoring List - by claim_code
*/
public function GetDetailMonitoringList(Request $request, $claim_code)
{
// get claim request
$claim_request = DB::table('claim_requests')
->select('id')
->where('code', $claim_code)
->first();
// get claim
$claim = DB::table('claims')
->select('id')
->where('claim_request_id', empty($claim_request)==false ? $claim_request->id : '')
->first();
$detail_list = ClaimDailyMonitoring::where('claim_id', empty($claim) == false ? $claim->id : '')->get()->makeHidden(['updated_at']);
return response()->json([
'error' => false,
'message' => "success",
'data' => [
'detail_list'=> $detail_list,
]
],200);
}
/**
* Add Detail Monitoring List
*/
public function AddDetailMonitoringList(Request $request, $claim_code)
{
$request->merge(['claim_code' => $claim_code]);
// validation rule
$validator = Validator::make($request->all(),[
'claim_code' => 'required|exists:claim_requests,code',
'subject' => 'required',
'sistole' => 'required|numeric',
'diastole' => 'required|numeric',
'body_temperature' => 'required|numeric',
'respiration_rate' => 'required|numeric',
'analysis' => 'required',
'complaints' => 'required',
'medical_plan' => 'required',
],$this->messages());
// validation error
if ($validator->fails()) {
return response()->json([
'error' => true,
'message' => $validator->getMessageBag()
],400);
}
// get claim request
$claim_request = DB::table('claim_requests')
->select('id')
->where('code', $claim_code)
->first();
// get claim
$claim = DB::table('claims')
->select('id')
->where('claim_request_id', $claim_request->id)
->first();
DB::beginTransaction();
try {
// insert claim daily monitoring
$db_response = ClaimDailyMonitoring::create([
'claim_id' => $claim->id,
'subject' => $request->subject,
'sistole' => $request->sistole,
'diastole' => $request->diastole,
'body_temperature' => $request->body_temperature,
'respiration_rate' => $request->respiration_rate,
'analysis' => $request->analysis,
'complaints' => $request->complaints,
]);
// insert medical plan
foreach ($request->medical_plan as $row) {
MedicalPlan::create([
'claim_daily_monitoring_id' => $db_response->id,
'plan' => $row['medical_plan_str'],
]);
}
DB::commit();
return response()->json([
'error' => false,
'message' => "success",
'data' => []
],200);
}
catch (Exception $e) {
DB::rollBack();
return response()->json([
'error' => true,
'message' => $e->getMessage(),
'data' => []
],500);
}
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace App\Models;
use DB;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ClaimDailyMonitoring extends Model
{
use HasFactory;
protected $table = "claim_daily_monitoring";
protected $fillable = [
'claim_id',
'subject',
'body_temperature',
'respiration_rate',
'sistole',
'diastole',
'analysis',
'complaints'
];
protected $appends = ['medical_plan'];
public function getBodyTemperatureAttribute()
{
return round($this->attributes['body_temperature'], 0);
}
public function getSistoleAttribute()
{
return round($this->attributes['sistole'], 0);
}
public function getDiastoleAttribute()
{
return round($this->attributes['diastole'], 0);
}
public function getRespirationRateAttribute()
{
return round($this->attributes['respiration_rate'], 0);
}
public function getMedicalPlanAttribute()
{
$arr_medical_plan = [];
$medical_plan = DB::table('medical_plan')->where('claim_daily_monitoring_id','=',$this->attributes['id'])->get();
foreach ($medical_plan as $row) {
$arr_medical_plan[] = $row->plan;
}
return $arr_medical_plan;
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class MedicalPlan extends Model
{
use HasFactory;
protected $table = "medical_plan";
protected $fillable = [
'claim_daily_monitoring_id',
'plan'
];
}

View File

@@ -0,0 +1,39 @@
<?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('claim_daily_monitoring', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('claim_id');
$table->text('subject');
$table->decimal('body_temperature', 11, 2);
$table->decimal('respiration_rate', 11, 2);
$table->decimal('sistole', 11, 2);
$table->decimal('diastole', 11, 2);
$table->text('analysis');
$table->text('complaints');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('claim_daily_monitoring');
}
};

View File

@@ -0,0 +1,33 @@
<?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('medical_plan', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('claim_daily_monitoring_id');
$table->text('plan');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('medical_plan');
}
};

View File

@@ -4,4 +4,5 @@ PORT=8000
REACT_APP_HOST_API_URL="http://lms.test"
VITE_API_URL="https://aso-api.linksehat.dev/api/internal"
# VITE_API_URL="https://aso-api.linksehat.dev/api/internal"
VITE_API_URL="http://localhost:8000/api/internal"

View File

@@ -72,6 +72,12 @@ const navConfig = [
// { title: 'Report', path: '/case-report' },
// ],
},
{
title: 'CASE MANAGEMENT',
children: [
{ title: 'Daily Monitoring', path: '/case_management/daily_monitoring' },
],
},
{
title: 'CUSTOMER SERVICES',
children: [

View File

@@ -0,0 +1,73 @@
/**
* Core
* ============================================
*/
import { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { Box, Grid, IconButton, Typography } from '@mui/material';
import { ArrowBackIosNew } from '@mui/icons-material';
/**
* Components
* ============================================
*/
// - Global -
import Page from '../../../components/Page';
// - Local -
/**
* Utils, Types, Functions
* ============================================
*/
import { getClaimList } from './Model/Functions';
import { ClaimListType, MemberDetailType } from './Model/Types';
import ClaimList from './Components/ClaimList';
export default function Claim() {
const navigate = useNavigate()
const { member_id } = useParams();
// State
// --------------------
const [memberDetail, setMemberDetail] = useState<MemberDetailType>();
const [claimList, setClaimList] = useState<ClaimListType[]>();
// Use Effect
// --------------------
useEffect(() => {
loadDataTableData();
}, [])
// Load Data
// -------------------
const loadDataTableData = async () => {
const response = await getClaimList(member_id??'');
setMemberDetail(response.member_detail);
setClaimList(response.claim_list);
}
return (
<Page title={ `claims | ${memberDetail?.name??'_ _ _'}` } sx={{ px: 2 }}>
<Grid container gap={6}>
{/* back button */}
<Grid item xs={12}>
<Box sx={{ display: 'flex', alignItems: 'center'}}>
<IconButton size='large' color='inherit' onClick={() => navigate(`/case_management/daily_monitoring`)} >
<ArrowBackIosNew/>
</IconButton>
<Typography variant="h5" sx={{ marginLeft: '24px' }}>
{memberDetail?.name??'_ _ _'}
</Typography>
</Box>
</Grid>
{/* tabel claims */}
<Grid item xs={12}>
<ClaimList claim_list={claimList??null} />
</Grid>
</Grid>
</Page>
);
}

View File

@@ -0,0 +1,80 @@
/**
* Core
* ============================================
*/
import { useEffect, useState } from "react";
import { Box, Paper, TableContainer, Table, TableHead, TableRow, TableCell, TableBody } from "@mui/material";
/**
* Component
* ============================================
*/
import ClaimListRow from "./ClaimListRow";
/**
* Types & Functions
* ============================================
*/
import { ClaimListType } from "../Model/Types";
type Props = {
claim_list: ClaimListType[] | null,
}
export default function ClaimList({ ...props }: Props) {
// Tabel Style
// --------------------
const TableHeadStyle = {
fontWeight: 'bold',
};
return (
<Box>
<TableContainer component={Paper}>
<Table sx={{ minWidth: 250 }} size='medium' aria-label="collapsible table">
{/* Head Table */}
<TableHead>
<TableRow>
<TableCell style={TableHeadStyle} align="left" width={50} />
<TableCell style={TableHeadStyle} align="left" width={160}>Admission Date</TableCell>
<TableCell style={TableHeadStyle} align="left" width={160}>Discharge Date</TableCell>
<TableCell style={TableHeadStyle} align="left" width={200}>Code</TableCell>
<TableCell style={TableHeadStyle} align="left" width={'*'}>Service Type</TableCell>
<TableCell style={TableHeadStyle} align="left" width={200}>Status</TableCell>
<TableCell align="left" width={"10"} />
</TableRow>
</TableHead>
{/* Body Table */}
{props.claim_list == null ?
(
<TableBody>
<TableRow>
<TableCell colSpan={7} align="center">Loading</TableCell>
</TableRow>
</TableBody>
)
:
(
props.claim_list.length == 0 ?
(
<TableBody>
<TableRow>
<TableCell colSpan={7} align="center">No Data</TableCell>
</TableRow>
</TableBody>
)
:
(
<TableBody>
{props.claim_list.map((row: ClaimListType, index) => (
<ClaimListRow key={index} number={index+1} row={row} />
))}
</TableBody>
)
)}
</Table>
</TableContainer>
</Box>
)
}

View File

@@ -0,0 +1,88 @@
/**
* Core
* ============================================
*/
import React, { useState } from "react";
import { useNavigate } from "react-router";
import { Box, Collapse, MenuItem, TableCell, TableRow, Stack } from "@mui/material";
import Visibility from '@mui/icons-material/Visibility';
import AddIcon from '@mui/icons-material/Add';
/**
* Component
* ============================================
*/
// - Global -
import Label from "@/components/Label";
import TableMoreMenu from '@/components/table/TableMoreMenu';
/**
* Utils, Types, Functions
* ============================================
*/
import { fDate } from "@/utils/formatTime";
import { ClaimListType } from "../Model/Types";
type Props = {
row: ClaimListType,
number: number
}
export default function ClaimListRow ({ ...props }: Props) {
const navigate = useNavigate()
return (
<React.Fragment>
<TableRow hover sx={{ '& > td': { borderBottom: '1' } }}>
<TableCell align="left" />
<TableCell align="left">
{props.row.admission_dates == "0000-00-00 00:00:00" ?
('-')
:
(
<Label
variant="ghost"
color="default"
>
{fDate(props.row.admission_dates)}
</Label>
)}
</TableCell>
<TableCell align="left">
{props.row.discharge_dates == "0000-00-00 00:00:00" ?
('-')
:
(
<Label
variant="ghost"
color="default"
>
{fDate(props.row.discharge_dates)}
</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="right" onClick={(e) => e.stopPropagation()}>
<Stack direction="row" justifyContent="flex-end" spacing={1}>
<TableMoreMenu actions={
<>
<MenuItem onClick={() => navigate(`/case_management/daily_monitoring/${props.row.member_id}/claims/${props.row.claim_code}/list_monitoring`)}>
<Visibility />
View
</MenuItem>
<MenuItem onClick={() => navigate(`/case_management/daily_monitoring/${props.row.member_id}/claims/${props.row.claim_code}/add_monitoring`)}>
<AddIcon />
Daily Monitoring
</MenuItem>
</>
} />
</Stack>
</TableCell>
</TableRow>
</React.Fragment>
);
}

View File

@@ -0,0 +1,93 @@
/**
* Core
* ============================================
*/
import { useEffect, useState } from "react";
import { Box, Paper, TableContainer, Table, TableHead, TableRow, TableCell, TableBody } from "@mui/material";
/**
* Types & Functions
* ============================================
*/
import { getDailyMonitoringList } from "../Model/Functions";
import { DailyMonitoringListType } from "../Model/Types";
import DailyMonitoringListRow from "./DailyMonitoringListRow";
export default function DailyMonitoringList() {
// State
// --------------------
const [dataTableIsLoading, setDataTableLoading] = useState<boolean>(true);
const [dataTableData, setDataTableData] = useState<DailyMonitoringListType[]>([]);
// Tabel Style
// --------------------
const TableHeadStyle = {
fontWeight: 'bold',
};
// Use Effect
// --------------------
useEffect(() => {
loadDataTableData();
}, [])
// Load Data
// -------------------
const loadDataTableData = async () => {
setDataTableLoading(true);
const response = await getDailyMonitoringList();
setDataTableLoading(false);
setDataTableData(response);
}
return (
<Box>
<TableContainer component={Paper}>
<Table sx={{ minWidth: 250 }} size='medium' aria-label="collapsible table">
{/* Head Table */}
<TableHead>
<TableRow>
<TableCell style={TableHeadStyle} align="left" width={50} />
<TableCell style={TableHeadStyle} align="left" width={150}>Member ID</TableCell>
<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 align="left" width={"10"} />
</TableRow>
</TableHead>
{/* Body Table */}
{dataTableIsLoading ?
(
<TableBody>
<TableRow>
<TableCell colSpan={6} align="center">Loading</TableCell>
</TableRow>
</TableBody>
)
:
(
dataTableData.length == 0 ?
(
<TableBody>
<TableRow>
<TableCell colSpan={6} align="center">No Data</TableCell>
</TableRow>
</TableBody>
)
:
(
<TableBody>
{dataTableData.map((row: DailyMonitoringListType, index) => (
<DailyMonitoringListRow key={index} number={index+1} row={row} />
))}
</TableBody>
)
)}
</Table>
</TableContainer>
</Box>
)
}

View File

@@ -0,0 +1,72 @@
/**
* Core
* ============================================
*/
import React, { useState } from "react";
import { useNavigate } from "react-router";
import { Box, Collapse, MenuItem, TableCell, TableRow, Stack } from "@mui/material";
import Visibility from '@mui/icons-material/Visibility';
/**
* Component
* ============================================
*/
// - Global -
import Label from "@/components/Label";
import TableMoreMenu from '@/components/table/TableMoreMenu';
/**
* Utils, Types, Functions
* ============================================
*/
import { fDate } from "@/utils/formatTime";
import { DailyMonitoringListType } from "../Model/Types";
type Props = {
row: DailyMonitoringListType,
number: number
}
export default function DailyMonitoringListRow ({ ...props }: Props) {
const navigate = useNavigate()
return (
<React.Fragment>
<TableRow hover sx={{ '& > td': { borderBottom: '1' } }}>
<TableCell align="left" />
<TableCell align="left">{props.row.member_id}</TableCell>
<TableCell align="left">{props.row.name}</TableCell>
<TableCell align="left">
<Label
variant="ghost"
color="default"
>
{fDate(props.row.startdate)}
</Label>
</TableCell>
<TableCell align="left">
<Label
variant="ghost"
color="default"
>
{fDate(props.row.enddate)}
</Label>
</TableCell>
<TableCell align="right" onClick={(e) => e.stopPropagation()}>
<Stack direction="row" justifyContent="flex-end" spacing={1}>
<TableMoreMenu actions={
<>
<MenuItem onClick={() => navigate(`/case_management/daily_monitoring/${props.row.member_id}/claims`)}>
<Visibility />
View
</MenuItem>
</>
} />
</Stack>
</TableCell>
</TableRow>
</React.Fragment>
);
}

View File

@@ -0,0 +1,294 @@
/**
* Core
* ============================================
*/
import { useFieldArray, useForm } from 'react-hook-form';
import { useNavigate, useParams } from 'react-router-dom';
import { Box, IconButton, Typography, Grid, Card, Button } from '@mui/material';
import { LoadingButton } from "@mui/lab";
/**
* Components
* ============================================
*/
import Page from '@/components/Page';
import { FormProvider, RHFTextField } from '@/components/hook-form';
/**
* Icon
* ============================================
*/
import ArrowBackIosNew from '@mui/icons-material/ArrowBackIosNew';
import AddIcon from '@mui/icons-material/Add';
import RemoveIcon from '@mui/icons-material/Remove';
/**
* Utils, Types, Functions
* ============================================
*/
import { AddClaimDetail } from '../Model/Functions';
import { DetailMonitoringListType} from '../Model/Types';
export default function DetailMonitoringList() {
const { member_id, claim_code } = useParams();
const navigate = useNavigate()
const pageTitle = claim_code??'_ _ _ _';
// setup form
// ====================================
const defaultValues: any = {
subject : '',
body_temperature: '',
sistole : '',
diastole : '',
respiration_rate: '',
complaints : '',
analysis : '',
medical_plan : [{
medical_plan_str: ''
}]
};
const methods = useForm<any>({
defaultValues
});
const {fields, append, remove} = useFieldArray({name: 'medical_plan',control: methods.control})
const { handleSubmit, reset, formState: { isDirty, isSubmitting } } = methods;
// Submit Form
// =====================================
const submitHandler = async (data: DetailMonitoringListType) => {
console.log(claim_code);
const response = await AddClaimDetail(claim_code??'', data);
if (response == true) {
reset();
}
}
return (
<Page title={pageTitle}>
<Box sx={{ display: 'flex', alignItems: 'center', pl: '12px', mb: '40px' }}>
<IconButton size='large' color='inherit' onClick={() => navigate(`/case_management/daily_monitoring/${member_id}/claims`)} >
<ArrowBackIosNew/>
</IconButton>
<Typography variant="h5" sx={{ marginLeft: '24px' }}>
{pageTitle}
</Typography>
</Box>
<Box sx={{ px: '28px' }}>
<FormProvider methods={methods} onSubmit={handleSubmit(submitHandler)}>
<Card sx={{ padding: '24px' }}>
<Grid container spacing={6}>
{/* Subject */}
<Grid item xs={12}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Typography variant="body1" component="div">
Subject* :
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextField
id="subject"
name='subject'
placeholder='Subjective'
/>
</Grid>
</Grid>
</Grid>
{/* Objectif */}
<Grid item xs={12}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Typography variant="body1" component="div">
Objectif
</Typography>
</Grid>
<Grid item xs={12}>
<Grid container spacing={3}>
<Grid item xs={3}>
<Typography variant="body1" component="div" color={'GrayText'}>
Body Temperature* :
</Typography>
</Grid>
<Grid item xs={3}>
<Typography variant="body1" component="div" color={'GrayText'}>
Sistole* :
</Typography>
</Grid>
<Grid item xs={3}>
<Typography variant="body1" component="div" color={'GrayText'}>
Diastole* :
</Typography>
</Grid>
<Grid item xs={3}>
<Typography variant="body1" component="div" color={'GrayText'}>
Respiration Rate* :
</Typography>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Grid container spacing={3}>
<Grid item xs={2}>
<RHFTextField
id="body_temperature"
name='body_temperature'
placeholder='Body Temperature'
/>
</Grid>
<Grid item xs={1} sx={{ display: 'flex', alignItems: 'center' }}>
<Typography variant="body1" component="div" color={'GrayText'}>
Cel
</Typography>
</Grid>
<Grid item xs={2}>
<RHFTextField
id="sistole"
name='sistole'
placeholder='Sistole'
/>
</Grid>
<Grid item xs={1} sx={{ display: 'flex', alignItems: 'center' }}>
<Typography variant="body1" component="div" color={'GrayText'}>
mm[Hg]
</Typography>
</Grid>
<Grid item xs={2}>
<RHFTextField
id="diastole"
name='diastole'
placeholder='Diastole'
/>
</Grid>
<Grid item xs={1} sx={{ display: 'flex', alignItems: 'center' }}>
<Typography variant="body1" component="div" color={'GrayText'}>
mm[Hg]
</Typography>
</Grid>
<Grid item xs={2}>
<RHFTextField
id="respiration_rate"
name='respiration_rate'
placeholder='Respiration Rate'
/>
</Grid>
<Grid item xs={1} sx={{ display: 'flex', alignItems: 'center' }}>
<Typography variant="body1" component="div" color={'GrayText'}>
/min
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
{/* Complaints */}
<Grid item xs={12}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Typography variant="body1" component="div">
Complaints* :
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextField
id="complaints"
name='complaints'
placeholder='Complaints'
/>
</Grid>
</Grid>
</Grid>
{/* Analysis */}
<Grid item xs={12}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Typography variant="body1" component="div">
Analysis* :
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextField
id="analysis"
name='analysis'
placeholder='Analysis'
/>
</Grid>
</Grid>
</Grid>
{/* Medical Plan */}
<Grid item xs={12}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Typography variant="body1" component="div">
Medical Plan* :
</Typography>
</Grid>
<Grid item xs={12}>
{
fields.map((field,index) => {
return (
<Grid key={field.id} container sx={{ mb: 3 }}>
<Grid item xs={11}>
<RHFTextField
id="analysis"
name={`medical_plan.${index}.medical_plan_str`}
placeholder='Medical Plan'
/>
</Grid>
{
index == (fields.length-1) ?
(
<Grid item xs={1} sx={{ textAlign: 'center' }}>
<IconButton size='large' color='primary' onClick={() => append({medical_plan_str: ''})}>
<AddIcon />
</IconButton>
</Grid>
)
:
(
<Grid item xs={1} sx={{ textAlign: 'center' }}>
<IconButton size='large' color='error' onClick={() => remove(index)}>
<RemoveIcon />
</IconButton>
</Grid>
)
}
</Grid>
)
})
}
</Grid>
</Grid>
</Grid>
{/* Button Cancle & Save */}
<Grid item xs={12} md={12}>
<Box display="flex" justifyContent={'flex-end'}>
<Box display="flex" gap={1}>
<Button variant="outlined" color="inherit" onClick={() => navigate(`/case_management/daily_monitoring/${member_id}/claims`)}>
Cancel
</Button>
<LoadingButton disabled={!isDirty} type="submit" variant="contained" loading={isSubmitting}>
Save Changes
</LoadingButton>
</Box>
</Box>
</Grid>
</Grid>
</Card>
</FormProvider>
</Box>
</Page>
);
}

View File

@@ -0,0 +1,241 @@
/**
* Core
* ============================================
*/
import { useEffect, useState } from 'react';
import { useFieldArray, useForm } from 'react-hook-form';
import { useNavigate, useParams } from 'react-router-dom';
import { Box, IconButton, Typography, Grid, Card, List, ListItem } from '@mui/material';
import { LoadingButton } from "@mui/lab";
/**
* Components
* ============================================
*/
// - Global -
import Page from '@/components/Page';
import Label from "@/components/Label";
/**
* Icon
* ============================================
*/
import ArrowBackIosNew from '@mui/icons-material/ArrowBackIosNew';
import FiberManualRecord from '@mui/icons-material/FiberManualRecord';
/**
* Utils, Types, Functions
* ============================================
*/
import { fDate } from "@/utils/formatTime";
import { AddClaimDetail, getClaimDetailList } from '../Model/Functions';
import { DetailMonitoringListType } from '../Model/Types';
export default function DetailMonitoringList() {
const { member_id, claim_code } = useParams();
const navigate = useNavigate()
const pageTitle = claim_code??'_ _ _ _';
// State
// --------------------
const [detailMonitoringList, setDetailMonitoringList] = useState<DetailMonitoringListType[]>();
// Use Effect
// --------------------
useEffect(() => {
loadDataTableData();
}, [])
// Load Data
// -------------------
const loadDataTableData = async () => {
const response = await getClaimDetailList(claim_code??'');
setDetailMonitoringList(response);
}
return (
<Page title={pageTitle} sx={{ px: 2 }}>
<Grid container gap={6}>
{/* back button */}
<Grid item xs={12}>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<IconButton size='large' color='inherit' onClick={() => navigate(`/case_management/daily_monitoring/${member_id}/claims`)} >
<ArrowBackIosNew/>
</IconButton>
<Typography variant="h5" sx={{ marginLeft: '24px' }}>
{pageTitle}
</Typography>
</Box>
</Grid>
{/* tabel claims */}
<Grid item xs={12}>
<Grid container gap={4} sx={{ px: 2 }}>
{
detailMonitoringList?.map((row, index) => {
return (
<Grid key={index} item xs={12}>
<Card sx={{ border: '1px solid rgba(0,0,0,0.125)', px: '32px', py: '24px'}}>
{/* card header */}
<Box sx={{ pb: '20px', mb: '20px', borderBottom: '1px solid rgba(0,0,0,0.125)' }}>
<Label
variant="ghost"
color="default"
>
{row.created_at ? fDate(row.created_at) : '-'}
</Label>
</Box>
{/* card body */}
<Grid container gap={4}>
<Grid item xs={12}>
<Grid container gap={1}>
<Grid item xs={12}>
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
Subject :
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="body2" color={"GrayText"}>
{row.subject}
</Typography>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Grid container gap={1}>
<Grid item xs={12}>
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
Object :
</Typography>
</Grid>
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={6}>
<Typography variant="body2" color={"GrayText"}>
Body Temperature
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">
{row.body_temperature}
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2" color={"GrayText"}>
Sistole
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">
{row.sistole} mm[Hg]
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2" color={"GrayText"}>
Diastole
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">
{row.diastole} mm[Hg]
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2" color={"GrayText"}>
Respiration Rate
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2">
{row.respiration_rate} / min
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Grid container gap={1}>
<Grid item xs={12}>
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
Subject :
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="body2" color={"GrayText"}>
{row.subject}
</Typography>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Grid container gap={1}>
<Grid item xs={12}>
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
Analysis :
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="body2" color={"GrayText"}>
{row.analysis}
</Typography>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Grid container gap={1}>
<Grid item xs={12}>
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
Complaints :
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="body2" color={"GrayText"}>
{row.complaints}
</Typography>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Grid container gap={1}>
<Grid item xs={12}>
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
Medical Plan :
</Typography>
</Grid>
<Grid item xs={12}>
<List sx={{ color: 'GrayText' }}>
{
row.medical_plan.map((str, index) => {
return (
<ListItem key={index}>
<FiberManualRecord sx={{ fontSize: '8px', mr: '10px' }} /> {str}
</ListItem>
)
})
}
</List>
</Grid>
</Grid>
</Grid>
</Grid>
</Card>
</Grid>
)
})
}
</Grid>
</Grid>
</Grid>
</Page>
);
}

View File

@@ -0,0 +1,107 @@
import axios from '@/utils/axios';
import { enqueueSnackbar } from 'notistack';
import { DailyMonitoringListType, DetailMonitoringListType, ResponseListingClaimType } from "./Types";
/**
* Listing Daily Monitoring
*/
export const getDailyMonitoringList = async ( ): Promise<DailyMonitoringListType[]> => {
const response = await axios.get('/case_management/daily_monitoring/memberlist')
.then((res) =>{
return res.data.data.member_list;
})
.catch((res) => {
enqueueSnackbar(res.response.data.message, {
variant: 'error',
});
return [];
});
return response;
};
/**
* Listing Claim
*/
export const getClaimList = async ( member_id: string ): Promise<ResponseListingClaimType> => {
const response = await axios.get(`/case_management/daily_monitoring/claimlist/${member_id}`)
.then((res) =>{
return res.data.data;
})
.catch((res) => {
enqueueSnackbar(res.response.data.message, {
variant: 'error',
});
return null;
});
return response;
};
/**
* Add Claim Detail
*/
export const AddClaimDetail = async ( claim_code: string,data: DetailMonitoringListType ): Promise<boolean> => {
const response = await axios.post(`/case_management/daily_monitoring/detail/${claim_code}/add`, {
...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[key][0], {
variant: 'warning',
});
}
}
else {
enqueueSnackbar(res.response.data.message, {
variant: 'error',
});
}
return false;
});
return response;
};
/**
* Get Claim Detail List
*/
export const getClaimDetailList = async ( claim_code: string ): Promise<DetailMonitoringListType[]> => {
const response = await axios.get(`/case_management/daily_monitoring/detail/${claim_code}/list`)
.then((res) =>{
return res.data.data.detail_list;
})
.catch((res) => {
if (res.response.status == 400) {
let arr_message = res.response.data.message;
for (const key in arr_message) {
enqueueSnackbar(arr_message[key][0], {
variant: 'warning',
});
}
}
else {
enqueueSnackbar(res.response.data.message, {
variant: 'error',
});
}
return [];
});
return response;
};

View File

@@ -0,0 +1,57 @@
/**
* List Daily Monitoring
*/
export type DailyMonitoringListType = {
member_id : string,
name : string,
startdate : string,
enddate : string,
}
/**
* Response Listing Claim
*/
export type ResponseListingClaimType = {
member_detail : MemberDetailType,
claim_list : ClaimListType[],
}
/**
* Member Detail
*/
export type MemberDetailType = {
id : string,
member_id : string,
name : string,
}
/**
* List Claim
*/
export type ClaimListType = {
claim_id : number,
admission_dates : string,
discharge_dates : string,
claim_code : string,
claim_status : string,
service_type : string,
member_id : string
}
/**
* Detail Claim
*/
export type DetailMonitoringListType = {
id : string|null,
claim_id : string|null,
claim_code : string,
subject : string,
body_temperature: string,
respiration_rate: string,
sistole : string,
diastole : string
analysis : string,
complaints : string,
medical_plan : string[],
created_at : string|null
}

View File

@@ -0,0 +1,48 @@
/**
* Core
* ============================================
*/
import { Box, Grid } from '@mui/material';
/**
* Components
* ============================================
*/
// - Global -
import Page from '../../../components/Page';
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
// - Local -
import DailyMonitoringList from './Components/DailyMonitoringList';
export default function DailyMonitoring() {
const pageTitle = "Daily Monitoring";
return (
<Page title={ pageTitle } sx={{ px: 2 }}>
<Grid container>
{/* page header */}
<Grid item xs={12}>
<HeaderBreadcrumbs
heading={ pageTitle }
sx={{ px: 1 }}
links={[
{
name: 'Dashboard',
href: '/dashboard',
},
{
name: 'Daily Monitoring',
href: '/case_management/daily_monitoring',
},
]}
/>
</Grid>
{/* tabel daily monitoring */}
<Grid item xs={12}>
<DailyMonitoringList />
</Grid>
</Grid>
</Page>
);
}

View File

@@ -984,7 +984,7 @@ export default function List(props: any) {
<TableCell style={headStyle} align="left">
Status
</TableCell>
<TableCell style={headStyle} align="left">
<TableCell style={headStyle} align="right">
<TableMoreMenu actions={
<>
<MenuItem onClick={() => navigate(`/corporates/${corporate_id}/diagnosis-exclusions/history`)}>
@@ -999,7 +999,7 @@ export default function List(props: any) {
{dataTableIsLoading ? (
<TableBody>
<TableRow>
<TableCell colSpan={8} align="center">
<TableCell colSpan={7} align="center">
Loading
</TableCell>
</TableRow>
@@ -1007,7 +1007,7 @@ export default function List(props: any) {
) : dataTableData.data.length == 0 ? (
<TableBody>
<TableRow>
<TableCell colSpan={8} align="center">
<TableCell colSpan={7} align="center">
No Data
</TableCell>
</TableRow>

View File

@@ -86,7 +86,7 @@ export default function CustomizedAccordions() {
setExpanded(newExpanded ? panel : false);
};
const pageTitle = 'Diagnosis History';
const { themeStretch } = useSettings();
const { id } = useParams();
@@ -152,10 +152,10 @@ export default function CustomizedAccordions() {
<TableBody>
{Object.entries(item.old_values).map(([key, value]) => {
let renderedValue;
if (key === 'deleted_by' ||
key === 'deleted_at' ||
key === 'created_by' ||
key === 'created_at' ||
if (key === 'deleted_by' ||
key === 'deleted_at' ||
key === 'created_by' ||
key === 'created_at' ||
key === 'updated_by' ||
key === 'description'||
key === 'version'||

View File

@@ -216,7 +216,28 @@ export default function Router() {
path: 'corporates/:corporate_id/edit',
element: <CorporateCreate />,
},
{
path: 'case_management', // Case Management
element: '',
children: [
{
path: 'daily_monitoring',
element: <DailyMonitoring />
},
{
path: 'daily_monitoring/:member_id/claims',
element: <DailyMonitoringClaims />
},
{
path: 'daily_monitoring/:member_id/claims/:claim_code/add_monitoring',
element: <DetailMonitoringForm />
},
{
path: 'daily_monitoring/:member_id/claims/:claim_code/list_monitoring',
element: <DetailMonitoringList />
},
]
},
{
path: 'corporates/:corporate_id/corporate-plans/create',
element: <CorporatePlanCreate />,
@@ -531,6 +552,16 @@ const CorporateFormularium = Loadable(lazy(() => import('../pages/Corporates/For
const CorporateFormulariumCreate = Loadable(lazy(() => import('../pages/Corporates/Formularium/New/CreateForm')));
const CorporateFormulariumHistory = Loadable(lazy(() => import('../pages/Corporates/Formularium/New/History')))
/**
* Case Management
* -------------------------------
*/
// Daily Monitoring
const DailyMonitoring = Loadable(lazy(() => import('../pages/CaseManagement/DailyMonitoring/index')))
const DailyMonitoringClaims = Loadable(lazy(() => import('../pages/CaseManagement/DailyMonitoring/Claim')))
const DetailMonitoringForm = Loadable(lazy(() => import('../pages/CaseManagement/DailyMonitoring/Components/DetailMonitoringForm')))
const DetailMonitoringList = Loadable(lazy(() => import('../pages/CaseManagement/DailyMonitoring/Components/DetailMonitoringList')))
const MasterDiagnosisTemplate = Loadable(lazy(() => import('../pages/Master/Diagnosis/Master/Index')));
const MasterDiagnosisTemplateCreate = Loadable(lazy(() => import('../pages/Master/Diagnosis/Master/CreateUpdate')));
const MasterDiagnosisTemplateHistories = Loadable(