Merge remote-tracking branch 'origin/staging' into origin/production
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 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[]>();
|
||||
|
||||
// Load Data
|
||||
// -------------------
|
||||
const loadDataTableData = async () => {
|
||||
const response = await getClaimList(member_id??'');
|
||||
|
||||
setMemberDetail(response.member_detail);
|
||||
setClaimList(response.claim_list);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, [])
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Core
|
||||
* ============================================
|
||||
*/
|
||||
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>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* 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_date == null?
|
||||
('-')
|
||||
:
|
||||
(
|
||||
<Label
|
||||
variant="ghost"
|
||||
color="default"
|
||||
>
|
||||
{fDate(props.row.admission_date)}
|
||||
</Label>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{props.row.discharge_date == null ?
|
||||
('-')
|
||||
:
|
||||
(
|
||||
<Label
|
||||
variant="ghost"
|
||||
color="default"
|
||||
>
|
||||
{fDate(props.row.discharge_date)}
|
||||
</Label>
|
||||
)}
|
||||
</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={
|
||||
<>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
@@ -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',
|
||||
};
|
||||
|
||||
// Load Data
|
||||
// -------------------
|
||||
const loadDataTableData = async () => {
|
||||
setDataTableLoading(true);
|
||||
|
||||
const response = await getDailyMonitoringList();
|
||||
|
||||
setDataTableLoading(false);
|
||||
setDataTableData(response);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, [])
|
||||
|
||||
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 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>
|
||||
|
||||
{/* 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>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 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="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={
|
||||
<>
|
||||
<MenuItem onClick={() => navigate(`/case_management/daily_monitoring/${props.row.member_id}/claims`)}>
|
||||
<Visibility />
|
||||
View
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</Stack>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
/**
|
||||
* 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 { AddMonitoringDetail } 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: DetailMonitoringListType = {
|
||||
id : '',
|
||||
claim_code : '',
|
||||
claim_id : '',
|
||||
subject : '',
|
||||
body_temperature: '',
|
||||
sistole : '',
|
||||
diastole : '',
|
||||
respiration_rate: '',
|
||||
complaints : '',
|
||||
analysis : '',
|
||||
medical_plan : [{
|
||||
medical_plan_str: ''
|
||||
}],
|
||||
created_at : ''
|
||||
};
|
||||
|
||||
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 AddMonitoringDetail(claim_code??'', data);
|
||||
|
||||
if (response == true) {
|
||||
reset();
|
||||
navigate('case_management/daily_monitoring/'+claim_code+'claims');
|
||||
window.location.reload()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Page title={pageTitle}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', pl: '22px', 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>
|
||||
);
|
||||
}
|
||||
@@ -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 { getMonitoringDetailList } 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 getMonitoringDetailList(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((data, index) => {
|
||||
return (
|
||||
<ListItem key={index}>
|
||||
<FiberManualRecord sx={{ fontSize: '8px', mr: '10px' }} /> {data.medical_plan_str}
|
||||
</ListItem>
|
||||
)
|
||||
})
|
||||
}
|
||||
</List>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
</Grid>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
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/memberlist')
|
||||
.then((res) =>{
|
||||
return res.data.data.member_list;
|
||||
})
|
||||
.catch((res) => {
|
||||
enqueueSnackbar("server error !", {
|
||||
variant: 'error',
|
||||
});
|
||||
|
||||
return [];
|
||||
});
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
/**
|
||||
* Listing Claim
|
||||
*/
|
||||
export const getClaimList = async ( member_id: string ): Promise<ResponseListingClaimType> => {
|
||||
const response = await axios.get(`/case_management/claimlist/${member_id}`)
|
||||
.then((res) =>{
|
||||
return res.data.data;
|
||||
})
|
||||
.catch((res) => {
|
||||
enqueueSnackbar("server error !", {
|
||||
variant: 'error',
|
||||
});
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add Monitoring Detail
|
||||
*/
|
||||
export const AddMonitoringDetail = 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("server error !", {
|
||||
variant: 'error',
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get Monitoring Detail List
|
||||
*/
|
||||
export const getMonitoringDetailList = 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) => {
|
||||
enqueueSnackbar("server error !", {
|
||||
variant: 'error',
|
||||
});
|
||||
|
||||
return [];
|
||||
});
|
||||
|
||||
return response;
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* List Daily Monitoring
|
||||
*/
|
||||
export type DailyMonitoringListType = {
|
||||
member_id : string,
|
||||
name : string,
|
||||
startdate : string,
|
||||
enddate : string,
|
||||
addmision_date : string,
|
||||
provider : 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_date : string,
|
||||
discharge_date : string,
|
||||
claim_code : string,
|
||||
claim_status : string,
|
||||
service_type : string,
|
||||
member_id : string
|
||||
}
|
||||
|
||||
/**
|
||||
* Detail Monitoring List
|
||||
*/
|
||||
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 : MedicalPlanStrType[],
|
||||
created_at : string|null
|
||||
}
|
||||
|
||||
export type MedicalPlanStrType = {
|
||||
medical_plan_str: string
|
||||
}
|
||||
@@ -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: pageTitle,
|
||||
href: '/case_management/daily_monitoring',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* tabel daily monitoring */}
|
||||
<Grid item xs={12}>
|
||||
<DailyMonitoringList />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Card, Stack } from "@mui/material";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import Page from "../../../components/Page";
|
||||
import List from "./List";
|
||||
|
||||
|
||||
|
||||
export default function Claims() {
|
||||
|
||||
const pageTitle = 'Inpatient Monitoring';
|
||||
return (
|
||||
<Page title={ pageTitle } sx={{ mx: 2}}>
|
||||
|
||||
<HeaderBreadcrumbs
|
||||
heading={ pageTitle }
|
||||
links={[
|
||||
{ name: 'Dashboard', href: '/dashboard' },
|
||||
{
|
||||
name: 'Inpatient Monitoring',
|
||||
href: '/inpatient_monitoring',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
{/* <Stack> */}
|
||||
<List />
|
||||
{/* </Stack> */}
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,582 @@
|
||||
// @mui
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
Collapse,
|
||||
IconButton,
|
||||
MenuItem,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
Stack,
|
||||
Menu,
|
||||
ButtonGroup,
|
||||
Link,
|
||||
Chip,
|
||||
TableHead,
|
||||
Grid,
|
||||
} from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
|
||||
import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined';
|
||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||
// hooks
|
||||
import React, { ChangeEvent, useEffect, useRef, useState } from 'react';
|
||||
import { Navigate, useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import useSettings from '@/hooks/useSettings';
|
||||
// components
|
||||
import axios from '../../../utils/axios';
|
||||
import { LaravelPaginatedData, LaravelPaginatedDataDefault } from '../../../@types/paginated-data';
|
||||
import DataTable from '../../../components/LaravelTable';
|
||||
import { fCurrency } from '../../../utils/formatNumber';
|
||||
import EditRoundedIcon from '@mui/icons-material/EditRounded';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { Divider } from '@mui/material';
|
||||
import Iconify from '@/components/Iconify';
|
||||
import DialogDetailClaim from '@/components/dialogs/DialogDetailClaim';
|
||||
import { fDateTimesecond } from '@/utils/formatTime';
|
||||
import { capitalizeFirstLetter } from '@/utils/formatString';
|
||||
import Label from '@/components/Label';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
import { Import } from '@/@types/claims';
|
||||
|
||||
import { FinalLogType } from '../../CustomerService/FinalLog/Model/Types';
|
||||
// import LoadingButton from '@/theme/overrides/LoadingButton';
|
||||
|
||||
export default function List() {
|
||||
const { themeColorPresets } = useSettings();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState<Import>(null);
|
||||
|
||||
const navigate = useNavigate()
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
||||
const handleSearchChange = (event: any) => {
|
||||
const newSearchText = event.target.value ?? '';
|
||||
setSearchText(newSearchText);
|
||||
};
|
||||
|
||||
const handleSearchSubmit = (event: any) => {
|
||||
event.preventDefault();
|
||||
props.onSearch({ search: searchText }); // Trigger to Parent
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// Trigger First Search
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '100%' }}>
|
||||
<TextField
|
||||
id="search-input"
|
||||
ref={searchInput}
|
||||
label="Search"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
onChange={handleSearchChange}
|
||||
value={searchText}
|
||||
placeholder='Search Code or Name...'
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
function ImportForm(props: any) {
|
||||
// IMPORT
|
||||
// Create Button Menu
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const createMenu = Boolean(anchorEl);
|
||||
const importForm = useRef<HTMLInputElement>(null);
|
||||
const [currentImportFileName, setCurrentImportFileName] = useState(null);
|
||||
const [importLoading, setImportLoading] = useState(false);
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleImportButton = () => {
|
||||
if (importForm?.current) {
|
||||
handleClose();
|
||||
importForm.current ? importForm.current.click() : console.log('No File selected');
|
||||
} else {
|
||||
alert('No file selected');
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancelImportButton = () => {
|
||||
importForm.current.value = '';
|
||||
importForm.current.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
};
|
||||
|
||||
const handleImportChange = (event: any) => {
|
||||
if (event.target.files[0]) {
|
||||
setCurrentImportFileName(event.target.files[0].name);
|
||||
} else {
|
||||
setCurrentImportFileName(null);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpload = () => {
|
||||
if (importForm.current?.files.length) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', importForm.current?.files[0]);
|
||||
|
||||
setImportLoading(true);
|
||||
axios
|
||||
.post(`claim-requests/import`, formData)
|
||||
.then((response) => {
|
||||
handleCancelImportButton();
|
||||
loadDataTableData();
|
||||
setImportResult(response.data);
|
||||
// alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows');
|
||||
setImportLoading(false);
|
||||
})
|
||||
.catch((response) => {
|
||||
enqueueSnackbar(
|
||||
'Looks like something went wrong. Please check your data and try again. ' +
|
||||
response.message,
|
||||
{ variant: 'error' }
|
||||
);
|
||||
setImportLoading(false);
|
||||
});
|
||||
} else {
|
||||
enqueueSnackbar('No File Selected', { variant: 'warning' });
|
||||
}
|
||||
};
|
||||
|
||||
const handleGetTemplate = (type :string) => {
|
||||
axios.get('corporates/import-document-example/' + type)
|
||||
.then((response) => {
|
||||
const link = document.createElement('a');
|
||||
link.href = response.data.data.file_url;
|
||||
link.setAttribute('download', response.data.data.file_name);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
handleClose();
|
||||
})
|
||||
}
|
||||
|
||||
const handleGetData = (type :string) => {
|
||||
axios.get(`corporates/${corporate_id}/data-plan-benefit`)
|
||||
.then((response) => {
|
||||
const link = document.createElement('a');
|
||||
link.href = response.data.data.file_url;
|
||||
link.setAttribute('download', response.data.data.file_name);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
handleClose();
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<input
|
||||
type="file"
|
||||
id="file"
|
||||
ref={importForm}
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleImportChange}
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain"
|
||||
/>
|
||||
{!currentImportFileName && (
|
||||
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter} />
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<UploadIcon />}
|
||||
sx={{ p: 1.8 }}
|
||||
onClick={handleClick}
|
||||
>
|
||||
Import
|
||||
</Button>
|
||||
<Menu
|
||||
id="import-button"
|
||||
anchorEl={anchorEl}
|
||||
open={createMenu}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
'aria-labelledby': 'basic-button',
|
||||
}}
|
||||
>
|
||||
<MenuItem onClick={handleImportButton}>Import</MenuItem>
|
||||
<MenuItem onClick={() => {handleGetTemplate('claim-request')}}>Download Template</MenuItem>
|
||||
<MenuItem onClick={() => {handleGetData('data-plan-benefit')}}>Download Claim Request</MenuItem>
|
||||
</Menu>
|
||||
{/* <Button
|
||||
variant="contained"
|
||||
startIcon={<AddIcon />}
|
||||
sx={{ p: 1.8 }}
|
||||
onClick={() => {
|
||||
navigate('/claim-requests/create');
|
||||
}}
|
||||
>
|
||||
Create
|
||||
</Button> */}
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{currentImportFileName && (
|
||||
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<ButtonGroup variant="outlined" aria-label="outlined button group" fullWidth>
|
||||
<Button onClick={handleImportButton} fullWidth>
|
||||
{currentImportFileName ?? 'No File Selected'}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleCancelImportButton}
|
||||
size="small"
|
||||
fullWidth={false}
|
||||
sx={{ p: 1.8 }}
|
||||
>
|
||||
<CancelIcon color="error" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<LoadingButton
|
||||
id="upload-button"
|
||||
variant="outlined"
|
||||
startIcon={<UploadIcon />}
|
||||
sx={{ p: 1.8 }}
|
||||
onClick={handleUpload}
|
||||
loading={importLoading}
|
||||
>
|
||||
Upload
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
)}
|
||||
{importResult && (
|
||||
<Stack direction={'row'} sx={{ px: 2, pb: 2 }}>
|
||||
<Box sx={{ color: 'text.secondary' }}>
|
||||
Last Import Result Report :{' '}
|
||||
<a href={importResult.result_file?.url ?? '#'}>
|
||||
{importResult.result_file?.name ?? '-'}
|
||||
</a>
|
||||
</Box>
|
||||
</Stack>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Dummy Default Data
|
||||
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>(
|
||||
LaravelPaginatedDataDefault
|
||||
);
|
||||
|
||||
const loadDataTableData = async (appliedFilter: any | null = null) => {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const response = await axios.get('/customer-service/request?final_log=1&service_code=IP', { params: filter });
|
||||
// console.log(response.data);
|
||||
setDataTableLoading(false);
|
||||
|
||||
setDataTableData(response.data);
|
||||
};
|
||||
|
||||
const applyFilter = async (searchFilter: { search: string }) => {
|
||||
await loadDataTableData(searchFilter);
|
||||
setSearchParams(searchFilter);
|
||||
};
|
||||
|
||||
const handlePageChange = (event: ChangeEvent, value: number): void => {
|
||||
const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]);
|
||||
loadDataTableData(filter);
|
||||
setSearchParams(filter);
|
||||
};
|
||||
|
||||
const handleApprove = (claimRequest) => {
|
||||
axios
|
||||
.post(`claim-requests/${claimRequest.id}/approve`)
|
||||
.then((response) => {
|
||||
enqueueSnackbar('Success Approve', { variant: 'success' });
|
||||
loadDataTableData();
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' });
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, []);
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
// Called on every row to map the data to the columns
|
||||
function createData(data: FinalLogType) {
|
||||
return {
|
||||
...data,
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
/* ------------------ TABLE ROW ------------------ */
|
||||
}
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [loadingApprove, setLoadingApprove] = React.useState(false);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
{/* <TableCell>
|
||||
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</TableCell> */ }
|
||||
{/* <TableCell align="left">
|
||||
<Typography
|
||||
// onClick={() => {
|
||||
// handleShowClaim(row);
|
||||
// }}
|
||||
>
|
||||
{row.id}
|
||||
</Typography>
|
||||
</TableCell> */}
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.member_name}</TableCell>
|
||||
<TableCell align="left"><Label>{fDateTimesecond(row.submission_date)}</Label></TableCell>
|
||||
<TableCell align="left">{row.service_name}</TableCell>
|
||||
<TableCell align="left">{row.payment_type_name}</TableCell>
|
||||
<TableCell align="left">
|
||||
{ row.status_final_log == "requested" ?
|
||||
(<Label variant='ghost' color='primary'>{capitalizeFirstLetter(row.status_final_log)}</Label>) :
|
||||
row.status_final_log == "declined" ?
|
||||
(<Label color='error'> {capitalizeFirstLetter(row.status_final_log)}</Label>)
|
||||
:
|
||||
(<Label color='success'> {capitalizeFirstLetter(row.status_final_log)}</Label>)
|
||||
}
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
{/* <MenuItem onClick={() => navigate(`/claim-requests/edit/${row.id}`)}>
|
||||
<EditOutlinedIcon />
|
||||
Edit
|
||||
</MenuItem> */}
|
||||
<MenuItem onClick={() => navigate ('/custormer-service/final-log/detail/'+row.id+'')}>
|
||||
<FindInPageOutlinedIcon />
|
||||
Detail
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</TableCell>
|
||||
{/* <TableCell>
|
||||
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
handleShowClaim(row);
|
||||
}}
|
||||
>
|
||||
<Iconify icon="eva:eye-fill" />
|
||||
</IconButton>
|
||||
</TableCell> */}
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={99}>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ borderBottom: 1 }}>
|
||||
<Stack
|
||||
divider={<Divider orientation="horizontal" flexItem />}
|
||||
spacing={1}
|
||||
sx={{ marginY: 2 }}
|
||||
>
|
||||
<Box>
|
||||
<Typography fontWeight={600}>Berkas Hasil Penunjang</Typography>
|
||||
{/* {row.files_by_type?.claim_kondisi &&
|
||||
row.files_by_type?.claim_kondisi.map((file, index) => (
|
||||
<Stack direction="row" key={index}>
|
||||
<Typography sx={{ marginRight: 2 }}>-</Typography>{' '}
|
||||
<a href={file.url} target="_blank">
|
||||
{file.name}
|
||||
</a>
|
||||
</Stack>
|
||||
))} */}
|
||||
|
||||
{row.files_by_type?.claim_kondisi && (
|
||||
<>
|
||||
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Kondisi</Typography>
|
||||
{row.files_by_type?.claim_kondisi.map((file, index) => (
|
||||
|
||||
<Stack direction="row" key={index}>
|
||||
<a href={file.url} target="_blank">
|
||||
{file.name}
|
||||
</a>
|
||||
</Stack>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
||||
{row.files_by_type?.claim_diagnosis && (
|
||||
<>
|
||||
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Diagnosa</Typography>
|
||||
{row.files_by_type?.claim_diagnosis.map((file, index) => (
|
||||
|
||||
<Stack direction="row" key={index}>
|
||||
<a href={file.url} target="_blank">
|
||||
{file.name}
|
||||
</a>
|
||||
</Stack>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
||||
{row.files_by_type?.claim_result && (
|
||||
<>
|
||||
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Hasil</Typography>
|
||||
{row.files_by_type?.claim_result.map((file, index) => (
|
||||
|
||||
<Stack direction="row" key={index}>
|
||||
<a href={file.url} target="_blank">
|
||||
{file.name}
|
||||
</a>
|
||||
</Stack>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{(!row.files_by_type?.claim_result && !row.files_by_type?.claim_diagnosis && !row.files_by_type?.claim_kondisi)&& <Typography>Tidak ada berkas</Typography>}
|
||||
</Box>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
{
|
||||
/* ------------------ END TABLE ROW ------------------ */
|
||||
}
|
||||
|
||||
function TableContent() {
|
||||
return (
|
||||
<Table aria-label="collapsible table">
|
||||
{/* ------------------ TABLE HEADER ------------------ */}
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{/* <TableCell style={headStyle} align="left" /> */}
|
||||
{/* <TableCell style={headStyle} align="left">
|
||||
ID Request LOG
|
||||
</TableCell> */}
|
||||
<TableCell style={headStyle} align="left">
|
||||
Code
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Name
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Date of Submission
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Service Type
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Claim Method
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Status
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="right"></TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
{/* ------------------ END TABLE HEADER ------------------ */}
|
||||
|
||||
{/* ------------------ TABLE ROW ------------------ */}
|
||||
{dataTableIsLoading ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">
|
||||
Loading
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : dataTableData.data.length === 0 ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">
|
||||
No Data
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody>
|
||||
{dataTableData.data.map((row) => (
|
||||
<Row key={row.id} row={row} />
|
||||
))}
|
||||
</TableBody>
|
||||
)}
|
||||
{/* ------------------ END TABLE ROW ------------------ */}
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Dialog Detail Claim Request
|
||||
const [openDialogDetailClaim, setOpenDialogDetailClaim] = useState(false);
|
||||
const [loadingClaimDetail, setLoadingClaimDetail] = useState(true);
|
||||
const [currentClaim, setCurrentClaim] = useState(null);
|
||||
|
||||
function handleShowClaim(claimRequest) {
|
||||
setLoadingClaimDetail(true);
|
||||
setOpenDialogDetailClaim(true);
|
||||
|
||||
axios
|
||||
.get(`/claim-requests/${claimRequest.id}`)
|
||||
.then(({ data }) => {
|
||||
setCurrentClaim(data.data);
|
||||
setLoadingClaimDetail(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
enqueueSnackbar(err.message, { variant: 'error' });
|
||||
});
|
||||
}
|
||||
|
||||
function handleDownloadLog() {}
|
||||
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid item sm={12}>
|
||||
<ImportForm />
|
||||
</Grid>
|
||||
|
||||
<Grid item sm={12}>
|
||||
<DataTable
|
||||
isLoading={dataTableIsLoading}
|
||||
lastRequest={0}
|
||||
data={dataTableData}
|
||||
handlePageChange={handlePageChange}
|
||||
TableContent={<TableContent />}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item sm={12}>
|
||||
<DialogDetailClaim
|
||||
openDialog={openDialogDetailClaim}
|
||||
setOpenDialog={setOpenDialogDetailClaim}
|
||||
title={{ name: 'Claim Request Detail' }}
|
||||
data={{ claim: currentClaim, isLoading: loadingClaimDetail, handleDownloadLog }}
|
||||
></DialogDetailClaim>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
@@ -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/laboratorium_result`)} >
|
||||
<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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Core
|
||||
* ============================================
|
||||
*/
|
||||
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>
|
||||
)
|
||||
}
|
||||
@@ -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_date == "0000-00-00 00:00:00" ?
|
||||
('-')
|
||||
:
|
||||
(
|
||||
<Label
|
||||
variant="ghost"
|
||||
color="default"
|
||||
>
|
||||
{fDate(props.row.admission_date)}
|
||||
</Label>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{props.row.discharge_date == "0000-00-00 00:00:00" ?
|
||||
('-')
|
||||
:
|
||||
(
|
||||
<Label
|
||||
variant="ghost"
|
||||
color="default"
|
||||
>
|
||||
{fDate(props.row.discharge_date)}
|
||||
</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/laboratorium_result/${props.row.member_id}/claims/${props.row.claim_code}/list_lab_result`)}>
|
||||
<Visibility />
|
||||
View
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate(`/case_management/laboratorium_result/${props.row.member_id}/claims/${props.row.claim_code}/add_lab_result`)}>
|
||||
<AddIcon />
|
||||
Laboratorium Result
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</Stack>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/**
|
||||
* Core
|
||||
* ============================================
|
||||
*/
|
||||
import { useRef } from 'react';
|
||||
import { useFieldArray, useForm } from 'react-hook-form';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { Box, IconButton, Typography, Grid, Card, Button, ButtonBase, Stack } from '@mui/material';
|
||||
import { LoadingButton } from "@mui/lab";
|
||||
|
||||
/**
|
||||
* Components
|
||||
* ============================================
|
||||
*/
|
||||
import Page from '@/components/Page';
|
||||
import { FormProvider, RHFDatepicker, RHFTextField } from '@/components/hook-form';
|
||||
import RHFDatePickerV2 from '@/components/hook-form/RHFDatePickerV2';
|
||||
|
||||
/**
|
||||
* Icon
|
||||
* ============================================
|
||||
*/
|
||||
import ArrowBackIosNew from '@mui/icons-material/ArrowBackIosNew';
|
||||
import Iconify from '@/components/Iconify';
|
||||
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
|
||||
|
||||
/**
|
||||
* Utils, Types, Functions
|
||||
* ============================================
|
||||
*/
|
||||
import { AddLabResultDetail } from '../Model/Functions';
|
||||
import { DetailLabResultListType} from '../Model/Types';
|
||||
|
||||
export default function DetailMonitoringList() {
|
||||
const { member_id, claim_code } = useParams();
|
||||
const navigate = useNavigate()
|
||||
const pageTitle = claim_code??'_ _ _ _';
|
||||
const fileInput = useRef<HTMLInputElement>(null);
|
||||
|
||||
// setup form
|
||||
// ====================================
|
||||
const defaultValues: DetailLabResultListType = {
|
||||
id : '',
|
||||
claim_id : '',
|
||||
claim_code : '',
|
||||
date : null,
|
||||
location : '',
|
||||
examination : '',
|
||||
lab_result_file : [],
|
||||
created_at : ''
|
||||
};
|
||||
|
||||
const methods = useForm<any>({
|
||||
defaultValues
|
||||
});
|
||||
|
||||
const { handleSubmit, reset, watch, setValue, formState: { isDirty, isSubmitting } } = methods;
|
||||
const formValues = watch();
|
||||
|
||||
// Handle File Input
|
||||
// =====================================
|
||||
const handleInputChange = (event: any) => {
|
||||
if (event.target.files[0]) {
|
||||
|
||||
let arr_lab_result_file = formValues.lab_result_file;
|
||||
arr_lab_result_file.push(event.target.files[0]);
|
||||
|
||||
setValue('lab_result_file', arr_lab_result_file)
|
||||
}
|
||||
else {
|
||||
console.log('NO FILE');
|
||||
}
|
||||
};
|
||||
|
||||
// Handle Remove File
|
||||
// =====================================
|
||||
const handleRemoveFile = (target_index: number) => {
|
||||
let arr_lab_result_file = formValues.lab_result_file.filter((file: any, index: number) =>{
|
||||
if (target_index !== index) {
|
||||
return file;
|
||||
}
|
||||
});
|
||||
|
||||
setValue('lab_result_file', arr_lab_result_file)
|
||||
};
|
||||
|
||||
// Submit Form
|
||||
// =====================================
|
||||
const submitHandler = async (data: DetailLabResultListType) => {
|
||||
const response = await AddLabResultDetail(claim_code??'', data);
|
||||
|
||||
if (response == true) {
|
||||
reset(defaultValues);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Page title={pageTitle}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', pl: '22px', mb: '40px' }}>
|
||||
<IconButton size='large' color='inherit' onClick={() => navigate(`/case_management/laboratorium_result/${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}>
|
||||
{/* Date */}
|
||||
<Grid item xs={6}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" component="div">
|
||||
Date* :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
|
||||
<RHFDatePickerV2
|
||||
label=''
|
||||
name="date"
|
||||
dateFormat='dd-MMMM-yyyy'
|
||||
fullWidth
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Location */}
|
||||
<Grid item xs={6}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" component="div">
|
||||
Location* :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
|
||||
<RHFTextField
|
||||
id="location"
|
||||
name='location'
|
||||
placeholder='Location'
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Examination */}
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" component="div">
|
||||
Examination* :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
|
||||
<RHFTextField
|
||||
id="examination"
|
||||
name='examination'
|
||||
placeholder='Examination'
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* list file & button upload */}
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
{
|
||||
formValues.lab_result_file.map((file: any, index: number) => (
|
||||
<Stack direction="row" justifyContent={'space-between'} key={index} sx={{ mb: '16px' }}>
|
||||
<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={() => handleRemoveFile(index)}
|
||||
sx={{cursor: 'pointer'}}
|
||||
></Iconify>
|
||||
</Stack>
|
||||
))
|
||||
}
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
|
||||
<ButtonBase sx={{ p: 4, 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',
|
||||
}}
|
||||
>
|
||||
<Iconify icon="icon-park-outline:upload-one" fontSize="3em" />
|
||||
<Typography variant="body1" fontWeight="bold">
|
||||
Upload Result
|
||||
</Typography>
|
||||
</Box>
|
||||
<input
|
||||
type="file"
|
||||
id="file"
|
||||
ref={fileInput}
|
||||
style={{ display: 'none' }}
|
||||
multiple
|
||||
onChange={handleInputChange}
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf"
|
||||
/>
|
||||
</ButtonBase>
|
||||
</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/laboratorium_result/${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>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* 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, Stack, Link } 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 InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
|
||||
|
||||
/**
|
||||
* Utils, Types, Functions
|
||||
* ============================================
|
||||
*/
|
||||
import { fDate } from "@/utils/formatTime";
|
||||
import { getLabResultDetailList } from '../Model/Functions';
|
||||
import { DetailLabResultListType } from '../Model/Types';
|
||||
|
||||
|
||||
export default function DetailLabResultList() {
|
||||
const { member_id, claim_code } = useParams();
|
||||
const navigate = useNavigate()
|
||||
const pageTitle = claim_code??'_ _ _ _';
|
||||
|
||||
// State
|
||||
// --------------------
|
||||
const [LabResultList, setLabResultList] = useState<DetailLabResultListType[]>();
|
||||
|
||||
// Use Effect
|
||||
// --------------------
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, [])
|
||||
|
||||
// Load Data
|
||||
// -------------------
|
||||
const loadDataTableData = async () => {
|
||||
const response = await getLabResultDetailList(claim_code??'');
|
||||
|
||||
setLabResultList(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/laboratorium_result/${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 }}>
|
||||
{
|
||||
LabResultList?.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={3}>
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={1}>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body2" color={"GrayText"}>
|
||||
Date
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body2">
|
||||
{row.date}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body2" color={"GrayText"}>
|
||||
Location
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body2">
|
||||
{row.location}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body2" color={"GrayText"}>
|
||||
Examination
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body2">
|
||||
{row.examination}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Grid container gap={1}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
|
||||
Document :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{
|
||||
row.lab_result_file.map((data, index) => {
|
||||
return (
|
||||
<Stack direction="row" justifyContent={'space-between'} key={index} sx={{ mt: '16px' }}>
|
||||
<Link href={data.lab_result_file_obj.path} underline='hover' target="_blank">
|
||||
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
|
||||
<InsertDriveFileIcon />
|
||||
<Typography variant="body2" gutterBottom>{data.lab_result_file_obj.original_name??'-'}</Typography>
|
||||
</Stack>
|
||||
</Link>
|
||||
</Stack>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
</Grid>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -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 { LaboratoriumResultListType } from "../Model/Types";
|
||||
import LaboratoriumListRow from "./LaboratoriumResultListRow";
|
||||
|
||||
export default function LaboratoriumResultList() {
|
||||
// State
|
||||
// --------------------
|
||||
const [dataTableIsLoading, setDataTableLoading] = useState<boolean>(true);
|
||||
const [dataTableData, setDataTableData] = useState<LaboratoriumResultListType[]>([]);
|
||||
|
||||
// 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: LaboratoriumResultListType, index) => (
|
||||
<LaboratoriumListRow key={index} number={index+1} row={row} />
|
||||
))}
|
||||
</TableBody>
|
||||
)
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
@@ -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 { LaboratoriumResultListType } from "../Model/Types";
|
||||
|
||||
type Props = {
|
||||
row: LaboratoriumResultListType,
|
||||
number: number
|
||||
}
|
||||
|
||||
export default function LaboratoriumResultListRow ({ ...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/laboratorium_result/${props.row.member_id}/claims`)}>
|
||||
<Visibility />
|
||||
View
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</Stack>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import axios from '@/utils/axios';
|
||||
import { makeFormData } from '@/utils/jsonToFormData';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { DetailLabResultListType, LaboratoriumResultListType, ResponseListingClaimType } from "./Types";
|
||||
import { fDate } from '@/utils/formatTime';
|
||||
|
||||
/**
|
||||
* Listing Daily Monitoring
|
||||
*/
|
||||
export const getDailyMonitoringList = async ( ): Promise<LaboratoriumResultListType[]> => {
|
||||
const response = await axios.get('/case_management/memberlist')
|
||||
.then((res) =>{
|
||||
return res.data.data.member_list;
|
||||
})
|
||||
.catch((res) => {
|
||||
enqueueSnackbar("server error !", {
|
||||
variant: 'error',
|
||||
});
|
||||
|
||||
return [];
|
||||
});
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
/**
|
||||
* Listing Claim
|
||||
*/
|
||||
export const getClaimList = async ( member_id: string ): Promise<ResponseListingClaimType> => {
|
||||
const response = await axios.get(`/case_management/claimlist/${member_id}`)
|
||||
.then((res) =>{
|
||||
return res.data.data;
|
||||
})
|
||||
.catch((res) => {
|
||||
enqueueSnackbar("server error !", {
|
||||
variant: 'error',
|
||||
});
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add Lab Result Detail
|
||||
*/
|
||||
export const AddLabResultDetail = async ( claim_code: string,data: DetailLabResultListType ): Promise<boolean> => {
|
||||
data.date = data.date != '' && data.date != null ? fDate(data.date) : '';
|
||||
|
||||
const formData = makeFormData({...data});
|
||||
|
||||
const response = await axios.post(`/case_management/laboratorium_result/detail/${claim_code}/add`, formData)
|
||||
.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("server error !", {
|
||||
variant: 'error',
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get Lab Result Detail List
|
||||
*/
|
||||
export const getLabResultDetailList = async ( claim_code: string ): Promise<DetailLabResultListType[]> => {
|
||||
const response = await axios.get(`/case_management/laboratorium_result/detail/${claim_code}/list`)
|
||||
.then((res) =>{
|
||||
return res.data.data.lab_result_list;
|
||||
})
|
||||
.catch((res) => {
|
||||
enqueueSnackbar("server error !", {
|
||||
variant: 'error',
|
||||
});
|
||||
|
||||
return [];
|
||||
});
|
||||
|
||||
return response;
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* List Laboratorium
|
||||
*/
|
||||
export type LaboratoriumResultListType = {
|
||||
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_date : string,
|
||||
discharge_date : string,
|
||||
claim_code : string,
|
||||
claim_status : string,
|
||||
service_type : string,
|
||||
member_id : string
|
||||
}
|
||||
|
||||
/**
|
||||
* Detail Lab Result List
|
||||
*/
|
||||
export type DetailLabResultListType = {
|
||||
id : string|null,
|
||||
claim_id : string|null,
|
||||
claim_code : string,
|
||||
date : string|null,
|
||||
location : string,
|
||||
examination : string,
|
||||
lab_result_file : LabResultFileStrType[],
|
||||
created_at : string|null
|
||||
}
|
||||
|
||||
export type LabResultFileStrType = {
|
||||
lab_result_file_obj: any
|
||||
}
|
||||
@@ -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 LaboratoriumResultList from './Components/LaboratoriumResultList';
|
||||
|
||||
export default function LaboratoriumResult() {
|
||||
const pageTitle = "Laboratorium Result";
|
||||
|
||||
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: pageTitle,
|
||||
href: '/case_management/laboratorium_result',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{/* tabel daily monitoring */}
|
||||
<Grid item xs={12}>
|
||||
<LaboratoriumResultList />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
/**
|
||||
* Core
|
||||
* ============================================
|
||||
*/
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { Box, FormControlLabel, Grid, Checkbox, Typography, CircularProgress , Button, styled, Stack, IconButton, Card} from '@mui/material';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
|
||||
/**
|
||||
* Components
|
||||
* ============================================
|
||||
*/
|
||||
// - Global -
|
||||
import Label from '@/components/Label';
|
||||
// - Local -
|
||||
import FormCreateSearch from './FormCreateSearch';
|
||||
import FormCreateListChoose from './FormCreateListChoose';
|
||||
import FormCreateBtnUpload from './FormCreateBtnUpload';
|
||||
|
||||
/**
|
||||
* Icon, Utils, Types, Functions, theme, hook
|
||||
* ============================================
|
||||
*/
|
||||
import { ArrowBackIosNew } from '@mui/icons-material';
|
||||
import { fDateTimesecond } from '@/utils/formatTime';
|
||||
import { MemberListType } from '../Model/Types';
|
||||
import { addClaimRequest, getMemberList } from '../Model/Functions';
|
||||
import palette from '@/theme/palette';
|
||||
import FormCreateFilesUpload from './FormCreateFilesUpload';
|
||||
import useLoadOnScroll from '@/hooks/useLoadOnScroll';
|
||||
import useCollapseDrawer from '@/hooks/useCollapseDrawer';
|
||||
import FormCreateBtnChoose from './FormCreateBtnChoose';
|
||||
import axios from '../../../utils/axios';
|
||||
|
||||
export default function FormCreate() {
|
||||
const navigate = useNavigate()
|
||||
const defaultListChoosed:MemberListType[] = [];
|
||||
|
||||
// State
|
||||
// -------------------------
|
||||
const [keyword, setKeyword] = useState<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>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { styled, Button } from "@mui/material";
|
||||
import useCollapseDrawer from "@/hooks/useCollapseDrawer";
|
||||
|
||||
/**
|
||||
* Custom Style
|
||||
* ============================================
|
||||
*/
|
||||
const DivCustom1 = styled('div')(({ theme }) => ({
|
||||
background: 'white',
|
||||
position: 'fixed',
|
||||
left: '350px',
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
paddingLeft: '32px',
|
||||
paddingRight: '32px',
|
||||
paddingTop: '32px',
|
||||
paddingBottom: '48px',
|
||||
[theme.breakpoints.between('sm', 'lg')]: {
|
||||
left: '0px',
|
||||
},
|
||||
}));
|
||||
|
||||
type Props = {
|
||||
disabled: boolean,
|
||||
title : string,
|
||||
handleClickProp: () => void
|
||||
}
|
||||
|
||||
export default function FormCreateBtnChoose ({disabled, title, handleClickProp}: Props) {
|
||||
const { collapseClick } = useCollapseDrawer();
|
||||
|
||||
return (
|
||||
<DivCustom1 sx={{ left: collapseClick ? '80px' : '350px' }}>
|
||||
<Button variant="contained" color="primary" disabled={disabled} sx={{ width: '100%', p: '11px' }} onClick={handleClickProp}>
|
||||
{title}
|
||||
</Button>
|
||||
</DivCustom1>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { useRef } from "react";
|
||||
import { Box, ButtonBase, Typography } from "@mui/material";
|
||||
import Iconify from "@/components/Iconify";
|
||||
|
||||
type Props = {
|
||||
handleChangeInputProp: (event: any) => void
|
||||
}
|
||||
|
||||
export default function FormCreateBtnUpload ({handleChangeInputProp}: Props) {
|
||||
const fileInput = useRef<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>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import Iconify from "@/components/Iconify";
|
||||
import { ArrowBackIosNew, InsertDriveFile } from '@mui/icons-material';
|
||||
import { Stack, Typography } from "@mui/material";
|
||||
|
||||
type Props = {
|
||||
file: any,
|
||||
handleRemoveFileProp: () => void,
|
||||
}
|
||||
|
||||
export default function FormCreateFilesUpload({ file, handleRemoveFileProp }: Props) {
|
||||
return (
|
||||
<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>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Core
|
||||
* ============================================
|
||||
*/
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Box, FormControlLabel, Grid, Checkbox, Typography, Card} from '@mui/material';
|
||||
|
||||
/**
|
||||
* Components
|
||||
* ============================================
|
||||
*/
|
||||
// - Global -
|
||||
import Label from '@/components/Label';
|
||||
// - Local -
|
||||
|
||||
/**
|
||||
* Icon, Utils, Types, Functions, theme, hook
|
||||
* ============================================
|
||||
*/
|
||||
import { fDateTimesecond } from '@/utils/formatTime';
|
||||
import { MemberListType } from '../Model/Types';
|
||||
import palette from '@/theme/palette';
|
||||
|
||||
/**
|
||||
* Props
|
||||
* =====================================================
|
||||
*/
|
||||
type Props = {
|
||||
data: MemberListType,
|
||||
ListChoosed: MemberListType[],
|
||||
handleCheckedProp: (checked: boolean, data: MemberListType) => void,
|
||||
};
|
||||
|
||||
export default function FormCreateListChoose({data, ListChoosed, handleCheckedProp}: Props) {
|
||||
const [isChoosed, setIsChoosed] = useState<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>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Core
|
||||
* ============================================
|
||||
*/
|
||||
import { useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { Grid } from '@mui/material';
|
||||
|
||||
/**
|
||||
* Components
|
||||
* ============================================
|
||||
*/
|
||||
// - Global -
|
||||
import { FormProvider, RHFTextField } from '@/components/hook-form';
|
||||
// - Local -
|
||||
|
||||
/**
|
||||
* Icon, Utils, Types, Functions
|
||||
* ============================================
|
||||
*/
|
||||
import { Search } from '@mui/icons-material';
|
||||
import { SearchType } from '../Model/Types';
|
||||
|
||||
type Props = {
|
||||
onSubmit: (keyword: string) => void,
|
||||
onEmpty: () => void,
|
||||
};
|
||||
|
||||
const FormCreateSearch = ({ onSubmit, onEmpty }: Props) => {
|
||||
const defaultValuesSearchForm = {
|
||||
keyword: ''
|
||||
};
|
||||
|
||||
const methodsSearchForm = useForm<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
|
||||
@@ -0,0 +1,456 @@
|
||||
import * as Yup from 'yup';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import React, { useRef, useEffect, useMemo, useState } from 'react';
|
||||
import axios from '../../../utils/axios';
|
||||
import { FormProvider, RHFTextField } from '../../../components/hook-form';
|
||||
|
||||
import { makeFormData } from '@/utils/jsonToFormData';
|
||||
import {
|
||||
Autocomplete,
|
||||
Button,
|
||||
Grid,
|
||||
Stack,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
useTheme,
|
||||
List,
|
||||
ListItem,
|
||||
IconButton,
|
||||
ListItemAvatar,
|
||||
Avatar,
|
||||
ListItemText,
|
||||
Card,
|
||||
InputAdornment,
|
||||
Divider,
|
||||
ButtonBase,
|
||||
Box,
|
||||
} from '@mui/material';
|
||||
import Iconify from '../../../components/Iconify';
|
||||
import CalendarTodayIcon from '@mui/icons-material/CalendarToday';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { fCurrency } from '../../../utils/formatNumber';
|
||||
import MemberSelectDialog from '../../../components/dialogs/MemberSelectDialog';
|
||||
import { Add, ArrowBackIosNew, DeleteOutline } from '@mui/icons-material';
|
||||
import { ClaimRequest, Files } from '@/@types/claims';
|
||||
import { fDateTimesecond } from '@/utils/formatTime';
|
||||
|
||||
interface FormValuesProps extends Partial<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>
|
||||
);
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
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, useNavigate } from 'react-router-dom';
|
||||
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';
|
||||
@@ -15,49 +17,46 @@ import { enqueueSnackbar } from 'notistack';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { fCurrency } from '../../utils/formatNumber';
|
||||
import Iconify from '../../components/Iconify';
|
||||
import Form from './Form';
|
||||
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 { themeStretch } = useSettings();
|
||||
const { id } = useParams();
|
||||
|
||||
const [currentClaim, setCurrentClaim] = useState();
|
||||
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]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit) {
|
||||
axios.get('/claims/' + id).then((res) => {
|
||||
// console.log('Yeet', res.data);
|
||||
setCurrentClaim(res.data);
|
||||
});
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
|
||||
return (
|
||||
<Page title={isEdit ? `Edit Claim : ${currentClaim?.id}` : "Create New Claim"}>
|
||||
<Page title={isEdit ? `Edit Claim Request` : "Create New Claim"}>
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<Stack direction="row" alignItems="center">
|
||||
<HeaderBreadcrumbs
|
||||
heading={
|
||||
!isEdit
|
||||
? 'Create New Claim'
|
||||
: `Edit Claim : ${currentClaim?.code}`
|
||||
}
|
||||
links={[
|
||||
{ name: 'Dashboard', href: '/dashboard' },
|
||||
{
|
||||
name: 'Claim',
|
||||
href: '/claims',
|
||||
},
|
||||
{ name: !isEdit ? 'Create' : currentClaim?.id ?? '' },
|
||||
]}
|
||||
/>
|
||||
</Stack>
|
||||
{
|
||||
id == undefined
|
||||
?
|
||||
(
|
||||
<FormCreate />
|
||||
)
|
||||
:
|
||||
(
|
||||
<FormEdit isEdit={isEdit} currentClaim={currentClaim} />
|
||||
)
|
||||
}
|
||||
|
||||
<Form isEdit={isEdit} currentClaim={currentClaim} />
|
||||
</Container>
|
||||
</Page>
|
||||
);
|
||||
|
||||
306
frontend/dashboard/src/pages/ClaimRequests/Detail.tsx
Normal file
306
frontend/dashboard/src/pages/ClaimRequests/Detail.tsx
Normal file
@@ -0,0 +1,306 @@
|
||||
// mui
|
||||
import { Container, Grid, Stack, Typography, Card, TextField, Divider, ButtonBase, Box, IconButton } from '@mui/material';
|
||||
// components
|
||||
import Page from '../../components/Page';
|
||||
// utils
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
// react
|
||||
import { useNavigate, useParams, useLocation } from 'react-router-dom';
|
||||
import { useEffect, useState, useRef } from 'react';
|
||||
import axios from '../../utils/axios';
|
||||
// pages
|
||||
import DetailTimeline from '../../pages/ClaimRequests/DetailTimeline';
|
||||
import DetailStepper from '../../pages/ClaimRequests/DetailStepper';
|
||||
import { format } from 'date-fns';
|
||||
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
|
||||
import Button from '@mui/material/Button';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import RemoveIcon from '@mui/icons-material/Remove';
|
||||
import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers';
|
||||
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
||||
import Iconify from '@/components/Iconify';
|
||||
import { fPostFormat } from '@/utils/formatTime';
|
||||
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
|
||||
import DownloadIcon from '@mui/icons-material/Download';
|
||||
import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import { fDateTimesecond } from '@/utils/formatTime';
|
||||
import { makeFormData } from '@/utils/jsonToFormData';
|
||||
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Detail() {
|
||||
const location = useLocation();
|
||||
const queryParams = new URLSearchParams(location.search);
|
||||
const code = queryParams.get('code');
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { themeStretch } = useSettings();
|
||||
const [data, setData] = useState();
|
||||
const [dataDialog, setDataDialog] = useState();
|
||||
const [document, setDocument] = useState(null);
|
||||
|
||||
const { id } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
axios
|
||||
.get('/claim-requests/detail/'+id)
|
||||
.then((response) => {
|
||||
setData(response.data);
|
||||
setDataDialog(response.data.data.dialog_submits);
|
||||
setDocument(response.data.data.documents);
|
||||
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
|
||||
}, []);
|
||||
|
||||
const [isInvoiceVisible, setInvoiceVisibility] = useState(false);
|
||||
|
||||
const handleInvoice = () => {
|
||||
setInvoiceVisibility(!isInvoiceVisible);
|
||||
}
|
||||
const currentDate = new Date();
|
||||
const formattedCurrentDate = format(currentDate, 'dd MMM yyyy');
|
||||
const [dateInvoice, setDateInvoice] = useState(currentDate);
|
||||
|
||||
const fileInvoiceInput = useRef<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>
|
||||
);
|
||||
}
|
||||
58
frontend/dashboard/src/pages/ClaimRequests/DetailStepper.tsx
Normal file
58
frontend/dashboard/src/pages/ClaimRequests/DetailStepper.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import * as React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Stepper from '@mui/material/Stepper';
|
||||
import Step from '@mui/material/Step';
|
||||
import StepLabel from '@mui/material/StepLabel';
|
||||
import { useEffect, useState } from 'react';
|
||||
import ClearIcon from '@mui/icons-material/Clear';
|
||||
|
||||
const steps = [
|
||||
'Request',
|
||||
'Review',
|
||||
'Approval',
|
||||
'Decline',
|
||||
];
|
||||
|
||||
export default function HorizontalLinearAlternativeLabelStepper({data}) {
|
||||
const [active, setActive] = useState(0);
|
||||
const [status, SetStatus] = useState(null);
|
||||
let updatedSteps = [...steps];
|
||||
useEffect(() => {
|
||||
if (data && data.data) {
|
||||
if (data.data.status.status === 'requested') {
|
||||
setActive(1);
|
||||
updatedSteps = updatedSteps.filter(step => step !== 'Decline');
|
||||
}
|
||||
else if (data.data.status.status === 'reviewed') {
|
||||
setActive(2);
|
||||
updatedSteps = updatedSteps.filter(step => step !== 'Decline');
|
||||
}
|
||||
else if (data.data.status.status === 'approved')
|
||||
{
|
||||
setActive(3);
|
||||
updatedSteps = updatedSteps.filter(step => step !== 'Decline');
|
||||
}
|
||||
else if(data.data.status.status === 'declined')
|
||||
{
|
||||
setActive(4)
|
||||
updatedSteps = updatedSteps.filter(step => step !== 'Approval');
|
||||
}
|
||||
}
|
||||
SetStatus(updatedSteps);
|
||||
}, [data]);
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
}
|
||||
426
frontend/dashboard/src/pages/ClaimRequests/DetailTimeline.tsx
Normal file
426
frontend/dashboard/src/pages/ClaimRequests/DetailTimeline.tsx
Normal file
@@ -0,0 +1,426 @@
|
||||
import * as React from 'react';
|
||||
import Timeline from '@mui/lab/Timeline';
|
||||
import TimelineItem, { timelineItemClasses } from '@mui/lab/TimelineItem';
|
||||
import TimelineSeparator from '@mui/lab/TimelineSeparator';
|
||||
import TimelineConnector from '@mui/lab/TimelineConnector';
|
||||
import TimelineContent from '@mui/lab/TimelineContent';
|
||||
import TimelineDot from '@mui/lab/TimelineDot';
|
||||
import {Typography, Card, Stack, ButtonBase, Box, Divider} from '@mui/material';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import Button from '@mui/material/Button';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import Iconify from '../../components/Iconify';
|
||||
import { useEffect, useState, useRef } from 'react';
|
||||
import { format } from 'date-fns';
|
||||
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
|
||||
import DescriptionIcon from '@mui/icons-material/Description';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import axios from '../../utils/axios';
|
||||
import { makeFormData } from '@/utils/jsonToFormData';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { useParams} from 'react-router-dom';
|
||||
|
||||
const Item1 = styled(Paper)(({ theme }) => ({
|
||||
...theme.typography.body2,
|
||||
padding: theme.spacing(1),
|
||||
textAlign: 'center',
|
||||
backgroundColor: '#919EAB29',
|
||||
color: '#637381',
|
||||
width: 'fit-content',
|
||||
marginRight: 'auto',
|
||||
}));
|
||||
|
||||
const Item2 = styled(Paper)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
|
||||
...theme.typography.body2,
|
||||
padding: theme.spacing(1),
|
||||
textAlign: 'center',
|
||||
color: theme.palette.text.secondary,
|
||||
width: 'fit-content',
|
||||
marginLeft: 'auto',
|
||||
}));
|
||||
|
||||
export default function NoOppositeContent({data}) {
|
||||
const [timeline, setTimeline] = useState(null);
|
||||
const [requestFile, setRequestFile] = useState(null);
|
||||
const [document, setDocument] = useState(null);
|
||||
useEffect(() => {
|
||||
if (data && data.data) {
|
||||
setTimeline(data.data.timeline);
|
||||
setRequestFile(data.data.request_files);
|
||||
setDocument(data.data.documents);
|
||||
}
|
||||
|
||||
}, [data]);
|
||||
|
||||
// Diagnosis
|
||||
const fileRequestDocumentInputDiagnosis = useRef<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>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,596 +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, { useEffect, useMemo, useState } from 'react';
|
||||
import axios from '../../utils/axios';
|
||||
import { FormProvider, RHFTextField } from '../../components/hook-form';
|
||||
import {
|
||||
Autocomplete,
|
||||
Button,
|
||||
Grid,
|
||||
Stack,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
useTheme,
|
||||
List,
|
||||
ListItem,
|
||||
IconButton,
|
||||
ListItemAvatar,
|
||||
Avatar,
|
||||
ListItemText,
|
||||
} from '@mui/material';
|
||||
import Iconify from '../../components/Iconify';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { fCurrency } from '../../utils/formatNumber';
|
||||
import MemberSelectDialog from '../../components/dialogs/MemberSelectDialog';
|
||||
import { Add, DeleteOutline } from '@mui/icons-material';
|
||||
|
||||
type Props = {
|
||||
isEdit: boolean;
|
||||
currentClaim?: any;
|
||||
};
|
||||
|
||||
export default function ClaimForm({ isEdit, currentClaim }: Props) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const NewCorporateSchema = Yup.object().shape({
|
||||
name: Yup.string().required('Name is required'),
|
||||
code: Yup.string().required('Corporate Code is required'),
|
||||
active: Yup.boolean().required('Corporate Status is required'),
|
||||
// file: Yup.boolean().required('Corporate Status is required'),
|
||||
});
|
||||
|
||||
const defaultValues = useMemo(
|
||||
() => ({
|
||||
member: currentClaim?.member || {},
|
||||
member_id: currentClaim?.member_id || null,
|
||||
diagnosis_id: currentClaim?.diagnosis_id || null,
|
||||
total_claim: currentClaim?.total_claim || 0,
|
||||
}),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[currentClaim]
|
||||
);
|
||||
|
||||
const methods = useForm<any>({
|
||||
resolver: yupResolver(NewCorporateSchema),
|
||||
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({})
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
console.log('defaultValues', defaultValues);
|
||||
if (isEdit && currentClaim) {
|
||||
reset(defaultValues);
|
||||
setMember(defaultValues.member)
|
||||
}
|
||||
if (!isEdit) {
|
||||
reset(defaultValues);
|
||||
setMember(defaultValues.member)
|
||||
}
|
||||
}, [isEdit, currentClaim]);
|
||||
|
||||
const fileSelected = (event, type) => {
|
||||
const files = event.target.files;
|
||||
const currentFiles = getValues(`uploaded_files.${type}`) ?? [];
|
||||
|
||||
setValue(`uploaded_files.${type}`, [...currentFiles, ...files]);
|
||||
|
||||
console.log('currentFiles', getValues('uploaded_files'));
|
||||
};
|
||||
|
||||
const memberSelected = (member) => {
|
||||
setMember(member)
|
||||
};
|
||||
|
||||
const checkLimit = async () => {
|
||||
console.log('CHECKING LIMIT');
|
||||
};
|
||||
|
||||
const onSubmit = async (data: any) => {
|
||||
try {
|
||||
if (!isEdit) {
|
||||
const response = await axios.post('/claims', data);
|
||||
} else {
|
||||
const response = await axios.put('/claims/' + currentClaim?.id ?? '', data);
|
||||
}
|
||||
reset();
|
||||
enqueueSnackbar(
|
||||
!isEdit ? 'Organizations Created Successfully!' : 'Organizations Udpated Successfully!',
|
||||
{ variant: 'success' }
|
||||
);
|
||||
navigate('/claims');
|
||||
} 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(value[0] ?? 'Failed Processing Request', { variant: 'error' });
|
||||
}
|
||||
} else {
|
||||
enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' });
|
||||
}
|
||||
}
|
||||
|
||||
const ascent = document?.querySelector('ascent');
|
||||
if (ascent != null) {
|
||||
ascent.innerHTML = '';
|
||||
}
|
||||
};
|
||||
|
||||
function generate(files, element: React.ReactElement) {
|
||||
return files.map((value) =>
|
||||
React.cloneElement(element, {
|
||||
key: value,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const headStyle = {};
|
||||
return (
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<Stack spacing={3}>
|
||||
<Typography variant="h6">Member</Typography>
|
||||
|
||||
<Stack spacing={2} direction="row">
|
||||
<Grid item xs={12}>
|
||||
<RHFTextField
|
||||
name="member_id"
|
||||
label="Member"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
value={member?.name || ''}
|
||||
InputProps={{
|
||||
readOnly: true,
|
||||
}}
|
||||
onClick={() => {
|
||||
if (!isEdit) setIsMemberDialogOpen(true);
|
||||
if (isEdit) enqueueSnackbar('Cannot Change Member', { variant: 'error' });
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
{/* <Grid item xs={2}>
|
||||
<Button variant="outlined" fullWidth sx={{ p: 1.8 }} onClick={() => {
|
||||
setIsMemberDialogOpen(true)
|
||||
}}>
|
||||
{member ? 'Change' : 'Search'}
|
||||
</Button>
|
||||
</Grid> */}
|
||||
</Stack>
|
||||
|
||||
{member?.id && (
|
||||
<Stack>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Table border="light-700">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Name
|
||||
</TableCell>
|
||||
<TableCell align="left">{member?.full_name}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
DOB
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{member?.birth_date} ({member?.age + ' years'})
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Marital Status
|
||||
</TableCell>
|
||||
<TableCell align="left">{member?.marital_status}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Record Type
|
||||
</TableCell>
|
||||
<TableCell align="left">{member?.record_type}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Principal ID
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{member?.principal_id} (
|
||||
{member?.relation_with_principal})
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Table border="light-700">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Plan
|
||||
</TableCell>
|
||||
<TableCell align="left">{member?.current_plan?.code}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Active
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{member?.current_plan?.start} -{' '}
|
||||
{member?.current_plan?.end} (Active)
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Corporate Limit
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{fCurrency(0)} / {fCurrency(member?.current_plan?.limit_rules)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Plan Usage
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{fCurrency(0)} / {fCurrency(member?.current_plan?.limit_rules)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
<Controller
|
||||
name="benefit"
|
||||
control={control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Autocomplete
|
||||
options={memberBenefits}
|
||||
getOptionLabel={(option) =>
|
||||
option ? `#${option.id} (${option.code}) ${option.description}` : ''
|
||||
}
|
||||
value={value || ''}
|
||||
onChange={(event: any, newValue: any) => {
|
||||
setValue('benefit_id', newValue?.id);
|
||||
onChange(newValue);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
name="benefit"
|
||||
{...params}
|
||||
label="Benefit"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
// onKeyPress={(event) => {
|
||||
// if (event.key === 'Enter')
|
||||
// searchDiagnosis(event.target.value)
|
||||
// }}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Controller
|
||||
name="diagnosis"
|
||||
control={control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Autocomplete
|
||||
options={diagnosisOption}
|
||||
getOptionLabel={(option) => (option ? `(${option.code}) ${option.name}` : '')}
|
||||
value={value || ''}
|
||||
onChange={(event: any, newValue: any) => {
|
||||
setValue('diagnosis_id', newValue?.id);
|
||||
// setValue('diagnosis', newValue)
|
||||
onChange(newValue);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
name="diagnosis"
|
||||
{...params}
|
||||
label="Diagnosis"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
onKeyPress={(event) => {
|
||||
if (event.key === 'Enter') searchDiagnosis(event.target.value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
{isCheckingLimit && (
|
||||
<Stack
|
||||
sx={{
|
||||
backgroundColor: 'gray',
|
||||
paddingY: 1,
|
||||
paddingX: 1.5,
|
||||
mb: 2,
|
||||
borderRadius: '3-xl',
|
||||
}}
|
||||
>
|
||||
{/* Checking */}
|
||||
<Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
|
||||
<Iconify
|
||||
icon="bxs:info-circle"
|
||||
width={12}
|
||||
height={13}
|
||||
sx={{ color: '#424242', marginRight: '6px' }}
|
||||
/>
|
||||
<Typography variant="caption" component="span">
|
||||
Please Wait, Checking Eligibilty
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
{false && isCheckingLimit == false && isEligible == null && (
|
||||
<Stack
|
||||
sx={{
|
||||
backgroundColor: 'gray',
|
||||
paddingY: 1,
|
||||
paddingX: 1.5,
|
||||
mb: 2,
|
||||
borderRadius: '3-xl',
|
||||
}}
|
||||
>
|
||||
{/* No Data Selected */}
|
||||
<Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
|
||||
<Iconify
|
||||
icon="bxs:info-circle"
|
||||
width={12}
|
||||
height={13}
|
||||
sx={{ color: '#424242', marginRight: '6px' }}
|
||||
/>
|
||||
<Typography variant="caption" component="span">
|
||||
Please Select Diagnosis !
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
{!isCheckingLimit && isEligible !== null && isEligible && (
|
||||
<Stack
|
||||
sx={{
|
||||
backgroundColor: '#B2E8E8',
|
||||
paddingY: 1,
|
||||
paddingX: 1.5,
|
||||
mb: 2,
|
||||
borderRadius: '3-xl',
|
||||
}}
|
||||
>
|
||||
{/* Eligible */}
|
||||
<Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
|
||||
<Iconify
|
||||
icon="bxs:lock-alt"
|
||||
width={12}
|
||||
height={13}
|
||||
sx={{ color: '#424242', marginRight: '6px' }}
|
||||
/>
|
||||
<Typography variant="caption" component="span">
|
||||
Diagnosis is Eligible
|
||||
</Typography>
|
||||
</Typography>
|
||||
<Typography sx={{ typography: 'caption', color: '#637381' }}>
|
||||
125.000.000 / 125.000.000
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
{!isCheckingLimit && isEligible !== null && !isEligible && (
|
||||
<Stack
|
||||
sx={{
|
||||
backgroundColor: '#B2E8E8',
|
||||
paddingY: 1,
|
||||
paddingX: 1.5,
|
||||
mb: 2,
|
||||
borderRadius: '3-xl',
|
||||
}}
|
||||
>
|
||||
{/* Not Eligible */}
|
||||
{/* <Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
|
||||
<Iconify
|
||||
icon="bxs:lock-alt"
|
||||
width={12}
|
||||
height={13}
|
||||
sx={{ color: '#424242', marginRight: '6px' }}
|
||||
/>
|
||||
<Typography variant="caption" component="span">
|
||||
Not Eligible
|
||||
</Typography>
|
||||
</Typography>
|
||||
<Typography sx={{ typography: 'caption', color: '#637381' }}>
|
||||
125.000.000 / 125.000.000
|
||||
</Typography> */}
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
<RHFTextField type="number" name="total_claim" label="Total Claim" />
|
||||
|
||||
{isEdit && (
|
||||
<React.Fragment>
|
||||
<Typography variant="h6">Documents</Typography>
|
||||
|
||||
<List>
|
||||
{(getValues('uploaded_files.invoice') && getValues('uploaded_files.invoice').length
|
||||
? getValues('uploaded_files.invoice')
|
||||
: []
|
||||
).map((file, index) => (
|
||||
<ListItem
|
||||
secondaryAction={
|
||||
<IconButton edge="end" aria-label="delete">
|
||||
<DeleteOutline />
|
||||
</IconButton>
|
||||
}
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
{/* <FileIcon /> */}
|
||||
I
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={file.name} secondary={file.type} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<Add />}
|
||||
component="label"
|
||||
sx={{ paddingY: 2, width: '100%', ':hover': { border: 'none' } }}
|
||||
>
|
||||
Invoice
|
||||
<input
|
||||
name="invoice"
|
||||
hidden
|
||||
accept="image/*,application/pdf"
|
||||
multiple
|
||||
type="file"
|
||||
onChange={(event) => {
|
||||
fileSelected(event, 'invoice');
|
||||
}}
|
||||
/>
|
||||
</Button>
|
||||
<List>
|
||||
{(getValues('uploaded_files.prescription') && getValues('uploaded_files.prescription').length
|
||||
? getValues('uploaded_files.prescription')
|
||||
: []
|
||||
).map((file, index) => (
|
||||
<ListItem
|
||||
secondaryAction={
|
||||
<IconButton edge="end" aria-label="delete">
|
||||
<DeleteOutline />
|
||||
</IconButton>
|
||||
}
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
{/* <FileIcon /> */}
|
||||
P
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={file.name} secondary={file.type} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<Add />}
|
||||
component="label"
|
||||
sx={{ paddingY: 2, width: '100%', ':hover': { border: 'none' } }}
|
||||
>
|
||||
Prescription
|
||||
<input
|
||||
name="prescription"
|
||||
hidden
|
||||
accept="image/*,application/pdf"
|
||||
multiple
|
||||
type="file"
|
||||
onChange={(event) => {
|
||||
fileSelected(event, 'prescription');
|
||||
}}
|
||||
/>
|
||||
</Button>
|
||||
|
||||
<List>
|
||||
{(getValues('uploaded_files.diagnosis') && getValues('uploaded_files.diagnosis').length
|
||||
? getValues('uploaded_files.diagnosis')
|
||||
: []
|
||||
).map((file, index) => (
|
||||
<ListItem
|
||||
secondaryAction={
|
||||
<IconButton edge="end" aria-label="delete">
|
||||
<DeleteOutline />
|
||||
</IconButton>
|
||||
}
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
{/* <FileIcon /> */}
|
||||
DR
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={file.name} secondary={file.type} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<Add />}
|
||||
component="label"
|
||||
sx={{ paddingY: 2, width: '100%', ':hover': { border: 'none' } }}
|
||||
>
|
||||
Doctor Result
|
||||
<input
|
||||
name="invoice"
|
||||
hidden
|
||||
accept="image/*,application/pdf"
|
||||
multiple
|
||||
type="file"
|
||||
onChange={(event) => {
|
||||
fileSelected(event, 'diagnosis');
|
||||
}}
|
||||
/>
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
{isEligible === true ? (
|
||||
<LoadingButton
|
||||
onClick={handleSubmit(onSubmit)}
|
||||
variant="contained"
|
||||
color="success"
|
||||
style={{ color: '#ffffff' }}
|
||||
size="large"
|
||||
fullWidth={true}
|
||||
loading={isCheckingLimit}
|
||||
>
|
||||
Create Claim
|
||||
</LoadingButton>
|
||||
) : (
|
||||
<LoadingButton
|
||||
onClick={checkLimit}
|
||||
variant="outlined"
|
||||
size="large"
|
||||
fullWidth={true}
|
||||
loading={isCheckingLimit}
|
||||
>
|
||||
Check Limit
|
||||
</LoadingButton>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
<MemberSelectDialog
|
||||
openDialog={isMemberDialogOpen}
|
||||
setOpenDialog={setIsMemberDialogOpen}
|
||||
onSelect={memberSelected}
|
||||
></MemberSelectDialog>
|
||||
</FormProvider>
|
||||
);
|
||||
}
|
||||
@@ -17,12 +17,17 @@ import {
|
||||
ButtonGroup,
|
||||
Link,
|
||||
Chip,
|
||||
TableHead,
|
||||
Grid,
|
||||
} from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
|
||||
import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined';
|
||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||
// hooks
|
||||
import React, { ChangeEvent, useEffect, useRef, useState } from 'react';
|
||||
import { Navigate, useNavigate, useSearchParams } from 'react-router-dom';
|
||||
@@ -38,12 +43,19 @@ import { enqueueSnackbar } from 'notistack';
|
||||
import { Divider } from '@mui/material';
|
||||
import Iconify from '@/components/Iconify';
|
||||
import DialogDetailClaim from '@/components/dialogs/DialogDetailClaim';
|
||||
import { fDateTimesecond } from '@/utils/formatTime';
|
||||
import { capitalizeFirstLetter } from '@/utils/formatString';
|
||||
import Label from '@/components/Label';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
import { Import } from '@/@types/claims';
|
||||
// import LoadingButton from '@/theme/overrides/LoadingButton';
|
||||
|
||||
export default function List() {
|
||||
const { themeColorPresets } = useSettings();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
const [importResult, setImportResult] = useState<Import>(null);
|
||||
|
||||
const navigate = useNavigate()
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
@@ -75,6 +87,7 @@ export default function List() {
|
||||
fullWidth
|
||||
onChange={handleSearchChange}
|
||||
value={searchText}
|
||||
placeholder='Search Code or Name...'
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
@@ -87,26 +100,174 @@ export default function List() {
|
||||
const createMenu = Boolean(anchorEl);
|
||||
const importForm = useRef<HTMLInputElement>(null);
|
||||
const [currentImportFileName, setCurrentImportFileName] = useState(null);
|
||||
const [importLoading, setImportLoading] = useState(false);
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleImportButton = () => {
|
||||
if (importForm?.current) {
|
||||
handleClose();
|
||||
importForm.current ? importForm.current.click() : console.log('No File selected');
|
||||
} else {
|
||||
alert('No file selected');
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancelImportButton = () => {
|
||||
importForm.current.value = '';
|
||||
importForm.current.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
};
|
||||
|
||||
const handleImportChange = (event: any) => {
|
||||
if (event.target.files[0]) {
|
||||
setCurrentImportFileName(event.target.files[0].name);
|
||||
} else {
|
||||
setCurrentImportFileName(null);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpload = () => {
|
||||
if (importForm.current?.files.length) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', importForm.current?.files[0]);
|
||||
|
||||
setImportLoading(true);
|
||||
axios
|
||||
.post(`claim-requests/import`, formData)
|
||||
.then((response) => {
|
||||
handleCancelImportButton();
|
||||
loadDataTableData();
|
||||
setImportResult(response.data);
|
||||
// alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows');
|
||||
setImportLoading(false);
|
||||
})
|
||||
.catch((response) => {
|
||||
enqueueSnackbar(
|
||||
'Looks like something went wrong. Please check your data and try again. ' +
|
||||
response.message,
|
||||
{ variant: 'error' }
|
||||
);
|
||||
setImportLoading(false);
|
||||
});
|
||||
} else {
|
||||
enqueueSnackbar('No File Selected', { variant: 'warning' });
|
||||
}
|
||||
};
|
||||
|
||||
const handleGetTemplate = (type :string) => {
|
||||
axios.get('corporates/import-document-example/' + type)
|
||||
.then((response) => {
|
||||
const link = document.createElement('a');
|
||||
link.href = response.data.data.file_url;
|
||||
link.setAttribute('download', response.data.data.file_name);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
handleClose();
|
||||
})
|
||||
}
|
||||
|
||||
const handleGetData = (type :string) => {
|
||||
axios.get(`corporates/${corporate_id}/data-plan-benefit`)
|
||||
.then((response) => {
|
||||
const link = document.createElement('a');
|
||||
link.href = response.data.data.file_url;
|
||||
link.setAttribute('download', response.data.data.file_name);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
handleClose();
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter} />
|
||||
{/* <Button
|
||||
variant="outlined"
|
||||
startIcon={<AddIcon />}
|
||||
sx={{ p: 1.8 }}
|
||||
onClick={() => {
|
||||
navigate('/claims/create');
|
||||
}}
|
||||
>
|
||||
Create
|
||||
</Button> */}
|
||||
</Stack>
|
||||
<input
|
||||
type="file"
|
||||
id="file"
|
||||
ref={importForm}
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleImportChange}
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain"
|
||||
/>
|
||||
{!currentImportFileName && (
|
||||
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter} />
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<UploadIcon />}
|
||||
sx={{ p: 1.8 }}
|
||||
onClick={handleClick}
|
||||
>
|
||||
Import
|
||||
</Button>
|
||||
<Menu
|
||||
id="import-button"
|
||||
anchorEl={anchorEl}
|
||||
open={createMenu}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
'aria-labelledby': 'basic-button',
|
||||
}}
|
||||
>
|
||||
<MenuItem onClick={handleImportButton}>Import</MenuItem>
|
||||
<MenuItem onClick={() => {handleGetTemplate('claim-request')}}>Download Template</MenuItem>
|
||||
<MenuItem onClick={() => {handleGetData('data-plan-benefit')}}>Download Claim Request</MenuItem>
|
||||
</Menu>
|
||||
<Button
|
||||
variant="contained"
|
||||
startIcon={<AddIcon />}
|
||||
sx={{ p: 1.8 }}
|
||||
onClick={() => {
|
||||
navigate('/claim-requests/create');
|
||||
}}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{currentImportFileName && (
|
||||
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<ButtonGroup variant="outlined" aria-label="outlined button group" fullWidth>
|
||||
<Button onClick={handleImportButton} fullWidth>
|
||||
{currentImportFileName ?? 'No File Selected'}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleCancelImportButton}
|
||||
size="small"
|
||||
fullWidth={false}
|
||||
sx={{ p: 1.8 }}
|
||||
>
|
||||
<CancelIcon color="error" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<LoadingButton
|
||||
id="upload-button"
|
||||
variant="outlined"
|
||||
startIcon={<UploadIcon />}
|
||||
sx={{ p: 1.8 }}
|
||||
onClick={handleUpload}
|
||||
loading={importLoading}
|
||||
>
|
||||
Upload
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
)}
|
||||
{importResult && (
|
||||
<Stack direction={'row'} sx={{ px: 2, pb: 2 }}>
|
||||
<Box sx={{ color: 'text.secondary' }}>
|
||||
Last Import Result Report :{' '}
|
||||
<a href={importResult.result_file?.url ?? '#'}>
|
||||
{importResult.result_file?.name ?? '-'}
|
||||
</a>
|
||||
</Box>
|
||||
</Stack>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -176,45 +337,46 @@ export default function List() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell>
|
||||
{/* <TableCell>
|
||||
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
</TableCell> */ }
|
||||
<TableCell align="left">
|
||||
<Typography
|
||||
onClick={() => {
|
||||
handleShowClaim(row);
|
||||
}}
|
||||
color={themeColorPresets}
|
||||
// onClick={() => {
|
||||
// handleShowClaim(row);
|
||||
// }}
|
||||
>
|
||||
{row.code}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.member?.full_name}</TableCell>
|
||||
<TableCell align="left">{row.member?.full_name}</TableCell>
|
||||
<TableCell align="left">{row.submission_date}</TableCell>
|
||||
<TableCell align="left"><Label>{fDateTimesecond(row.submission_date)}</Label></TableCell>
|
||||
<TableCell align="left">{row.service_name}</TableCell>
|
||||
<TableCell align="left">{row.payment_type_name}</TableCell>
|
||||
<TableCell align="right">
|
||||
<Chip label={row.status} />
|
||||
<TableCell align="left">
|
||||
{ row.status == "requested" ?
|
||||
(<Label variant='ghost' color='primary'>{capitalizeFirstLetter(row.status)}</Label>) :
|
||||
(<Label color='success'> {capitalizeFirstLetter(row.status)}</Label>)
|
||||
}
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
{row.status == 'requested' && (
|
||||
<LoadingButton
|
||||
loading={loadingApprove}
|
||||
variant="outlined"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
handleApprove(row);
|
||||
}}
|
||||
>
|
||||
Ajukan Claim <Iconify icon="eva:arrow-forward-outline"></Iconify>
|
||||
</LoadingButton>
|
||||
)}
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => navigate(`/claim-requests/edit/${row.id}`)}>
|
||||
<EditOutlinedIcon />
|
||||
Edit
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate ('/claim-requests/detail/'+row.id+'')}>
|
||||
<FindInPageOutlinedIcon />
|
||||
Detail
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</TableCell>
|
||||
{/* <TableCell>
|
||||
|
||||
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
handleShowClaim(row);
|
||||
@@ -236,17 +398,58 @@ export default function List() {
|
||||
>
|
||||
<Box>
|
||||
<Typography fontWeight={600}>Berkas Hasil Penunjang</Typography>
|
||||
{row.files_by_type?.result &&
|
||||
row.files_by_type?.result.map((file, index) => (
|
||||
{/* {row.files_by_type?.claim_kondisi &&
|
||||
row.files_by_type?.claim_kondisi.map((file, index) => (
|
||||
<Stack direction="row" key={index}>
|
||||
<Typography sx={{ marginRight: 2 }}>-</Typography>{' '}
|
||||
<a href={file.url} target="_blank">
|
||||
{file.name}
|
||||
</a>
|
||||
</Stack>
|
||||
))}
|
||||
))} */}
|
||||
|
||||
{!row.files_by_type?.result && <Typography>Tidak ada berkas</Typography>}
|
||||
{row.files_by_type?.claim_kondisi && (
|
||||
<>
|
||||
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Kondisi</Typography>
|
||||
{row.files_by_type?.claim_kondisi.map((file, index) => (
|
||||
|
||||
<Stack direction="row" key={index}>
|
||||
<a href={file.url} target="_blank">
|
||||
{file.name}
|
||||
</a>
|
||||
</Stack>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
||||
{row.files_by_type?.claim_diagnosis && (
|
||||
<>
|
||||
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Diagnosa</Typography>
|
||||
{row.files_by_type?.claim_diagnosis.map((file, index) => (
|
||||
|
||||
<Stack direction="row" key={index}>
|
||||
<a href={file.url} target="_blank">
|
||||
{file.name}
|
||||
</a>
|
||||
</Stack>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
||||
{row.files_by_type?.claim_result && (
|
||||
<>
|
||||
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Hasil</Typography>
|
||||
{row.files_by_type?.claim_result.map((file, index) => (
|
||||
|
||||
<Stack direction="row" key={index}>
|
||||
<a href={file.url} target="_blank">
|
||||
{file.name}
|
||||
</a>
|
||||
</Stack>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{(!row.files_by_type?.claim_result && !row.files_by_type?.claim_diagnosis && !row.files_by_type?.claim_kondisi)&& <Typography>Tidak ada berkas</Typography>}
|
||||
</Box>
|
||||
</Stack>
|
||||
</Box>
|
||||
@@ -264,9 +467,9 @@ export default function List() {
|
||||
return (
|
||||
<Table aria-label="collapsible table">
|
||||
{/* ------------------ TABLE HEADER ------------------ */}
|
||||
<TableBody>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" />
|
||||
{/* <TableCell style={headStyle} align="left" /> */}
|
||||
<TableCell style={headStyle} align="left">
|
||||
Code
|
||||
</TableCell>
|
||||
@@ -274,23 +477,20 @@ export default function List() {
|
||||
Name
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Nomor Polis
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Tanggal Pengajuan
|
||||
Date of Submission
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Service Type
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Claim Type
|
||||
Claim Method
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Status
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="right"></TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</TableHead>
|
||||
{/* ------------------ END TABLE HEADER ------------------ */}
|
||||
|
||||
{/* ------------------ TABLE ROW ------------------ */}
|
||||
@@ -346,23 +546,28 @@ export default function List() {
|
||||
function handleDownloadLog() {}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<ImportForm />
|
||||
<Grid container>
|
||||
<Grid item sm={12}>
|
||||
<ImportForm />
|
||||
</Grid>
|
||||
|
||||
<DataTable
|
||||
isLoading={dataTableIsLoading}
|
||||
lastRequest={0}
|
||||
data={dataTableData}
|
||||
handlePageChange={handlePageChange}
|
||||
TableContent={<TableContent />}
|
||||
/>
|
||||
|
||||
<DialogDetailClaim
|
||||
openDialog={openDialogDetailClaim}
|
||||
setOpenDialog={setOpenDialogDetailClaim}
|
||||
title={{ name: 'Claim Request Detail' }}
|
||||
data={{ claim: currentClaim, isLoading: loadingClaimDetail, handleDownloadLog }}
|
||||
></DialogDetailClaim>
|
||||
</Card>
|
||||
<Grid item sm={12}>
|
||||
<DataTable
|
||||
isLoading={dataTableIsLoading}
|
||||
lastRequest={0}
|
||||
data={dataTableData}
|
||||
handlePageChange={handlePageChange}
|
||||
TableContent={<TableContent />}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item sm={12}>
|
||||
<DialogDetailClaim
|
||||
openDialog={openDialogDetailClaim}
|
||||
setOpenDialog={setOpenDialogDetailClaim}
|
||||
title={{ name: 'Claim Request Detail' }}
|
||||
data={{ claim: currentClaim, isLoading: loadingClaimDetail, handleDownloadLog }}
|
||||
></DialogDetailClaim>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import axios from '@/utils/axios';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { MemberListType } from './Types';
|
||||
import { makeFormData } from '@/utils/jsonToFormData';
|
||||
|
||||
/**
|
||||
* Listing Member
|
||||
*/
|
||||
export const getMemberList = async ( page: number, keyword: string ): Promise<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;
|
||||
};
|
||||
25
frontend/dashboard/src/pages/ClaimRequests/Model/Types.tsx
Normal file
25
frontend/dashboard/src/pages/ClaimRequests/Model/Types.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Search Type
|
||||
*/
|
||||
export type SearchType = {
|
||||
keyword: string,
|
||||
}
|
||||
|
||||
/**
|
||||
* Member List
|
||||
*/
|
||||
export type MemberListType = {
|
||||
id : string,
|
||||
member_id : string,
|
||||
name : string,
|
||||
service_type : ServiceType[],
|
||||
patien_type? : string,
|
||||
file_kondisi? : any[],
|
||||
file_diagnosa? : any[],
|
||||
file_penunjang? : any[],
|
||||
}
|
||||
|
||||
export type ServiceType = {
|
||||
code : string
|
||||
name : string
|
||||
}
|
||||
@@ -28,31 +28,26 @@ export default function ClaimsCreateUpdate() {
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit) {
|
||||
axios.get('/claims/' + id).then((res) => {
|
||||
// console.log('Yeet', res.data);
|
||||
setCurrentClaim(res.data);
|
||||
});
|
||||
axios.get(`/claims/${id}/edit`).then((res) => {
|
||||
console.log('Yeet', res.data.data);
|
||||
setCurrentClaim(res.data.data);
|
||||
});;
|
||||
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
|
||||
return (
|
||||
<Page title={isEdit ? `Edit Claim : ${currentClaim?.id}` : "Create New Claim"}>
|
||||
<Page title={'Edit Claim Management'}>
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<Stack direction="row" alignItems="center">
|
||||
<HeaderBreadcrumbs
|
||||
heading={
|
||||
!isEdit
|
||||
? 'Create New Claim'
|
||||
: `Edit Claim : ${currentClaim?.code}`
|
||||
}
|
||||
heading={`Edit Claim Management`}
|
||||
links={[
|
||||
{ name: 'Dashboard', href: '/dashboard' },
|
||||
{
|
||||
name: 'Claim',
|
||||
href: '/claims',
|
||||
name: 'Claim Management',
|
||||
},
|
||||
{ name: !isEdit ? 'Create' : currentClaim?.id ?? '' },
|
||||
]}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
1569
frontend/dashboard/src/pages/Claims/Detail.tsx
Normal file
1569
frontend/dashboard/src/pages/Claims/Detail.tsx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -24,16 +24,18 @@ import {
|
||||
ListItemAvatar,
|
||||
Avatar,
|
||||
ListItemText,
|
||||
Card,
|
||||
} from '@mui/material';
|
||||
import Iconify from '../../components/Iconify';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { fCurrency } from '../../utils/formatNumber';
|
||||
import MemberSelectDialog from '../../components/dialogs/MemberSelectDialog';
|
||||
import { Add, DeleteOutline } from '@mui/icons-material';
|
||||
import { ClaimsEdit } from '@/@types/claims';
|
||||
|
||||
type Props = {
|
||||
isEdit: boolean;
|
||||
currentClaim?: any;
|
||||
currentClaim?: ClaimsEdit;
|
||||
};
|
||||
|
||||
export default function ClaimForm({ isEdit, currentClaim }: Props) {
|
||||
@@ -42,18 +44,27 @@ export default function ClaimForm({ isEdit, currentClaim }: Props) {
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const NewCorporateSchema = Yup.object().shape({
|
||||
name: Yup.string().required('Name is required'),
|
||||
code: Yup.string().required('Corporate Code is required'),
|
||||
active: Yup.boolean().required('Corporate Status is required'),
|
||||
benefit_desc: Yup.string().required('Benefit Desc is required'),
|
||||
amount_incurred: Yup.string().required('Amount Incurred is required'),
|
||||
amount_approved: Yup.number().required('Amount Approved is required'),
|
||||
amount_not_approved: Yup.number().required('Amount Not Approved is required'),
|
||||
excess_paid: Yup.number().required('Excess Paid is required'),
|
||||
// file: Yup.boolean().required('Corporate Status is required'),
|
||||
});
|
||||
|
||||
const defaultValues = useMemo(
|
||||
() => ({
|
||||
member: currentClaim?.member || {},
|
||||
plan_id: currentClaim?.plan_id || null,
|
||||
payor_id: currentClaim?.payor_id || null,
|
||||
corporate_id: currentClaim?.corporate_id || null,
|
||||
policy_number: currentClaim?.policy_number || null,
|
||||
member_id: currentClaim?.member_id || null,
|
||||
diagnosis_id: currentClaim?.diagnosis_id || null,
|
||||
total_claim: currentClaim?.total_claim || 0,
|
||||
benefit_code: currentClaim?.benefit_code || '-',
|
||||
benefit_desc: currentClaim?.benefit_desc || '-',
|
||||
amount_incurred: currentClaim?.amount_incurred || 0,
|
||||
amount_approved: currentClaim?.amount_approved || 0,
|
||||
amount_not_approved: currentClaim?.amount_not_approved || 0,
|
||||
excess_paid: currentClaim?.excess_paid || 0,
|
||||
}),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[currentClaim]
|
||||
@@ -88,11 +99,11 @@ export default function ClaimForm({ isEdit, currentClaim }: Props) {
|
||||
console.log('defaultValues', defaultValues);
|
||||
if (isEdit && currentClaim) {
|
||||
reset(defaultValues);
|
||||
setMember(defaultValues.member)
|
||||
// setMember(defaultValues.member)
|
||||
}
|
||||
if (!isEdit) {
|
||||
reset(defaultValues);
|
||||
setMember(defaultValues.member)
|
||||
// setMember(defaultValues.member)
|
||||
}
|
||||
}, [isEdit, currentClaim]);
|
||||
|
||||
@@ -105,13 +116,13 @@ export default function ClaimForm({ isEdit, currentClaim }: Props) {
|
||||
console.log('currentFiles', getValues('uploaded_files'));
|
||||
};
|
||||
|
||||
const memberSelected = (member) => {
|
||||
setMember(member)
|
||||
};
|
||||
// const memberSelected = (member) => {
|
||||
// setMember(member)
|
||||
// };
|
||||
|
||||
const checkLimit = async () => {
|
||||
console.log('CHECKING LIMIT');
|
||||
};
|
||||
// const checkLimit = async () => {
|
||||
// console.log('CHECKING LIMIT');
|
||||
// };
|
||||
|
||||
const onSubmit = async (data: any) => {
|
||||
try {
|
||||
@@ -122,7 +133,7 @@ export default function ClaimForm({ isEdit, currentClaim }: Props) {
|
||||
}
|
||||
reset();
|
||||
enqueueSnackbar(
|
||||
!isEdit ? 'Organizations Created Successfully!' : 'Organizations Udpated Successfully!',
|
||||
!isEdit ? 'Organizations Created Successfully!' : 'Claim Udpated Successfully!',
|
||||
{ variant: 'success' }
|
||||
);
|
||||
navigate('/claims');
|
||||
@@ -154,443 +165,86 @@ export default function ClaimForm({ isEdit, currentClaim }: Props) {
|
||||
const headStyle = {};
|
||||
return (
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<Stack spacing={3}>
|
||||
<Typography variant="h6">Member</Typography>
|
||||
|
||||
<Stack spacing={2} direction="row">
|
||||
<Grid item xs={12}>
|
||||
<RHFTextField
|
||||
name="member_id"
|
||||
label="Member"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
value={member?.name || ''}
|
||||
InputProps={{
|
||||
readOnly: true,
|
||||
}}
|
||||
onClick={() => {
|
||||
if (!isEdit) setIsMemberDialogOpen(true);
|
||||
if (isEdit) enqueueSnackbar('Cannot Change Member', { variant: 'error' });
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
{/* <Grid item xs={2}>
|
||||
<Button variant="outlined" fullWidth sx={{ p: 1.8 }} onClick={() => {
|
||||
setIsMemberDialogOpen(true)
|
||||
}}>
|
||||
{member ? 'Change' : 'Search'}
|
||||
</Button>
|
||||
</Grid> */}
|
||||
</Stack>
|
||||
|
||||
{member?.id && (
|
||||
<Stack>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Table border="light-700">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Name
|
||||
</TableCell>
|
||||
<TableCell align="left">{member?.full_name}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
DOB
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{member?.birth_date} ({member?.age + ' years'})
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Marital Status
|
||||
</TableCell>
|
||||
<TableCell align="left">{member?.marital_status}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Record Type
|
||||
</TableCell>
|
||||
<TableCell align="left">{member?.record_type}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Principal ID
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{member?.principal_id} (
|
||||
{member?.relation_with_principal})
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Table border="light-700">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Plan
|
||||
</TableCell>
|
||||
<TableCell align="left">{member?.current_plan?.code}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Active
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{member?.current_plan?.start} -{' '}
|
||||
{member?.current_plan?.end} (Active)
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Corporate Limit
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{fCurrency(0)} / {fCurrency(member?.current_plan?.limit_rules)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Plan Usage
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{fCurrency(0)} / {fCurrency(member?.current_plan?.limit_rules)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Grid>
|
||||
<Card sx={{paddingX:2, paddingY:3}}>
|
||||
<Grid container spacing={2}>
|
||||
{/* Baris ke 1 */}
|
||||
<Grid item xs={3}>
|
||||
<Typography marginBottom={2} variant="subtitle1">Plan ID*</Typography>
|
||||
<RHFTextField name="plan_id" disabled />
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography marginBottom={2} variant="subtitle1">Payor ID*</Typography>
|
||||
<RHFTextField name="payor_id" disabled />
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography marginBottom={2} variant="subtitle1">Corporate ID*</Typography>
|
||||
<RHFTextField name="corporate_id"disabled />
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography marginBottom={2} variant="subtitle1">Policy Number*</Typography>
|
||||
<RHFTextField name="policy_number" disabled />
|
||||
</Grid>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
<Controller
|
||||
name="benefit"
|
||||
control={control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Autocomplete
|
||||
options={memberBenefits}
|
||||
getOptionLabel={(option) =>
|
||||
option ? `#${option.id} (${option.code}) ${option.description}` : ''
|
||||
}
|
||||
value={value || ''}
|
||||
onChange={(event: any, newValue: any) => {
|
||||
setValue('benefit_id', newValue?.id);
|
||||
onChange(newValue);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
name="benefit"
|
||||
{...params}
|
||||
label="Benefit"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
// onKeyPress={(event) => {
|
||||
// if (event.key === 'Enter')
|
||||
// searchDiagnosis(event.target.value)
|
||||
// }}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{/* Baris ke 2 */}
|
||||
<Grid item xs={3}>
|
||||
<Typography marginBottom={2} variant="subtitle1">Memeber ID*</Typography>
|
||||
<RHFTextField name="member_id" disabled />
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography marginBottom={2} variant="subtitle1">Benefit Code*</Typography>
|
||||
<RHFTextField name="benefit_code" disabled />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography marginBottom={2} variant="subtitle1">Benefit Desc*</Typography>
|
||||
<RHFTextField name="benefit_desc" label="Benefit Desc" />
|
||||
</Grid>
|
||||
|
||||
<Controller
|
||||
name="diagnosis"
|
||||
control={control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Autocomplete
|
||||
options={diagnosisOption}
|
||||
getOptionLabel={(option) => (option ? `(${option.code}) ${option.name}` : '')}
|
||||
value={value || ''}
|
||||
onChange={(event: any, newValue: any) => {
|
||||
setValue('diagnosis_id', newValue?.id);
|
||||
// setValue('diagnosis', newValue)
|
||||
onChange(newValue);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
name="diagnosis"
|
||||
{...params}
|
||||
label="Diagnosis"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
onKeyPress={(event) => {
|
||||
if (event.key === 'Enter') searchDiagnosis(event.target.value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
{isCheckingLimit && (
|
||||
<Stack
|
||||
sx={{
|
||||
backgroundColor: 'gray',
|
||||
paddingY: 1,
|
||||
paddingX: 1.5,
|
||||
mb: 2,
|
||||
borderRadius: '3-xl',
|
||||
}}
|
||||
>
|
||||
{/* Checking */}
|
||||
<Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
|
||||
<Iconify
|
||||
icon="bxs:info-circle"
|
||||
width={12}
|
||||
height={13}
|
||||
sx={{ color: '#424242', marginRight: '6px' }}
|
||||
/>
|
||||
<Typography variant="caption" component="span">
|
||||
Please Wait, Checking Eligibilty
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
{false && isCheckingLimit == false && isEligible == null && (
|
||||
<Stack
|
||||
sx={{
|
||||
backgroundColor: 'gray',
|
||||
paddingY: 1,
|
||||
paddingX: 1.5,
|
||||
mb: 2,
|
||||
borderRadius: '3-xl',
|
||||
}}
|
||||
>
|
||||
{/* No Data Selected */}
|
||||
<Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
|
||||
<Iconify
|
||||
icon="bxs:info-circle"
|
||||
width={12}
|
||||
height={13}
|
||||
sx={{ color: '#424242', marginRight: '6px' }}
|
||||
/>
|
||||
<Typography variant="caption" component="span">
|
||||
Please Select Diagnosis !
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
{!isCheckingLimit && isEligible !== null && isEligible && (
|
||||
<Stack
|
||||
sx={{
|
||||
backgroundColor: '#B2E8E8',
|
||||
paddingY: 1,
|
||||
paddingX: 1.5,
|
||||
mb: 2,
|
||||
borderRadius: '3-xl',
|
||||
}}
|
||||
>
|
||||
{/* Eligible */}
|
||||
<Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
|
||||
<Iconify
|
||||
icon="bxs:lock-alt"
|
||||
width={12}
|
||||
height={13}
|
||||
sx={{ color: '#424242', marginRight: '6px' }}
|
||||
/>
|
||||
<Typography variant="caption" component="span">
|
||||
Diagnosis is Eligible
|
||||
</Typography>
|
||||
</Typography>
|
||||
<Typography sx={{ typography: 'caption', color: '#637381' }}>
|
||||
125.000.000 / 125.000.000
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
{!isCheckingLimit && isEligible !== null && !isEligible && (
|
||||
<Stack
|
||||
sx={{
|
||||
backgroundColor: '#B2E8E8',
|
||||
paddingY: 1,
|
||||
paddingX: 1.5,
|
||||
mb: 2,
|
||||
borderRadius: '3-xl',
|
||||
}}
|
||||
>
|
||||
{/* Not Eligible */}
|
||||
{/* <Typography sx={{ typography: 'caption', display: 'flex', alignItems: 'center' }}>
|
||||
<Iconify
|
||||
icon="bxs:lock-alt"
|
||||
width={12}
|
||||
height={13}
|
||||
sx={{ color: '#424242', marginRight: '6px' }}
|
||||
/>
|
||||
<Typography variant="caption" component="span">
|
||||
Not Eligible
|
||||
</Typography>
|
||||
</Typography>
|
||||
<Typography sx={{ typography: 'caption', color: '#637381' }}>
|
||||
125.000.000 / 125.000.000
|
||||
</Typography> */}
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
<RHFTextField type="number" name="total_claim" label="Total Claim" />
|
||||
|
||||
{isEdit && (
|
||||
<React.Fragment>
|
||||
<Typography variant="h6">Documents</Typography>
|
||||
|
||||
<List>
|
||||
{(getValues('uploaded_files.invoice') && getValues('uploaded_files.invoice').length
|
||||
? getValues('uploaded_files.invoice')
|
||||
: []
|
||||
).map((file, index) => (
|
||||
<ListItem
|
||||
secondaryAction={
|
||||
<IconButton edge="end" aria-label="delete">
|
||||
<DeleteOutline />
|
||||
</IconButton>
|
||||
}
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
{/* <FileIcon /> */}
|
||||
I
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={file.name} secondary={file.type} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<Add />}
|
||||
component="label"
|
||||
sx={{ paddingY: 2, width: '100%', ':hover': { border: 'none' } }}
|
||||
>
|
||||
Invoice
|
||||
<input
|
||||
name="invoice"
|
||||
hidden
|
||||
accept="image/*,application/pdf"
|
||||
multiple
|
||||
type="file"
|
||||
onChange={(event) => {
|
||||
fileSelected(event, 'invoice');
|
||||
{/* Baris ke 3 */}
|
||||
<Grid item xs={3}>
|
||||
<Typography marginBottom={2} variant="subtitle1">Amount Incurred*</Typography>
|
||||
<RHFTextField name="amount_incurred" label="Amount Incurred" type="number" />
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography marginBottom={2} variant="subtitle1">Amount Approved*</Typography>
|
||||
<RHFTextField name="amount_approved" label="Amount Approved" type="number" />
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography marginBottom={2} variant="subtitle1">Amount Not Approved*</Typography>
|
||||
<RHFTextField name="amount_not_approved" label="Amount Not Approved" type="number" />
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography marginBottom={2} variant="subtitle1">Excess Paid*</Typography>
|
||||
<RHFTextField name="excess_paid" label="Excess Paid*" type="number" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
<Grid container marginTop={2}>
|
||||
<Grid item xs={12} md={12} >
|
||||
<Stack direction="row" alignItems="center" justifyContent="flex-end">
|
||||
<Button
|
||||
sx={{
|
||||
margin: 1
|
||||
}}
|
||||
/>
|
||||
</Button>
|
||||
<List>
|
||||
{(getValues('uploaded_files.prescription') && getValues('uploaded_files.prescription').length
|
||||
? getValues('uploaded_files.prescription')
|
||||
: []
|
||||
).map((file, index) => (
|
||||
<ListItem
|
||||
secondaryAction={
|
||||
<IconButton edge="end" aria-label="delete">
|
||||
<DeleteOutline />
|
||||
</IconButton>
|
||||
}
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
{/* <FileIcon /> */}
|
||||
P
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={file.name} secondary={file.type} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<Add />}
|
||||
component="label"
|
||||
sx={{ paddingY: 2, width: '100%', ':hover': { border: 'none' } }}
|
||||
>
|
||||
Prescription
|
||||
<input
|
||||
name="prescription"
|
||||
hidden
|
||||
accept="image/*,application/pdf"
|
||||
multiple
|
||||
type="file"
|
||||
onChange={(event) => {
|
||||
fileSelected(event, 'prescription');
|
||||
}}
|
||||
/>
|
||||
</Button>
|
||||
|
||||
<List>
|
||||
{(getValues('uploaded_files.diagnosis') && getValues('uploaded_files.diagnosis').length
|
||||
? getValues('uploaded_files.diagnosis')
|
||||
: []
|
||||
).map((file, index) => (
|
||||
<ListItem
|
||||
secondaryAction={
|
||||
<IconButton edge="end" aria-label="delete">
|
||||
<DeleteOutline />
|
||||
</IconButton>
|
||||
}
|
||||
>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
{/* <FileIcon /> */}
|
||||
DR
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={file.name} secondary={file.type} />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<Add />}
|
||||
component="label"
|
||||
sx={{ paddingY: 2, width: '100%', ':hover': { border: 'none' } }}
|
||||
>
|
||||
Doctor Result
|
||||
<input
|
||||
name="invoice"
|
||||
hidden
|
||||
accept="image/*,application/pdf"
|
||||
multiple
|
||||
type="file"
|
||||
onChange={(event) => {
|
||||
fileSelected(event, 'diagnosis');
|
||||
}}
|
||||
/>
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
{isEligible === true ? (
|
||||
<LoadingButton
|
||||
onClick={handleSubmit(onSubmit)}
|
||||
variant="contained"
|
||||
color="success"
|
||||
style={{ color: '#ffffff' }}
|
||||
size="large"
|
||||
fullWidth={true}
|
||||
loading={isCheckingLimit}
|
||||
>
|
||||
Create Claim
|
||||
</LoadingButton>
|
||||
) : (
|
||||
<LoadingButton
|
||||
onClick={checkLimit}
|
||||
variant="outlined"
|
||||
size="large"
|
||||
fullWidth={true}
|
||||
loading={isCheckingLimit}
|
||||
>
|
||||
Check Limit
|
||||
</LoadingButton>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
<MemberSelectDialog
|
||||
openDialog={isMemberDialogOpen}
|
||||
setOpenDialog={setIsMemberDialogOpen}
|
||||
onSelect={memberSelected}
|
||||
></MemberSelectDialog>
|
||||
</FormProvider>
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="large"
|
||||
color='inherit'
|
||||
onClick={() => navigate(`/claims`)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<LoadingButton
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="large"
|
||||
// fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
>
|
||||
Save
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</FormProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,13 +16,10 @@ import {
|
||||
Menu,
|
||||
ButtonGroup,
|
||||
Tooltip,
|
||||
TableHead,
|
||||
} from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined';
|
||||
import AssessmentIcon from '@mui/icons-material/Assessment';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
// hooks
|
||||
import React, { ChangeEvent, useEffect, useRef, useState } from 'react';
|
||||
import { Link, Navigate, useNavigate, useSearchParams } from 'react-router-dom';
|
||||
@@ -35,6 +32,13 @@ import EditRoundedIcon from '@mui/icons-material/EditRounded';
|
||||
import { Chip } from '@mui/material';
|
||||
import Iconify from '@/components/Iconify';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { fDate } from '../../utils/formatTime';
|
||||
import { Claims } from '@/@types/claims';
|
||||
import Label from '@/components/Label';
|
||||
import { capitalizeFirstLetter } from '@/utils/formatString';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
import Edit from '@mui/icons-material/Edit';
|
||||
import { Download } from '@mui/icons-material';
|
||||
|
||||
export default function List() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
@@ -83,10 +87,16 @@ export default function List() {
|
||||
fullWidth
|
||||
onChange={handleSearchChange}
|
||||
value={searchText}
|
||||
placeholder='Search Code or Member ID...'
|
||||
/>
|
||||
<Tooltip title="Benefit Usage Report">
|
||||
<Button variant="outlined" startIcon={<AssessmentIcon />} sx={{ p: 1.8 }} onClick={handleGetData}/>
|
||||
</Tooltip>
|
||||
<Button
|
||||
variant="contained"
|
||||
startIcon={<Download />}
|
||||
onClick={() => handleGetData('DO')}
|
||||
sx={{ p: 1.8 }}
|
||||
>
|
||||
Export
|
||||
</Button>
|
||||
</Stack>
|
||||
</form>
|
||||
);
|
||||
@@ -152,7 +162,7 @@ export default function List() {
|
||||
};
|
||||
|
||||
// Called on every row to map the data to the columns
|
||||
function createData(data: any): any {
|
||||
function createData(data: Claims): Claims {
|
||||
return {
|
||||
...data,
|
||||
};
|
||||
@@ -168,41 +178,44 @@ export default function List() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell>
|
||||
{/* <TableCell>
|
||||
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.member?.full_name}</TableCell>
|
||||
<TableCell align="left">{row.plan?.code}</TableCell>
|
||||
<TableCell align="left">{row.claim_request?.service?.name}</TableCell>
|
||||
<TableCell align="left">
|
||||
({row.diagnoses[0]?.icd?.code}) {row.diagnoses[0]?.icd?.name}
|
||||
</TableCell>
|
||||
<TableCell align="left">{fCurrency(row.total_claim)}</TableCell>
|
||||
</TableCell> */}
|
||||
<TableCell align="left">{row.claim_request?.code}</TableCell>
|
||||
{/* <TableCell align="left">{row.code}</TableCell> */}
|
||||
<TableCell align="left">{row.member?.current_plan?.code}</TableCell>
|
||||
<TableCell align="left">{row.member?.current_corporate?.payor_id}</TableCell>
|
||||
<TableCell align="left">{row.member?.current_corporate?.code}</TableCell>
|
||||
<TableCell align="left">{row.member?.current_corporate?.current_policy?.code}</TableCell>
|
||||
<TableCell align="left">{row.member?.member_id}</TableCell>
|
||||
<TableCell align="left">{row.benefit_desc}</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
{row.status == 'draft' && (<Chip label='Draft' color="default" variant="outlined" />)}
|
||||
{row.status == 'requested' && (<Chip label='Requested' color="primary" />)}
|
||||
{row.status == 'received' && (<Chip label='Received' color="success" variant='outlined' />)}
|
||||
{row.status == 'approved' && (<Chip label='Approved' color="success" />)}
|
||||
{row.status == 'postpone' && (<Chip label='Postpone' color="primary" variant="outlined" />)}
|
||||
{row.status == 'paid' && (<Chip label='Paid' color="warning" />)}
|
||||
{row.status == 'declined' && (<Chip label='Declined' color="error" />)}
|
||||
{row.status == 'draft' && (<Label color='secondary' variant='ghost'>{capitalizeFirstLetter(row.status)}</Label>)}
|
||||
{row.status == 'requested' && (<Label color='primary' variant='ghost'>{capitalizeFirstLetter(row.status)}</Label>)}
|
||||
{row.status == 'received' && (<Label color='secondary' variant='ghost'>{capitalizeFirstLetter(row.status)}</Label>)}
|
||||
{row.status == 'approved' && (<Label color='success' variant='ghost'>{capitalizeFirstLetter(row.status)}</Label>)}
|
||||
{row.status == 'postpone' && (<Label color='secondary' variant='ghost'>{capitalizeFirstLetter(row.status)}</Label>)}
|
||||
{row.status == 'paid' && (<Label color='secondary' variant='ghost'>{capitalizeFirstLetter(row.status)}</Label>)}
|
||||
{row.status == 'declined' && (<Label color='error' variant='ghost'>{capitalizeFirstLetter(row.status)}</Label>)}
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="right">
|
||||
{['approved', 'paid'].includes(row.status) && (
|
||||
<Iconify icon="eva:eye-fill" onClick={(e) => {
|
||||
navigate('/claims/' + row.id);
|
||||
}}></Iconify>
|
||||
)}
|
||||
{!['approved', 'paid'].includes(row.status) && (
|
||||
<Iconify icon="eva:edit-outline" onClick={(e) => {
|
||||
navigate('/claims/' + row.id);
|
||||
}}></Iconify>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() =>navigate(`/claims/edit/${row.id}`) }>
|
||||
<Edit />
|
||||
Edit
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate('/claims/detail/'+row.id+'') }>
|
||||
<FindInPageOutlinedIcon />
|
||||
Detail
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
|
||||
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
@@ -227,35 +240,38 @@ export default function List() {
|
||||
return (
|
||||
<Table aria-label="collapsible table">
|
||||
{/* ------------------ TABLE HEADER ------------------ */}
|
||||
<TableBody>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" />
|
||||
{/* <TableCell style={headStyle} align="left" /> */}
|
||||
<TableCell style={headStyle} align="left">
|
||||
Code
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Member Name
|
||||
Plan ID
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Plan
|
||||
Payor ID
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Benefit
|
||||
Corporate ID
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Diagnosis
|
||||
Policy Number
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Total Claim
|
||||
Member ID
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Benefit Desc
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Status
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="right">
|
||||
Action
|
||||
<TableCell style={headStyle} align="left">
|
||||
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</TableHead>
|
||||
{/* ------------------ END TABLE HEADER ------------------ */}
|
||||
|
||||
{/* ------------------ TABLE ROW ------------------ */}
|
||||
|
||||
58
frontend/dashboard/src/pages/Claims/Model/Functions.tsx
Normal file
58
frontend/dashboard/src/pages/Claims/Model/Functions.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import axios from "@/utils/axios";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
import { BenefitConfigurationListType } from "./Types";
|
||||
|
||||
/**
|
||||
* Get Benefit Configuration List
|
||||
*/
|
||||
export const getBenefitConfigurationList = async ( claim_id: string ): Promise<BenefitConfigurationListType[]> => {
|
||||
const response = await axios.get(`/claims/${claim_id}/benefit-configuration`)
|
||||
.then((res) =>{
|
||||
return res.data.data.benefit_list;
|
||||
})
|
||||
.catch((res) => {
|
||||
enqueueSnackbar("server error !", {
|
||||
variant: 'error',
|
||||
});
|
||||
|
||||
return [];
|
||||
});
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
/**
|
||||
* Edit Benefit Configuration
|
||||
*/
|
||||
export const editBenefitConfiguration = async ( data: BenefitConfigurationListType ): Promise<boolean> => {
|
||||
const response = await axios.put(`/claims/benefit-configuration/edit/${data.claim_service_benefits_id}`, {
|
||||
...data
|
||||
})
|
||||
.then((res) =>{
|
||||
enqueueSnackbar(res.data.message, {
|
||||
variant: 'success',
|
||||
});
|
||||
|
||||
return true;
|
||||
})
|
||||
.catch((res) => {
|
||||
if (res.response.status == 400) {
|
||||
let arr_message = res.response.data.message;
|
||||
|
||||
for (const key in arr_message) {
|
||||
enqueueSnackbar(arr_message[key][0], {
|
||||
variant: 'warning',
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
enqueueSnackbar("server error !", {
|
||||
variant: 'error',
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return response;
|
||||
};
|
||||
11
frontend/dashboard/src/pages/Claims/Model/Types.tsx
Normal file
11
frontend/dashboard/src/pages/Claims/Model/Types.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Benefit Configuration List Type
|
||||
*/
|
||||
export type BenefitConfigurationListType = {
|
||||
claim_service_benefits_id: number,
|
||||
benefit_name: string,
|
||||
amount_incurred: number,
|
||||
amount_approved: number,
|
||||
amount_not_approved: number,
|
||||
excess_paid: number
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import ClaimDetail from './components/ClaimDetail';
|
||||
import DialogHistoryPerawatan from './components/DialogHistoryPerawatan';
|
||||
import { IconButton } from '@mui/material';
|
||||
import { Tooltip } from '@mui/material';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
export default function ClaimsCreateUpdate() {
|
||||
const { themeStretch } = useSettings();
|
||||
@@ -48,6 +49,10 @@ export default function ClaimsCreateUpdate() {
|
||||
const [currentClaim, setCurrentClaim] = useState();
|
||||
const [documents, setDocuments] = useState([]);
|
||||
|
||||
const claimsHistoryData = useSelector((state) => state.claimsHistory)
|
||||
|
||||
console.log(claimsHistoryData)
|
||||
|
||||
const Item = styled(Paper)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
|
||||
...theme.typography.body2,
|
||||
@@ -66,6 +71,12 @@ export default function ClaimsCreateUpdate() {
|
||||
setClaimItems([...claimItems, ...items]);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if(claimsHistoryData) {
|
||||
setClaimItems(claimsHistoryData)
|
||||
}
|
||||
},[claimsHistoryData])
|
||||
|
||||
const handleSaveClaimItems = () => {
|
||||
console.log('Storing ', claimItems);
|
||||
setLoadingClaimItems(true);
|
||||
@@ -305,6 +316,9 @@ export default function ClaimsCreateUpdate() {
|
||||
</LoadingButton>
|
||||
)}
|
||||
</Stack>
|
||||
<Stack direction="row" justifyContent="space-between" alignItems="center">
|
||||
<Typography>Admission Date : {currentClaim?.claim_request?.submission_date}</Typography>
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
@@ -347,7 +361,7 @@ export default function ClaimsCreateUpdate() {
|
||||
<Typography variant="body2" fontWeight={600}>
|
||||
Nomor Polis
|
||||
</Typography>
|
||||
<Typography variant="body2">{currentClaim?.member?.full_name}</Typography>
|
||||
<Typography variant="body2">{currentClaim?.member?.current_policy?.code}</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={6}>
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
import * as Yup from 'yup';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Box, Grid } from '@mui/material';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import Button from '@mui/material/Button';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogActions from '@mui/material/DialogActions';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { FormProvider } from '@/components/hook-form';
|
||||
import RHFTextFieldMoney from '@/components/hook-form/v2/RHFTextFieldMoney';
|
||||
|
||||
/**
|
||||
* Custom Style
|
||||
* =====================================================
|
||||
*/
|
||||
const BootstrapDialog = styled(Dialog)(({ theme }) => ({
|
||||
|
||||
}));
|
||||
|
||||
/**
|
||||
* Utils, Types, Functions
|
||||
* ============================================
|
||||
*/
|
||||
import palette from '@/theme/palette';
|
||||
import { BenefitConfigurationListType } from '../Model/Types';
|
||||
import { editBenefitConfiguration } from '../Model/Functions';
|
||||
|
||||
/**
|
||||
* Props
|
||||
* =====================================================
|
||||
*/
|
||||
type Props = {
|
||||
data?: BenefitConfigurationListType,
|
||||
isOpen: boolean,
|
||||
handleCancleProp: () => void,
|
||||
handleSuccessProp: () => void,
|
||||
};
|
||||
|
||||
export default function BenefitConfigurationDialog({ ...props }: Props) {
|
||||
|
||||
// setup form
|
||||
// ====================================
|
||||
const defaultValues: BenefitConfigurationListType = {
|
||||
claim_service_benefits_id: 0,
|
||||
benefit_name: '',
|
||||
amount_incurred: 0,
|
||||
amount_approved: 0,
|
||||
amount_not_approved: 0,
|
||||
excess_paid: 0,
|
||||
};
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
amount_incurred : Yup.string().typeError('').required(''),
|
||||
amount_approved : Yup.string().typeError('').required(''),
|
||||
amount_not_approved : Yup.string().typeError('').required(''),
|
||||
excess_paid : Yup.string().typeError('').required(''),
|
||||
});
|
||||
|
||||
const methods = useForm<any>({
|
||||
resolver: yupResolver(validationSchema),
|
||||
defaultValues
|
||||
});
|
||||
|
||||
const { handleSubmit, reset, watch, setValue, formState: { isDirty, isSubmitting, errors } } = methods;
|
||||
|
||||
console.log(errors);
|
||||
console.log(watch());
|
||||
|
||||
// Submit Form
|
||||
// =====================================
|
||||
const submitHandler = async (data: BenefitConfigurationListType) => {
|
||||
let response = await editBenefitConfiguration(data);
|
||||
|
||||
if (response == true) {
|
||||
props.handleSuccessProp()
|
||||
props.handleCancleProp()
|
||||
}
|
||||
}
|
||||
|
||||
// Set Value Form
|
||||
// =====================================
|
||||
useEffect(() => {
|
||||
setValue('claim_service_benefits_id', props.data?.claim_service_benefits_id)
|
||||
setValue('amount_incurred', props.data?.amount_incurred)
|
||||
setValue('amount_approved', props.data?.amount_approved)
|
||||
setValue('amount_not_approved', props.data?.amount_not_approved)
|
||||
setValue('excess_paid', props.data?.excess_paid)
|
||||
}, [props.data])
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
onClose={props.handleCancleProp}
|
||||
aria-labelledby="customized-dialog-title"
|
||||
open={props.isOpen}
|
||||
maxWidth={'md'}
|
||||
>
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(submitHandler)}>
|
||||
<DialogTitle sx={{ m: 0, p: 2, background: palette.light.primary.main, color: palette.light.grey[0], display: 'flex', alignItems: 'center', justifyContent: 'space-between' }} id="customized-dialog-title">
|
||||
<Typography variant="body2" sx={{ fontWeight: 'bold' }}>
|
||||
Client Benefit Configuration
|
||||
</Typography>
|
||||
|
||||
<IconButton
|
||||
aria-label="close"
|
||||
onClick={props.handleCancleProp}
|
||||
sx={{color: (theme) => theme.palette.grey[0]}}
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</DialogTitle>
|
||||
|
||||
<DialogContent sx={{ p: '0px' }}>
|
||||
<Box sx={{ py: '24px', px: '32px'}}>
|
||||
<Box sx={{ p: '24px', border: '1px solid rgba(0,0,0,0.125)', borderRadius: '12px'}}>
|
||||
<Grid container spacing={3}>
|
||||
{/* Benefit Name */}
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body2" sx={{ fontWeight: 'bold'}}>
|
||||
{props.data?.benefit_name}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={3}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body2" component="div">
|
||||
Amount Incurred*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
|
||||
<RHFTextFieldMoney
|
||||
id="amount_incurred"
|
||||
name='amount_incurred'
|
||||
placeholder='Amount Incurred'
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={3}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body2" component="div">
|
||||
Amount Approved*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
|
||||
<RHFTextFieldMoney
|
||||
id="amount_approved"
|
||||
name='amount_approved'
|
||||
placeholder='Amount Approved'
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={3}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body2" component="div">
|
||||
Amount Not Approved*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
|
||||
<RHFTextFieldMoney
|
||||
id="amount_not_approved"
|
||||
name='amount_not_approved'
|
||||
placeholder='Amount Not Approved'
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={3}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body2" component="div">
|
||||
Excess Paid*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
|
||||
<RHFTextFieldMoney
|
||||
id="excess_paid"
|
||||
name='excess_paid'
|
||||
placeholder='Excess Paid'
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<Button variant='outlined' onClick={props.handleCancleProp} aria-label="close">
|
||||
Cancle
|
||||
</Button>
|
||||
<LoadingButton disabled={!isDirty} type="submit" variant="contained" loading={isSubmitting}>
|
||||
Save Changes
|
||||
</LoadingButton>
|
||||
</DialogActions>
|
||||
</FormProvider>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* Core
|
||||
* ============================================
|
||||
*/
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useParams } from 'react-router';
|
||||
import { Box, Typography, Grid, MenuItem } from '@mui/material';
|
||||
|
||||
/**
|
||||
* Components
|
||||
* ============================================
|
||||
*/
|
||||
// - Global -
|
||||
import MoreMenu from '@/components/MoreMenu';
|
||||
|
||||
/**
|
||||
* Icon
|
||||
* ============================================
|
||||
*/
|
||||
import { EditOutlined } from '@mui/icons-material';
|
||||
|
||||
/**
|
||||
* Utils, Types, Functions
|
||||
* ============================================
|
||||
*/
|
||||
import { BenefitConfigurationListType } from '../Model/Types';
|
||||
import { getBenefitConfigurationList } from '../Model/Functions';
|
||||
import palette from '@/theme/palette';
|
||||
import BenefitConfigurationDialog from './BenefitConfigurationDialog';
|
||||
import { fNumber } from '@/utils/formatNumber';
|
||||
|
||||
export default function BenefitConfigurationList() {
|
||||
const { id: claim_id } = useParams();
|
||||
|
||||
// State
|
||||
// --------------------
|
||||
const [BenefitConfigurationList, setBenefitConfigurationList] = useState<BenefitConfigurationListType[]>();
|
||||
const [BenefitConfigurationData, setBenefitConfigurationData] = useState<BenefitConfigurationListType>();
|
||||
const [isDialogOpen, setIsDialogOpen] = useState<boolean>(false);
|
||||
|
||||
// Use Effect
|
||||
// --------------------
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, [])
|
||||
|
||||
// Load Data
|
||||
// -------------------
|
||||
const loadDataTableData = async () => {
|
||||
const response = await getBenefitConfigurationList(claim_id??'');
|
||||
|
||||
setBenefitConfigurationList(response);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{/* row list */}
|
||||
{
|
||||
BenefitConfigurationList?.map((row, index) => {
|
||||
return (
|
||||
<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'}}>
|
||||
{row.benefit_name}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6} sx={{ display: 'flex', placeContent: 'end' }}>
|
||||
<MoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => {
|
||||
setIsDialogOpen(true)
|
||||
setBenefitConfigurationData(row)
|
||||
}}
|
||||
>
|
||||
<EditOutlined />
|
||||
Edit
|
||||
</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={3}>
|
||||
<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(row.amount_incurred)}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Amount Approved */}
|
||||
<Grid item xs={3}>
|
||||
<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(row.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(row.amount_not_approved)}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Excess Paid* */}
|
||||
<Grid item xs={3}>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="caption">
|
||||
Excess Paid*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
|
||||
{fNumber(row.excess_paid)}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
{/* Dialog */}
|
||||
<BenefitConfigurationDialog data={BenefitConfigurationData} isOpen={isDialogOpen} handleCancleProp={() => setIsDialogOpen(false)} handleSuccessProp={() => loadDataTableData()} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import { Stack } from '@mui/material';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import React, { useState } from 'react';
|
||||
import FormHistoryPerawatan from './FormHistoryPerawatan';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { claimsHistoryAction } from '@/store/claimsHistorySlice';
|
||||
|
||||
type DialogHistoryPerawatanType = {
|
||||
openDialog: boolean;
|
||||
@@ -18,6 +20,7 @@ type DialogHistoryPerawatanType = {
|
||||
export default function DialogHistoryPerawatan({ openDialog, setOpenDialog, onSubmit, claim, encounter } : DialogHistoryPerawatanType) {
|
||||
|
||||
const isEdit = encounter?.id != null
|
||||
const dispatch = useDispatch()
|
||||
// const benefits = member?.current_plan?.benefits ?? [];
|
||||
// const [selectedBenefits, setSelectedBenefits] = useState([]);
|
||||
|
||||
@@ -38,6 +41,10 @@ export default function DialogHistoryPerawatan({ openDialog, setOpenDialog, onSu
|
||||
.then((res) => {
|
||||
enqueueSnackbar(res.data.message, {variant: 'success'})
|
||||
setOpenDialog(false);
|
||||
window.location.reload(); // tolong benerin ya
|
||||
// axios.get(`claims/${claim.id}`).then((res) => {
|
||||
// dispatch(claimsHistoryAction.setClaims(res.data.data.encounter))
|
||||
// })
|
||||
})
|
||||
.catch((err) => {
|
||||
enqueueSnackbar(err.message, {variant: 'error'})
|
||||
@@ -47,6 +54,10 @@ export default function DialogHistoryPerawatan({ openDialog, setOpenDialog, onSu
|
||||
.then((res) => {
|
||||
enqueueSnackbar(res.data.message, {variant: 'success'})
|
||||
setOpenDialog(false);
|
||||
window.location.reload(); // tolong benerin ya
|
||||
// axios.get(`claims/${claim.id}`).then((res) => {
|
||||
// dispatch(claimsHistoryAction.setClaims(res.data.data.encounter))
|
||||
// })
|
||||
})
|
||||
.catch((err) => {
|
||||
enqueueSnackbar(err.message, {variant: 'error'})
|
||||
|
||||
@@ -97,9 +97,6 @@ export default function Documents({ files }) {
|
||||
<Stack sx={{px: 2}}>
|
||||
<Typography variant="body2">Dokumen Diagnosa</Typography>
|
||||
</Stack>
|
||||
<Stack sx={{px: 2}}>
|
||||
<Typography variant="body2">Dokumen Diagnosa</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
|
||||
|
||||
@@ -2,21 +2,43 @@ import * as Yup from 'yup';
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import { Card, Collapse, Divider, Grid, Stack, Typography } from "@mui/material";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useNavigate, 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 CorporateTabNavigations from "../CorporateTabNavigations";
|
||||
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
|
||||
import DivisionsList from "./List";
|
||||
import { useMemo, useState } from 'react';
|
||||
import FormEdit from "./Form";
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { Benefit } from '@/@types/corporates';
|
||||
import axios from '@/utils/axios';
|
||||
|
||||
|
||||
|
||||
export default function Divisions() {
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const { corporate_id } = useParams();
|
||||
const { corporate_id, benefit_id } = useParams();
|
||||
const [ currentCorporateBenefit, setCurrentCorporateBenefit ] = useState<Benefit>();
|
||||
const navigate = useNavigate();
|
||||
const isEdit = !!benefit_id;
|
||||
useEffect(() => {
|
||||
console.log(benefit_id);
|
||||
if (isEdit) {
|
||||
axios.get('/corporates/'+corporate_id+'/corporate-benefits/'+benefit_id+'/edit')
|
||||
.then((res) => {
|
||||
setCurrentCorporateBenefit(res.data);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.response.status === 404) {
|
||||
navigate('/404');
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [corporate_id, benefit_id]);
|
||||
|
||||
|
||||
const NewDivisionSchema = Yup.object().shape({
|
||||
name: Yup.string().required('Name is required'),
|
||||
@@ -51,97 +73,12 @@ export default function Divisions() {
|
||||
console.log(data);
|
||||
};
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const benefits = [
|
||||
{
|
||||
'category' : 'General Practitioner',
|
||||
'childs' : [
|
||||
{
|
||||
'name' : 'External Doctor Online',
|
||||
'code' : 'gp-external-doctor-online'
|
||||
},
|
||||
{
|
||||
'name' : 'External Doctor Offline',
|
||||
'code' : 'gp-external-doctor-offline'
|
||||
},
|
||||
{
|
||||
'name' : 'Internal Doctor Online',
|
||||
'code' : 'gp-internal-doctor-online'
|
||||
},
|
||||
{
|
||||
'name' : 'Internal Doctor Offline',
|
||||
'code' : 'gp-internal-doctor-offline'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
'category' : 'Specialist',
|
||||
'childs' : [
|
||||
{
|
||||
'name' : 'External Doctor Online',
|
||||
'code' : 'sp-external-doctor-online'
|
||||
},
|
||||
{
|
||||
'name' : 'External Doctor Offline',
|
||||
'code' : 'sp-external-doctor-offline'
|
||||
},
|
||||
{
|
||||
'name' : 'Internal Doctor Online',
|
||||
'code' : 'sp-internal-doctor-online'
|
||||
},
|
||||
{
|
||||
'name' : 'Internal Doctor Offline',
|
||||
'code' : 'sp-internal-doctor-offline'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
'category' : 'Medicines',
|
||||
'childs' : [
|
||||
{
|
||||
'name' : 'Vitamins',
|
||||
'code' : 'medicines-vitamins'
|
||||
},
|
||||
{
|
||||
'name' : 'Delivery Fee',
|
||||
'code' : 'medicines-delivery-fee'
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
const products = [
|
||||
{
|
||||
'name' : 'Inpatient',
|
||||
'code' : 'IP',
|
||||
},
|
||||
{
|
||||
'name' : 'Outpatient',
|
||||
'code' : 'OP',
|
||||
},
|
||||
{
|
||||
'name' : 'Dental',
|
||||
'code' : 'DT',
|
||||
},
|
||||
{
|
||||
'name' : 'Dental',
|
||||
'code' : 'DTL',
|
||||
},
|
||||
{
|
||||
'name' : 'Matternity',
|
||||
'code' : 'MT',
|
||||
},
|
||||
{
|
||||
'name' : 'Special Benefit',
|
||||
'code' : 'SB',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Page title="Create Benefit">
|
||||
|
||||
<HeaderBreadcrumbs
|
||||
{/* <HeaderBreadcrumbs
|
||||
heading={'Create Benefit'}
|
||||
links={[
|
||||
{ name: 'Dashboard', href: '/dashboard' },
|
||||
@@ -162,9 +99,9 @@ export default function Divisions() {
|
||||
href: '/corporates/'+id+'/benefits/create',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
/> */}
|
||||
|
||||
|
||||
{/*
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Card sx={{ p: 2 }}>
|
||||
@@ -235,7 +172,17 @@ export default function Divisions() {
|
||||
</FormProvider>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid> */}
|
||||
<Stack direction="row" alignItems="center">
|
||||
<ArrowBackIosIcon
|
||||
onClick={() => navigate(`/corporates/${corporate_id}/benefit`)}
|
||||
sx={{ cursor: 'pointer' }}
|
||||
/>
|
||||
<Typography variant="h5" sx={{ marginRight:2, flexGrow: 1 }}>
|
||||
Edit Plan
|
||||
</Typography>
|
||||
</Stack>
|
||||
<FormEdit isEdit={true} currentCorporateBenefit={currentCorporateBenefit}/>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as Yup from 'yup';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { Box, Card, Grid, Stack, Typography } from '@mui/material';
|
||||
import { CorporatePlan } from '../../../@types/corporates';
|
||||
import { Box, Button, Card, Grid, Stack, Typography } from '@mui/material';
|
||||
import { Benefit } from '../../../@types/corporates';
|
||||
import { FormProvider, RHFSwitch, RHFTextField } from '../../../components/hook-form';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
@@ -12,39 +12,36 @@ import axios from '../../../utils/axios';
|
||||
|
||||
type Props = {
|
||||
isEdit: boolean;
|
||||
currentCorporatePlan?: CorporatePlan;
|
||||
currentCorporateBenefit?: Benefit;
|
||||
};
|
||||
|
||||
export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Props) {
|
||||
export default function CorporateBenefitForm({ isEdit, currentCorporateBenefit }: Props) {
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
const navigate = useNavigate();
|
||||
const { corporate_id } = useParams();
|
||||
const { corporate_id, benefit_id } = useParams();
|
||||
|
||||
const NewCorporatePlanSchema = Yup.object().shape({
|
||||
name: Yup.string().required('Name is required'),
|
||||
code: Yup.string().required('Corporate Code is required'),
|
||||
const NewCorporateBenefitSchema = Yup.object().shape({
|
||||
budget: Yup.string().required('Budget is required'),
|
||||
});
|
||||
|
||||
const defaultValues = useMemo(
|
||||
() => ({
|
||||
name: currentCorporatePlan?.name || '',
|
||||
code: currentCorporatePlan?.code || '',
|
||||
active: currentCorporatePlan?.active === 1 ? true : false,
|
||||
budget: currentCorporateBenefit?.budget || '',
|
||||
}),
|
||||
[currentCorporatePlan]
|
||||
[currentCorporateBenefit]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit && currentCorporatePlan) {
|
||||
if (isEdit && currentCorporateBenefit) {
|
||||
reset(defaultValues);
|
||||
}
|
||||
if (!isEdit) {
|
||||
reset(defaultValues);
|
||||
}
|
||||
}, [isEdit, currentCorporatePlan]);
|
||||
}, [isEdit, currentCorporateBenefit]);
|
||||
|
||||
const methods = useForm({
|
||||
resolver: yupResolver(NewCorporatePlanSchema),
|
||||
resolver: yupResolver(NewCorporateBenefitSchema),
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
@@ -81,12 +78,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
|
||||
});
|
||||
} else {
|
||||
await axios
|
||||
.put('/corporate/' + corporate_id + '/divisions/' + currentCorporatePlan?.id, data)
|
||||
.put('/corporates/' + corporate_id + '/corporate-benefits/' + benefit_id, data)
|
||||
.then((res) => {
|
||||
enqueueSnackbar('Division updated successfully', { variant: 'success' });
|
||||
})
|
||||
.then((res) => {
|
||||
navigate('/corporate/' + corporate_id + '/divisions/', { replace: true });
|
||||
navigate('/corporates/' + corporate_id + '/benefits', { replace: true });
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
enqueueSnackbar('Update Failed : ' + response.data.message, { variant: 'error' });
|
||||
@@ -95,30 +92,44 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<Box sx={{ margin: 1, pb: 2, pl: 4 }}>
|
||||
<Grid container>
|
||||
<Grid item xs={6} sx={{ padding: 2 }}>
|
||||
<Grid item xs={12} sx={{ padding: 2 }}>
|
||||
<Grid container>
|
||||
<Stack direction="row" alignItems="center" sx={{ width: '100%' }}>
|
||||
<Typography variant="subtitle2" sx={{ mr: 2 }}>
|
||||
ASO/Budget
|
||||
</Typography>
|
||||
<RHFTextField name="budget" />
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={6} sx={{ padding: 2 }}>
|
||||
<Grid container>
|
||||
<Stack direction="row" alignItems="center" sx={{ width: '100%' }}>
|
||||
<Typography variant="subtitle2" sx={{ mr: 2 }}>
|
||||
ASO/Budget
|
||||
</Typography>
|
||||
<RHFTextField name="budget" />
|
||||
<RHFTextField name="budget" type='number'/>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Stack direction="row" alignItems="center" justifyContent="flex-end">
|
||||
<Button
|
||||
sx={{marginTop:2}}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="large"
|
||||
color='inherit'
|
||||
onClick={() => navigate(`/corporates/${corporate_id}/benefits`)}
|
||||
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<LoadingButton
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="large"
|
||||
// fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
sx={{marginTop:2, marginLeft:2}}
|
||||
>
|
||||
Save
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</Box>
|
||||
</FormProvider>
|
||||
);
|
||||
|
||||
@@ -35,19 +35,19 @@ export default function Divisions() {
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id,
|
||||
href: '/corporates/' + corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Benefit',
|
||||
href: '/corporate/' + corporate_id + '/benefits',
|
||||
href: '/corporates/' + corporate_id + '/benefits',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Card>
|
||||
{/* <Card> */}
|
||||
<CorporateTabNavigations position={'benefits'} />
|
||||
<DivisionsList />
|
||||
</Card>
|
||||
{/* </Card> */}
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -85,7 +85,7 @@ export default function CustomizedAccordions() {
|
||||
(panel: string) => (event: React.SyntheticEvent, newExpanded: boolean) => {
|
||||
setExpanded(newExpanded ? panel : false);
|
||||
};
|
||||
const pageTitle = 'Audittrail Corporate';
|
||||
const pageTitle = 'Corporate Dashboard';
|
||||
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
@@ -121,11 +121,11 @@ export default function CustomizedAccordions() {
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id + '/plans',
|
||||
href: '/corporates/' + corporate_id + '/benefits',
|
||||
},
|
||||
{
|
||||
name: 'Audittrail Corporate',
|
||||
href: '/corporate/' + corporate_id + '/plans',
|
||||
name: 'Benefit',
|
||||
href: '/corporates/' + corporate_id + '/benefits',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
@@ -155,6 +155,7 @@ export default function CustomizedAccordions() {
|
||||
if (key !== 'reason') {
|
||||
return null; // Melewati iterasi saat key adalah 'deleted_by'
|
||||
}
|
||||
|
||||
renderedValue = item.new_values[key];
|
||||
|
||||
const field = key.charAt(0).toUpperCase() + key.slice(1);
|
||||
|
||||
@@ -33,11 +33,11 @@ export default function Divisions() {
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id,
|
||||
href: '/corporates/' + corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Claim History',
|
||||
href: '/corporate/' + corporate_id + '/claim-histories',
|
||||
href: '/corporates/' + corporate_id + '/claim-histories',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -8,6 +8,9 @@ import axios from '../../../utils/axios';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import CorporatePlanForm from './Form';
|
||||
import { CorporatePlan } from '../../../@types/corporates';
|
||||
import { Stack } from "@mui/system";
|
||||
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
|
||||
import { Typography } from "@mui/material";
|
||||
|
||||
|
||||
|
||||
@@ -36,8 +39,8 @@ export default function PlanCreate() {
|
||||
|
||||
return (
|
||||
<Page title="Create Corporate Plan">
|
||||
<HeaderBreadcrumbs
|
||||
heading={'Create Corporate Plan'}
|
||||
{/* <HeaderBreadcrumbs
|
||||
heading={ 'Edit Plan'}
|
||||
links={[
|
||||
{
|
||||
name: 'Corporates',
|
||||
@@ -56,7 +59,16 @@ export default function PlanCreate() {
|
||||
href: '/corporates/'+corporate_id+'/corporate-plans/'+id,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
/> */}
|
||||
<Stack direction="row" alignItems="center">
|
||||
<ArrowBackIosIcon
|
||||
onClick={() => navigate(`/corporates/${corporate_id}/plans`)}
|
||||
sx={{ cursor: 'pointer' }}
|
||||
/>
|
||||
<Typography variant="h5" sx={{ marginRight:2, flexGrow: 1 }}>
|
||||
Edit Plan
|
||||
</Typography>
|
||||
</Stack>
|
||||
|
||||
<CorporatePlanForm isEdit={isEdit} currentCorporatePlan={currentCorporatePlan}/>
|
||||
</Page>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as Yup from 'yup';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { Card, Grid, Stack, Typography } from '@mui/material';
|
||||
import { Card, Grid, Stack, Typography, Button } from '@mui/material';
|
||||
import { CorporatePlan } from '../../../@types/corporates';
|
||||
import { FormProvider, RHFEditor, RHFSwitch, RHFTextField } from '../../../components/hook-form';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
@@ -22,16 +22,22 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
|
||||
const { corporate_id } = useParams();
|
||||
|
||||
const NewCorporatePlanSchema = Yup.object().shape({
|
||||
name: Yup.string().required('Name is required'),
|
||||
code: Yup.string().required('Corporate Code is required'),
|
||||
service: Yup.string().required('Corporate Service is required'),
|
||||
plan: Yup.string().required('Corporate Plan is required'),
|
||||
type: Yup.string().required('Corporate Type is required'),
|
||||
limit: Yup.string().required('Corporate Limit is required'),
|
||||
});
|
||||
|
||||
const defaultValues = useMemo(
|
||||
() => ({
|
||||
name: currentCorporatePlan?.name || '',
|
||||
// name: currentCorporatePlan?.name || '',
|
||||
code: currentCorporatePlan?.code || '',
|
||||
active: currentCorporatePlan?.active || true,
|
||||
description: currentCorporatePlan?.description || '',
|
||||
// active: currentCorporatePlan?.active || true,
|
||||
type: currentCorporatePlan?.type || '',
|
||||
limit: currentCorporatePlan?.limit_rules || '',
|
||||
service: currentCorporatePlan?.service_code || '',
|
||||
plan: currentCorporatePlan?.corporate_plan_id || '',
|
||||
}),
|
||||
[currentCorporatePlan]
|
||||
);
|
||||
@@ -62,14 +68,15 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
|
||||
} = methods;
|
||||
|
||||
const onSubmit = async (data: any) => {
|
||||
console.log(data);
|
||||
if (!isEdit) {
|
||||
await axios
|
||||
.post('/corporate/' + corporate_id + '/corporate-plans', data)
|
||||
.post('/corporates/' + corporate_id + '/corporate-plans', data)
|
||||
.then((res) => {
|
||||
enqueueSnackbar('Corporate Plan created successfully', { variant: 'success' });
|
||||
})
|
||||
.then((res) => {
|
||||
navigate('/corporate/' + corporate_id + '/corporate-plans', { replace: true });
|
||||
navigate(`/corporates/${corporate_id}/plans`, { replace: true });
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
if (response.status === 422) {
|
||||
@@ -83,12 +90,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
|
||||
});
|
||||
} else {
|
||||
await axios
|
||||
.put('/corporate/' + corporate_id + '/corporate-plans/' + currentCorporatePlan?.id, data)
|
||||
.put('/corporates/' + corporate_id + '/corporate-plans/' + currentCorporatePlan?.id, data)
|
||||
.then((res) => {
|
||||
enqueueSnackbar('Corporate Plan updated successfully', { variant: 'success' });
|
||||
})
|
||||
.then((res) => {
|
||||
navigate('/corporate/' + corporate_id + '/corporate-plans/', { replace: true });
|
||||
navigate('/corporates/' + corporate_id + '/plans', { replace: true });
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
enqueueSnackbar('Update Failed : ' + response.data.message, { variant: 'error' });
|
||||
@@ -98,12 +105,34 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
|
||||
|
||||
return (
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={8}>
|
||||
<Card sx={{ p: 2 }}>
|
||||
<Card sx={{ p: 2, marginTop: 2 }}>
|
||||
<Grid container spacing={4} paddingX={2} paddingY={2}>
|
||||
<Grid item xs={3}>
|
||||
<Typography variant="subtitle1">Service*</Typography>
|
||||
<RHFTextField name="service" label="service" sx={{marginTop:2}}/>
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography variant="subtitle1">Plan*</Typography>
|
||||
<RHFTextField name="plan" label="plan" sx={{marginTop:2}} />
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography variant="subtitle1">Code*</Typography>
|
||||
<RHFTextField name="code" label="code" sx={{marginTop:2}} />
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography variant="subtitle1">Type*</Typography>
|
||||
<RHFTextField name="type" label="type" sx={{marginTop:2}} />
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="subtitle1">Plan Limit*</Typography>
|
||||
<RHFTextField name="limit" label="limit" sx={{marginTop:2}} />
|
||||
</Grid>
|
||||
|
||||
{/* <Grid item xs={3}>
|
||||
<Stack spacing={3}>
|
||||
<Typography variant="h6">Corporate Plan Detail</Typography>
|
||||
|
||||
|
||||
<RHFTextField name="name" label="Name" />
|
||||
|
||||
<RHFTextField name="code" label="Code" />
|
||||
@@ -122,17 +151,35 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
|
||||
fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
>
|
||||
Create Corporate Plan
|
||||
{ isEdit ? 'Update' : 'Create'} Corporate Plan
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Grid> */}
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<Card sx={{ p: 2 }}>
|
||||
<RHFSwitch name="active" label="Active" />
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
<Stack direction="row" alignItems="center" justifyContent="flex-end">
|
||||
<Button
|
||||
sx={{marginTop:2}}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="large"
|
||||
color='inherit'
|
||||
onClick={() => navigate(`/corporates/${corporate_id}/plans`)}
|
||||
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<LoadingButton
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="large"
|
||||
// fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
sx={{marginTop:2, marginLeft:2}}
|
||||
>
|
||||
Save
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</FormProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -32,11 +32,11 @@ export default function Divisions() {
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id,
|
||||
href: '/corporates/' + corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Corporate Plan',
|
||||
href: '/corporate/' + corporate_id + '/corporate-plans',
|
||||
href: '/corporates/' + corporate_id + '/corporate-plans',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -44,10 +44,10 @@ export default function CorporateTabNavigations({ position }: Props) {
|
||||
path: 'benefits',
|
||||
label: 'Benefit',
|
||||
},
|
||||
{
|
||||
path: 'divisions',
|
||||
label: 'Division',
|
||||
},
|
||||
// {
|
||||
// path: 'divisions',
|
||||
// label: 'Division',
|
||||
// },
|
||||
{
|
||||
path: 'members',
|
||||
label: 'Member List',
|
||||
@@ -61,15 +61,16 @@ export default function CorporateTabNavigations({ position }: Props) {
|
||||
label: 'Hospital',
|
||||
},
|
||||
{
|
||||
path: 'formularium',
|
||||
path: 'formulariums',
|
||||
label: 'Formularium',
|
||||
},
|
||||
{
|
||||
path: 'claim-history',
|
||||
label: 'Claim History',
|
||||
},
|
||||
// {
|
||||
// path: 'claim-history',
|
||||
// label: 'Claim History',
|
||||
// },
|
||||
];
|
||||
useEffect(() => {
|
||||
console.log(position);
|
||||
let currentIndex = mainTabItems.findIndex((item) => item.path === position);
|
||||
setCurrentTab(currentIndex);
|
||||
}, []);
|
||||
@@ -89,7 +90,7 @@ export default function CorporateTabNavigations({ position }: Props) {
|
||||
<Tab
|
||||
key={index}
|
||||
onClick={() => {
|
||||
navigate('/corporate/' + corporate_id + '/' + mainTabItems[index].path);
|
||||
navigate('/corporates/' + corporate_id + '/' + mainTabItems[index].path);
|
||||
}}
|
||||
label={tabItem.label}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* Core
|
||||
* ============================================
|
||||
*/
|
||||
import axios from '@/utils/axios';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { Box, IconButton, Typography, Grid, Card, TextField, Autocomplete, Button } from '@mui/material';
|
||||
|
||||
/**
|
||||
* Components
|
||||
* ============================================
|
||||
*/
|
||||
import Page from '../../../components/Page';
|
||||
import { LoadingButton } from "@mui/lab";
|
||||
import { FormProvider, RHFCustomMultiCheckbox, RHFTextField } from '@/components/hook-form';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
|
||||
/**
|
||||
* Icon
|
||||
* ============================================
|
||||
*/
|
||||
import ArrowBackIosNew from '@mui/icons-material/ArrowBackIosNew';
|
||||
|
||||
export default function Divisions() {
|
||||
const pageTitle = 'Edit Exclusion';
|
||||
const navigate = useNavigate()
|
||||
const { corporate_id, exclusion_id } = useParams(); // id di url
|
||||
const [ plans, setPlans ] = useState<string[]>([]); // option untuk field plans
|
||||
|
||||
// checkbox option
|
||||
// ====================================
|
||||
const msc_checkbox_option = [
|
||||
{
|
||||
value: 'm',
|
||||
label: 'Member',
|
||||
},
|
||||
{
|
||||
value: 's',
|
||||
label: 'Spouse',
|
||||
},
|
||||
{
|
||||
value: 'c',
|
||||
label: 'Child',
|
||||
},
|
||||
]
|
||||
|
||||
const gender_checkbox_option = [
|
||||
{
|
||||
value: 'male',
|
||||
label: 'Male',
|
||||
},
|
||||
{
|
||||
value: 'female',
|
||||
label: 'Female',
|
||||
},
|
||||
]
|
||||
|
||||
// setup form
|
||||
// ====================================
|
||||
const defaultValues: any = {
|
||||
msc: [],
|
||||
gender: [],
|
||||
min_age: '',
|
||||
max_age: '',
|
||||
plans: [],
|
||||
};
|
||||
|
||||
const methods = useForm<any>({
|
||||
defaultValues
|
||||
});
|
||||
|
||||
const { setValue, handleSubmit, reset, watch, formState: { isDirty, isSubmitting } } = methods;
|
||||
const formValues = watch();
|
||||
|
||||
// set form value
|
||||
// =====================================
|
||||
useEffect(() => {
|
||||
axios.get(`corporates/${corporate_id}/diagnosis-exclusions/${exclusion_id}`)
|
||||
.then((res) => {
|
||||
// plan option
|
||||
setPlans(res.data.data.plans);
|
||||
|
||||
// set value
|
||||
let res_plan = res.data.data.exclusion.rules.plan;
|
||||
|
||||
if (res_plan.length == 1 && res_plan[0] == '') {
|
||||
res_plan = [];
|
||||
}
|
||||
|
||||
reset({
|
||||
msc : res.data.data.exclusion.rules.msc[0].split(','),
|
||||
gender : res.data.data.exclusion.rules.gender[0].split(','),
|
||||
min_age : res.data.data.exclusion.value_rules.min_age,
|
||||
max_age : res.data.data.exclusion.value_rules.max_age,
|
||||
plans : res_plan,
|
||||
})
|
||||
})
|
||||
}, [exclusion_id]);
|
||||
|
||||
// Submit Form
|
||||
// =====================================
|
||||
const submitHandler = async (data: any) => {
|
||||
let one_row = {
|
||||
msc: {
|
||||
m: data.msc.includes('m'),
|
||||
s: data.msc.includes('s'),
|
||||
c: data.msc.includes('c'),
|
||||
},
|
||||
gender : {
|
||||
male : data.gender.includes('male') == true ? 1 : 0,
|
||||
female: data.gender.includes('female') == true ? 1 : 0,
|
||||
},
|
||||
min_age: data.min_age,
|
||||
max_age: data.max_age,
|
||||
plan : data.plans.join(','),
|
||||
icd_id : exclusion_id,
|
||||
}
|
||||
|
||||
return axios
|
||||
.post(`/corporates/${corporate_id}/diagnosis-exclusions/store`, {
|
||||
type: 'one_row',
|
||||
icd_id: exclusion_id,
|
||||
one_row
|
||||
})
|
||||
.then((res) => {
|
||||
enqueueSnackbar('Exclusion Updated', {
|
||||
variant: 'success',
|
||||
});
|
||||
|
||||
reset({
|
||||
msc : data.msc,
|
||||
gender : data.gender,
|
||||
min_age : data.min_age,
|
||||
max_age : data.max_age,
|
||||
plans : data.plans,
|
||||
})
|
||||
|
||||
return true;
|
||||
})
|
||||
.catch((res) => {
|
||||
enqueueSnackbar('Terjadi kesalahan pada server', {
|
||||
variant: 'error',
|
||||
});
|
||||
|
||||
return true;
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Page title={pageTitle}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', pl: '12px', mb: '40px' }}>
|
||||
<IconButton size='large' color='inherit' onClick={() => navigate(`/corporates/${corporate_id}/diagnosis-exclusions`)} >
|
||||
<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}>
|
||||
{/* MSC row */}
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" component="div" color={'GrayText'}>
|
||||
MSC* :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<RHFCustomMultiCheckbox name="msc" options={msc_checkbox_option} sx={{ flexDirection: 'row' }} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Gender row */}
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" component="div" color={'GrayText'}>
|
||||
Gender* :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<RHFCustomMultiCheckbox name="gender" options={gender_checkbox_option} sx={{ flexDirection: 'row' }} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Age row */}
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" component="div" color={'GrayText'}>
|
||||
Age* :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={3} md={3}>
|
||||
<RHFTextField
|
||||
id="min_age"
|
||||
name='min_age'
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={3} md={3}>
|
||||
<RHFTextField
|
||||
id="max_age"
|
||||
name='max_age'
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Plan Section */}
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" component="div" color={'GrayText'}>
|
||||
Plan* :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
|
||||
<Autocomplete
|
||||
options={plans}
|
||||
fullWidth
|
||||
multiple
|
||||
limitTags={5}
|
||||
getOptionLabel={(option) => {
|
||||
return option ?? false
|
||||
}}
|
||||
value={formValues.plans}
|
||||
isOptionEqualToValue={(option, value) =>{
|
||||
return option === value
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Plan" variant="outlined" />
|
||||
)}
|
||||
onChange={(event,value) => {
|
||||
setValue('plans', value, {shouldDirty: true});
|
||||
}}
|
||||
/>
|
||||
</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(`/corporates/${corporate_id}/diagnosis-exclusions`)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<LoadingButton disabled={!isDirty} type="submit" variant="contained" loading={isSubmitting}>
|
||||
Save Changes
|
||||
</LoadingButton>
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
</FormProvider>
|
||||
</Box>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
// @mui
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
Collapse,
|
||||
Container,
|
||||
FormControl,
|
||||
Grid,
|
||||
IconButton,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
OutlinedInput,
|
||||
Paper,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
Badge,
|
||||
Stack,
|
||||
} from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import ArrowForwardIosSharpIcon from '@mui/icons-material/ArrowForwardIosSharp';
|
||||
import MuiAccordion, { AccordionProps } from '@mui/material/Accordion';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import MuiAccordionSummary, {
|
||||
AccordionSummaryProps,
|
||||
} from '@mui/material/AccordionSummary';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import axios from '../../../utils/axios';
|
||||
import { ConfiguredCorporateContext } from '@/contexts/ConfiguredCorporateContext';
|
||||
import MuiAccordionDetails from '@mui/material/AccordionDetails';
|
||||
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
|
||||
import { Corporate } from '@/@types/corporates';
|
||||
import { fDate, fDateTime } from '@/utils/formatTime';
|
||||
|
||||
const Accordion = styled((props: AccordionProps) => (
|
||||
<MuiAccordion disableGutters elevation={0} square {...props} />
|
||||
))(({ theme }) => ({
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
'&:not(:last-child)': {
|
||||
borderBottom: 0,
|
||||
},
|
||||
'&:before': {
|
||||
display: 'none',
|
||||
},
|
||||
}));
|
||||
|
||||
const AccordionSummary = styled((props: AccordionSummaryProps) => (
|
||||
<MuiAccordionSummary
|
||||
expandIcon={<ArrowForwardIosSharpIcon sx={{ fontSize: '0.9rem' }} />}
|
||||
{...props}
|
||||
/>
|
||||
))(({ theme }) => ({
|
||||
backgroundColor:
|
||||
theme.palette.mode === 'dark'
|
||||
? 'rgba(255, 255, 255, .05)'
|
||||
: 'rgba(0, 0, 0, .03)',
|
||||
flexDirection: 'row-reverse',
|
||||
'& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': {
|
||||
transform: 'rotate(90deg)',
|
||||
},
|
||||
'& .MuiAccordionSummary-content': {
|
||||
marginLeft: theme.spacing(1),
|
||||
},
|
||||
}));
|
||||
|
||||
const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({
|
||||
padding: theme.spacing(2),
|
||||
borderTop: '1px solid rgba(0, 0, 0, .125)',
|
||||
}));
|
||||
|
||||
export default function CustomizedAccordions() {
|
||||
const [expanded, setExpanded] = React.useState<string | false>('panel1');
|
||||
|
||||
const handleChange =
|
||||
(panel: string) => (event: React.SyntheticEvent, newExpanded: boolean) => {
|
||||
setExpanded(newExpanded ? panel : false);
|
||||
};
|
||||
const pageTitle = 'History Corporate Exclusions';
|
||||
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const { corporate_id, id } = useParams();
|
||||
|
||||
const [corporate, setCorporate] = useState<Corporate | null>();
|
||||
const [ currentCorporate, setCurrentCorporate ] = useState<Corporate>();
|
||||
|
||||
const configuredCorporateContext = useContext(ConfiguredCorporateContext);
|
||||
|
||||
useEffect(() => {
|
||||
setCorporate(configuredCorporateContext.currentCorporate);
|
||||
const model = 'App\\Models\\ExclusionImport';
|
||||
const url = `/audittrail/${corporate_id}?model=${model}`;
|
||||
axios.get(url)
|
||||
.then((res) => {
|
||||
setCurrentCorporate(res.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Terjadi kesalahan:', error);
|
||||
});
|
||||
|
||||
}, [configuredCorporateContext]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<HeaderBreadcrumbs
|
||||
heading={pageTitle}
|
||||
links={[
|
||||
{
|
||||
name: 'Corporates',
|
||||
href: '/corporates',
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id + '/diagnosis-exclusions',
|
||||
|
||||
},
|
||||
{
|
||||
name: 'History Corporate Exclusion',
|
||||
href: '/corporate/' + corporate_id + '/plans',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{currentCorporate?.data.map((item, index) => (
|
||||
<Accordion
|
||||
key={index}
|
||||
expanded={expanded === `panel${index}`}
|
||||
onChange={handleChange(`panel${index}`)}
|
||||
>
|
||||
<AccordionSummary
|
||||
aria-controls={`panel${index}d-content`}
|
||||
id={`panel${index}d-header`}
|
||||
>
|
||||
<Typography>{`Data has ${item.action} by ${item.user_id} on ${fDateTime(item.updated_at)}`}</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align="center">Field</TableCell>
|
||||
<TableCell align="center">Old Value</TableCell>
|
||||
<TableCell align="center">New Values</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{Object.entries(item.old_values).map(([key, value]) => {
|
||||
let renderedValue;
|
||||
if (key === 'deleted_by' || key === 'created_by' || key === 'updated_by' || key === 'file_path') {
|
||||
return null; // Melewati iterasi saat key adalah 'deleted_by'
|
||||
}
|
||||
switch (key) {
|
||||
case 'welcome_message':
|
||||
renderedValue = item.new_values[key].replace(/<[^>]*>/g, '');
|
||||
value = value.replace(/<[^>]*>/g, '');
|
||||
break;
|
||||
case 'help_text':
|
||||
renderedValue = item.new_values[key].replace(/<[^>]*>/g, '');
|
||||
value = value.replace(/<[^>]*>/g, '');
|
||||
break;
|
||||
case 'active':
|
||||
renderedValue = item.new_values[key] == 1 ? 'Active' : 'Inactive';
|
||||
value = value == 1 ? 'Active' : 'Inactive';
|
||||
break;
|
||||
case 'created_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
case 'updated_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
case 'updated_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
case 'delete_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
default:
|
||||
renderedValue = item.new_values[key];
|
||||
break;
|
||||
}
|
||||
|
||||
const field = key.charAt(0).toUpperCase() + key.slice(1);
|
||||
if (value != renderedValue){
|
||||
return (
|
||||
<TableRow key={key} sx={{ '&:last-child td, &:last-child th': { border: 0 } }}>
|
||||
<TableCell>{`${field}`}</TableCell>
|
||||
<TableCell align="center">{`${value}`}</TableCell>
|
||||
<TableCell align="center">{renderedValue}</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
})}
|
||||
|
||||
</TableBody>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -36,11 +36,11 @@ export default function Divisions() {
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id,
|
||||
href: '/corporates/' + corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Diagnosis Exclusion',
|
||||
href: '/corporate/' + corporate_id + '/diagnosis-exclusions',
|
||||
href: '/corporates/' + corporate_id + '/diagnosis-exclusions',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// @mui
|
||||
import * as Yup from 'yup';
|
||||
import {
|
||||
Autocomplete,
|
||||
Box,
|
||||
@@ -38,14 +39,17 @@ import {
|
||||
} from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import GetApp from '@mui/icons-material/GetApp';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
// hooks
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
import { Link, useParams, useSearchParams, useNavigate } from 'react-router-dom';
|
||||
// components
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
import axios from '../../../utils/axios';
|
||||
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||
import { Icd } from '../../../@types/diagnosis';
|
||||
@@ -53,6 +57,14 @@ import BasePagination from '../../../components/BasePagination';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { Icon } from '@iconify/react';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import HistoryIcon from '@mui/icons-material/History';
|
||||
import CachedIcon from '@mui/icons-material/Cached';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
import { EditOutlined, FindInPageOutlined } from '@mui/icons-material';
|
||||
import Label from '@/components/Label';
|
||||
import { display } from '@mui/system';
|
||||
import DialogUpdateStatus from '@/components/DialogUpdateStatus'
|
||||
import { FormProvider, RHFSelect } from '@/components/hook-form';
|
||||
|
||||
export default function List(props: any) {
|
||||
const { themeStretch } = useSettings();
|
||||
@@ -81,7 +93,7 @@ export default function List(props: any) {
|
||||
}, [searchParams]);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '100%' }}>
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '90%' }}>
|
||||
<TextField
|
||||
id="search-input"
|
||||
ref={searchInput}
|
||||
@@ -145,7 +157,7 @@ export default function List(props: any) {
|
||||
handleCancelImportButton();
|
||||
loadDataTableData();
|
||||
setImportResult(response.data);
|
||||
|
||||
|
||||
setImportLoading(false);
|
||||
// alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows');
|
||||
})
|
||||
@@ -155,14 +167,14 @@ export default function List(props: any) {
|
||||
response.message,
|
||||
{ variant: 'error' }
|
||||
);
|
||||
|
||||
|
||||
setImportLoading(false);
|
||||
})
|
||||
} else {
|
||||
enqueueSnackbar('No File Selected', { variant: 'warning' });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleGetTemplate = (type :string) => {
|
||||
axios.get('corporates/import-document-example/' + type)
|
||||
.then((response) => {
|
||||
@@ -190,17 +202,19 @@ export default function List(props: any) {
|
||||
<SearchInput onSearch={applyFilter} />
|
||||
{/* <h1>kjasndkjandskjasndkjansdkjansd</h1> */}
|
||||
<Button
|
||||
id="import-button"
|
||||
variant="outlined"
|
||||
startIcon={<AddIcon />}
|
||||
sx={{ p: 1.8 }}
|
||||
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={createMenu ? 'true' : undefined}
|
||||
onClick={handleClick}
|
||||
id="import-button"
|
||||
variant="contained"
|
||||
startIcon={<GetApp />}
|
||||
sx={{ p: 1.8,width: '200px' }}
|
||||
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={createMenu ? 'true' : undefined}
|
||||
onClick={handleClick}
|
||||
color='primary'
|
||||
>
|
||||
Import
|
||||
Import
|
||||
</Button>
|
||||
|
||||
<Menu
|
||||
id="import-button"
|
||||
anchorEl={anchorEl}
|
||||
@@ -264,6 +278,14 @@ export default function List(props: any) {
|
||||
...icd,
|
||||
};
|
||||
}
|
||||
type DataContent = {
|
||||
service: string;
|
||||
id: number;
|
||||
status: number;
|
||||
code: string,
|
||||
name: string,
|
||||
rules: string,
|
||||
};
|
||||
const plans = props?.data.map((plan: any) => {
|
||||
return {
|
||||
value: plan.code,
|
||||
@@ -297,6 +319,16 @@ export default function List(props: any) {
|
||||
const { row, index, data } = props;
|
||||
}
|
||||
|
||||
const [isDialogOpen, setDialogOpen] = useState(false)
|
||||
let titles = {
|
||||
name: 'Update Status',
|
||||
icon: '-'
|
||||
}
|
||||
const [dataValue, setDataValue] = useState('');
|
||||
const [dataDescription, setDescriptionValue] = useState('');
|
||||
const [url, setUrl] = useState('');
|
||||
|
||||
|
||||
function Row(props: {
|
||||
row: ReturnType<typeof createData>;
|
||||
data: any;
|
||||
@@ -329,9 +361,6 @@ export default function List(props: any) {
|
||||
|
||||
const [openEdit, setOpenEdit] = React.useState(false);
|
||||
|
||||
console.log('open', open);
|
||||
console.log('openEdit', openEdit);
|
||||
|
||||
// const [plans, setPlans] = useState([]);
|
||||
|
||||
const plans = data;
|
||||
@@ -461,290 +490,217 @@ export default function List(props: any) {
|
||||
|
||||
console.log('exclusions', exclusions);
|
||||
|
||||
// const handleActivate = (row: any) => {
|
||||
|
||||
// axios
|
||||
// .put(`/corporates/diagnosis-exclusions/update_activation`, {
|
||||
// id: row.id,
|
||||
// active: row.active == 1 ? 0 : 1,
|
||||
// })
|
||||
// .then((res) => {
|
||||
// setDataTableData({
|
||||
// ...dataTableData,
|
||||
// data: dataTableData.data.map((model) => {
|
||||
// let updatedModel = model;
|
||||
|
||||
// if (model.id == row.id) {
|
||||
// updatedModel.active = row.active == 1 ? 0 : 1;
|
||||
// }
|
||||
|
||||
// return updatedModel;
|
||||
// }),
|
||||
// });
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// if (error.response.status == 400) {
|
||||
// let data = error.response.data.messages;
|
||||
|
||||
// for (const key in data) {
|
||||
// enqueueSnackbar(
|
||||
// data[key][0],
|
||||
// { variant: 'error' }
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// enqueueSnackbar(
|
||||
// error.response.data.message ?? error.message ?? 'Failed Processing Request',
|
||||
// { variant: 'error' }
|
||||
// );
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
|
||||
const handleActivate = (isOpen: boolean, dataValue: DataContent) => {
|
||||
console.log(dataValue)
|
||||
setDialogOpen(isOpen)
|
||||
setDataValue(dataValue)
|
||||
setDescriptionValue('Are you sure to inactive this service ?')
|
||||
setUrl(url)
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell>
|
||||
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.service_code}</TableCell>
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="left">{Object.keys(row.rules).length ? 'With Rules' : 'All'}</TableCell>
|
||||
<TableCell align="left" onClick={() => {if(open==true) setOpen(!open)}}/>
|
||||
<TableCell align="left" onClick={() => {if(open==true) setOpen(!open)}}>
|
||||
{row.service_code}
|
||||
</TableCell>
|
||||
<TableCell align="left" onClick={() => {if(open==true) setOpen(!open)}}>
|
||||
{row.code}
|
||||
</TableCell>
|
||||
<TableCell align="left" onClick={() => {if(open==true) setOpen(!open)}}>
|
||||
{row.name}
|
||||
</TableCell>
|
||||
<TableCell align="left" onClick={() => {if(open==true) setOpen(!open)}}>
|
||||
{Object.keys(row.rules).length ? 'With Rules' : 'All'}
|
||||
</TableCell>
|
||||
<TableCell align="left" onClick={() => {if(open==true) setOpen(!open)}}>
|
||||
{row.active == 1 && (
|
||||
<Label
|
||||
variant="ghost"
|
||||
color="success"
|
||||
size="small"
|
||||
>
|
||||
Active
|
||||
</Label>
|
||||
)}
|
||||
{row.active != 1 && (
|
||||
<Label
|
||||
variant="ghost"
|
||||
color="error"
|
||||
size="small"
|
||||
>
|
||||
Inactive
|
||||
</Label>
|
||||
)}
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
{openEdit ? (
|
||||
<Button
|
||||
variant="contained"
|
||||
color="success"
|
||||
size="small"
|
||||
sx={{
|
||||
color: '#fff',
|
||||
}}
|
||||
onClick={(event) => {
|
||||
setOpenEdit(!openEdit);
|
||||
if (open == false) {
|
||||
setOpen(true);
|
||||
}
|
||||
handleConfigExclusion(event, row, '', 'one_row');
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="success"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
setOpenEdit(true);
|
||||
setOpen(true);
|
||||
}}
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="error"
|
||||
size="small"
|
||||
sx={{ ml: 2 }}
|
||||
onClick={() => {
|
||||
setOpenDelete(true);
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => setOpen(!open)}>
|
||||
<FindInPageOutlined />
|
||||
Detail
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate(`/corporates/${corporate_id}/diagnosis-exclusions/${row.id}/edit`)} >
|
||||
<EditOutlined />
|
||||
Edit
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => handleActivate(true, {
|
||||
code: row.code,
|
||||
name: row.name,
|
||||
rules: Object.keys(row.rules).length ? 'With Rules' : 'All',
|
||||
id:row.id,
|
||||
status: row.active,
|
||||
service: row.service_code
|
||||
})
|
||||
} >
|
||||
<CachedIcon />
|
||||
Update Status
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={99}>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
{open == true ? (
|
||||
openEdit == false ? (
|
||||
<Box sx={{ borderBottom: 1 }}>
|
||||
{Object.keys(row.rules).length ? (
|
||||
<div>
|
||||
<Typography variant="body" sx={{ fontWeight: 'bold' }}>
|
||||
Excluded Only for :
|
||||
</Typography>
|
||||
|
||||
{row.rules.msc && (
|
||||
<Typography variant="body" component="div">
|
||||
MSC : {row.rules.msc.join(', ') ?? '-'}
|
||||
</Typography>
|
||||
)}
|
||||
{row.rules.gender && (
|
||||
<Typography variant="body" component="div">
|
||||
Gender : {row.rules.gender.join(', ') ?? '-'}
|
||||
</Typography>
|
||||
)}
|
||||
{(row.rules.min_age || row.rules.max_age) && (
|
||||
<Typography variant="body" component="div">
|
||||
Age : {row.rules.min_age ?? '-'} - {row.rules.max_age ?? '-'}
|
||||
</Typography>
|
||||
)}
|
||||
{row.rules.plan && (
|
||||
<Typography variant="body" component="div">
|
||||
Plan : {row.rules.plan.join(', ') ?? '-'}
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<Typography variant="body2" gutterBottom component="div">
|
||||
Excluded for All
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
) : (
|
||||
// <CollapseEdit row={row} index={index} plans={plans} />
|
||||
<Box sx={{ borderBottom: 1, pb: 2 }}>
|
||||
<Typography variant="body2" sx={{ fontWeight: 'bold', mb: 2 }}>
|
||||
Edit Exclusion :
|
||||
</Typography>
|
||||
|
||||
<Stack direction={'column'} spacing={2}>
|
||||
<FormControl fullWidth>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={2} md={2}>
|
||||
<Typography id="demo-simple-select-label">MSC</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={10} md={10}>
|
||||
<Stack direction={'row'} spacing={2}>
|
||||
<Grid item xs={3} md={3}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={row.value_rules.msc?.m == '1'}
|
||||
onChange={(event) => {
|
||||
// handleConfigExclusion(event, row, 'm', 'msc');
|
||||
handleChange(index, event, 'msc', row.id, 'm');
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label="Member"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={3} md={3}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={row.value_rules.msc?.s == '1'}
|
||||
onChange={(event) => {
|
||||
// handleConfigExclusion(event, row, 's', 'msc');
|
||||
handleChange(index, event, 'msc', row.id, 's');
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label="Spouse"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={3} md={3}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={row.value_rules.msc?.c == '1'}
|
||||
onChange={(event) => {
|
||||
// handleConfigExclusion(event, row, 'c', 'msc');
|
||||
handleChange(index, event, 'msc', row.id, 'c');
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label="Child"
|
||||
/>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</FormControl>
|
||||
|
||||
<FormControl fullWidth>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={2} md={2}>
|
||||
<Typography id="demo-simple-select-label">Gender</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10} md={10}>
|
||||
<Stack direction={'row'} spacing={2}>
|
||||
<Grid item xs={3} md={3}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={row.value_rules.gender?.male == '1'}
|
||||
onChange={(event) => {
|
||||
// handleConfigExclusion(event, row, 'male', 'gender');
|
||||
handleChange(index, event, 'gender', row.id, 'male');
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label="Male"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={3} md={3}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={row.value_rules.gender?.female == '1'}
|
||||
onChange={(event) => {
|
||||
// handleConfigExclusion(event, row, 'female', 'gender');
|
||||
handleChange(index, event, 'gender', row.id, 'female');
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label="Female"
|
||||
/>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</FormControl>
|
||||
<FormControl fullWidth>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={2} md={2}>
|
||||
<Typography id="demo-simple-select-label">Age</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10} md={10}>
|
||||
<Stack direction={'row'} spacing={2}>
|
||||
<Grid item xs={3} md={3}>
|
||||
<TextField
|
||||
id="outlined-number"
|
||||
type="number"
|
||||
defaultValue={row.value_rules.min_age ?? ''}
|
||||
onChange={(event) => {
|
||||
handleMinAge(event);
|
||||
handleChange(index, event, 'min_age', row.id);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
handleConfigExclusion(event, row, minAge, 'min_age');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={3} md={3}>
|
||||
<TextField
|
||||
id="outlined-number"
|
||||
type="number"
|
||||
defaultValue={row.value_rules.max_age ?? ''}
|
||||
onChange={(event) => {
|
||||
handleMaxAge(event);
|
||||
handleChange(index, event, 'max_age', row.id);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
handleConfigExclusion(event, row, maxAge, 'max_age');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</FormControl>
|
||||
<FormControl fullWidth>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={2} md={2}>
|
||||
<Typography id="demo-simple-select-label">Plan</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={10} md={10}>
|
||||
<Stack direction={'row'} spacing={2}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Autocomplete
|
||||
id="combo-box-demo"
|
||||
options={plans}
|
||||
multiple
|
||||
limitTags={5}
|
||||
fullWidth
|
||||
getOptionLabel={(option) => option.label}
|
||||
defaultValue={converToArray(row.value_rules.plan) || []}
|
||||
isOptionEqualToValue={(option, value) =>
|
||||
option.value === value.value
|
||||
}
|
||||
onChange={(event, value) => {
|
||||
handlePlanChange(event, value);
|
||||
handleChange(index, event, 'plan', row.id, value);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
handleConfigExclusion(event, row, valuePlan, 'plan');
|
||||
}
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Plan" variant="outlined" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</FormControl>
|
||||
</Stack>
|
||||
</Box>
|
||||
)
|
||||
) : null}
|
||||
{open == true ? (
|
||||
<Box sx={{ padding: '24px' }}>
|
||||
<Card sx={{ padding: '24px' }}>
|
||||
<Grid container spacing={6}>
|
||||
<Grid item xs={8}>
|
||||
<Typography variant="body1" sx={{ fontWeight: 'bold'}}>
|
||||
Excluded Only for :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={3}>
|
||||
<Typography variant="body1" component="div" color={'GrayText'}>
|
||||
MSC :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={9} sx={{ display: 'flex', gap: 1 }}>
|
||||
{row?.rules?.msc && row?.rules?.msc[0] ? (
|
||||
row?.rules?.msc[0].split(',').map((text, i) => {
|
||||
let labelMSC: string = text;
|
||||
switch (labelMSC) {
|
||||
case 'm':
|
||||
labelMSC = 'Member';
|
||||
break;
|
||||
case 'c':
|
||||
labelMSC = 'Child';
|
||||
break;
|
||||
case 's':
|
||||
labelMSC = 'Spouse';
|
||||
break;
|
||||
default:
|
||||
labelMSC = 'Member';
|
||||
}
|
||||
return (
|
||||
<Typography key={i} component="div">
|
||||
<Label>{labelMSC}</Label>
|
||||
</Typography>
|
||||
);
|
||||
})
|
||||
) : '-'}
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography variant="body1" component="div" color={'GrayText'}>
|
||||
Gender :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={9} sx={{display: 'flex', gap: 1}}>
|
||||
{row?.rules?.gender && row?.rules?.gender[0] ? (
|
||||
row?.rules?.gender[0].split(',').map((text,i) => {
|
||||
const capitalizedText = text.charAt(0).toUpperCase() + text.slice(1);
|
||||
return (
|
||||
<Typography key={i} component="div">
|
||||
<Label>{capitalizedText}</Label>
|
||||
</Typography>
|
||||
)
|
||||
})
|
||||
) : '-'}
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography variant="body1" component="div" color={'GrayText'}>
|
||||
Min Age :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={9} sx={{display: 'flex', gap: 1}}>
|
||||
<Typography component="div">
|
||||
{row?.rules?.min_age && row?.rules?.min_age[0] ? row?.rules?.min_age[0] : '-'}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography variant="body1" component="div" color={'GrayText'}>
|
||||
Max Age :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={9} sx={{display: 'flex', gap: 1}}>
|
||||
<Typography component="div">
|
||||
{row?.rules?.max_age && row?.rules?.max_age[0] ? row?.rules?.max_age[0] : '-'}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={3}>
|
||||
<Typography variant="body1" component="div" color={'GrayText'}>
|
||||
Plan :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={9} sx={{display: 'flex', gap: 1}}>
|
||||
<Typography component="div">
|
||||
{row?.rules?.plan && row?.rules?.plan[0] ? row?.rules?.plan[0] : '-'}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
</Box>
|
||||
) : null }
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -843,6 +799,18 @@ export default function List(props: any) {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const onSubmit = async (row : any) => {
|
||||
try {
|
||||
handleUpdate(dataValue.status, dataValue.id, row.reason)
|
||||
} catch (error: any) {
|
||||
console.log('data gagal');
|
||||
}
|
||||
|
||||
const ascent = document?.querySelector('ascent');
|
||||
if (ascent != null) {
|
||||
ascent.innerHTML = '';
|
||||
}
|
||||
};
|
||||
const applyFilter = async (searchFilter: any) => {
|
||||
await loadDataTableData({ search: searchFilter });
|
||||
setSearchParams({ search: searchFilter });
|
||||
@@ -858,6 +826,138 @@ export default function List(props: any) {
|
||||
loadDataTableData();
|
||||
}, []);
|
||||
|
||||
const navigate = useNavigate()
|
||||
|
||||
const NewCorporateSchema = Yup.object().shape({
|
||||
reason: Yup.string().required('Reason Edit is required'),
|
||||
});
|
||||
|
||||
const methods = useForm<FormValuesProps>({
|
||||
resolver: yupResolver(NewCorporateSchema),
|
||||
});
|
||||
|
||||
|
||||
const {
|
||||
reset,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
} = methods;
|
||||
|
||||
const handleUpdate = (active: number, id: number, reason:string) => {
|
||||
console.log(active)
|
||||
axios
|
||||
.put(`/corporates/diagnosis-exclusions/update_activation`, {
|
||||
id: id,
|
||||
active: active,
|
||||
reason: reason
|
||||
})
|
||||
.then((res) => {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
const getContent = () => (
|
||||
<>
|
||||
<Stack paddingX={2} paddingY={2}>
|
||||
<Typography variant='subtitle1'>Are you sure to {dataValue?.status == 1 ? 'inactive' : 'active'} this benefit ?</Typography>
|
||||
</Stack>
|
||||
<Card>
|
||||
<Grid container paddingX={2} paddingY={2}>
|
||||
<Grid item xs={5} md={5}>
|
||||
<Typography variant='inherit'>Service</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={7}>
|
||||
<Typography variant='subtitle1'>{dataValue?.service}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={5} md={5} marginTop={2}>
|
||||
<Typography variant='inherit'>Code</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={7} marginTop={2}>
|
||||
<Typography variant='subtitle1'>{dataValue?.code}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={5} md={5} marginTop={2}>
|
||||
<Typography variant='inherit'>Name</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={7} marginTop={2}>
|
||||
<Typography variant='subtitle1'>{dataValue?.name}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={5} md={5} marginTop={2}>
|
||||
<Typography variant='inherit'>Rules</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={7} marginTop={2}>
|
||||
<Typography variant='subtitle1'>{dataValue?.rules}</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
|
||||
<Typography marginTop={5} marginBottom={3} variant='subtitle1'>
|
||||
Reason for update*
|
||||
</Typography>
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<RHFSelect
|
||||
name="reason"
|
||||
label="Reason for update"
|
||||
>
|
||||
<option value=""></option>
|
||||
<option value="Agreement changed">Agreement changed</option>
|
||||
<option value="Endorsement">Endorsement</option>
|
||||
<option value="Renewal">Renewal</option>
|
||||
<option value="Worng Setting">Worng Setting</option>
|
||||
</RHFSelect>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
justifyContent="flex-end"
|
||||
direction={{ xs: 'column', md: 'row' }}
|
||||
spacing={2}
|
||||
marginTop={5}
|
||||
>
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Button
|
||||
sx={{
|
||||
boxShadow: 'none',
|
||||
}}
|
||||
variant="outlined"
|
||||
size="medium"
|
||||
fullWidth={true}
|
||||
onClick={() => setDialogOpen(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
{dataValue?.status == 1?
|
||||
<LoadingButton
|
||||
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)'}}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="medium"
|
||||
fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
color='error'
|
||||
>
|
||||
Inactive
|
||||
</LoadingButton>
|
||||
:
|
||||
<LoadingButton
|
||||
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)'}}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="medium"
|
||||
fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
color='success'
|
||||
>
|
||||
Active
|
||||
</LoadingButton>
|
||||
|
||||
|
||||
}
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
</FormProvider>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<ImportForm />
|
||||
@@ -866,9 +966,9 @@ export default function List(props: any) {
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" />
|
||||
<TableCell align="left" width={50} />
|
||||
<TableCell style={headStyle} align="left">
|
||||
Service
|
||||
</TableCell>
|
||||
@@ -881,15 +981,25 @@ export default function List(props: any) {
|
||||
<TableCell style={headStyle} align="left">
|
||||
Rules
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="center">
|
||||
Action
|
||||
<TableCell style={headStyle} align="left">
|
||||
Status
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="right">
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => navigate(`/corporates/${corporate_id}/diagnosis-exclusions/history`)}>
|
||||
<HistoryIcon />
|
||||
History
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</TableHead>
|
||||
{dataTableIsLoading ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">
|
||||
<TableCell colSpan={7} align="center">
|
||||
Loading
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -897,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>
|
||||
@@ -920,6 +1030,16 @@ export default function List(props: any) {
|
||||
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||
</Card>
|
||||
|
||||
<DialogUpdateStatus
|
||||
openDialog={isDialogOpen}
|
||||
setOpenDialog={setDialogOpen}
|
||||
title={titles}
|
||||
data={dataValue}
|
||||
description={dataDescription}
|
||||
content={getContent()}
|
||||
// maxWidth='50px'
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
189
frontend/dashboard/src/pages/Corporates/DialogUpdateStatus.tsx
Normal file
189
frontend/dashboard/src/pages/Corporates/DialogUpdateStatus.tsx
Normal file
@@ -0,0 +1,189 @@
|
||||
import * as Yup from 'yup';
|
||||
import { enqueueSnackbar, useSnackbar } from 'notistack';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
// @mui
|
||||
import { styled } from '@mui/material/styles';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { Box, Button, Grid, Stack, Typography, Chip, Autocomplete } from '@mui/material';
|
||||
import { CorporateService } from '../../@types/corporates';
|
||||
// components
|
||||
import { FormProvider, RHFTextField, RHFSwitch, RHFSelect } from '../../components/hook-form';
|
||||
import axios from '../../utils/axios';
|
||||
import { LaravelPaginatedData } from '../../@types/paginated-data';
|
||||
|
||||
// import { Contact } from '../../../../@types/contact';
|
||||
import { Link, useParams, useSearchParams } from 'react-router-dom';
|
||||
|
||||
// @mui
|
||||
// components
|
||||
import MuiDialog from '../../components/MuiDialog';
|
||||
// React
|
||||
import { ReactElement } from 'react';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const HeaderStyle = styled('header')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
padding: theme.spacing(2),
|
||||
justifyContent: 'space-between',
|
||||
}));
|
||||
|
||||
type DataContent = {
|
||||
info: string;
|
||||
date: string;
|
||||
time: string;
|
||||
};
|
||||
|
||||
type MuiDialogProps = {
|
||||
title?: {
|
||||
name?: string;
|
||||
icon?: string;
|
||||
};
|
||||
openDialog: boolean;
|
||||
setOpenDialog: Function;
|
||||
content?: ReactElement;
|
||||
id: number;
|
||||
};
|
||||
|
||||
type FormValuesProps = {
|
||||
value: string;
|
||||
active: boolean;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const DialogUpdateStatus = ({ title, openDialog, setOpenDialog, id }: MuiDialogProps) => {
|
||||
const NewCorporateSchema = Yup.object().shape({
|
||||
reason: Yup.string().required('Corporate Status is required'),
|
||||
});
|
||||
|
||||
const methods = useForm<FormValuesProps>({
|
||||
resolver: yupResolver(NewCorporateSchema),
|
||||
});
|
||||
|
||||
const {
|
||||
reset,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
} = methods;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (openDialog === false) {
|
||||
reset();
|
||||
}
|
||||
}, [openDialog, reset]);
|
||||
|
||||
const handleActivate = (id: number, status: string) => {
|
||||
axios
|
||||
.put(`/corporates/${id}/activation`, {
|
||||
active: status == 'active',
|
||||
})
|
||||
.then((res) => {
|
||||
console.log(res)
|
||||
enqueueSnackbar(
|
||||
'Succes',
|
||||
{ variant: 'success' }
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
// console.log('asdasd', error.response.data.message)
|
||||
enqueueSnackbar(
|
||||
error.response.data.message ?? error.message ?? 'Failed Processing Request',
|
||||
{ variant: 'error' }
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmit = async (row : ReturnType<typeof createData>) => {
|
||||
try {
|
||||
handleActivate(1, 'active')
|
||||
} catch (error: any) {
|
||||
|
||||
}
|
||||
|
||||
const ascent = document?.querySelector('ascent');
|
||||
if (ascent != null) {
|
||||
ascent.innerHTML = '';
|
||||
}
|
||||
};
|
||||
|
||||
function createData(corporateService: CorporateService): CorporateService {
|
||||
return {
|
||||
...corporateService,
|
||||
};
|
||||
}
|
||||
|
||||
const getContent = (props: { row: ReturnType<typeof createData> }) => (
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<Stack spacing={3}>
|
||||
<Box sx={{ width: '100%', typography: 'body1', p: 2, mt: 1 }}>
|
||||
<Grid item xs={12}>
|
||||
<RHFSelect
|
||||
name="reason"
|
||||
label="Reason for update"
|
||||
>
|
||||
<option value=""></option>
|
||||
<option value="Agreement changed">Agreement changed</option>
|
||||
<option value="Endorsement">Endorsement</option>
|
||||
<option value="Renewal">Renewal</option>
|
||||
<option value="Worng Setting">Worng Setting</option>
|
||||
</RHFSelect>
|
||||
</Grid>
|
||||
|
||||
<Box sx={{ pt: 5 }}>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
justifyContent="flex-end"
|
||||
direction={{ xs: 'column', md: 'row' }}
|
||||
// sx={{ textAlign: { xs: 'center', md: 'left' } }}
|
||||
spacing={2}
|
||||
>
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Button
|
||||
sx={{
|
||||
boxShadow: 'none',
|
||||
}}
|
||||
variant="outlined"
|
||||
size="medium"
|
||||
fullWidth={true}
|
||||
onClick={() => setOpenDialog(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<LoadingButton
|
||||
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)' }}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="medium"
|
||||
fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
>
|
||||
Save
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Box>
|
||||
</Stack>
|
||||
</FormProvider>
|
||||
);
|
||||
|
||||
return (
|
||||
<MuiDialog
|
||||
title={title}
|
||||
openDialog={openDialog}
|
||||
setOpenDialog={setOpenDialog}
|
||||
content={getContent()}
|
||||
maxWidth="sm"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default DialogUpdateStatus;
|
||||
@@ -3,18 +3,29 @@ import { useNavigate, useParams } from "react-router-dom";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import Page from "../../../components/Page";
|
||||
import useSettings from "../../../hooks/useSettings";
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import {useContext, useEffect, useMemo, useState } from 'react';
|
||||
import axios from '../../../utils/axios';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import CorporatePlanForm from './Form';
|
||||
import { CorporatePlan } from '../../../@types/corporates';
|
||||
import { Corporate } from "@/@types/corporates";
|
||||
import { ConfiguredCorporateContext } from "@/contexts/ConfiguredCorporateContext";
|
||||
|
||||
|
||||
|
||||
export default function PlanCreate() {
|
||||
const { themeStretch } = useSettings();
|
||||
const { corporate_id, id } = useParams();
|
||||
const [corporate, setCorporate] = useState<Corporate|null>();
|
||||
const configuredCorporateContext = useContext(ConfiguredCorporateContext);
|
||||
|
||||
useEffect(() => {
|
||||
setCorporate(configuredCorporateContext.currentCorporate);
|
||||
}, [configuredCorporateContext])
|
||||
|
||||
const [ currentCorporatePlan, setCurrentCorporatePlan ] = useState<CorporatePlan>();
|
||||
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const isEdit = !!id;
|
||||
@@ -44,16 +55,16 @@ export default function PlanCreate() {
|
||||
href: '/corporates',
|
||||
},
|
||||
{
|
||||
name: 'Corporate Name',
|
||||
href: '/corporates/'+corporate_id,
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/'+corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Division',
|
||||
href: '/corporates/'+corporate_id+'/divisions',
|
||||
href: '/corporate/'+corporate_id+'/divisions',
|
||||
},
|
||||
{
|
||||
name: !isEdit ? 'Create' : 'Edit',
|
||||
href: '/corporates/'+corporate_id+'/divisions/'+id,
|
||||
href: '/corporate/'+corporate_id+'/divisions/'+id,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -36,11 +36,11 @@ export default function Divisions() {
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id,
|
||||
href: '/corporates/' + corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Division',
|
||||
href: '/corporate/' + corporate_id + '/divisions',
|
||||
href: '/corporates/' + corporate_id + '/divisions',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -41,6 +41,14 @@ import axios from '../../../utils/axios';
|
||||
import { CorporatePlan } from '../../../@types/corporates';
|
||||
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||
import BasePagination from '../../../components/BasePagination';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||
import HistoryIcon from '@mui/icons-material/History';
|
||||
import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined';
|
||||
import CachedOutlinedIcon from '@mui/icons-material/CachedOutlined';
|
||||
import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
|
||||
export default function PlanList() {
|
||||
const { themeStretch } = useSettings();
|
||||
@@ -97,74 +105,33 @@ export default function PlanList() {
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell>
|
||||
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.id}</TableCell>
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="left">{row.description}</TableCell>
|
||||
<TableCell align="right">
|
||||
<Button variant="outlined" color="success" size="small">
|
||||
Active
|
||||
</Button>
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
<Link to={`/corporate/${row.corporate_id}/divisions/${row.id}/edit`}>
|
||||
<Button variant="outlined" color="success" size="small">
|
||||
Edit
|
||||
</Button>
|
||||
</Link>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={10}>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ borderBottom: 1 }}>
|
||||
<Typography variant="body2" gutterBottom component="div">
|
||||
No Extra Data
|
||||
</Typography>
|
||||
</Box>
|
||||
{false && (
|
||||
<Box sx={{ margin: 1 }}>
|
||||
<Typography variant="h6" gutterBottom component="div">
|
||||
Rules
|
||||
</Typography>
|
||||
<Table size="small" aria-label="purchases">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Date</TableCell>
|
||||
<TableCell>Customer</TableCell>
|
||||
<TableCell align="right">Amount</TableCell>
|
||||
<TableCell align="right">Total price ($)</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{/* {row.history ? row.history.map((historyRow) => ( */}
|
||||
<TableRow key={row.id}>
|
||||
<TableCell component="th" scope="row">
|
||||
{row.start} - {row.end}
|
||||
</TableCell>
|
||||
<TableCell>{row.start}</TableCell>
|
||||
<TableCell align="right">{row.start}</TableCell>
|
||||
<TableCell align="right">{row.start}</TableCell>
|
||||
</TableRow>
|
||||
{/* ))
|
||||
: (
|
||||
<TableRow>
|
||||
<TableCell colSpan={8}>No Data</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
} */}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Box>
|
||||
)}
|
||||
</Collapse>
|
||||
<TableCell align="center">{row.id ? row.id : '-'}</TableCell>
|
||||
<TableCell align="left">{row.code ? row.code : '-'}</TableCell>
|
||||
<TableCell align="left">{row.name ? row.name : '-'}</TableCell>
|
||||
<TableCell align="left">{row.description ? row.description : '-'}</TableCell>
|
||||
<TableCell align="left">
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => navigate ('')}>
|
||||
<FindInPageOutlinedIcon />
|
||||
Details
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => handleEditData(row)}>
|
||||
<EditOutlinedIcon />
|
||||
Edit
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => handleEditDataStatus(row)}>
|
||||
<CachedOutlinedIcon />
|
||||
Update Status
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate ('')}>
|
||||
<HistoryIcon />
|
||||
History
|
||||
</MenuItem>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
@@ -194,7 +161,6 @@ export default function PlanList() {
|
||||
const response = await axios.get('/corporates/' + corporate_id + '/divisions', {
|
||||
params: filter,
|
||||
});
|
||||
// console.log(response.data);
|
||||
setDataTableLoading(false);
|
||||
|
||||
setDataTableData(response.data);
|
||||
@@ -219,48 +185,147 @@ export default function PlanList() {
|
||||
loadDataTableData();
|
||||
}, []);
|
||||
|
||||
// Dialog for devisions
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
//validation dialog
|
||||
const [nameField, setNameField] = useState('');
|
||||
const [nameFieldError, setNameFieldError] = useState('');
|
||||
const [codeField, setCodeField] = useState('');
|
||||
const [codeFieldError, setCodeFieldError] = useState('');
|
||||
const [descriptionField, setDescriptionField] = useState('');
|
||||
// ID for edit data
|
||||
const [idField, setIdField] = useState('');
|
||||
|
||||
const isRequiredFieldsFilled = () => {
|
||||
return nameField.trim() !== '' && codeField.trim() !== '';
|
||||
};
|
||||
|
||||
const handleAddData = () => {
|
||||
setOpenDialog(true);
|
||||
}
|
||||
|
||||
const handleCloseDialog = () => {
|
||||
setOpenDialog(false);
|
||||
setNameField('');
|
||||
setCodeField('');
|
||||
setDescriptionField('');
|
||||
setIdField('');
|
||||
}
|
||||
|
||||
const handleSaveData = () => {
|
||||
const addData = {
|
||||
code: codeField,
|
||||
name: nameField,
|
||||
description: descriptionField,
|
||||
};
|
||||
// Check conditions add or update data
|
||||
if(idField)
|
||||
{
|
||||
// Update data
|
||||
axios
|
||||
.put('/corporates/'+corporate_id+'/divisions/'+idField+'', addData)
|
||||
.then((response) => {
|
||||
enqueueSnackbar('Data saved successfully', { variant: 'success' });
|
||||
loadDataTableData();
|
||||
handleCloseDialog();
|
||||
})
|
||||
.catch((error) => {
|
||||
enqueueSnackbar('Failed to add data', { variant: 'error' });
|
||||
});
|
||||
}
|
||||
else{
|
||||
// Save data
|
||||
axios
|
||||
.post('/corporates/'+corporate_id+'/divisions', addData)
|
||||
.then((response) => {
|
||||
enqueueSnackbar('Data saved successfully', { variant: 'success' });
|
||||
loadDataTableData();
|
||||
handleCloseDialog();
|
||||
})
|
||||
.catch((error) => {
|
||||
enqueueSnackbar('Failed to add data', { variant: 'error' });
|
||||
});
|
||||
}
|
||||
}
|
||||
//Edit data
|
||||
const handleEditData = (data) => {
|
||||
setIdField(data.id)
|
||||
setNameField(data.name);
|
||||
setCodeField(data.code);
|
||||
setDescriptionField(data.description);
|
||||
setOpenDialog(true);
|
||||
}
|
||||
// End dialog for devisions
|
||||
|
||||
// Dialog for update status devisions
|
||||
const [openDialogStatus, setOpenDialogStatus] = useState(false);
|
||||
// Active for update status
|
||||
const [activeField, setActiveField] = useState('');
|
||||
const handleCloseDialogStatus = () => {
|
||||
setOpenDialogStatus(false);
|
||||
setNameField('');
|
||||
setCodeField('');
|
||||
setDescriptionField('');
|
||||
setIdField('');
|
||||
setActiveField('');
|
||||
}
|
||||
|
||||
const handleSaveDataStatus = () => {
|
||||
|
||||
}
|
||||
|
||||
const handleEditDataStatus = (data) => {
|
||||
setIdField(data.id)
|
||||
setNameField(data.name);
|
||||
setCodeField(data.code);
|
||||
setDescriptionField(data.description);
|
||||
setActiveField(data.active);
|
||||
setOpenDialogStatus(true);
|
||||
}
|
||||
// End dialog for update status devisions
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter} />
|
||||
<Link to={`/corporate/${corporate_id}/divisions/create`}>
|
||||
<Button
|
||||
component="button"
|
||||
id="upload-button"
|
||||
variant="outlined"
|
||||
startIcon={<AddIcon />}
|
||||
sx={{ p: 1.8 }}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
</Link>
|
||||
<Button
|
||||
component="button"
|
||||
id="upload-button"
|
||||
startIcon={<AddIcon />}
|
||||
sx={{ p: 1.8, color: '#FFFFFF', backgroundColor: '#19BBBB', width: '125px', height: '48px' }}
|
||||
onClick={handleAddData}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
<Card>
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" />
|
||||
<TableCell style={headStyle} align="left">
|
||||
ID
|
||||
<TableCell sx={{width: '10%'}} align="center">
|
||||
<Typography variant='subtitle2'>ID</Typography>
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Code
|
||||
<TableCell sx={{width: '10%'}} align="left">
|
||||
<Typography variant='subtitle2'>Code</Typography>
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Name
|
||||
<TableCell sx={{width: '20%'}} align="left">
|
||||
<Typography variant='subtitle2'>Name</Typography>
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Description
|
||||
<TableCell sx={{width: '50%'}} align="left">
|
||||
<Typography variant='subtitle2'>Description</Typography>
|
||||
</TableCell>
|
||||
<TableCell sx={{width: '10%'}} align="left">
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</TableHead>
|
||||
{dataTableIsLoading ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">
|
||||
<TableCell colSpan={4} align="center">
|
||||
Loading
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -268,7 +333,7 @@ export default function PlanList() {
|
||||
) : dataTableData.data.length == 0 ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">
|
||||
<TableCell colSpan={4} align="center">
|
||||
No Data
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -284,6 +349,101 @@ export default function PlanList() {
|
||||
</TableContainer>
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||
</Card>
|
||||
{/* Dialog */}
|
||||
<Dialog open={openDialog} onClose={handleCloseDialog} 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}>
|
||||
{idField ? (
|
||||
<>
|
||||
<Typography variant="h6">Edit Data</Typography>
|
||||
</>
|
||||
): (
|
||||
<>
|
||||
<Typography variant="h6">Create Data</Typography>
|
||||
</>
|
||||
)}
|
||||
|
||||
</Stack>
|
||||
<IconButton sx={{ color: '#FFF' }} onClick={handleCloseDialog}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Stack spacing={2} sx={{marginTop: 2}}>
|
||||
<TextField
|
||||
label="Code"
|
||||
required
|
||||
value={codeField ? codeField : ''}
|
||||
onChange={(e) =>{
|
||||
setCodeField(e.target.value);
|
||||
setCodeFieldError(e.target.value.trim() === '' ? 'This field is required' : '');
|
||||
}}
|
||||
fullWidth
|
||||
inputProps={{ maxLength: 50 }}
|
||||
error={!!codeFieldError}
|
||||
helperText={codeFieldError}
|
||||
/>
|
||||
<TextField
|
||||
label="Name"
|
||||
required
|
||||
value={nameField ? nameField : ''}
|
||||
onChange={(e) =>{
|
||||
setNameField(e.target.value);
|
||||
setNameFieldError(e.target.value.trim() === '' ? 'This field is required' : '');
|
||||
}}
|
||||
fullWidth
|
||||
inputProps={{ maxLength: 50 }}
|
||||
error={!!nameFieldError}
|
||||
helperText={nameFieldError}
|
||||
/>
|
||||
<TextField
|
||||
label="Description"
|
||||
value={descriptionField ? descriptionField : ''}
|
||||
onChange={(e) =>{
|
||||
setDescriptionField(e.target.value);
|
||||
}}
|
||||
fullWidth
|
||||
inputProps={{ maxLength: 255 }}
|
||||
/>
|
||||
</Stack>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleCloseDialog}>Cancel</Button>
|
||||
<Button onClick={handleSaveData} variant="contained" color="primary" disabled={!isRequiredFieldsFilled()}>Save</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
{/* Dialog Update Status */}
|
||||
<Dialog open={openDialogStatus} onClose={handleCloseDialogStatus} 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">Update Status</Typography>
|
||||
</Stack>
|
||||
<IconButton sx={{ color: '#FFF' }} onClick={handleCloseDialogStatus}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Stack spacing={2} padding={2}>
|
||||
<Typography variant='body1'>Are you sure to inactive this division ?</Typography>
|
||||
<Card>
|
||||
<Stack direction='row' spacing={2}>
|
||||
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Code</Typography>
|
||||
<Typography variant='subtitle2' sx={{width: '70%'}}>{codeField}</Typography>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Stack>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={handleCloseDialogStatus}>Cancel</Button>
|
||||
<Button onClick={handleSaveDataStatus} variant="contained" color="error">Inactive</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,14 +10,19 @@ import { styled } from '@mui/material/styles';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
FormHelperText,
|
||||
FormLabel,
|
||||
Grid,
|
||||
InputLabel,
|
||||
Menu,
|
||||
MenuItem,
|
||||
OutlinedInput,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
Stack,
|
||||
@@ -44,6 +49,8 @@ import { fCurrency } from '../../utils/formatNumber';
|
||||
import RHFAutocomplete from '../../components/hook-form/RHFAutocomplete';
|
||||
import UploadImage from '../../components/UploadImage';
|
||||
import { fPostFormat } from '@/utils/formatTime';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import Link from '@/theme/overrides/Link';
|
||||
|
||||
const LabelStyle = styled(Typography)(({ theme }) => ({
|
||||
...theme.typography.subtitle2,
|
||||
@@ -117,12 +124,14 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
NewCorporateSchema = Yup.object().shape({
|
||||
isEdited: Yup.boolean(),
|
||||
name: Yup.string().required('Name is required'),
|
||||
|
||||
code: Yup.string()
|
||||
.required('Corporate Code is required')
|
||||
.test('unique-code', 'Code must be unique', async function (value) {
|
||||
const existingCodes = await getExistingCodes();
|
||||
return !existingCodes.includes(value);
|
||||
}),
|
||||
}),
|
||||
// payor_id: Yup.string().required('Payor is required'),
|
||||
active: Yup.boolean().required('Corporate Status is required'),
|
||||
type: Yup.string().required('Type is required'),
|
||||
welcome_message: Yup.string().required('Welcome Message is required'),
|
||||
@@ -487,9 +496,10 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
<Card sx={{ p: 3 }}>
|
||||
<Stack spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h5">Corporate Profile</Typography>
|
||||
<Typography variant="h5" color={'primary'}>Corporate Profile</Typography>
|
||||
</Grid>
|
||||
|
||||
<Typography variant='subtitle1' color="#637381">Corporate Profile*</Typography>
|
||||
<RHFSelect name="type" label="Type" placeholder="Type">
|
||||
<option value="" />
|
||||
{types.map((option, index) => (
|
||||
@@ -516,10 +526,13 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
))}
|
||||
</RHFSelect>
|
||||
)}
|
||||
<Typography variant='subtitle1' color="#637381">Corporate Code*</Typography>
|
||||
<RHFTextField name="code" label="Corporate Code" disabled={isDisabled} />
|
||||
|
||||
<Typography variant='subtitle1' color="#637381">Corporate Name*</Typography>
|
||||
<RHFTextField name="name" label="Corporate Name" disabled={isDisabled} />
|
||||
|
||||
<Typography variant='subtitle1' color="#637381">Payor ID*</Typography>
|
||||
<RHFTextField name="payor_id" label="Payor ID" disabled={isDisabled} />
|
||||
|
||||
{isEdit && (
|
||||
@@ -534,15 +547,15 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
)}
|
||||
|
||||
<Stack spacing={1}>
|
||||
<Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
|
||||
Welcome Message
|
||||
<Typography variant="subtitle1" color="#637381">
|
||||
Welcome Message *
|
||||
</Typography>
|
||||
<RHFEditor name="welcome_message" />
|
||||
<RHFEditor name="welcome_message" placeholder="Akun anda telah terverifikasi"/>
|
||||
</Stack>
|
||||
|
||||
<Stack spacing={1}>
|
||||
<Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
|
||||
Help Text
|
||||
<Typography variant="subtitle1" color="#637381">
|
||||
Help Text *
|
||||
</Typography>
|
||||
<RHFEditor name="help_text" />
|
||||
</Stack>
|
||||
@@ -614,27 +627,30 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
{/* <Card sx={{ p:3, mb:3, background: 'gray', color: 'white' }}><Typography>Policy Detail</Typography></Card> */}
|
||||
<Card sx={{ p: 3 }}>
|
||||
<Stack spacing={3} mt={2}>
|
||||
<Typography variant="h5">Policy Detail</Typography>
|
||||
<Typography variant="h5" color={'primary'}>Policy Detail</Typography>
|
||||
|
||||
<input type="hidden" name="policy_id" />
|
||||
|
||||
<Stack spacing={1}>
|
||||
<Typography variant="subtitle2">Policy Number*</Typography>
|
||||
<RHFTextField name="policy_code" label="Policy Number" />
|
||||
{!currentCorporate?.id && (
|
||||
<Typography variant="caption">Will be generated if empty</Typography>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
{/* <Typography>Minimal Deposit Policy Level</Typography> */}
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<RHFDatepicker name="policy_start" label="Start Date" />
|
||||
<Typography variant="subtitle2" sx={{marginBottom: '10px'}}>Tanggal Mulai Kerjasama*</Typography>
|
||||
<RHFDatepicker name="policy_start" label="Start Date *" />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<RHFDatepicker name="policy_end" label="End Date" />
|
||||
<Typography variant="subtitle2" sx={{marginBottom: '10px'}}>Tanggal Akhir Kerjasama*</Typography>
|
||||
<RHFDatepicker name="policy_end" label="End Date *" />
|
||||
</Grid>
|
||||
</Stack>
|
||||
|
||||
<Typography variant="subtitle2">Deposit Intial Fund*</Typography>
|
||||
<RHFTextField
|
||||
name="policy_total_premi"
|
||||
label={'Deposit Intial Fund (' + fCurrency(values.policy_total_premi) + ')'}
|
||||
@@ -643,7 +659,7 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
|
||||
<Typography variant="subtitle2">
|
||||
Minimal Deposit Policy Level
|
||||
</Typography>
|
||||
</Grid>
|
||||
@@ -667,7 +683,7 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
|
||||
<Typography variant="subtitle2">
|
||||
Minimal Alert Level
|
||||
</Typography>
|
||||
</Grid>
|
||||
@@ -691,7 +707,7 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
|
||||
<Typography variant="subtitle2">
|
||||
Stop Service Level
|
||||
</Typography>
|
||||
</Grid>
|
||||
@@ -716,16 +732,106 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<Grid item xs={12} md={4}>
|
||||
<LoadingButton
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="large"
|
||||
fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
>
|
||||
{!isEdit ? 'Save New Corporate' : 'Save Corporate'}
|
||||
</LoadingButton>
|
||||
{/* Type contrack */}
|
||||
{/* <Grid item xs={12} md={12}>
|
||||
<Card sx={{ p: 3 }}>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Typography variant="h5" color="#19BBBB">Tipe Pembayaran</Typography>
|
||||
</Grid>
|
||||
<Grid container item xs={12} md={12} justifyContent="flex-end">
|
||||
<Button
|
||||
size='small'
|
||||
variant="contained"
|
||||
startIcon={<AddIcon sx={{ color: 'black', fontWeight: 'bold' }} />}
|
||||
sx={{ p: 1.8, typography: 'subtitle2', backgroundColor: '#DFE3E8' }}
|
||||
>
|
||||
<Typography variant="subtitle2" color="black">Contract</Typography>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Stack>
|
||||
|
||||
<Grid item xs={12} md={12}>
|
||||
<Typography variant="h5">#1</Typography>
|
||||
</Grid>
|
||||
|
||||
<Stack direction="row" spacing={4} sx={{marginTop: '24px'}}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Typography variant="subtitle1" >Tanggal Mulai Kontrak*</Typography>
|
||||
</Grid>
|
||||
<Grid container item xs={12} md={6}>
|
||||
<Typography variant="subtitle1">Tanggal Akhir Kontrak*</Typography>
|
||||
</Grid>
|
||||
</Stack>
|
||||
<Stack direction="row" spacing={4} sx={{marginTop: '24px'}}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<RHFDatepicker name="contract_start" label="Start Date" />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<RHFDatepicker name="contract_start" label="End Date" />
|
||||
</Grid>
|
||||
</Stack>
|
||||
|
||||
<Grid item xs={12} md={12} sx={{marginTop: '24px'}}>
|
||||
<Typography variant="subtitle2">Tipe Pembayaran</Typography>
|
||||
<RadioGroup
|
||||
aria-labelledby="demo-radio-buttons-group-label"
|
||||
defaultValue="female"
|
||||
name="type_payment"
|
||||
>
|
||||
<FormControlLabel value="1" control={<Radio />} label="Deposit" />
|
||||
<FormControlLabel value="2" control={<Radio />} label="Hutang" />
|
||||
<FormControlLabel value="3" control={<Radio />} label="Penagihan Hutang" />
|
||||
</RadioGroup>
|
||||
</Grid>
|
||||
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Grid container item xs={12} md={12} justifyContent="flex-end">
|
||||
<Button
|
||||
size='small'
|
||||
variant="contained"
|
||||
startIcon={<AddIcon sx={{ color: 'black', fontWeight: 'bold' }} />}
|
||||
sx={{ p: 1.8, typography: 'subtitle2', backgroundColor: '#FFFFFF', marginRight: '20px' }}
|
||||
>
|
||||
<Typography variant="subtitle2" color="black">Cancel</Typography>
|
||||
</Button>
|
||||
<LoadingButton
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="small"
|
||||
loading={isSubmitting}
|
||||
>
|
||||
<Typography variant="subtitle2" color="black">Save</Typography>
|
||||
</LoadingButton>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Grid> */}
|
||||
|
||||
<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(`/corporates`)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<LoadingButton
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="large"
|
||||
// fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
>
|
||||
Save
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</FormProvider>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Card, Grid } from '@mui/material';
|
||||
import { Card, Grid, Container } from '@mui/material';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
|
||||
import Page from '../../../components/Page';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import CorporateTabNavigations from '../CorporateTabNavigations';
|
||||
import List from './List';
|
||||
import List from './New/List';
|
||||
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import { ConfiguredCorporateContext } from '@/contexts/ConfiguredCorporateContext';
|
||||
@@ -24,9 +24,9 @@ export default function CorporateFormularium() {
|
||||
}, [configuredCorporateContext]);
|
||||
|
||||
return (
|
||||
<Page title="Formularium">
|
||||
<Page title="Corporate Formularium">
|
||||
<HeaderBreadcrumbs
|
||||
heading={'Formularium'}
|
||||
heading={'Corporate Formularium'}
|
||||
links={[
|
||||
{
|
||||
name: 'Corporates',
|
||||
@@ -34,17 +34,17 @@ export default function CorporateFormularium() {
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id,
|
||||
href: '/corporates/' + corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Formularium',
|
||||
href: '/corporate/' + corporate_id + '/formularium',
|
||||
href: '/corporates/' + corporate_id + '/formulariums',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Card>
|
||||
<CorporateTabNavigations position={'formularium'} />
|
||||
<CorporateTabNavigations position={'formulariums'} />
|
||||
<List />
|
||||
</Card>
|
||||
</Page>
|
||||
|
||||
355
frontend/dashboard/src/pages/Corporates/Formularium/List-old.tsx
Normal file
355
frontend/dashboard/src/pages/Corporates/Formularium/List-old.tsx
Normal file
@@ -0,0 +1,355 @@
|
||||
// @mui
|
||||
import { Box, Button, Card, Collapse, IconButton, InputLabel, MenuItem, OutlinedInput, Paper, Select, SelectChangeEvent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Badge, Tab, Tabs, CardHeader, Stack, Menu, ButtonGroup, Input, Grid } from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
// hooks
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
// components
|
||||
import axios from '../../../utils/axios';
|
||||
import { CorporatePlan } from '../../../@types/corporates';
|
||||
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||
import BasePagination from '../../../components/BasePagination';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
|
||||
|
||||
export default function PlanList() {
|
||||
const { themeStretch } = useSettings();
|
||||
const { corporate_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Dummy Default Data
|
||||
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>({
|
||||
current_page: 1,
|
||||
data: [],
|
||||
path: "",
|
||||
first_page_url: "",
|
||||
last_page: 1,
|
||||
last_page_url: "",
|
||||
next_page_url: "",
|
||||
prev_page_url: "",
|
||||
per_page: 10,
|
||||
from: 0,
|
||||
to: 0,
|
||||
total: 0
|
||||
});
|
||||
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
// const filterForm = useRef();
|
||||
const [searchText, setSearchText] = useState("");
|
||||
const [searchStatus, setSearchStatus] = useState("active");
|
||||
|
||||
const handleSearchChange = (event: any) => {
|
||||
const newSearchText = event.target.value ?? ''
|
||||
setSearchText(newSearchText);
|
||||
}
|
||||
|
||||
const handleStatusChange = (event: any) => {
|
||||
const newSearchStatus = event.target.value ?? ''
|
||||
console.log('changing to', newSearchStatus)
|
||||
setSearchStatus(newSearchStatus)
|
||||
// console.log(searchStatus);
|
||||
|
||||
const searchFilter = {
|
||||
"search" : searchText,
|
||||
"status" : newSearchStatus
|
||||
};
|
||||
|
||||
props.onSearch(searchFilter);
|
||||
}
|
||||
|
||||
const handleSubmit = (event?: any) => {
|
||||
event?.preventDefault();
|
||||
const searchFilter = {
|
||||
"search" : searchText,
|
||||
"status" : searchStatus
|
||||
};
|
||||
|
||||
props.onSearch(searchFilter); // Trigger to Parent
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
setSearchStatus(searchParams.get('status') ?? searchStatus ?? 'active');
|
||||
}, [searchParams])
|
||||
|
||||
return (
|
||||
<form id="search-form" onSubmit={handleSubmit} style={{ width: '100%' }}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={9}>
|
||||
<TextField id="search-input" ref={searchInput} label="Search" variant="outlined" fullWidth onChange={handleSearchChange} value={searchText}/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={3}>
|
||||
<Select
|
||||
label="Status"
|
||||
value={searchStatus}
|
||||
onChange={handleStatusChange}
|
||||
sx={{ width: '100%' }}
|
||||
>
|
||||
<MenuItem value="active">Active</MenuItem>
|
||||
<MenuItem value="inactive">Inactive</MenuItem>
|
||||
<MenuItem value="all">All</MenuItem>
|
||||
</Select>
|
||||
</Grid>
|
||||
{/* ITS FUCKING MAGIC, SUBMIT BY ENTER WORKING IF THIS BUTTON IS AVAILABLE */}
|
||||
<Button type='submit' variant="outlined" sx={{ p: 1.8, display: 'none' }}>Search</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
// Called on every row to map the data to the columns
|
||||
function createData( plan: CorporatePlan ): CorporatePlan {
|
||||
return {
|
||||
...plan,
|
||||
}
|
||||
}
|
||||
|
||||
const handleInactiveAction = (formularium : any) => {
|
||||
enqueueSnackbar('Fuck yuo'), { variant: 'error' };
|
||||
axios
|
||||
.put('/corporates/'+corporate_id+'/formulariums/'+formularium.id+'/activate')
|
||||
.then(() => {
|
||||
setDataTableData(
|
||||
{
|
||||
...dataTableData,
|
||||
data: dataTableData.data.map((item: any) => {
|
||||
if (item.id === formularium.id) {
|
||||
return {
|
||||
...item,
|
||||
status: 'active'
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
})
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
enqueueSnackbar(error.data?.message ?? (error.message ?? 'Failed Processing Request'), { variant: 'error' });
|
||||
})
|
||||
}
|
||||
|
||||
const handleActiveAction = (formularium : any) => {
|
||||
axios
|
||||
.put('/corporates/'+corporate_id+'/formulariums/'+formularium.id+'/deactivate')
|
||||
.then(() => {
|
||||
setDataTableData(
|
||||
{
|
||||
...dataTableData,
|
||||
data: dataTableData.data.map((item: any) => {
|
||||
if (item.id === formularium.id) {
|
||||
return {
|
||||
...item,
|
||||
status: 'inactive'
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
})
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' });
|
||||
})
|
||||
}
|
||||
|
||||
// Generate the every row of the table
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell>
|
||||
<IconButton
|
||||
aria-label="expand row"
|
||||
size="small"
|
||||
onClick={() => setOpen(!open)}
|
||||
>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.atc_code}</TableCell>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="left">{row.category_name}</TableCell>
|
||||
<TableCell align="left">{row.uom}</TableCell>
|
||||
{/* <TableCell align="left">{row.items_count}</TableCell> */}
|
||||
<TableCell align="right">{( row.status == 'active' ?
|
||||
<Button variant="outlined" onClick={() => { handleActiveAction(row) }} color="success" size="small">Active</Button> :
|
||||
<Button variant="outlined" onClick={() => { handleInactiveAction(row) }} color="error" size="small">Tidak Digunakan</Button>
|
||||
)}</TableCell>
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
<TableCell />
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={15}>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ pb: 2 }}>
|
||||
<Typography sx={{ fontWeight: '600', mb: 1 }}>Detail</Typography>
|
||||
<Grid container sx={{ pb: 2, mb: 2, borderBottom: 1 }}>
|
||||
<Grid item xs={6}>
|
||||
<Grid container>
|
||||
<Grid item xs={4}>
|
||||
Description
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
: {row.description ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
General Indication
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
: {row.general_indication ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
Composition
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
: {row.composition ?? '-'}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid container>
|
||||
<Grid item xs={4}>
|
||||
Kategori Obat
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
: {row.kategori_obat ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
BPOM Registration
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
: {row.bpom_registration ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
Classifications
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
: {row.classifications ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
Cat For
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
: {row.cat_for ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
Class
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
: {row.class ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
Manufacturer
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
: {row.manufacturer ?? '-'}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
const loadDataTableData = async (appliedFilter : any | null = null) => {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const response = await axios.get('/corporates/'+corporate_id+'/formulariums', { params: filter });
|
||||
// console.log(response.data);
|
||||
setDataTableLoading(false);
|
||||
|
||||
setDataTableData(response.data);
|
||||
}
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const applyFilter = async (searchFilter: any) => {
|
||||
await loadDataTableData(searchFilter);
|
||||
setSearchParams(searchFilter);
|
||||
}
|
||||
|
||||
const handlePageChange = (event : ChangeEvent, value: number) => {
|
||||
const filter = Object.fromEntries([...searchParams.entries(), ["page", value]]);
|
||||
loadDataTableData(filter);
|
||||
setSearchParams(filter);
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter}/>
|
||||
</Stack>
|
||||
|
||||
<Card>
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" />
|
||||
<TableCell style={headStyle} align="left">Code</TableCell>
|
||||
<TableCell style={headStyle} align="left">ATC Code</TableCell>
|
||||
<TableCell style={headStyle} align="left">Name</TableCell>
|
||||
<TableCell style={headStyle} align="left">Category Name</TableCell>
|
||||
<TableCell style={headStyle} align="left">UOM</TableCell>
|
||||
<TableCell style={headStyle} align="center">Status</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
{dataTableIsLoading ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">Loading</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
dataTableData.data.length == 0 ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">No Data</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody>
|
||||
{dataTableData.data.map(row => (
|
||||
<Row key={row.code} row={row} />
|
||||
))}
|
||||
</TableBody>
|
||||
)
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange}/>
|
||||
</Card>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// @mui
|
||||
import { Box, Button, Card, Collapse, IconButton, InputLabel, MenuItem, OutlinedInput, Paper, Select, SelectChangeEvent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Badge, Tab, Tabs, CardHeader, Stack, Menu, ButtonGroup, Input, Grid } from '@mui/material';
|
||||
import { Box, Button, Card, Collapse, IconButton, InputLabel, MenuItem, OutlinedInput, Paper, Grid, Select, SelectChangeEvent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Badge, Tab, Tabs, CardHeader, Stack, Menu, ButtonGroup, Pagination } from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
@@ -8,23 +8,307 @@ import CancelIcon from '@mui/icons-material/Cancel';
|
||||
// hooks
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
// components
|
||||
import axios from '../../../utils/axios';
|
||||
import { CorporatePlan } from '../../../@types/corporates';
|
||||
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||
import { Icd } from '../../../@types/diagnosis';
|
||||
import BasePagination from '../../../components/BasePagination';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
|
||||
|
||||
export default function PlanList() {
|
||||
export default function List() {
|
||||
const navigate = useNavigate();
|
||||
const { themeStretch } = useSettings();
|
||||
const { corporate_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const navigate = useNavigate();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const handleSearchChange = (event: any) => {
|
||||
const newSearchText = event.target.value ?? ''
|
||||
setSearchText(newSearchText);
|
||||
}
|
||||
|
||||
const handleSearchSubmit = (event: any) => {
|
||||
event.preventDefault();
|
||||
props.onSearch(searchText); // Trigger to Parent
|
||||
}
|
||||
|
||||
useEffect(() => { // Trigger First Search
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
}, [searchParams])
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '100%' }}>
|
||||
<TextField id="search-input" ref={searchInput} label="Search" variant="outlined" fullWidth onChange={handleSearchChange} value={searchText}/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
function ImportForm(props: any) {
|
||||
// IMPORT
|
||||
// Create Button Menu
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const createMenu = Boolean(anchorEl);
|
||||
const importForm = useRef<HTMLInputElement>(null)
|
||||
const [currentImportFileName, setCurrentImportFileName] = useState(null)
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleImportButton = () => {
|
||||
if (importForm?.current) {
|
||||
handleClose();
|
||||
importForm.current ? importForm.current.click() : console.log('No File selected');
|
||||
} else {
|
||||
alert('No file selected')
|
||||
}
|
||||
}
|
||||
|
||||
const handleCancelImportButton = () => {
|
||||
importForm.current.value = "";
|
||||
importForm.current.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
}
|
||||
|
||||
const handleGetTemplate = (type :string) => {
|
||||
axios.get('corporates/import-document-example/' + type)
|
||||
.then((response) => {
|
||||
const link = document.createElement('a');
|
||||
link.href = response.data.data.file_url;
|
||||
link.setAttribute('download', response.data.data.file_name);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
handleClose();
|
||||
})
|
||||
}
|
||||
|
||||
const handleImportChange = (event: any) => {
|
||||
if (event.target.files[0]) {
|
||||
setCurrentImportFileName(event.target.files[0].name)
|
||||
} else {
|
||||
setCurrentImportFileName(null);
|
||||
}
|
||||
}
|
||||
|
||||
const handleFormulariumList = async (appliedFilter = null) => {
|
||||
axios.get(`corporates/${corporate_id}/formulariums/list`).then((response) => {
|
||||
const link = document.createElement('a');
|
||||
link.href = response.data.data.file_url;
|
||||
link.setAttribute('download', response.data.data.file_name);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
handleClose();
|
||||
enqueueSnackbar('Download Success', { variant: 'succes' })
|
||||
})
|
||||
.catch(response => {
|
||||
enqueueSnackbar('Looks like something went wrong. Please check your data and try again. ' + response.message, { variant: 'error' })
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
const handleUpload = () => {
|
||||
if (importForm.current?.files.length) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", importForm.current?.files[0])
|
||||
axios.post(`corporates/${corporate_id}/formulariums/import`, formData )
|
||||
.then(response => {
|
||||
handleCancelImportButton();
|
||||
loadDataTableData();
|
||||
setImportResult(response.data)
|
||||
// alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows');
|
||||
})
|
||||
.catch(response => {
|
||||
enqueueSnackbar('Looks like something went wrong. Please check your data and try again. ' + response.message, { variant: 'error' })
|
||||
})
|
||||
} else {
|
||||
enqueueSnackbar('No File Selected', { variant: 'warning' })
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<input type='file' id='file' ref={importForm} style={{ display: 'none' }} onChange={handleImportChange} accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain" />
|
||||
{( !currentImportFileName && <Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter}/>
|
||||
{/* <h1>kjasndkjandskjasndkjansdkjansd</h1> */}
|
||||
<Button
|
||||
id="import-button"
|
||||
variant='outlined'
|
||||
startIcon={<AddIcon />} sx={{ p: 1.8 }}
|
||||
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={createMenu ? 'true' : undefined}
|
||||
onClick={handleClick}
|
||||
>
|
||||
Import
|
||||
</Button>
|
||||
<Menu
|
||||
id="import-button"
|
||||
anchorEl={anchorEl}
|
||||
open={createMenu}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
'aria-labelledby': 'basic-button',
|
||||
}}
|
||||
>
|
||||
{/* <MenuItem onClick={() => {navigate(`/master/formularium/create/${formularium_template_id}`)} }>Create</MenuItem> */}
|
||||
<MenuItem onClick={handleImportButton}>Import</MenuItem>
|
||||
<MenuItem onClick={() => {handleGetTemplate('master-formularium-corporate')}}>Download Template</MenuItem>
|
||||
<MenuItem onClick={handleFormulariumList}>Download Formularium</MenuItem>
|
||||
</Menu>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{( currentImportFileName && <Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<ButtonGroup variant="outlined" aria-label="outlined button group" fullWidth>
|
||||
<Button onClick={handleImportButton} fullWidth>{currentImportFileName ?? "No File Selected"}</Button>
|
||||
<Button onClick={handleCancelImportButton} size="small" fullWidth={false} sx={{ p: 1.8 }}><CancelIcon color="error"/></Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<Button
|
||||
id="upload-button"
|
||||
variant='outlined'
|
||||
startIcon={<UploadIcon />} sx={{ p: 1.8 }}
|
||||
onClick={handleUpload}
|
||||
>
|
||||
Upload
|
||||
</Button>
|
||||
</Stack>
|
||||
)}
|
||||
{( importResult &&
|
||||
<Stack direction={'row'} sx={{ px: 2, pb: 2 }}>
|
||||
<Box sx={{ color: "text.secondary" }}>Last Import Result Report : <a href={importResult.result_file?.url ?? "#"}>{importResult.result_file?.name ?? "-"}</a></Box>
|
||||
</Stack>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Called on every row to map the data to the columns
|
||||
function createData( icd: Icd ): Icd {
|
||||
return {
|
||||
...icd,
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the every row of the table
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell>
|
||||
<IconButton
|
||||
aria-label="expand row"
|
||||
size="small"
|
||||
onClick={() => setOpen(!open)}
|
||||
>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.atc_code}</TableCell>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="left">{row.category_name}</TableCell>
|
||||
<TableCell align="left">{row.uom}</TableCell>
|
||||
<TableCell align="left">{row.active}</TableCell>
|
||||
|
||||
{/* <TableCell align="right"><Button variant="outlined" color="success" size="small">Active</Button></TableCell>
|
||||
<TableCell align="right"><Button variant="outlined" color="error" size="small">Disable</Button></TableCell> */}
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
<TableCell />
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={15}>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ pb: 2 }}>
|
||||
<Typography sx={{ fontWeight: '600', mb: 1 }}>Detail</Typography>
|
||||
<Grid container sx={{ pb: 2, mb: 2, borderBottom: 1 }}>
|
||||
<Grid item xs={6}>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
Description
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.description ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
General Indication
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.general_indication ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
Composition
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.composition ?? '-'}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
Kategori Obat
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.kategori_obat ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
BPOM Registration
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.bpom_registration ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
Classifications
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.classifications ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
Cat For
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.cat_for ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
Class
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.class ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
Manufacturer
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.manufacturer ?? '-'}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
// Dummy Default Data
|
||||
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||
const [dataTableLastRequest, setDataTableLastRequest] = useState(0);
|
||||
const [dataTableResponseState, setDataTableResponseState] = useState('idle');
|
||||
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>({
|
||||
current_page: 1,
|
||||
data: [],
|
||||
@@ -39,169 +323,12 @@ export default function PlanList() {
|
||||
to: 0,
|
||||
total: 0
|
||||
});
|
||||
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
// const filterForm = useRef();
|
||||
const [searchText, setSearchText] = useState("");
|
||||
const [searchStatus, setSearchStatus] = useState("active");
|
||||
|
||||
const handleSearchChange = (event: any) => {
|
||||
const newSearchText = event.target.value ?? ''
|
||||
setSearchText(newSearchText);
|
||||
}
|
||||
|
||||
const handleStatusChange = (event: any) => {
|
||||
const newSearchStatus = event.target.value ?? ''
|
||||
console.log('changing to', newSearchStatus)
|
||||
setSearchStatus(newSearchStatus)
|
||||
// console.log(searchStatus);
|
||||
|
||||
const searchFilter = {
|
||||
"search" : searchText,
|
||||
"status" : newSearchStatus
|
||||
};
|
||||
|
||||
props.onSearch(searchFilter);
|
||||
}
|
||||
|
||||
const handleSubmit = (event?: any) => {
|
||||
event?.preventDefault();
|
||||
const searchFilter = {
|
||||
"search" : searchText,
|
||||
"status" : searchStatus
|
||||
};
|
||||
|
||||
props.onSearch(searchFilter); // Trigger to Parent
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
setSearchStatus(searchParams.get('status') ?? searchStatus ?? 'active');
|
||||
}, [searchParams])
|
||||
|
||||
return (
|
||||
<form id="search-form" onSubmit={handleSubmit} style={{ width: '100%' }}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={9}>
|
||||
<TextField id="search-input" ref={searchInput} label="Search" variant="outlined" fullWidth onChange={handleSearchChange} value={searchText}/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={3}>
|
||||
<Select
|
||||
label="Status"
|
||||
value={searchStatus}
|
||||
onChange={handleStatusChange}
|
||||
sx={{ width: '100%' }}
|
||||
>
|
||||
<MenuItem value="active">Active</MenuItem>
|
||||
<MenuItem value="inactive">Inactive</MenuItem>
|
||||
<MenuItem value="all">All</MenuItem>
|
||||
</Select>
|
||||
</Grid>
|
||||
{/* ITS FUCKING MAGIC, SUBMIT BY ENTER WORKING IF THIS BUTTON IS AVAILABLE */}
|
||||
<Button type='submit' variant="outlined" sx={{ p: 1.8, display: 'none' }}>Search</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
// Called on every row to map the data to the columns
|
||||
function createData( plan: CorporatePlan ): CorporatePlan {
|
||||
return {
|
||||
...plan,
|
||||
}
|
||||
}
|
||||
|
||||
const handleInactiveAction = (formularium : any) => {
|
||||
enqueueSnackbar('Fuck yuo'), { variant: 'error' };
|
||||
axios
|
||||
.put('/corporates/'+corporate_id+'/formulariums/'+formularium.id+'/activate')
|
||||
.then(() => {
|
||||
setDataTableData(
|
||||
{
|
||||
...dataTableData,
|
||||
data: dataTableData.data.map((item: any) => {
|
||||
if (item.id === formularium.id) {
|
||||
return {
|
||||
...item,
|
||||
status: 'active'
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
})
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
enqueueSnackbar(error.data?.message ?? (error.message ?? 'Failed Processing Request'), { variant: 'error' });
|
||||
})
|
||||
}
|
||||
|
||||
const handleActiveAction = (formularium : any) => {
|
||||
axios
|
||||
.put('/corporates/'+corporate_id+'/formulariums/'+formularium.id+'/deactivate')
|
||||
.then(() => {
|
||||
setDataTableData(
|
||||
{
|
||||
...dataTableData,
|
||||
data: dataTableData.data.map((item: any) => {
|
||||
if (item.id === formularium.id) {
|
||||
return {
|
||||
...item,
|
||||
status: 'inactive'
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
})
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' });
|
||||
})
|
||||
}
|
||||
|
||||
// Generate the every row of the table
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell align="left">{row.id}</TableCell>
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="left">{row.items_count}</TableCell>
|
||||
<TableCell align="right">{( row.status == 'active' ?
|
||||
<Button variant="outlined" onClick={() => { handleActiveAction(row) }} color="success" size="small">Active</Button> :
|
||||
<Button variant="outlined" onClick={() => { handleInactiveAction(row) }} color="error" size="small">Tidak Digunakan</Button>
|
||||
)}</TableCell>
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={10}>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ borderBottom: 1 }}>
|
||||
<Typography variant="body2" gutterBottom component="div">
|
||||
No Extra Data
|
||||
</Typography>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
const [dataTablePage, setDataTablePage] = useState(5);
|
||||
|
||||
const loadDataTableData = async (appliedFilter : any | null = null) => {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const response = await axios.get('/corporates/'+corporate_id+'/formulariums', { params: filter });
|
||||
const response = await axios.get(`corporates/${corporate_id}/formulariums`, { params: filter });
|
||||
// console.log(response.data);
|
||||
setDataTableLoading(false);
|
||||
|
||||
@@ -212,9 +339,9 @@ export default function PlanList() {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const applyFilter = async (searchFilter: any) => {
|
||||
await loadDataTableData(searchFilter);
|
||||
setSearchParams(searchFilter);
|
||||
const applyFilter = async (searchFilter: string) => {
|
||||
await loadDataTableData({ "search" : searchFilter });
|
||||
setSearchParams({ "search" : searchFilter });
|
||||
}
|
||||
|
||||
const handlePageChange = (event : ChangeEvent, value: number) => {
|
||||
@@ -223,28 +350,26 @@ export default function PlanList() {
|
||||
setSearchParams(filter);
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter}/>
|
||||
</Stack>
|
||||
|
||||
<ImportForm />
|
||||
<Card>
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" width={50}>#</TableCell>
|
||||
<TableCell style={headStyle} align="left" />
|
||||
<TableCell style={headStyle} align="left">Code</TableCell>
|
||||
<TableCell style={headStyle} align="left">ATC Code</TableCell>
|
||||
<TableCell style={headStyle} align="left">Name</TableCell>
|
||||
<TableCell style={headStyle} align="left">Total Item</TableCell>
|
||||
<TableCell style={headStyle} align="right">Status</TableCell>
|
||||
<TableCell style={headStyle} align="left">Category Name</TableCell>
|
||||
<TableCell style={headStyle} align="left">UOM</TableCell>
|
||||
<TableCell style={headStyle} align="left">Status</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
{dataTableIsLoading ?
|
||||
@@ -265,13 +390,14 @@ export default function PlanList() {
|
||||
) : (
|
||||
<TableBody>
|
||||
{dataTableData.data.map(row => (
|
||||
<Row key={row.code} row={row} />
|
||||
<Row key={row.id} row={row} />
|
||||
))}
|
||||
</TableBody>
|
||||
)
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange}/>
|
||||
</Card>
|
||||
</Stack>
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
// @mui
|
||||
import { Box, Button, Card, Collapse, IconButton, InputLabel, MenuItem, OutlinedInput, Paper, Grid, Select, SelectChangeEvent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Badge, Tab, Tabs, CardHeader, Stack, Menu, ButtonGroup, Pagination } from '@mui/material';
|
||||
import { LoadingButton } from "@mui/lab";
|
||||
import { CachedOutlined, FindInPageOutlined } from '@mui/icons-material';
|
||||
// hooks
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../../hooks/useSettings';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
// components
|
||||
import axios from '../../../../utils/axios';
|
||||
import Label from '@/components/Label';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
import InfoDetail from "./InfoDetail";
|
||||
import { DetailCorpFormularium } from "./Types";
|
||||
import DialogUpdateStatus from '@/components/DialogUpdateStatus'
|
||||
import { RHFSelect, FormProvider } from '@/components/hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import * as Yup from 'yup';
|
||||
import { CorporateFormulariumList } from "./Types";
|
||||
|
||||
type ParamsDetail = {
|
||||
props: DetailCorpFormularium,
|
||||
formularium: CorporateFormulariumList,
|
||||
}
|
||||
|
||||
export default function CategoryDetail({props, formularium} : ParamsDetail) {
|
||||
|
||||
type FormValuesProps = {
|
||||
value: string;
|
||||
active: boolean;
|
||||
};
|
||||
const { corporate_id } = useParams();
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [isDialogOpen, setDialogOpen] = useState(false)
|
||||
let titles = {
|
||||
name: 'Update Status',
|
||||
icon: '-'
|
||||
}
|
||||
const [dataValue, setDataValue] = useState<CorporateFormulariumList | null>(null);
|
||||
const [dataDescription, setDescriptionValue] = useState('');
|
||||
const [url, setUrl] = useState('');
|
||||
|
||||
const handleActivate = (isOpen: boolean, dataValue: CorporateFormulariumList) => {
|
||||
console.log(dataValue)
|
||||
setDialogOpen(isOpen)
|
||||
setDataValue(dataValue)
|
||||
setDescriptionValue('Are you sure to inactive this formularium ?')
|
||||
setUrl(url)
|
||||
};
|
||||
|
||||
const NewCorporateSchema = Yup.object().shape({
|
||||
reason: Yup.string().required('Reason Edit is required'),
|
||||
});
|
||||
|
||||
const methods = useForm<FormValuesProps>({
|
||||
resolver: yupResolver(NewCorporateSchema)
|
||||
})
|
||||
|
||||
const {
|
||||
reset,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
} = methods;
|
||||
|
||||
const onSubmit = async (row : any) => {
|
||||
try {
|
||||
handleUpdate(dataValue?.active, dataValue?.id, row.reason)
|
||||
} catch (error: any) {
|
||||
console.log('data gagal');
|
||||
}
|
||||
|
||||
const ascent = document?.querySelector('ascent');
|
||||
if (ascent != null) {
|
||||
ascent.innerHTML = '';
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdate = (active: string, id: number, reason: string) => {
|
||||
if (active == "Active") {
|
||||
active = "0"
|
||||
} else {
|
||||
active = "1"
|
||||
}
|
||||
axios
|
||||
.put(`/corporates/${corporate_id}/formulariums-update-status/${id}`, {
|
||||
active: active,
|
||||
})
|
||||
.then((res) => {
|
||||
console.log(res.data.message)
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
const getContent = () => (
|
||||
<>
|
||||
<Stack paddingX={2} paddingY={2}>
|
||||
<Typography variant='subtitle1'>Are you sure to {dataValue?.active === "Active" ? 'inactive' : 'active'} this Formularium ?</Typography>
|
||||
<Stack>
|
||||
<Card>
|
||||
<Grid container paddingX={2} paddingY={2}>
|
||||
<Grid item xs={5} md={5}>
|
||||
<Typography variant='inherit'>Formularium Name</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={7}>
|
||||
<Typography variant='subtitle1'>{dataValue?.category}</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
|
||||
<Typography marginTop={5} marginBottom={3} variant='subtitle1'>Reason for Update</Typography>
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<RHFSelect
|
||||
name='reason'
|
||||
label="Reason for update"
|
||||
>
|
||||
<option value=""></option>
|
||||
<option value="Agreement changed">Agreement changed</option>
|
||||
<option value="Endorsement">Endorsement</option>
|
||||
<option value="Renewal">Renewal</option>
|
||||
<option value="Wrong Setting">Wrong Setting</option>
|
||||
</RHFSelect>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
justifyContent="flex-end"
|
||||
direction={{xs: 'column', md: 'row'}}
|
||||
spacing={2}
|
||||
marginTop={5}
|
||||
>
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Button
|
||||
sx={{ boxShadow: 'none'}}
|
||||
variant='outlined'
|
||||
size='medium'
|
||||
fullWidth={true}
|
||||
onClick={() => setDialogOpen(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
{dataValue?.active == "Active" ?
|
||||
<LoadingButton
|
||||
sx={{boxShadow: '0px 2px 4px rgba(0,0,0,0.1)'}}
|
||||
type='submit'
|
||||
variant='contained'
|
||||
size='medium'
|
||||
fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
color='error'
|
||||
>
|
||||
Inactive
|
||||
</LoadingButton> :
|
||||
<LoadingButton
|
||||
sx={{boxShadow: '0px 2px 4px rgba(0,0,0,0.1)'}}
|
||||
type='submit'
|
||||
variant='contained'
|
||||
size='medium'
|
||||
fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
color='success'
|
||||
>
|
||||
Active
|
||||
</LoadingButton>
|
||||
}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</FormProvider>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell align='left' width={50}/>
|
||||
<TableCell align='left'>{props.code}</TableCell>
|
||||
<TableCell align='left'>{props.name}</TableCell>
|
||||
<TableCell align='left' width={100}>
|
||||
{formularium.active == "Active" ? (
|
||||
<Label color='success'>Active</Label>
|
||||
): (
|
||||
<Label color='error'>Inactive</Label>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell align='center' width={100}>
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => setOpen(!open)}>
|
||||
<FindInPageOutlined />
|
||||
Detail
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => handleActivate(true, {
|
||||
id: formularium.id,
|
||||
formulaurium_category_id: formularium.formulaurium_category_id,
|
||||
category: formularium.category,
|
||||
description: formularium.description,
|
||||
active: formularium.active
|
||||
})
|
||||
}>
|
||||
<CachedOutlined />
|
||||
Update Status
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={5} style={{paddingBottom:0, paddingTop:0}}>
|
||||
<Collapse in={open} timeout='auto' unmountOnExit>
|
||||
<InfoDetail {...props}/>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
|
||||
<DialogUpdateStatus
|
||||
openDialog={isDialogOpen}
|
||||
setOpenDialog={setDialogOpen}
|
||||
description={dataDescription}
|
||||
title={titles}
|
||||
data={dataValue}
|
||||
content={getContent()}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import TableMoreMenu from "@/components/table/TableMoreMenu"
|
||||
import { FindInPageOutlined } from "@mui/icons-material"
|
||||
import HistoryIcon from '@mui/icons-material/History';
|
||||
import { Collapse, Grid, MenuItem, Paper, Table, TableCell, TableContainer, TableHead, TableRow } from "@mui/material"
|
||||
import React, { useEffect } from "react";
|
||||
import CategoryDetail from "./CategoryDetail";
|
||||
import { CorporateFormulariumList, DetailCorpFormularium, RespDetailFormularium } from "./Types";
|
||||
import axios from "@/utils/axios";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
|
||||
const CategoryRow: React.FC<CorporateFormulariumList> = (props) => {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const { corporate_id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [dataTableIsLoading, setDataTableLoading] = React.useState(true);
|
||||
const [dataTableData, setDataTableData] = React.useState<RespDetailFormularium | null>(null)
|
||||
const [dataRow, setDataRow] = React.useState<DetailCorpFormularium[] | null>(null)
|
||||
|
||||
const loadDataTableData = async (formulaurium_category_id: number) => {
|
||||
setDataTableLoading(true);
|
||||
const resp = await axios.get(`/corporates/${corporate_id}/formulariums/${formulaurium_category_id}`);
|
||||
console.log(resp.data);
|
||||
setDataTableLoading(false);
|
||||
setDataTableData(resp.data);
|
||||
setDataRow(resp.data.data);
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow>
|
||||
<TableCell align="left" width={50}/>
|
||||
<TableCell align="left">{props.category}</TableCell>
|
||||
<TableCell align="left">{props.description}</TableCell>
|
||||
<TableCell align="center" width={100}>
|
||||
<TableMoreMenu actions = {
|
||||
<>
|
||||
<MenuItem onClick={async () => { loadDataTableData(props.formulaurium_category_id); setOpen(!open)}}>
|
||||
<FindInPageOutlined />
|
||||
Detail
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate(`/corporates/${corporate_id}/formulariums/${props.id}/history`)}>
|
||||
<HistoryIcon />
|
||||
History
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow >
|
||||
<TableCell colSpan={5} align="center" style={{paddingBottom: 0, paddingTop: 0}}>
|
||||
<Collapse in={open} timeout='auto' unmountOnExit>
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align="left" width={50} />
|
||||
<TableCell align="left">Code</TableCell>
|
||||
<TableCell align="left">Name</TableCell>
|
||||
<TableCell align="left" width={100}>Status</TableCell>
|
||||
<TableCell align="center" width={100}></TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
{dataTableIsLoading ? (
|
||||
<TableCell colSpan={5} align="center">Loading</TableCell>
|
||||
) : dataTableData?.data.length == 0 ? (
|
||||
<TableCell colSpan={5} align="center">No Data</TableCell>
|
||||
) : (
|
||||
dataRow?.map(item => (
|
||||
<CategoryDetail props={item} formularium={props}/>
|
||||
))
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
export default CategoryRow
|
||||
@@ -0,0 +1,54 @@
|
||||
import { Card, Grid } from '@mui/material';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import HeaderBreadcrumbs from '../../../../components/HeaderBreadcrumbs';
|
||||
import Page from '../../../../components/Page';
|
||||
import useSettings from '../../../../hooks/useSettings';
|
||||
import CorporateTabNavigations from '../../CorporateTabNavigations';
|
||||
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import { ConfiguredCorporateContext } from '@/contexts/ConfiguredCorporateContext';
|
||||
import { Corporate } from '@/@types/corporates';
|
||||
import CorporateFormulariumCreateForm from "./Form"
|
||||
|
||||
|
||||
export default function CorporateFormulariumCreate() {
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const { corporate_id } = useParams();
|
||||
|
||||
const [corporate, setCorporate] = useState<Corporate | null>();
|
||||
|
||||
const configuredCorporateContext = useContext(ConfiguredCorporateContext);
|
||||
|
||||
useEffect(() => {
|
||||
setCorporate(configuredCorporateContext.currentCorporate);
|
||||
}, [configuredCorporateContext]);
|
||||
|
||||
return(
|
||||
<Page title='Create Formularium'>
|
||||
<HeaderBreadcrumbs
|
||||
heading={'Create Formularium'}
|
||||
links={[
|
||||
{
|
||||
name: 'Corporates',
|
||||
href: '/corporates'
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? "-",
|
||||
href: '/corporates/' + corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Formularium',
|
||||
href: '/corporates/' + corporate_id + '/formulariums',
|
||||
},
|
||||
{
|
||||
name: 'Create Formularium',
|
||||
href: '/corporates/' + corporate_id + '/formulariums/create',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<CorporateFormulariumCreateForm />
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
130
frontend/dashboard/src/pages/Corporates/Formularium/New/Form.tsx
Normal file
130
frontend/dashboard/src/pages/Corporates/Formularium/New/Form.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
import * as Yup from 'yup';
|
||||
import { useForm } from "react-hook-form";
|
||||
import { FormProvider, RHFSelect } from "../../../../components/hook-form";
|
||||
import { Button, Card, Grid, Typography } from "@mui/material";
|
||||
import { Stack, fontWeight } from "@mui/system";
|
||||
import { useNavigate, useParams } from "react-router";
|
||||
import React, { useEffect, useMemo } from "react";
|
||||
import { DetailCorpFormularium } from "./Types";
|
||||
import axios from "@/utils/axios";
|
||||
import { LoadingButton } from "@mui/lab";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
|
||||
|
||||
export default function CorporateFormulariumCreateForm() {
|
||||
const navigate = useNavigate();
|
||||
const { corporate_id } = useParams();
|
||||
|
||||
const NewCorporaeFormulariumSchema = Yup.object().shape({
|
||||
id: Yup.string().required('required'),
|
||||
});
|
||||
|
||||
const methods = useForm({
|
||||
resolver: yupResolver(NewCorporaeFormulariumSchema),
|
||||
});
|
||||
|
||||
const onSubmit = async (data: any) => {
|
||||
await axios
|
||||
.post(`/corporates/${corporate_id}/formulariums`, data)
|
||||
.then((res) => {
|
||||
console.log(res.data.message)
|
||||
enqueueSnackbar('Formularium created successfully', { variant: 'success'})
|
||||
})
|
||||
.then((res) => {
|
||||
navigate(`/corporates/${corporate_id}/formulariums/`, { replace: true })
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
if (response.status === 422) {
|
||||
for (const [key, value] of Object.entries(response.data.errors)) {
|
||||
setError(key, {message: value[0]});
|
||||
enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' });
|
||||
}
|
||||
}
|
||||
else {
|
||||
enqueueSnackbar('Create Failed: '+ response.data.message, { variant: "error"})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const {
|
||||
setError,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting }
|
||||
} = methods;
|
||||
|
||||
// Data Dummy
|
||||
const options = ["Dummy 1", "Dummy 2", "Dummy 3"];
|
||||
|
||||
const [dataDropdownIsLoading, setDataDropdownLoading] = React.useState(true);
|
||||
const [dataDropdownData, setDataDropdownData] = React.useState<DetailCorpFormularium[] | null>(null)
|
||||
const loadDataDropdown = async () => {
|
||||
setDataDropdownLoading(true);
|
||||
const resp = await axios.get(`corporates/${corporate_id}/formulariums-create`);
|
||||
console.log(resp.data);
|
||||
setDataDropdownLoading(false);
|
||||
|
||||
setDataDropdownData(resp.data.data)
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadDataDropdown();
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<Grid item xs={12}>
|
||||
<Card sx={{p:2}}>
|
||||
<Stack spacing={3}>
|
||||
<Typography variant="h6">Formularium Name*</Typography>
|
||||
<RHFSelect name="id" label="Category" placeholder="Category" fullWidth={true}>
|
||||
<option value=""/>
|
||||
{dataDropdownData?.map((item, index) => (
|
||||
<option key={index} value={item.id}>
|
||||
{item.name}
|
||||
</option>
|
||||
))}
|
||||
</RHFSelect>
|
||||
</Stack>
|
||||
</Card>
|
||||
<Stack direction="row" spacing={4} sx={{marginTop: '40px'}}>
|
||||
<Grid container item xs={12} md={12} justifyContent="flex-end" sx={{p:2}}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={() => navigate(`/corporates/${corporate_id}/formulariums/`)}
|
||||
sx={{
|
||||
p: 1,
|
||||
fontWeight: 'bold',
|
||||
color: 'black',
|
||||
outlineColor: 'black',
|
||||
marginRight: '20px',
|
||||
width: 100
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
<LoadingButton
|
||||
loading={isSubmitting}
|
||||
type='submit'
|
||||
variant="contained"
|
||||
sx={{
|
||||
p: 1,
|
||||
fontWeight: 'bold',
|
||||
backgroundColor: '#19BBBB',
|
||||
color: '#FFF',
|
||||
"&:hover":{
|
||||
backgroundColor: '#19BBBB', color: '#FFF',
|
||||
},
|
||||
width: 100
|
||||
}}
|
||||
>
|
||||
Create
|
||||
</LoadingButton>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Grid>
|
||||
|
||||
</FormProvider>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
// @mui
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
Collapse,
|
||||
Container,
|
||||
FormControl,
|
||||
Grid,
|
||||
IconButton,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
OutlinedInput,
|
||||
Paper,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
Badge,
|
||||
Stack,
|
||||
} from '@mui/material';
|
||||
import * as React from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import ArrowForwardIosSharpIcon from '@mui/icons-material/ArrowForwardIosSharp';
|
||||
import MuiAccordion, { AccordionProps } from '@mui/material/Accordion';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import MuiAccordionSummary, {
|
||||
AccordionSummaryProps,
|
||||
} from '@mui/material/AccordionSummary';
|
||||
import useSettings from '../../../../hooks/useSettings';
|
||||
import axios from '../../../../utils/axios';
|
||||
import { ConfiguredCorporateContext } from '@/contexts/ConfiguredCorporateContext';
|
||||
import MuiAccordionDetails from '@mui/material/AccordionDetails';
|
||||
import HeaderBreadcrumbs from '../../../../components/HeaderBreadcrumbs';
|
||||
import { Corporate } from '@/@types/corporates';
|
||||
import { fDate, fDateTime } from '@/utils/formatTime';
|
||||
|
||||
const Accordion = styled((props: AccordionProps) => (
|
||||
<MuiAccordion disableGutters elevation={0} square {...props} />
|
||||
))(({ theme }) => ({
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
'&:not(:last-child)': {
|
||||
borderBottom: 0,
|
||||
},
|
||||
'7:before': {
|
||||
display: 'none',
|
||||
},
|
||||
}));
|
||||
|
||||
const AccordionSummary = styled((props: AccordionSummaryProps) => (
|
||||
<MuiAccordionSummary expandIcon={<ArrowForwardIosSharpIcon sx={{ fontSize: '0.9rem'}} />}
|
||||
{...props}
|
||||
/>
|
||||
))(({ theme }) => ({
|
||||
backgroundColor: theme.palette.mode === 'dark'
|
||||
? 'rgba(255,255,255, .85)'
|
||||
: 'rgba(0,0,0, .03)',
|
||||
flexDirection: 'row-reverse',
|
||||
'& .MuiAccordionSummary-expandIconWrapper.Mui-expanded' : {
|
||||
transform: 'rotate(90deg)',
|
||||
},
|
||||
'& .MuiAccordionSummary-content': {
|
||||
marginLeft: theme.spacing(1),
|
||||
},
|
||||
}));
|
||||
|
||||
const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({
|
||||
padding: theme.spacing(2),
|
||||
borderTop: '1px solid rgba(0, 0, 0, .125)',
|
||||
}));
|
||||
|
||||
export default function CustomizedAccordions() {
|
||||
const [expanded, setExpanded] = React.useState<String | false>('panel1');
|
||||
|
||||
const handleChange = (panel: string) => (event: React.SyntheticEvent, newExpanded: boolean) => {
|
||||
setExpanded(newExpanded ? panel : false);
|
||||
};
|
||||
|
||||
const pageTitle = 'Corporate Formularium History'
|
||||
const { id } = useParams();
|
||||
const { corporate_id } = useParams();
|
||||
const [corporate, setCorporate] = useState<Corporate | null>();
|
||||
const [currentCorporate, setCurrentCorporate] = useState<Corporate>();
|
||||
const configuredCorporateContext = useContext(ConfiguredCorporateContext);
|
||||
|
||||
useEffect(() => {
|
||||
setCorporate(configuredCorporateContext.currentCorporate);
|
||||
const model = 'App\\Models\\CorporateFormularium';
|
||||
const url = `/audittrail/${id}?model=${model}`;
|
||||
axios.get(url)
|
||||
.then((res) => {
|
||||
setCurrentCorporate(res.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Terjadi kesalahan', error)
|
||||
});
|
||||
}, [configuredCorporateContext]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<HeaderBreadcrumbs
|
||||
heading={pageTitle}
|
||||
links={[
|
||||
{
|
||||
name: 'Corporates',
|
||||
href: '/corporates',
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporates/' + corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Formularium',
|
||||
href: '/corporates/' + corporate_id + '/formulariums',
|
||||
},
|
||||
{
|
||||
name: 'History',
|
||||
href: '/corporates/' + corporate_id + '/formulariums'
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{currentCorporate?.data.map((item, index) => (
|
||||
<Accordion
|
||||
key={index}
|
||||
expanded={expanded === `panel${index}`}
|
||||
onChange={handleChange(`panel${index}`)}
|
||||
>
|
||||
<AccordionSummary
|
||||
aria-controls={`panel${index}d-content`}
|
||||
id={`panel${index}d-header`}
|
||||
>
|
||||
<Typography>{`Data has ${item.action} by ${item.user_id} on ${fDateTime(item.updated_at)}`}</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label='collapsible table'>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align='center'>Field</TableCell>
|
||||
<TableCell align='center'>Old Value</TableCell>
|
||||
<TableCell align='center'>New Value</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{Object.entries(item.old_values).map(([key, value]) => {
|
||||
let renderedValue;
|
||||
if (key === 'deleted_by' ||
|
||||
key === 'deleted_at' ||
|
||||
key === 'created_by' ||
|
||||
key === 'created_at' ||
|
||||
key === 'updated_by' ||
|
||||
key === 'description'
|
||||
) {
|
||||
return null; // Melewati iterasi saat key adalah 'deleted_by'
|
||||
}
|
||||
switch (key) {
|
||||
case 'welcome_message':
|
||||
renderedValue = item.new_values[key].replace(/<[^>]*>/g, '');
|
||||
value = value.replace(/<[^>]*>/g, '');
|
||||
break;
|
||||
case 'help_text':
|
||||
renderedValue = item.new_values[key].replace(/<[^>]*>/g, '');
|
||||
value = value.replace(/<[^>]*>/g, '');
|
||||
break;
|
||||
case 'active':
|
||||
renderedValue = item.new_values[key] == 1 ? 'Active' : 'Inactive';
|
||||
value = value == 1 ? 'Active' : 'Inactive';
|
||||
break;
|
||||
case 'created_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
case 'updated_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
case 'updated_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
case 'delete_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
default:
|
||||
renderedValue = item.new_values[key];
|
||||
break;
|
||||
}
|
||||
|
||||
const field = key.charAt(0).toUpperCase() + key.slice(1);
|
||||
if (value == renderedValue) {
|
||||
return null
|
||||
} else {
|
||||
return (
|
||||
<TableRow key={key} sx={{ '&:last-child td, &:last-child th': { border: 0 } }}>
|
||||
<TableCell align="center">{`${field}`}</TableCell>
|
||||
<TableCell align="center">{`${value}`}</TableCell>
|
||||
<TableCell align="center">{renderedValue}</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { Collapse, TableCell, TableRow, Card, Box, Grid, Typography } from "@mui/material";
|
||||
import { DetailCorpFormularium } from "./Types";
|
||||
|
||||
|
||||
|
||||
export default function InfoDetail(props: DetailCorpFormularium) {
|
||||
|
||||
|
||||
return(
|
||||
<Card sx={{paddingX:2, paddingY:2, marginBottom:3}}>
|
||||
<Box sx={{margin: 1, pb: 2}}>
|
||||
<Grid container>
|
||||
<Grid item>
|
||||
<Typography sx={{ fontWeight: '600', mb: 1}}>Detail</Typography>
|
||||
<Grid container>
|
||||
<Grid item xs={2}>Description</Grid>
|
||||
<Grid item xs={10}> : {props.description}</Grid>
|
||||
|
||||
<Grid item xs={2}>General Indication</Grid>
|
||||
<Grid item xs={10}> : {props.general_indication}</Grid>
|
||||
|
||||
<Grid item xs={2}>Composition</Grid>
|
||||
<Grid item xs={10}> : {props.composition}</Grid>
|
||||
|
||||
<Grid item xs={2}>Kategori Obat</Grid>
|
||||
<Grid item xs={10}> : {props.kategori_obat}</Grid>
|
||||
|
||||
<Grid item xs={2}>BPOM Registration</Grid>
|
||||
<Grid item xs={10}> : {props.bpom_registration}</Grid>
|
||||
|
||||
<Grid item xs={2}>Classification</Grid>
|
||||
<Grid item xs={10}> : {props.classifications}</Grid>
|
||||
|
||||
<Grid item xs={2}>Cat For</Grid>
|
||||
<Grid item xs={10}> : {props.cat_for}</Grid>
|
||||
|
||||
<Grid item xs={2}>Class</Grid>
|
||||
<Grid item xs={10}> : {props.class}</Grid>
|
||||
|
||||
<Grid item xs={2}>Manufacturer</Grid>
|
||||
<Grid item xs={10}> : {props.manufacturer}</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
179
frontend/dashboard/src/pages/Corporates/Formularium/New/List.tsx
Normal file
179
frontend/dashboard/src/pages/Corporates/Formularium/New/List.tsx
Normal file
@@ -0,0 +1,179 @@
|
||||
// @mui
|
||||
import { Box, Button, Card, Collapse, IconButton, InputLabel, MenuItem, OutlinedInput, Paper, Grid, Select, SelectChangeEvent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Badge, Tab, Tabs, CardHeader, Stack, Menu, ButtonGroup, Pagination } from '@mui/material';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
// hooks
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../../hooks/useSettings';
|
||||
import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
// components
|
||||
import axiosInstance from '../../../../utils/axios';
|
||||
import axios from '../../../../utils/axios';
|
||||
import { LaravelPaginatedData } from '../../../../@types/paginated-data';
|
||||
import BasePagination from '../../../../components/BasePagination';
|
||||
import CategoryRow from './CategoryRow'
|
||||
import {CorporateFormulariumList} from "./Types";
|
||||
|
||||
|
||||
export default function List() {
|
||||
const navigate = useNavigate();
|
||||
const { corporate_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [dataRow, setDataRow] = useState<CorporateFormulariumList[] | null>(null);
|
||||
|
||||
// Dummy Default Data
|
||||
const [dataTableIsLoading, setDataTableLoading] = React.useState(true);
|
||||
const [dataTableData, setDataTableData] = React.useState<LaravelPaginatedData>({
|
||||
current_page: 1,
|
||||
data: [],
|
||||
path: '',
|
||||
first_page_url: '',
|
||||
last_page: 1,
|
||||
last_page_url: '',
|
||||
next_page_url: '',
|
||||
prev_page_url: '',
|
||||
per_page: 10,
|
||||
from: 0,
|
||||
to: 0,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
// Load Data
|
||||
const loadDataTableData = async (appliedFilter: any | null = null) => {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const resp = await axios.get(`/corporates/${corporate_id}/formulariums`, {params: filter});
|
||||
setDataTableLoading(false);
|
||||
setDataTableData(resp.data);
|
||||
setDataRow(resp.data.data);
|
||||
}
|
||||
|
||||
const applyFilter = async (searchFilter: any) => {
|
||||
await loadDataTableData({ search: searchFilter });
|
||||
setSearchParams({ search: searchFilter });
|
||||
console.log("here")
|
||||
};
|
||||
|
||||
const handlePageChange = (event: ChangeEvent, value: number) => {
|
||||
const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]);
|
||||
loadDataTableData(filter);
|
||||
setSearchParams(filter);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
console.log(dataTableData);
|
||||
console.log(dataRow);
|
||||
}, []);
|
||||
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const handleSearchChange = (event: any) => {
|
||||
const newSearchText = event.target.value ?? ''
|
||||
setSearchText(newSearchText);
|
||||
}
|
||||
|
||||
const handleSearchSubmit = (event: any) => {
|
||||
event.preventDefault();
|
||||
props.onSearch(searchText); // Trigger to Parent
|
||||
}
|
||||
|
||||
useEffect(() => { // Trigger First Search
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
}, [searchParams])
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '100%' }}>
|
||||
<TextField
|
||||
id="search-input"
|
||||
ref={searchInput}
|
||||
label="Search"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
onChange={handleSearchChange}
|
||||
value={searchText}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
function SearchCreate(props: any) {
|
||||
return (
|
||||
<div>
|
||||
<Stack direction={'row'} spacing={2} sx={{p:2}}>
|
||||
<SearchInput onSearch={applyFilter}/>
|
||||
<Button
|
||||
id='create-button'
|
||||
variant='contained'
|
||||
startIcon={<AddIcon />}
|
||||
onClick={() => navigate(`/corporates/${corporate_id}/formulariums/create`)}
|
||||
sx={{
|
||||
p: 1.8,
|
||||
backgroundColor: '#19BBBB', color: '#FFF',
|
||||
"&:hover":{
|
||||
backgroundColor: '#19BBBB', color: '#FFF',
|
||||
},
|
||||
width: '200px'
|
||||
}}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
</Stack>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
return(
|
||||
<React.Fragment>
|
||||
<Stack>
|
||||
<SearchCreate />
|
||||
<Card>
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align='left' width={50}></TableCell>
|
||||
<TableCell style={headStyle} align="left">Formularium Name</TableCell>
|
||||
<TableCell style={headStyle} align="left">Description</TableCell>
|
||||
<TableCell style={headStyle} align="center" width={100}></TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
{dataTableIsLoading ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={4} align="center">
|
||||
Loading
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : dataTableData.data.length == 0 ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={4} align="center">
|
||||
No Data
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody>
|
||||
{dataRow?.map(item => (
|
||||
<CategoryRow {...item}/>
|
||||
))}
|
||||
</TableBody>
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||
</Card>
|
||||
</Stack>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
export type CorporateFormularium = {
|
||||
current_page: number
|
||||
data: CorporateFormulariumList[]
|
||||
first_page_url: string
|
||||
from: number
|
||||
last_page: number
|
||||
last_page_url: string
|
||||
links: CorporateFormulariumPaginationLinks[]
|
||||
next_page_url: any
|
||||
per_page: number
|
||||
total: number
|
||||
}
|
||||
|
||||
export type CorporateFormulariumList = {
|
||||
id: number
|
||||
formulaurium_category_id: number
|
||||
category: string
|
||||
description: string
|
||||
active: string
|
||||
};
|
||||
|
||||
export type CorporateFormulariumPaginationLinks = {
|
||||
url?: string
|
||||
label: string
|
||||
active: boolean
|
||||
}
|
||||
|
||||
export type RespDetailFormularium = {
|
||||
status: number
|
||||
message: string
|
||||
data: DetailCorpFormularium[]
|
||||
}
|
||||
|
||||
export type DetailCorpFormularium = {
|
||||
id: number
|
||||
code: string
|
||||
name: string
|
||||
description: string
|
||||
manufacturer: string
|
||||
category_name: string
|
||||
kategori_obat: string
|
||||
uom: string
|
||||
general_indication: string
|
||||
composition: string
|
||||
atc_code: string
|
||||
class: string
|
||||
bpom_registration: string
|
||||
classifications: string
|
||||
cat_for: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
deleted_at: any
|
||||
created_by: number
|
||||
updated_by: number
|
||||
deleted_by: any
|
||||
formularium_template_id: number
|
||||
}
|
||||
@@ -121,11 +121,11 @@ export default function CustomizedAccordions() {
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id,
|
||||
href: '/corporates/' + corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Audittrail Corporate',
|
||||
href: '/corporate/' + corporate_id + '/plans',
|
||||
href: '/corporates/' + corporate_id + '/plans',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
@@ -139,7 +139,7 @@ export default function CustomizedAccordions() {
|
||||
aria-controls={`panel${index}d-content`}
|
||||
id={`panel${index}d-header`}
|
||||
>
|
||||
<Typography>{`Data has ${item.action} by ${item.user_id} on ${fDateTime(item.updated_at)}`}</Typography>
|
||||
<Typography variant='subtitle1'>{`Data has ${item.action} by ${item.user_id} on ${fDateTime(item.updated_at)}`}</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<TableHead>
|
||||
@@ -157,12 +157,13 @@ export default function CustomizedAccordions() {
|
||||
}
|
||||
switch (key) {
|
||||
case 'welcome_message':
|
||||
renderedValue = item.new_values[key].replace(/<[^>]*>/g, '');
|
||||
value = value.replace(/<[^>]*>/g, '');
|
||||
// renderedValue = item.new_values[key].replace(/<[^>]*>/g, '');
|
||||
renderedValue = item.new_values[key];
|
||||
value = value;
|
||||
break;
|
||||
case 'help_text':
|
||||
renderedValue = item.new_values[key].replace(/<[^>]*>/g, '');
|
||||
value = value.replace(/<[^>]*>/g, '');
|
||||
renderedValue = item.new_values[key];
|
||||
value = value;
|
||||
break;
|
||||
case 'active':
|
||||
renderedValue = item.new_values[key] == 1 ? 'Active' : 'Inactive';
|
||||
|
||||
@@ -1,64 +1,63 @@
|
||||
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import Page from "../../../components/Page";
|
||||
import useSettings from "../../../hooks/useSettings";
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import axios from '../../../utils/axios';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import CorporatePlanForm from './Form';
|
||||
import { CorporatePlan } from '../../../@types/corporates';
|
||||
import { useContext, useEffect, useMemo, useState } from 'react';
|
||||
import CorporateHospitalForm from './Form';
|
||||
import { Hospital } from '../../../@types/corporates';
|
||||
import { Corporate } from "@/@types/corporates";
|
||||
import { ConfiguredCorporateContext } from "@/contexts/ConfiguredCorporateContext";
|
||||
import { Stack, Typography } from '@mui/material';
|
||||
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
|
||||
|
||||
|
||||
|
||||
export default function PlanCreate() {
|
||||
const { themeStretch } = useSettings();
|
||||
export default function HospitalCreate() {
|
||||
const { corporate_id, id } = useParams();
|
||||
const [ currentCorporatePlan, setCurrentCorporatePlan ] = useState<CorporatePlan>();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [corporate, setCorporate] = useState<Corporate|null>();
|
||||
|
||||
const configuredCorporateContext = useContext(ConfiguredCorporateContext);
|
||||
|
||||
const isEdit = !!id;
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit) {
|
||||
axios.get('/corporates/'+corporate_id+'/divisions/'+id+'/edit')
|
||||
.then((res) => {
|
||||
setCurrentCorporatePlan(res.data);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.response.status === 404) {
|
||||
navigate('/404');
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [corporate_id, id]);
|
||||
setCorporate(configuredCorporateContext.currentCorporate);
|
||||
}, [corporate_id, id, configuredCorporateContext]);
|
||||
|
||||
|
||||
return (
|
||||
<Page title="Create Corporate Division">
|
||||
<HeaderBreadcrumbs
|
||||
heading={'Create Corporate Division'}
|
||||
links={[
|
||||
{
|
||||
name: 'Corporates',
|
||||
href: '/corporates',
|
||||
},
|
||||
{
|
||||
name: 'Corporate Name',
|
||||
href: '/corporates/'+corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Division',
|
||||
href: '/corporates/'+corporate_id+'/divisions',
|
||||
},
|
||||
{
|
||||
name: !isEdit ? 'Create' : 'Edit',
|
||||
href: '/corporates/'+corporate_id+'/divisions/'+id,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<CorporatePlanForm isEdit={isEdit} currentCorporatePlan={currentCorporatePlan}/>
|
||||
<Page title="Create Hospital">
|
||||
{isEdit ? (
|
||||
<Stack direction="row" alignItems="center" sx={{ marginBottom: 3 }}>
|
||||
<ArrowBackIosIcon sx={{cursor:'pointer'}} onClick={() => navigate(-1)}/>
|
||||
<Typography variant="h5" sx={{marginLeft:2}}>Edit Hospital</Typography>
|
||||
</Stack>
|
||||
) : (
|
||||
<HeaderBreadcrumbs
|
||||
heading={'Create Hospital'}
|
||||
links={[
|
||||
{
|
||||
name: 'Corporates',
|
||||
href: '/corporates',
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporates/'+corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Hospital',
|
||||
href: '/corporates/'+corporate_id+'/hospitals',
|
||||
},
|
||||
{
|
||||
name: !isEdit ? 'Create' : 'Edit',
|
||||
href: '/corporates/'+corporate_id+'/hospitals/create',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
<CorporateHospitalForm isEdit={isEdit} />
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,129 +1,171 @@
|
||||
import * as Yup from 'yup';
|
||||
import { LoadingButton } from "@mui/lab";
|
||||
import { Card, Grid, Stack, Typography } from "@mui/material";
|
||||
import { CorporatePlan } from "../../../@types/corporates";
|
||||
import { FormProvider, RHFSwitch, RHFTextField } from "../../../components/hook-form";
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { Button, Card, Grid, Stack, Typography, FormControl, InputLabel, Select, FormHelperText, MenuItem } from "@mui/material";
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import axios from '../../../utils/axios';
|
||||
|
||||
type Props = {
|
||||
isEdit: boolean;
|
||||
currentCorporatePlan?: CorporatePlan;
|
||||
};
|
||||
|
||||
export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Props) {
|
||||
export default function CorporateHospitalForm({ isEdit }: Props) {
|
||||
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
const navigate = useNavigate();
|
||||
const { corporate_id } = useParams();
|
||||
|
||||
const NewCorporatePlanSchema = Yup.object().shape({
|
||||
name: Yup.string().required('Name is required'),
|
||||
code: Yup.string().required('Corporate Code is required'),
|
||||
});
|
||||
|
||||
const defaultValues = useMemo(
|
||||
() => ({
|
||||
name: currentCorporatePlan?.name || '',
|
||||
code: currentCorporatePlan?.code || '',
|
||||
active: currentCorporatePlan?.active === 1 ? true : false,
|
||||
}),
|
||||
[currentCorporatePlan]
|
||||
);
|
||||
const { corporate_id, id, organization_id } = useParams();
|
||||
const [dataHospital, setDataHospital] = useState(null);
|
||||
let idHospital = organization_id && isEdit ? organization_id : 0;
|
||||
const [indexData, setIndexData] = useState(idHospital);
|
||||
const [updateData, setUpdateData] = useState(null);
|
||||
const [dataDefault, setDataDefault] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit && currentCorporatePlan) {
|
||||
reset(defaultValues);
|
||||
axios.get('/corporates/' + corporate_id + '/hospitals/data')
|
||||
.then((res) => {
|
||||
setDataHospital(res.data);
|
||||
const data = {
|
||||
corporate_id : corporate_id ? corporate_id : null,
|
||||
organization_id : res.data[0] ? res.data[0].id : null,
|
||||
code : res.data[0] ? res.data[0].code : null,
|
||||
name : res.data[0] ? res.data[0].name : null,
|
||||
}
|
||||
setDataDefault(data);
|
||||
})
|
||||
|
||||
}, [isEdit]);
|
||||
|
||||
const [addData, setAddData] = useState(dataDefault);
|
||||
|
||||
const handlePageChange = (index:any) => {
|
||||
setIndexData(index);
|
||||
const data = {
|
||||
corporate_id : corporate_id ? corporate_id : null,
|
||||
organization_id : dataHospital ? dataHospital[index].id : null,
|
||||
code : dataHospital ? dataHospital[index].code : null,
|
||||
name : dataHospital ? dataHospital[index].name : null,
|
||||
}
|
||||
if (!isEdit) {
|
||||
reset(defaultValues);
|
||||
setAddData(data);
|
||||
|
||||
}
|
||||
const handleSaveData = () => {
|
||||
//Save data
|
||||
axios
|
||||
.post('/corporates/'+corporate_id+'/hospitals/save', (addData ? addData : dataDefault))
|
||||
.then((response) => {
|
||||
if(response.data)
|
||||
{
|
||||
enqueueSnackbar('Data saved successfully', { variant: 'success' });
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
enqueueSnackbar('Failed to add data', { variant: 'error' });
|
||||
});
|
||||
}
|
||||
|
||||
const handlePageChangeUpdate = (id: any) => {
|
||||
setIndexData(id);
|
||||
const foundData = dataHospital?.find(item => item.id === id);
|
||||
const dataUpdate = {
|
||||
corporate_id : corporate_id ? corporate_id : null,
|
||||
organization_id : dataHospital ? foundData.id : null,
|
||||
code : dataHospital ? foundData.code : null,
|
||||
name : dataHospital ? foundData.name : null,
|
||||
}
|
||||
}, [isEdit, currentCorporatePlan]);
|
||||
setUpdateData(dataUpdate);
|
||||
}
|
||||
|
||||
const methods = useForm({
|
||||
resolver: yupResolver(NewCorporatePlanSchema),
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
const {
|
||||
reset,
|
||||
watch,
|
||||
control,
|
||||
setValue,
|
||||
getValues,
|
||||
setError,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
} = methods;
|
||||
|
||||
|
||||
const onSubmit = async (data: any) => {
|
||||
if (!isEdit) {
|
||||
await axios
|
||||
.post('/corporate/' + corporate_id + '/divisions', data)
|
||||
.then((res) => {
|
||||
enqueueSnackbar('Division created successfully', { variant: 'success' });
|
||||
})
|
||||
.then((res) => {
|
||||
navigate('/corporate/' + corporate_id + '/divisions', { replace: true });
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
if (response.status === 422) {
|
||||
for (const [key, value] of Object.entries(response.data.errors)) {
|
||||
setError(key, { message: value[0] });
|
||||
enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' });
|
||||
}
|
||||
}
|
||||
else {
|
||||
enqueueSnackbar('Create Failed : '+ response.data.message, { variant: 'error' });
|
||||
const handleUpdateData = () => {
|
||||
//Update data
|
||||
if(updateData)
|
||||
{
|
||||
axios
|
||||
.put('/corporates/'+corporate_id+'/hospitals/'+id+'/edit', updateData)
|
||||
.then((response) => {
|
||||
if(response.data)
|
||||
{
|
||||
enqueueSnackbar('Data updated successfully', { variant: 'success' });
|
||||
navigate(-1);
|
||||
window.history.replaceState(null, '', '/corporates/'+corporate_id+'/hospitals');
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
enqueueSnackbar('Failed to update data', { variant: 'error' });
|
||||
});
|
||||
} else {
|
||||
await axios
|
||||
.put('/corporate/' + corporate_id + '/divisions/' + currentCorporatePlan?.id , data)
|
||||
.then((res) => {
|
||||
enqueueSnackbar('Division updated successfully', { variant: 'success' });
|
||||
})
|
||||
.then((res) => {
|
||||
navigate('/corporate/' + corporate_id + '/divisions/' , { replace: true });
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' });
|
||||
});
|
||||
}
|
||||
};
|
||||
else
|
||||
{
|
||||
enqueueSnackbar('Data has not changed.', { variant: 'error' });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={8}>
|
||||
<Card sx={{ p: 2 }}>
|
||||
<Stack spacing={3}>
|
||||
<Stack>
|
||||
<Card sx={{ p: 2 }}>
|
||||
<Stack spacing={2} direction='column'>
|
||||
<Typography variant='subtitle1'>Hospital *</Typography>
|
||||
{dataHospital && dataHospital.length > 0 ? (
|
||||
isEdit ? (
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="id_hospital" required>
|
||||
Hospital
|
||||
</InputLabel>
|
||||
<Select
|
||||
id="id_hospital"
|
||||
value={dataHospital && dataHospital.length > 0 ? indexData : ''}
|
||||
fullWidth
|
||||
label="Hospital"
|
||||
onChange={(e) => {
|
||||
handlePageChangeUpdate(e.target.value);
|
||||
}}
|
||||
|
||||
>
|
||||
{dataHospital?.map((data, index) => (
|
||||
<MenuItem key={index} value={data.id}>{data.name}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormHelperText style={{ color: 'red' }}></FormHelperText>
|
||||
</FormControl>
|
||||
) : (
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="id_hospital" required>
|
||||
Hospital
|
||||
</InputLabel>
|
||||
<Select
|
||||
id="id_hospital"
|
||||
value={dataHospital && dataHospital.length > 0 ? indexData : ''}
|
||||
fullWidth
|
||||
label="Hospital"
|
||||
onChange={(e) => {
|
||||
handlePageChange(e.target.value);
|
||||
}}
|
||||
|
||||
>
|
||||
{dataHospital?.map((data, index) => (
|
||||
<MenuItem key={index} value={index}>{data.name}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormHelperText style={{ color: 'red' }}></FormHelperText>
|
||||
</FormControl>
|
||||
)
|
||||
) : (
|
||||
<Typography variant='body2' style={{ position: 'relative', margin: 'auto', width: 'fit-content' }}>
|
||||
Loading
|
||||
</Typography>
|
||||
|
||||
<Typography variant="h6">Division Detail</Typography>
|
||||
|
||||
<RHFTextField name="name" label="Name" />
|
||||
|
||||
<RHFTextField name="code" label="Code" />
|
||||
|
||||
<LoadingButton type="submit" variant="contained" size="large" fullWidth={true} loading={isSubmitting}>
|
||||
{ isEdit? 'Update' : 'Create' }
|
||||
</LoadingButton>
|
||||
|
||||
</Stack>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
<Card sx={{ p:2 }}>
|
||||
|
||||
<RHFSwitch name="active" label="Active" />
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</FormProvider>
|
||||
)}
|
||||
|
||||
<Stack direction='row' spacing={2} justifyContent='flex-end'>
|
||||
<Button variant="outlined" sx={{color: '#212B36'}} onClick={() => navigate(-1)}>Cancel</Button>
|
||||
{isEdit ? (
|
||||
<Button sx={{backgroundColor: '#19BBBB'}} variant="contained" onClick={() => handleUpdateData()}>Save</Button>
|
||||
):(
|
||||
<Button sx={{backgroundColor: '#19BBBB'}} variant="contained" onClick={() => handleSaveData()}>Save</Button>
|
||||
)}
|
||||
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
158
frontend/dashboard/src/pages/Corporates/Hospital/History.tsx
Normal file
158
frontend/dashboard/src/pages/Corporates/Hospital/History.tsx
Normal file
@@ -0,0 +1,158 @@
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import Page from "../../../components/Page";
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import { Hospital } from '../../../@types/corporates';
|
||||
import { Corporate } from "@/@types/corporates";
|
||||
import { ConfiguredCorporateContext } from "@/contexts/ConfiguredCorporateContext";
|
||||
import {
|
||||
Stack,
|
||||
Typography,
|
||||
Card,
|
||||
Paper,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Collapse,
|
||||
Box,
|
||||
Tab,
|
||||
} from '@mui/material';
|
||||
import axios from '@/utils/axios';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import { fDate, fDateTime } from '@/utils/formatTime';
|
||||
|
||||
|
||||
|
||||
export default function HospitalHistory() {
|
||||
const { corporate_id, id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [corporate, setCorporate] = useState<Corporate|null>();
|
||||
|
||||
const [ currentHospital, setCurrentHospital ] = useState<Hospital>();
|
||||
|
||||
const configuredCorporateContext = useContext(ConfiguredCorporateContext);
|
||||
|
||||
useEffect(() => {
|
||||
setCorporate(configuredCorporateContext.currentCorporate);
|
||||
const model = 'App\\Models\\CorporateHospital';
|
||||
const url = `/audittrail/${id}?model=${model}`;
|
||||
axios.get(url)
|
||||
.then((res) => {
|
||||
setCurrentHospital(res.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Terjadi kesalahan:', error);
|
||||
});
|
||||
}, [corporate_id, id, configuredCorporateContext]);
|
||||
|
||||
const [openRows, setOpenRows] = useState({});
|
||||
|
||||
const handleRowToggle = (index) => {
|
||||
setOpenRows((prevOpenRows) => ({
|
||||
...prevOpenRows,
|
||||
[index]: !prevOpenRows[index],
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<Page title="History Hospital">
|
||||
<HeaderBreadcrumbs
|
||||
heading={'History Hospital'}
|
||||
links={[
|
||||
{
|
||||
name: 'Corporates',
|
||||
href: '/corporates',
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporates/'+corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Hospital',
|
||||
href: '/corporates/'+corporate_id+'/hospitals',
|
||||
},
|
||||
{
|
||||
name: 'History',
|
||||
href: '/corporates/'+corporate_id+'/hospitals/history',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Card>
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
{/* Condition Table Body */}
|
||||
{currentHospital?.data.map((item, index) => (
|
||||
<TableBody key={index}>
|
||||
<TableRow sx={{backgroundColor: '#919EAB29'}}>
|
||||
<TableCell align="left" sx={{fontWeight: 'bold', width: '95%'}}><Typography variant="subtitle1">Data has {item.action} by {item.user_id} on {fDateTime(item.updated_at)}</Typography></TableCell>
|
||||
<TableCell align="left" sx={{width: '5%'}}>
|
||||
{openRows[index] ? (
|
||||
<KeyboardArrowDownIcon sx={{ cursor: 'pointer' }} onClick={() => handleRowToggle(index)} />
|
||||
) : (
|
||||
<KeyboardArrowRightIcon sx={{ cursor: 'pointer' }} onClick={() => handleRowToggle(index)} />
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow sx={{display: openRows[index] ? '' : 'none',}}>
|
||||
<TableCell colSpan={2}>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<Collapse in={openRows[index]} timeout="auto" unmountOnExit>
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align="left">
|
||||
<Typography sx={{width: '25%'}} variant="subtitle2">Field</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<Typography sx={{width: '25%'}} variant="subtitle2">Old Value</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<Typography sx={{width: '50%'}} variant="subtitle2">New Value</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{Object.entries(item.old_values).map(([key, value]) => {
|
||||
let renderedValue;
|
||||
if (key === 'code' || key === 'name') {
|
||||
renderedValue = item.new_values[key];
|
||||
const field = key.charAt(0).toUpperCase() + key.slice(1);
|
||||
return (
|
||||
<TableRow key={key}>
|
||||
<TableCell align="left">
|
||||
<Typography variant="body2">{field ? field : '-'}</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<Typography variant="body2">{value ? value : '-'}</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<Typography variant="body2">{renderedValue ? renderedValue : ''}</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
))}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Card>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -1,32 +1,33 @@
|
||||
import { Card, Grid, Typography } from '@mui/material';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
|
||||
import Page from '../../../components/Page';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import CorporateTabNavigations from '../CorporateTabNavigations';
|
||||
import DivisionsList from './List';
|
||||
import { Corporate } from "@/@types/corporates";
|
||||
import { ConfiguredCorporateContext } from "@/contexts/ConfiguredCorporateContext";
|
||||
import { Card } from "@mui/material";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import Page from "../../../components/Page";
|
||||
import useSettings from "../../../hooks/useSettings";
|
||||
import CorporateTabNavigations from "../CorporateTabNavigations";
|
||||
import List from "./List";
|
||||
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import { ConfiguredCorporateContext } from '@/contexts/ConfiguredCorporateContext';
|
||||
import { Corporate } from '@/@types/corporates';
|
||||
|
||||
export default function Divisions() {
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
export default function hospitals() {
|
||||
|
||||
const { corporate_id } = useParams();
|
||||
|
||||
const [corporate, setCorporate] = useState<Corporate | null>();
|
||||
|
||||
const [corporate, setCorporate] = useState<Corporate|null>();
|
||||
|
||||
const configuredCorporateContext = useContext(ConfiguredCorporateContext);
|
||||
|
||||
useEffect(() => {
|
||||
setCorporate(configuredCorporateContext.currentCorporate);
|
||||
}, [configuredCorporateContext]);
|
||||
}, [configuredCorporateContext])
|
||||
|
||||
return (
|
||||
<Page title="Hospitals">
|
||||
<Page title="Hospital">
|
||||
|
||||
<HeaderBreadcrumbs
|
||||
heading={'Hospitals'}
|
||||
heading={'Hospital'}
|
||||
links={[
|
||||
{
|
||||
name: 'Corporates',
|
||||
@@ -34,18 +35,18 @@ export default function Divisions() {
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id,
|
||||
href: '/corporates/' + corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Hospitals',
|
||||
href: '/corporate/' + corporate_id + '/hospitals',
|
||||
name: 'Hospital',
|
||||
href: '/corporates/' + corporate_id + '/hospitals',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Card>
|
||||
<CorporateTabNavigations position={'hospitals'} />
|
||||
<Typography sx={{ m: 4 }}>Feature Not Implemented Yet</Typography>
|
||||
<List />
|
||||
</Card>
|
||||
</Page>
|
||||
);
|
||||
|
||||
@@ -1,124 +1,164 @@
|
||||
// @mui
|
||||
import { Box, Button, Card, Collapse, IconButton, InputLabel, MenuItem, OutlinedInput, Paper, Select, SelectChangeEvent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Badge, Tab, Tabs, CardHeader, Stack, Menu, ButtonGroup } from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
IconButton,
|
||||
MenuItem,
|
||||
Paper,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
Stack,
|
||||
Collapse,
|
||||
Box,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Select,
|
||||
FormHelperText,
|
||||
Menu,
|
||||
ButtonGroup
|
||||
} from '@mui/material';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
// hooks
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
import React, { ChangeEvent, useEffect, useRef, useState } from 'react';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
// components
|
||||
import axios from '../../../utils/axios';
|
||||
import { CorporatePlan } from '../../../@types/corporates';
|
||||
import { Hospital } from '../../../@types/corporates';
|
||||
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||
import BasePagination from '../../../components/BasePagination';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||
import HistoryIcon from '@mui/icons-material/History';
|
||||
import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined';
|
||||
import CachedOutlinedIcon from '@mui/icons-material/CachedOutlined';
|
||||
import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import Label from '../../../components/Label';
|
||||
import DownloadIcon from '@mui/icons-material/Download';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
|
||||
export default function PlanList() {
|
||||
const { themeStretch } = useSettings();
|
||||
export default function HospitalList() {
|
||||
const { corporate_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
const [searchText, setSearchText] = useState("");
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
||||
const handleSearchChange = (event: any) => {
|
||||
const newSearchText = event.target.value ?? ''
|
||||
const newSearchText = event.target.value ?? '';
|
||||
setSearchText(newSearchText);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = (event: any) => {
|
||||
event.preventDefault();
|
||||
props.onSearch(searchText); // Trigger to Parent
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// console.log('Search Input: useEffect')
|
||||
useEffect(() => {
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
}, [searchParams])
|
||||
}, [searchParams]);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} style={{ width: '100%' }}>
|
||||
<TextField id="search-input" ref={searchInput} label="Search" variant="outlined" fullWidth onChange={handleSearchChange} value={searchText}/>
|
||||
<TextField
|
||||
id="search-input"
|
||||
ref={searchInput}
|
||||
label="Search"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
onChange={handleSearchChange}
|
||||
value={searchText}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
// Called on every row to map the data to the columns
|
||||
function createData( plan: CorporatePlan ): CorporatePlan {
|
||||
function createData(hospital: Hospital): Hospital {
|
||||
return {
|
||||
...plan,
|
||||
}
|
||||
...hospital,
|
||||
};
|
||||
}
|
||||
|
||||
// Generate the every row of the table
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const style1 = {
|
||||
color: '#637381'
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell>
|
||||
<IconButton
|
||||
aria-label="expand row"
|
||||
size="small"
|
||||
onClick={() => setOpen(!open)}
|
||||
>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
<TableRow sx={{ '& > *': open ? {borderBottom: 'unset'} : {}, cursor: open ? 'pointer' : '' }} onClick={() => {if(open==true) setOpen(!open)}}>
|
||||
<TableCell align="left">{row.code ? row.code : '-'}</TableCell>
|
||||
<TableCell align="left">{row.name ? row.name : '-'}</TableCell>
|
||||
<TableCell align="left">
|
||||
{row.active === 1 ? (
|
||||
<Label color='success' >
|
||||
Active
|
||||
</Label>
|
||||
) : (
|
||||
<Label color='error'>
|
||||
Inactive
|
||||
</Label>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => setOpen(!open)}>
|
||||
<FindInPageOutlinedIcon />
|
||||
Details
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => handleEditData(row)}>
|
||||
<EditOutlinedIcon />
|
||||
Edit
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => handleEditDataStatus(row)}>
|
||||
<CachedOutlinedIcon />
|
||||
Update Status
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate ('/corporates/'+corporate_id+'/hospitals/'+row.id+'/history')}>
|
||||
<HistoryIcon />
|
||||
History
|
||||
</MenuItem>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.id}</TableCell>
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="left">{row.description}</TableCell>
|
||||
<TableCell align="right"><Button variant="outlined" color="success" size="small">Active</Button></TableCell>
|
||||
<TableCell align="right"><Link to={`/corporates/${row.corporate_id}/divisions/${row.id}/edit`}><Button variant="outlined" color="success" size="small">Edit</Button></Link></TableCell>
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={10}>
|
||||
<TableRow sx={{display: open ? '' : 'none', cursor: open ? 'pointer' : ''}} onClick={() => {if(open==true) setOpen(!open)}}>
|
||||
<TableCell colSpan={4}>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ borderBottom: 1 }}>
|
||||
<Typography variant="body2" gutterBottom component="div">
|
||||
No Extra Data
|
||||
</Typography>
|
||||
</Box>
|
||||
{false && <Box sx={{ margin: 1 }}>
|
||||
<Typography variant="h6" gutterBottom component="div">
|
||||
Rules
|
||||
</Typography>
|
||||
<Table size="small" aria-label="purchases">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Date</TableCell>
|
||||
<TableCell>Customer</TableCell>
|
||||
<TableCell align="right">Amount</TableCell>
|
||||
<TableCell align="right">Total price ($)</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{/* {row.history ? row.history.map((historyRow) => ( */}
|
||||
<TableRow key={row.id}>
|
||||
<TableCell component="th" scope="row">{row.start} - {row.end}</TableCell>
|
||||
<TableCell>{row.start}</TableCell>
|
||||
<TableCell align="right">{row.start}</TableCell>
|
||||
<TableCell align="right">{row.start}</TableCell>
|
||||
</TableRow>
|
||||
{/* ))
|
||||
: (
|
||||
<TableRow>
|
||||
<TableCell colSpan={8}>No Data</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
} */}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Box>}
|
||||
<Card sx={{padding:2}}>
|
||||
<Box sx={{ pb: 2 }}>
|
||||
<Typography variant='subtitle1'>Detail</Typography>
|
||||
<Stack marginTop={2}>
|
||||
<Stack direction='row' spacing={1}>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '50%'}}>Code:</Typography>
|
||||
<Typography variant='body2' sx={{width: '50%'}}>{row.code ? row.code : '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={1}>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '50%'}}>Hospital Name:</Typography>
|
||||
<Typography variant='body2' sx={{width: '50%'}}>{row.name ? row.name : '-'}</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Card>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -131,104 +171,390 @@ export default function PlanList() {
|
||||
const [dataTableData, setDataTableData] = React.useState<LaravelPaginatedData>({
|
||||
current_page: 1,
|
||||
data: [],
|
||||
path: "",
|
||||
first_page_url: "",
|
||||
path: '',
|
||||
first_page_url: '',
|
||||
last_page: 1,
|
||||
last_page_url: "",
|
||||
next_page_url: "",
|
||||
prev_page_url: "",
|
||||
last_page_url: '',
|
||||
next_page_url: '',
|
||||
prev_page_url: '',
|
||||
per_page: 10,
|
||||
from: 0,
|
||||
to: 0,
|
||||
total: 0
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const loadDataTableData = async (appliedFilter : any | null = null) => {
|
||||
const loadDataTableData = async (appliedFilter: any | null = null) => {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const response = await axios.get('/corporates/'+corporate_id+'/divisions', { params: filter });
|
||||
// console.log(response.data);
|
||||
// Get Data Hospitals
|
||||
const response = await axios.get('/corporates/' + corporate_id + '/hospitals', {
|
||||
params: filter,
|
||||
});
|
||||
setDataTableLoading(false);
|
||||
|
||||
setDataTableData(response.data);
|
||||
}
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const applyFilter = async (searchFilter: any) => {
|
||||
await loadDataTableData({ "search" : searchFilter });
|
||||
setSearchParams({ "search" : searchFilter });
|
||||
}
|
||||
await loadDataTableData({ search: searchFilter });
|
||||
setSearchParams({ search: searchFilter });
|
||||
};
|
||||
|
||||
const handlePageChange = (event : ChangeEvent, value: number) => {
|
||||
const filter = Object.fromEntries([...searchParams.entries(), ["page", value]]);
|
||||
const handlePageChange = (event: ChangeEvent, value: number) => {
|
||||
const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]);
|
||||
loadDataTableData(filter);
|
||||
setSearchParams(filter);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, [])
|
||||
}, []);
|
||||
|
||||
//validation dialog
|
||||
const [nameField, setNameField] = useState('');
|
||||
const [codeField, setCodeField] = useState('');
|
||||
// ID for edit data
|
||||
const [idField, setIdField] = useState('');
|
||||
|
||||
const handleAddData = () => {
|
||||
navigate('/corporates/'+corporate_id+'/hospitals/create');
|
||||
}
|
||||
//Edit data
|
||||
const handleEditData = (data : any) => {
|
||||
navigate('/corporates/'+corporate_id+'/hospitals/edit/'+data.id+'/'+data.organization_id);
|
||||
}
|
||||
// End dialog for hospitals
|
||||
|
||||
// Dialog for update status hospitals
|
||||
const [openDialogStatus, setOpenDialogStatus] = useState(false);
|
||||
const [activeField, setActiveField] = useState(0);
|
||||
const [reasonUpdate,setReasonUpdate] = useState('Agreement changed');
|
||||
|
||||
const handleCloseDialogUpdate = () => {
|
||||
setOpenDialogStatus(false);
|
||||
setNameField('');
|
||||
setCodeField('');
|
||||
setIdField('');
|
||||
setActiveField(activeField);
|
||||
}
|
||||
|
||||
const handleSaveUpdateData = () => {
|
||||
let activeValue = 0;
|
||||
if(activeField === 1)
|
||||
{
|
||||
activeValue = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
activeValue = 1;
|
||||
}
|
||||
const updateData = {
|
||||
reason: reasonUpdate,
|
||||
active : activeValue,
|
||||
id: idField,
|
||||
};
|
||||
axios
|
||||
.put('/hospitals/'+idField+'/activation', updateData)
|
||||
.then((response) => {
|
||||
enqueueSnackbar('Data updated successfully', { variant: 'success' });
|
||||
loadDataTableData();
|
||||
handleCloseDialogUpdate();
|
||||
})
|
||||
.catch((error) => {
|
||||
enqueueSnackbar('Failed to add data', { variant: 'error' });
|
||||
});
|
||||
}
|
||||
|
||||
const handleEditDataStatus = (data: any) => {
|
||||
setIdField(data.id);
|
||||
setNameField(data.name);
|
||||
setCodeField(data.code);
|
||||
setActiveField(data.active);
|
||||
setOpenDialogStatus(true);
|
||||
}
|
||||
// End dialog for update status devisions
|
||||
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const createMenu = Boolean(anchorEl);
|
||||
const importHospital = useRef<HTMLInputElement>(null);
|
||||
const [currentImportFileName, setCurrentImportFileName] = useState(null);
|
||||
const [importLoading, setImportLoading] = useState(false);
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
const handleImportButton = () => {
|
||||
if (importHospital?.current) {
|
||||
handleClose();
|
||||
importHospital.current ? importHospital.current.click() : console.log('No File selected');
|
||||
} else {
|
||||
alert('No file selected');
|
||||
}
|
||||
};
|
||||
const handleCancelImportButton = () => {
|
||||
if(importHospital.current)
|
||||
{
|
||||
importHospital.current.value = '';
|
||||
importHospital.current.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
};
|
||||
const handleImportChange = (event: any) => {
|
||||
if (event.target.files[0]) {
|
||||
setCurrentImportFileName(event.target.files[0].name);
|
||||
} else {
|
||||
setCurrentImportFileName(null);
|
||||
}
|
||||
};
|
||||
const handleUpload = () => {
|
||||
if(importHospital.current && importHospital.current.files)
|
||||
{
|
||||
if (importHospital.current?.files.length) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', importHospital.current?.files[0]);
|
||||
setImportLoading(true);
|
||||
axios
|
||||
.post('corporates/'+corporate_id+'/hospitals/import', formData)
|
||||
.then((response) => {
|
||||
handleCancelImportButton();
|
||||
loadDataTableData();
|
||||
setImportResult(response.data);
|
||||
setImportLoading(false);
|
||||
enqueueSnackbar('Success Import Hospitals', { variant: 'success' });
|
||||
})
|
||||
.catch((response) => {
|
||||
enqueueSnackbar(
|
||||
'Looks like something went wrong. Please check your data and try again. ' +
|
||||
response.message,
|
||||
{ variant: 'error' }
|
||||
);
|
||||
setImportLoading(false);
|
||||
});
|
||||
} else {
|
||||
enqueueSnackbar('No File Selected', { variant: 'warning' });
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleGetTemplate = () => {
|
||||
axios.get('corporates/hospitals/download-template').then((response) => {
|
||||
const link = document.createElement('a');
|
||||
link.href = response.data.data.file_url;
|
||||
link.setAttribute('download', response.data.data.file_name);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
handleClose();
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<input
|
||||
type="file"
|
||||
id="file"
|
||||
ref={importHospital}
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleImportChange}
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain"
|
||||
/>
|
||||
{!currentImportFileName && (
|
||||
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter}/>
|
||||
<Link to={`/corporates/${corporate_id}/divisions/create`}>
|
||||
<Button
|
||||
component="button"
|
||||
id="upload-button"
|
||||
variant='outlined'
|
||||
startIcon={<AddIcon />} sx={{ p: 1.8 }}
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
</Link>
|
||||
<SearchInput onSearch={applyFilter} />
|
||||
<Button
|
||||
id="import-button"
|
||||
startIcon={<DownloadIcon />}
|
||||
sx={{ p: 1.8, color: '#FFFFFF', backgroundColor: '#19BBBB', width: '125px', height: '48px' }}
|
||||
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={createMenu ? 'true' : undefined}
|
||||
onClick={handleClick}
|
||||
>
|
||||
Import
|
||||
</Button>
|
||||
<Menu
|
||||
id="import-button"
|
||||
anchorEl={anchorEl}
|
||||
open={createMenu}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
'aria-labelledby': 'basic-button',
|
||||
}}
|
||||
>
|
||||
<MenuItem onClick={handleAddData}>
|
||||
<Typography variant='body2'>Create</Typography>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={handleImportButton}>
|
||||
<Typography variant='body2'>Import</Typography>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
handleGetTemplate();
|
||||
}}
|
||||
>
|
||||
<Typography variant='body2'> Download Template</Typography>
|
||||
</MenuItem>
|
||||
{/* <MenuItem onClick={handleICDList}>
|
||||
<Typography variant='body2'>Download ICD</Typography>
|
||||
</MenuItem> */}
|
||||
</Menu>
|
||||
</Stack>
|
||||
)}
|
||||
{currentImportFileName && (
|
||||
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<ButtonGroup variant="outlined" aria-label="outlined button group" fullWidth>
|
||||
<Button onClick={handleImportButton} fullWidth>
|
||||
{currentImportFileName ?? 'No File Selected'}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleCancelImportButton}
|
||||
size="small"
|
||||
fullWidth={false}
|
||||
sx={{ p: 1.8 }}
|
||||
>
|
||||
<CancelIcon color="error" />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
<Card>
|
||||
<LoadingButton
|
||||
id="upload-button"
|
||||
variant="outlined"
|
||||
startIcon={<UploadIcon />}
|
||||
sx={{ p: 1.8 }}
|
||||
onClick={handleUpload}
|
||||
loading={importLoading}
|
||||
>
|
||||
Upload
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
)}
|
||||
{importResult && (
|
||||
<Stack direction={'row'} sx={{ px: 2, pb: 2 }}>
|
||||
<Box sx={{ color: 'text.secondary' }}>
|
||||
Last Import Result :{' '}
|
||||
<Box sx={{ color: 'success.main', display: 'inline' }}>
|
||||
{importResult.data.total_success_row ?? 0}
|
||||
</Box>{' '}
|
||||
Row Processed,{' '}
|
||||
<Box sx={{ color: 'error.main', display: 'inline' }}>
|
||||
{importResult.data.total_failed_row}
|
||||
</Box>{' '}
|
||||
Failed
|
||||
{importResult.data.failed_rows.map((row, index) => (
|
||||
<Typography variant='body' key={index} color="error"> [Code={row.code ? row.code : 'Required'},Name={row.name ? row.name : 'Required'}]</Typography>
|
||||
))}
|
||||
</Box>
|
||||
</Stack>
|
||||
)}
|
||||
<Card>
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
{/* Table Head */}
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" />
|
||||
<TableCell style={headStyle} align="left">ID</TableCell>
|
||||
<TableCell style={headStyle} align="left">Code</TableCell>
|
||||
<TableCell style={headStyle} align="left">Name</TableCell>
|
||||
<TableCell style={headStyle} align="left">Description</TableCell>
|
||||
<TableCell sx={{width: '20%'}} align="left">
|
||||
<Typography variant='subtitle2'>Code</Typography>
|
||||
</TableCell>
|
||||
<TableCell sx={{width: '50%'}} align="left">
|
||||
<Typography variant='subtitle2'>Hospital</Typography>
|
||||
</TableCell>
|
||||
<TableCell sx={{width: '20%'}} align="left">
|
||||
<Typography variant='subtitle2'>Status</Typography>
|
||||
</TableCell>
|
||||
<TableCell sx={{width: '10%'}} align="left">
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
{dataTableIsLoading ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">Loading</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
dataTableData.data.length == 0 ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">No Data</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody>
|
||||
{dataTableData.data.map(row => (
|
||||
<Row key={row.code} row={row} />
|
||||
))}
|
||||
</TableBody>
|
||||
)
|
||||
</TableHead>
|
||||
{/* Condition Table Body */}
|
||||
{dataTableIsLoading ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={4} align="center">
|
||||
Loading
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : dataTableData.data.length == 0 ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={4} align="center">
|
||||
No Data
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody>
|
||||
{dataTableData.data.map((row) => (
|
||||
<Row key={row.id} row={row} />
|
||||
))}
|
||||
</TableBody>
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange}/>
|
||||
</Card>
|
||||
{/* Paginations */}
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||
</Card>
|
||||
{/* Dialog Update Status */}
|
||||
<Dialog open={openDialogStatus} onClose={handleCloseDialogUpdate} 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">Update Status</Typography>
|
||||
</Stack>
|
||||
<IconButton sx={{ color: '#FFF' }} onClick={handleCloseDialogUpdate}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Stack spacing={2} padding={2}>
|
||||
<Typography variant='body1'>Are you sure to {activeField == 1 ? 'Inactive' : 'Active'} this hospital ?</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%'}}>{codeField}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2}>
|
||||
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Hospital Name</Typography>
|
||||
<Typography variant='subtitle2' sx={{width: '70%'}}>{nameField}</Typography>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Stack>
|
||||
<Stack spacing={2} padding={2}>
|
||||
<Typography variant='subtitle1'>Reason for update*</Typography>
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="reason" required>
|
||||
Reason for update
|
||||
</InputLabel>
|
||||
<Select
|
||||
id="reason"
|
||||
value={reasonUpdate}
|
||||
fullWidth
|
||||
label="Reason for update"
|
||||
onChange={(e) => {
|
||||
setReasonUpdate(e.target.value);
|
||||
}}
|
||||
|
||||
>
|
||||
<MenuItem value="Agreement changed">Agreement changed</MenuItem>
|
||||
<MenuItem value="Endorsement">Endorsement</MenuItem>
|
||||
<MenuItem value="Renewal">Renewal</MenuItem>
|
||||
<MenuItem value="Worng Setting">Worng Setting</MenuItem>
|
||||
</Select>
|
||||
<FormHelperText style={{ color: 'red' }}></FormHelperText>
|
||||
</FormControl>
|
||||
</Stack>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant="outlined" sx={{color: '#212B36'}} onClick={handleCloseDialogUpdate}>Cancel</Button>
|
||||
<Button sx={{backgroundColor: activeField == 0 ? '#19BBBB' : '#FF4842'}} onClick={handleSaveUpdateData} variant="contained">{activeField == 1 ? 'Inactive' : 'Active'}</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -24,21 +24,33 @@ import {
|
||||
Typography,
|
||||
Badge,
|
||||
Stack,
|
||||
Dialog,
|
||||
} from '@mui/material';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
|
||||
// icon
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import PublishIcon from '@mui/icons-material/Publish';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import HistoryIcon from '@mui/icons-material/History';
|
||||
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||
import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined';
|
||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||
import SettingsOutlinedIcon from '@mui/icons-material/SettingsOutlined';
|
||||
import CachedOutlinedIcon from '@mui/icons-material/CachedOutlined';
|
||||
|
||||
// hooks
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
// components
|
||||
import Page from '../../components/Page';
|
||||
import DialogUpdateStatus from '../../components/DialogUpdateStatus';
|
||||
import axios from '../../utils/axios';
|
||||
import useAuth from '../../hooks/useAuth';
|
||||
import { Link, NavLink as RouterLink, useSearchParams } from 'react-router-dom';
|
||||
import React, { ChangeEvent, useEffect, useRef, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { Link, NavLink as RouterLink, useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import React, { ChangeEvent, ReactElement, useEffect, useRef, useState } from 'react';
|
||||
import { Theme, useTheme } from '@mui/material/styles';
|
||||
import { Corporate } from '../../@types/corporates';
|
||||
import { LaravelPaginatedData } from '../../@types/paginated-data';
|
||||
@@ -47,10 +59,45 @@ import BasePagination from '../../components/BasePagination';
|
||||
import { fCurrency } from '../../utils/formatNumber';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { fDate } from '@/utils/formatTime';
|
||||
import Popover from '@mui/material/Popover';
|
||||
|
||||
import ButtonStyles from '../../theme/overrides/Button';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
import Iconify from '@/components/Iconify';
|
||||
import Label from '@/components/Label';
|
||||
import { FormProvider, RHFSelect } from '@/components/hook-form';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
|
||||
|
||||
export default function Corporates() {
|
||||
const { themeStretch } = useSettings();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const navigate = useNavigate()
|
||||
|
||||
// Type
|
||||
type DataContent = {
|
||||
code: string;
|
||||
name: string;
|
||||
id: string;
|
||||
status: string|number;
|
||||
};
|
||||
|
||||
type MuiDialogProps = {
|
||||
title?: {
|
||||
name?: string;
|
||||
icon?: string;
|
||||
};
|
||||
openDialog: boolean;
|
||||
setOpenDialog: Function;
|
||||
content?: ReactElement;
|
||||
data?: DataContent[];
|
||||
};
|
||||
|
||||
type FormValuesProps = {
|
||||
value: string;
|
||||
active: boolean;
|
||||
};
|
||||
|
||||
// Called on every row to map the data to the columns
|
||||
function createData(corporate: Corporate): Corporate {
|
||||
@@ -58,6 +105,7 @@ export default function Corporates() {
|
||||
...corporate,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// Dummy Default Data
|
||||
const [dataTableIsLoading, setDataTableLoading] = React.useState(true);
|
||||
@@ -80,7 +128,7 @@ export default function Corporates() {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const response = await axios.get('/corporates', { params: filter });
|
||||
// console.log(response.data);
|
||||
console.log(response.data);
|
||||
setDataTableLoading(false);
|
||||
|
||||
setDataTableData(response.data);
|
||||
@@ -150,6 +198,8 @@ export default function Corporates() {
|
||||
typeof value === 'string' ? value.split(',') : value
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// END FILTER SELECT
|
||||
|
||||
// Component Search Input
|
||||
@@ -181,7 +231,8 @@ export default function Corporates() {
|
||||
ref={searchInput}
|
||||
label="Search"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
// fullWidth
|
||||
style={{ width: '85%' }}
|
||||
onChange={handleSearchChange}
|
||||
value={searchText}
|
||||
/>
|
||||
@@ -246,8 +297,8 @@ export default function Corporates() {
|
||||
Import
|
||||
</Button> */}
|
||||
<Link to={'/corporates/create'}>
|
||||
<Button variant="outlined" startIcon={<AddIcon />} sx={{ p: 1.8 }}>
|
||||
Create
|
||||
<Button variant="contained" startIcon={<AddIcon sx={{}} />} sx={{ p: 1.8, typography: 'subtitle2' }}>
|
||||
New Corporate
|
||||
</Button>
|
||||
</Link>
|
||||
{/* </Grid> */}
|
||||
@@ -262,75 +313,200 @@ export default function Corporates() {
|
||||
|
||||
// Component Row
|
||||
// Generate the every row of the table
|
||||
const [isDialogOpen, setDialogOpen] = useState(false)
|
||||
let titles = {
|
||||
name: 'Update Status',
|
||||
icon: '-'
|
||||
}
|
||||
const [dataValue, setDataValue] = useState();
|
||||
const [dataDescription, setDescriptionValue] = useState('');
|
||||
|
||||
|
||||
const NewCorporateSchema = Yup.object().shape({
|
||||
reason: Yup.string().required('Reason Edit is required'),
|
||||
});
|
||||
const methods = useForm<FormValuesProps>({
|
||||
resolver: yupResolver(NewCorporateSchema),
|
||||
});
|
||||
|
||||
const {
|
||||
reset,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
} = methods;
|
||||
|
||||
const onSubmit = async (row : any) => {
|
||||
try {
|
||||
console.log(dataValue)
|
||||
handleUpdate(dataValue.id, dataValue.status, row.reason)
|
||||
} catch (error: any) {
|
||||
console.log('data gagal');
|
||||
}
|
||||
|
||||
const ascent = document?.querySelector('ascent');
|
||||
if (ascent != null) {
|
||||
ascent.innerHTML = '';
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdate = (id: string, active: number, reason: string) => {
|
||||
axios
|
||||
.put(`/corporates/${id}/activation`, {
|
||||
active: active,
|
||||
reason: reason
|
||||
})
|
||||
.then((res) => {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const getContent = () => (
|
||||
<>
|
||||
<Stack paddingX={2} paddingY={2}>
|
||||
<Typography variant='subtitle1'>Are you sure to {dataValue?.status == 1 ? 'inactive' : 'active'} this service ?</Typography>
|
||||
</Stack>
|
||||
<Card>
|
||||
<Grid container paddingX={2} paddingY={2}>
|
||||
<Grid item xs={4} md={4}>
|
||||
<Typography variant='inherit'>Code</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
<Typography variant='subtitle1'>{dataValue?.code}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={4} md={4} marginTop={2}>
|
||||
<Typography variant='inherit'>Corporate Name</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={8} marginTop={2}>
|
||||
<Typography variant='subtitle1'>{dataValue?.name}</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
|
||||
<Typography marginTop={5} marginBottom={3} variant='subtitle1'>
|
||||
Reason for update*
|
||||
</Typography>
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<RHFSelect
|
||||
name="reason"
|
||||
label="Reason for update"
|
||||
>
|
||||
<option value=""></option>
|
||||
<option value="Agreement changed">Agreement changed</option>
|
||||
<option value="Endorsement">Endorsement</option>
|
||||
<option value="Renewal">Renewal</option>
|
||||
<option value="Worng Setting">Worng Setting</option>
|
||||
</RHFSelect>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
justifyContent="flex-end"
|
||||
direction={{ xs: 'column', md: 'row' }}
|
||||
spacing={2}
|
||||
marginTop={5}
|
||||
>
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Button
|
||||
sx={{
|
||||
boxShadow: 'none',
|
||||
}}
|
||||
variant="outlined"
|
||||
size="medium"
|
||||
fullWidth={true}
|
||||
onClick={() => setDialogOpen(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
{dataValue?.status == 1 ?
|
||||
<LoadingButton
|
||||
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)'}}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="medium"
|
||||
fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
color='error'
|
||||
>
|
||||
Inactive
|
||||
</LoadingButton>
|
||||
:
|
||||
<LoadingButton
|
||||
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)'}}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="medium"
|
||||
fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
color='success'
|
||||
>
|
||||
Active
|
||||
</LoadingButton>
|
||||
|
||||
|
||||
}
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
</FormProvider>
|
||||
</>
|
||||
);
|
||||
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const navigate = useNavigate()
|
||||
|
||||
const handleActivate = (model: any, status: string) => {
|
||||
axios
|
||||
.put(`/corporates/${row.id}/activation`, {
|
||||
// service_code: service.service_code,
|
||||
active: status == 'active',
|
||||
})
|
||||
.then((res) => {
|
||||
setDataTableData({
|
||||
...dataTableData,
|
||||
data: dataTableData.data.map((model) => {
|
||||
let updatedModel = model;
|
||||
if (row.id == model.id) {
|
||||
updatedModel.active = res.data.corporate.active;
|
||||
}
|
||||
return updatedModel;
|
||||
}),
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
// console.log('asdasd', error.response.data.message)
|
||||
enqueueSnackbar(
|
||||
error.response.data.message ?? error.message ?? 'Failed Processing Request',
|
||||
{ variant: 'error' }
|
||||
);
|
||||
});
|
||||
|
||||
const handleActivate = (isOpen: boolean, dataValue: DataContent) => {
|
||||
setDialogOpen(isOpen)
|
||||
setDataValue(dataValue)
|
||||
setDescriptionValue('Are you sure to inactive this coporate ?')
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableRow >
|
||||
<TableCell>
|
||||
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||
{/* <IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</IconButton> */}
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="left">
|
||||
{row.active == 1 && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="success"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
handleActivate(row, 'inactive');
|
||||
}}
|
||||
>
|
||||
<Label color='success'>
|
||||
Active
|
||||
</Button>
|
||||
</Label>
|
||||
// <Button
|
||||
// variant="outlined"
|
||||
// color="success"
|
||||
// size="small"
|
||||
// onClick={() => {
|
||||
// handleActivate(row, 'inactive');
|
||||
// }}
|
||||
// >
|
||||
// Active
|
||||
// </Button>
|
||||
)}
|
||||
{row.active != 1 && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="error"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
handleActivate(row, 'active');
|
||||
}}
|
||||
>
|
||||
<Label color='error'>
|
||||
Inactive
|
||||
</Button>
|
||||
</Label>
|
||||
// <Button
|
||||
// variant="outlined"
|
||||
// color="error"
|
||||
// size="small"
|
||||
// onClick={() => {
|
||||
// handleActivate(row, 'active');
|
||||
// }}
|
||||
// >
|
||||
// Inactive
|
||||
// </Button>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
<Stack direction="row" justifyContent="flex-end" spacing={1}>
|
||||
<TableCell align="right" sx={{borderBottom: 'unset'}}>
|
||||
{/* <Stack direction="row" justifyContent="flex-end" spacing={1}>
|
||||
<Link to={`/corporates/${row.id}/edit`}>
|
||||
<Button variant="outlined" color="primary" size="small">
|
||||
Edit
|
||||
@@ -344,147 +520,151 @@ export default function Corporates() {
|
||||
<Link to={`/corporate/${row.id}/corporate-history`}>
|
||||
<HistoryIcon />
|
||||
</Link>
|
||||
</Stack>
|
||||
</Stack> */}
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => setOpen(!open)}>
|
||||
<FindInPageOutlinedIcon />
|
||||
Detail
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate(`/corporates/${row.id}/edit`)}>
|
||||
<EditOutlinedIcon />
|
||||
Edit
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate(`/corporates/${row.id}`)}>
|
||||
<SettingsOutlinedIcon />
|
||||
Config
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate(`/corporates/${row.id}/corporate-history`)}>
|
||||
<HistoryIcon />
|
||||
History
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => handleActivate(true, {code: row.code, name: row.name, id:row.id, status: row.active})}>
|
||||
<CachedOutlinedIcon />
|
||||
Update Status
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
|
||||
|
||||
|
||||
{/* COLLAPSIBLE Detail ROW */}
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={9999}>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ margin: 1, borderBottom: 1, pb: 2 }}>
|
||||
<Typography sx={{ fontWeight: '600', mb: 1 }}>Current Policy Detail</Typography>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
Policy Code
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.current_policy?.code}
|
||||
</Grid>
|
||||
<Card sx={{paddingX: 2, paddingY: 2, marginBottom:3}}>
|
||||
<Box sx={{ margin: 1, pb: 2 }}>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
<Typography sx={{ fontWeight: '600', mb: 1 }}>Current Policy Detail</Typography>
|
||||
<Grid container>
|
||||
<Grid item xs={4}>
|
||||
Policy Code :
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
{row.current_policy?.code}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
Number of Plan
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.corporate_plans_count}
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
Number of Plan :
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
{row.corporate_plans_count}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
Number of Benefit
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.corporate_benefits_count}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
Number of Benefit :
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
{row.corporate_benefits_count}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
Period
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Box sx={{ display: 'flex', placeContent: 'space-between' }}>
|
||||
<span>: {fDate(row.current_policy?.start)}</span>-
|
||||
<span>{fDate(row.current_policy?.end)}</span>
|
||||
</Box>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
Total Premi
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
{row.current_policy ? (
|
||||
<Grid item xs={4}>
|
||||
Period :
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Box sx={{ display: 'flex', placeContent: 'space-between' }}>
|
||||
<span>
|
||||
: {fCurrency(row.current_policy?.total_premi).split(' ')[0]}
|
||||
</span>
|
||||
<span>{fCurrency(row.current_policy?.total_premi).split(' ')[1]}</span>
|
||||
{/* <span>: {fDate(row.current_policy?.start)}</span>- */}
|
||||
{/* <span>{fDate(row.current_policy?.end)}</span> */}
|
||||
</Box>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
Minimal Deposit
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
{row.current_policy ? (
|
||||
<Box sx={{ display: 'flex', placeContent: 'space-between' }}>
|
||||
<span>
|
||||
: {fCurrency(row.current_policy?.minimal_deposit_net).split(' ')[0]}
|
||||
</span>
|
||||
<span>
|
||||
{fCurrency(row.current_policy?.minimal_deposit_net).split(' ')[1]}
|
||||
</span>
|
||||
</Box>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
Total Premi :
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
{row.current_policy ? (
|
||||
<Box sx={{ display: 'flex', placeContent: 'space-between' }}>
|
||||
<span>
|
||||
{fCurrency(row.current_policy?.total_premi).split(' ')[0]}
|
||||
</span>
|
||||
<span>{fCurrency(row.current_policy?.total_premi).split(' ')[1]}</span>
|
||||
</Box>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
Corporate Limit
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
{row.current_policy ? (
|
||||
<Box sx={{ display: 'flex', placeContent: 'space-between' }}>
|
||||
<span>
|
||||
: {fCurrency(row.current_policy?.limit_balance).split(' ')[0]}
|
||||
</span>
|
||||
<span>
|
||||
{fCurrency(row.current_policy?.limit_balance).split(' ')[1]}
|
||||
</span>
|
||||
</Box>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
<Grid item xs={4}>
|
||||
Minimal Deposit :
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
{row.current_policy ? (
|
||||
<Box sx={{ display: 'flex', placeContent: 'space-between' }}>
|
||||
<span>
|
||||
{fCurrency(row.current_policy?.minimal_deposit_net).split(' ')[0]}
|
||||
</span>
|
||||
<span>
|
||||
{fCurrency(row.current_policy?.minimal_deposit_net).split(' ')[1]}
|
||||
</span>
|
||||
</Box>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item xs={4}>
|
||||
Corporate Limit :
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
{row.current_policy ? (
|
||||
<Box sx={{ display: 'flex', placeContent: 'space-between' }}>
|
||||
<span>
|
||||
{fCurrency(row.current_policy?.limit_balance).split(' ')[0]}
|
||||
</span>
|
||||
<span>
|
||||
{fCurrency(row.current_policy?.limit_balance).split(' ')[1]}
|
||||
</span>
|
||||
</Box>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Typography sx={{ fontWeight: '600', mb: 1, mt: 2 }}>Member Detail</Typography>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
Total Member
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.employees_count}
|
||||
<Grid item xs={6}>
|
||||
<Typography sx={{ fontWeight: '600', mb: 1 }}>Member Detail</Typography>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
Total Member :
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
{row.employees_count}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
Total Claim This Month :
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
0
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
<Grid Grid container>
|
||||
<Grid item xs={6}>
|
||||
Total Claim This Month
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: 0
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* <Typography sx={{ fontWeight: '600', mb: 1, mt: 2 }}>Sub Corporate</Typography>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
Sub Corporates ({row.sub_corporates.length})
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.sub_corporates?.map((corp) => corp.name).join(', ')}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid> */}
|
||||
</Box>
|
||||
</Box>
|
||||
</Card>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -499,6 +679,10 @@ export default function Corporates() {
|
||||
heading={'Coporate List'}
|
||||
links={[
|
||||
{ name: 'Dashboard', href: '/dashboard' },
|
||||
{
|
||||
name: 'Station Benefit & Membership',
|
||||
href: '/corporates',
|
||||
},
|
||||
{
|
||||
name: 'Corporates',
|
||||
href: '/corporates',
|
||||
@@ -508,27 +692,27 @@ export default function Corporates() {
|
||||
|
||||
<SearchInput onSearch={applyFilter} />
|
||||
|
||||
<Card>
|
||||
{/* <Card> */}
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" width={50} />
|
||||
<TableCell style={headStyle} align="left">
|
||||
<TableCell align="left" width={50} />
|
||||
<TableCell align="left">
|
||||
Code
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
<TableCell align="left">
|
||||
Name
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left" width={100}>
|
||||
<TableCell align="left" width={100}>
|
||||
Status
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="center" width={100}>
|
||||
Action
|
||||
<TableCell align="center" width={100}>
|
||||
{/* Action */}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</TableHead>
|
||||
{dataTableIsLoading ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
@@ -555,8 +739,17 @@ export default function Corporates() {
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||
</Card>
|
||||
{/* </Card> */}
|
||||
</Container>
|
||||
<DialogUpdateStatus
|
||||
openDialog={isDialogOpen}
|
||||
setOpenDialog={setDialogOpen}
|
||||
title={titles}
|
||||
data={dataValue}
|
||||
description={dataDescription}
|
||||
content={getContent()}
|
||||
/>
|
||||
</Page>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
166
frontend/dashboard/src/pages/Corporates/Member/History.tsx
Normal file
166
frontend/dashboard/src/pages/Corporates/Member/History.tsx
Normal file
@@ -0,0 +1,166 @@
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import Page from "../../../components/Page";
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import { Member } from '../../../@types/corporates';
|
||||
import { Corporate } from "@/@types/corporates";
|
||||
import { ConfiguredCorporateContext } from "@/contexts/ConfiguredCorporateContext";
|
||||
import {
|
||||
Stack,
|
||||
Typography,
|
||||
Card,
|
||||
Paper,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Collapse,
|
||||
Box,
|
||||
Tab,
|
||||
} from '@mui/material';
|
||||
import axios from '@/utils/axios';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import { fDate, fDateTime } from '@/utils/formatTime';
|
||||
|
||||
|
||||
|
||||
export default function MemberHistory() {
|
||||
const { corporate_id, member_id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [corporate, setCorporate] = useState<Corporate|null>();
|
||||
|
||||
const [ currentMember, setCurrentMember ] = useState<Member>();
|
||||
|
||||
const configuredCorporateContext = useContext(ConfiguredCorporateContext);
|
||||
|
||||
useEffect(() => {
|
||||
setCorporate(configuredCorporateContext.currentCorporate);
|
||||
const model = 'App\\Models\\Member';
|
||||
const url = `/audittrail/${member_id}?model=${model}`;
|
||||
axios.get(url)
|
||||
.then((res) => {
|
||||
setCurrentMember(res.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Terjadi kesalahan:', error);
|
||||
});
|
||||
}, [corporate_id, member_id, configuredCorporateContext]);
|
||||
|
||||
const [openRows, setOpenRows] = useState({});
|
||||
|
||||
const handleRowToggle = (index) => {
|
||||
setOpenRows((prevOpenRows) => ({
|
||||
...prevOpenRows,
|
||||
[index]: !prevOpenRows[index],
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<Page title="History Member">
|
||||
<HeaderBreadcrumbs
|
||||
heading={'History Member'}
|
||||
links={[
|
||||
{
|
||||
name: 'Corporates',
|
||||
href: '/corporates',
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporates/'+corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Member',
|
||||
href: '/corporates/'+corporate_id+'/members',
|
||||
},
|
||||
{
|
||||
name: 'History',
|
||||
href: '/corporates/'+corporate_id+'/members/history',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Card>
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
{/* Condition Table Body */}
|
||||
{currentMember?.data.map((item, index) => (
|
||||
<TableBody key={index}>
|
||||
<TableRow sx={{backgroundColor: '#919EAB29'}}>
|
||||
<TableCell align="left" sx={{fontWeight: 'bold', width: '95%'}}><Typography variant="subtitle1">Data has {item.action} by {item.user_id} on {fDateTime(item.updated_at)}</Typography></TableCell>
|
||||
<TableCell align="left" sx={{width: '5%'}}>
|
||||
{openRows[index] ? (
|
||||
<KeyboardArrowDownIcon sx={{ cursor: 'pointer' }} onClick={() => handleRowToggle(index)} />
|
||||
) : (
|
||||
<KeyboardArrowRightIcon sx={{ cursor: 'pointer' }} onClick={() => handleRowToggle(index)} />
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow sx={{display: openRows[index] ? '' : 'none',}}>
|
||||
<TableCell colSpan={2}>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<Collapse in={openRows[index]} timeout="auto" unmountOnExit>
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align="left">
|
||||
<Typography sx={{width: '25%'}} variant="subtitle2">Field</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<Typography sx={{width: '25%'}} variant="subtitle2">Old Value</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<Typography sx={{width: '50%'}} variant="subtitle2">New Value</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{Object.entries(item.old_values).map(([key, value]) => {
|
||||
let renderedValue;
|
||||
if (key === 'reason' || key === 'updated_at') {
|
||||
switch (key) {
|
||||
case 'updated_at':
|
||||
renderedValue = fDateTime(item.new_values[key]);
|
||||
value = fDateTime(value);
|
||||
break;
|
||||
default:
|
||||
renderedValue = item.new_values[key];
|
||||
break;
|
||||
}
|
||||
const field = key.charAt(0).toUpperCase() + key.slice(1);
|
||||
|
||||
return (
|
||||
<TableRow key={key}>
|
||||
<TableCell align="left">
|
||||
<Typography variant="body2">{field ? field : '-'}</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<Typography variant="body2">{value ? value : '-'}</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<Typography variant="body2">{renderedValue ? renderedValue : ''}</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
else{
|
||||
return null;
|
||||
}
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
))}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Card>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -33,11 +33,11 @@ export default function Divisions() {
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id,
|
||||
href: '/corporates/' + corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Member',
|
||||
href: '/corporate/' + corporate_id + '/members',
|
||||
href: '/corporates/' + corporate_id + '/members',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -29,6 +29,9 @@ import {
|
||||
Grid,
|
||||
Tooltip,
|
||||
Divider,
|
||||
ButtonBase,
|
||||
FormControl,
|
||||
FormHelperText,
|
||||
} from '@mui/material';
|
||||
import Iconify from '@/components/Iconify';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
@@ -40,7 +43,7 @@ import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
|
||||
// hooks
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import {Link, useParams, useSearchParams } from 'react-router-dom';
|
||||
import {Link, useParams, useNavigate, useSearchParams } from 'react-router-dom';
|
||||
// components
|
||||
import axios from '../../../utils/axios';
|
||||
import { Plan } from '../../../@types/corporates';
|
||||
@@ -52,8 +55,16 @@ import { LoadingButton } from '@mui/lab';
|
||||
import DialogLog from './sections/DialogLog';
|
||||
import HistoryIcon from '@mui/icons-material/History';
|
||||
import { makeFormData } from '@/utils/jsonToFormData';
|
||||
import DownloadIcon from '@mui/icons-material/Download';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined';
|
||||
import CachedOutlinedIcon from '@mui/icons-material/CachedOutlined';
|
||||
import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import Label from '../../../components/Label';
|
||||
|
||||
export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
const navigate = useNavigate();
|
||||
// Files MCU
|
||||
const fileMcuInput = useRef<HTMLInputElement>(null);
|
||||
const [fileMcus, setFileMcus] = useState([]);
|
||||
@@ -196,17 +207,17 @@ export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
setTimeout(() => {
|
||||
loadDataTableData();
|
||||
}, 2000);
|
||||
enqueueSnackbar(responseData.message ?? 'Berhasil tambah file MemberID '+member_id+', silahkan lihat dilaporan', { variant: 'success' });
|
||||
enqueueSnackbar(responseData.message ?? 'Berhasil tambah file Member ID '+member_id+', silahkan lihat dilaporan', { variant: 'success' });
|
||||
handleSubmitSuccess();
|
||||
}
|
||||
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
const responseData = response?.data;
|
||||
if(responseData)
|
||||
{
|
||||
enqueueSnackbar(responseData.message ?? 'Something Went Wrong', { variant: 'error' });
|
||||
}
|
||||
if(responseData)
|
||||
{
|
||||
enqueueSnackbar(responseData.message ?? 'Something Went Wrong', { variant: 'error' });
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
setSubmitLoading(false);
|
||||
@@ -319,12 +330,10 @@ export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
{!currentImportFileName && (
|
||||
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter} />
|
||||
{/* <h1>kjasndkjandskjasndkjansdkjansd</h1> */}
|
||||
<Button
|
||||
id="import-button"
|
||||
variant="outlined"
|
||||
startIcon={<AddIcon />}
|
||||
sx={{ p: 1.8 }}
|
||||
startIcon={<DownloadIcon />}
|
||||
sx={{ p: 1.8, color: '#FFFFFF', backgroundColor: '#19BBBB', width: '125px', height: '48px' }}
|
||||
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={createMenu ? 'true' : undefined}
|
||||
@@ -341,15 +350,19 @@ export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
'aria-labelledby': 'basic-button',
|
||||
}}
|
||||
>
|
||||
<MenuItem onClick={handleImportButton}>Import</MenuItem>
|
||||
<MenuItem onClick={handleImportButton}>
|
||||
<Typography variant='body2'>Import</Typography>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
handleGetTemplate('member');
|
||||
}}
|
||||
>
|
||||
Download Template
|
||||
<Typography variant='body2'> Download Template</Typography>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={handleMemberList}>
|
||||
<Typography variant='body2'>Download Member</Typography>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={handleMemberList}>Download Member</MenuItem>
|
||||
</Menu>
|
||||
</Stack>
|
||||
)}
|
||||
@@ -412,17 +425,14 @@ export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
}
|
||||
|
||||
const [columns, setColumns] = React.useState([
|
||||
{ id: 'member_id', label: 'MemberID', minWidth: 100, align: 'left' },
|
||||
// { id: 'principal_id', label: 'Mapping ID', minWidth: 100, align: 'left' },
|
||||
// { id: 'nik', label: 'NIK', minWidth: 100, align: 'left' },
|
||||
// { id: 'current_policy.policy_number', label: 'Policy Number', minWidth: 100, align: 'left' },
|
||||
{ id: 'effective_date', label: 'Effective Date', minWidth: 100, align: 'left' },
|
||||
{ id: 'name', label: 'Name', minWidth: 100, align: 'left' },
|
||||
// { id: 'nric', label: 'NRIC', minWidth: 100, align: 'left' },
|
||||
// { id: 'email', label: 'E-mail', minWidth: 100, align: 'left' },
|
||||
{ id: 'plan_id', label: 'PlanID', minWidth: 100, align: 'left' },
|
||||
{ id: 'activation_date', label: 'Activation Date', minWidth: 100, align: 'left' },
|
||||
{ id: 'termination_date', label: 'Termination Date', minWidth: 100, align: 'left' },
|
||||
{ id: 'member_id', label: 'Member ID', minWidth: 100, align: 'left', width: '15%' },
|
||||
{ id: 'effective_date', label: 'Effective Date', minWidth: 100, align: 'left', width: '15%' },
|
||||
{ id: 'name', label: 'Name', minWidth: 100, align: 'left', width: '20%' },
|
||||
{ id: 'plan_id', label: 'Plan', minWidth: 100, align: 'left', width: '10%' },
|
||||
{ id: 'activation_date', label: 'Activation Date', minWidth: 100, align: 'left', width: '15%' },
|
||||
{ id: 'termination_date', label: 'Termination Date', minWidth: 100, align: 'left', width: '15%' },
|
||||
{id: 'status', label: 'Status', minWidth: 100, align: 'left', width: '5%' },
|
||||
{id: 'action', label: '', minWidth: 100, align: 'left', width: '5%' },
|
||||
]);
|
||||
|
||||
// Generate the every row of the table
|
||||
@@ -432,17 +442,9 @@ export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
const [loadingLog, setLoadingLog] = React.useState(false);
|
||||
const [dialogLogOpen, setDialogLogOpen] = React.useState(false);
|
||||
|
||||
// useEffect(function () {
|
||||
// if (row.full_name == 'Pajri') {
|
||||
// setDialogLogOpen(true);
|
||||
// console.log('fuck');
|
||||
// }
|
||||
// }, []);
|
||||
|
||||
const handleActivate = (model: any, status: string) => {
|
||||
axios
|
||||
.put(`/members/${row.id}/activation`, {
|
||||
// service_code: service.service_code,
|
||||
active: status == 'active',
|
||||
})
|
||||
.then((res) => {
|
||||
@@ -458,284 +460,227 @@ export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
// console.log('asdasd', error.response.data.message)
|
||||
enqueueSnackbar(
|
||||
error.response.data.message ?? error.message ?? 'Failed Processing Request',
|
||||
{ variant: 'error' }
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const style1 = {
|
||||
color: '#637381'
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell>
|
||||
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
<TableRow key={row.id || index} sx={{ '& > *': open ? {borderBottom: 'unset'} : {}, cursor: open ? 'pointer' : '' }} onClick={() => {if(open==true) setOpen(!open)}}>
|
||||
<TableCell align="left">
|
||||
<Typography variant='body2'>{row.member_id ? row.member_id : '-'}</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="left">{row.member_id}</TableCell>
|
||||
<TableCell align="left">{row.members_effective_date}</TableCell>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="left">{row.current_plan?.code}</TableCell>
|
||||
<TableCell align="left">{row.activation_date}</TableCell>
|
||||
<TableCell align="left">{row.terminated_date}</TableCell>
|
||||
<TableCell align="center">
|
||||
{row.active == 1 && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="success"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
// handleActivate(row, 'inactive');
|
||||
clickHandler('edit');
|
||||
setEdit({id: row.id, service_code: row.service_code, status: 'inactive'});
|
||||
}}
|
||||
>
|
||||
<TableCell align="left">
|
||||
<Typography variant='body2'>{row.members_effective_date ? row.members_effective_date : '-'}</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<Typography variant='body2'>{row.name ? row.name : '-'}</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<Typography variant='body2'>
|
||||
{/* {row.current_plan?.code} */}
|
||||
{row.current_plans
|
||||
? row.current_plans.map((plan, index) => (
|
||||
<>
|
||||
{plan.code}
|
||||
{index < row.current_plans.length - 1 && ', '}
|
||||
</>
|
||||
))
|
||||
: '-'}
|
||||
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<Typography variant='body2'>{row.activation_date ? row.activation_date : '-'}</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<Typography variant='body2'>{row.terminated_date ? row.terminated_date : '-'}</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<Typography variant='body2'>
|
||||
{row.active === 1 ? (
|
||||
<Label color='success' >
|
||||
Active
|
||||
</Button>
|
||||
)}
|
||||
{row.active != 1 && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="error"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
// handleActivate(row, 'active');
|
||||
clickHandler('edit');
|
||||
setEdit({id: row.id, service_code: row.service_code, status: 'active'});
|
||||
}}
|
||||
>
|
||||
</Label>
|
||||
) : (
|
||||
<Label color='error'>
|
||||
Inactive
|
||||
</Button>
|
||||
</Label>
|
||||
)}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
<Tooltip title="History">
|
||||
<Link to={`/corporate/${corporate_id}/members/${row.id}/history`}>
|
||||
<HistoryIcon />
|
||||
</Link>
|
||||
</Tooltip>
|
||||
<TableCell align='left'>
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => setOpen(!open)}>
|
||||
<FindInPageOutlinedIcon />
|
||||
Details
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => handleEditDataStatus(row)}>
|
||||
<CachedOutlinedIcon />
|
||||
Update Status
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate ('/corporates/'+corporate_id+'/members/'+row.id+'/history')}>
|
||||
<HistoryIcon />
|
||||
History
|
||||
</MenuItem>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
<TableCell />
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={15}>
|
||||
<TableRow sx={{display: open ? '' : 'none', cursor: open ? 'pointer' : ''}} onClick={() => {if(open==true) setOpen(!open)}}>
|
||||
<TableCell colSpan={8}>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ pb: 2 }}>
|
||||
<Typography sx={{ fontWeight: '600', mb: 1 }}>Detail</Typography>
|
||||
<Grid container sx={{ pb: 2, mb: 2, borderBottom: 1 }}>
|
||||
<Grid item xs={6}>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
Mapping ID
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.principal_id ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
Policy Number
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.current_policy?.code ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
NRIC
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.nric ?? '-'}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
NIK
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.employeds[0]?.nik ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
Email
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.email ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
Phone
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.person?.phone ?? '-'}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
Birth Date
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.birth_date ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
Gender
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.gender ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
Marital Status
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.marital_status ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
Language
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.language ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
Race
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.race ?? '-'}
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
Relationship
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.relation_with_principal ?? '-'}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Typography sx={{ fontWeight: '600', mb: 1 }}>Claim History</Typography>
|
||||
<Grid container sx={{ pb: 2, mb: 2, borderBottom: 1 }}>
|
||||
<Grid item xs={6}>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
Requested
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.total_claims?.requested}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
Pending
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.total_claims?.received}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
Approved
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.total_claims?.approved}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
Declined
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.total_claims?.declined}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
Paid
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.total_claims?.paid}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Typography sx={{ fontWeight: '600', mb: 1 }}>File History</Typography>
|
||||
<Grid container sx={{ pb: 2, mb: 2, borderBottom: 1 }}>
|
||||
<Grid item xs={12}>
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
{row.file_mcu_names
|
||||
? row.file_mcu_names.split(',').map((fileName, index) => (
|
||||
<div key={index}>{fileName}</div>
|
||||
))
|
||||
: '-'}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid spacing={1}>
|
||||
<Stack sx={{ marginTop: 1}}>
|
||||
<LoadingButton
|
||||
id="upload-button"
|
||||
variant="outlined"
|
||||
startIcon={<InsertDriveFileIcon />}
|
||||
// sx={{ p: 1.8 }}
|
||||
// onClick={() => {handleDownloadLog(row)}}
|
||||
onClick={() => {
|
||||
setDialogLogOpen(true);
|
||||
}}
|
||||
loading={loadingLog}
|
||||
>
|
||||
Download LOG
|
||||
</LoadingButton>
|
||||
<Card sx={{padding:2}}>
|
||||
<Box sx={{ pb: 2 }}>
|
||||
<Typography variant='subtitle1'>Detail</Typography>
|
||||
<Stack marginTop={2}>
|
||||
<Stack direction='row' spacing={1}>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Mapping ID:</Typography>
|
||||
<Typography variant='body2' sx={{width: '25%'}}>{row.principal_id ? row.principal_id : '-'}</Typography>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Birth Date:</Typography>
|
||||
<Typography variant='body2' sx={{width: '25%'}}>{row.birth_date ? row.birth_date : '-'}</Typography>
|
||||
</Stack>
|
||||
{/* -------------------------------Upload Dokumen MCU------------------------------- */}
|
||||
<Stack sx={{ marginTop: 1}}>
|
||||
{/*<Stack
|
||||
divider={<Divider orientation="horizontal" flexItem />}
|
||||
spacing={1}
|
||||
sx={{ marginY: 2}}
|
||||
>
|
||||
{fileMcus &&
|
||||
fileMcus
|
||||
.filter((datas) => datas.id === row.id)
|
||||
.map((datas, index) => (
|
||||
<Stack direction="row" justifyContent={'space-between'} key={index}>
|
||||
<Typography sx={{ color: "text.secondary" }}>{datas.file.name}</Typography>
|
||||
<Iconify
|
||||
icon="eva:trash-2-outline"
|
||||
color={'darkred'}
|
||||
onClick={() => {
|
||||
removeMcuFiles(datas.id, index);
|
||||
}}
|
||||
sx={{ cursor: 'pointer' }}
|
||||
></Iconify>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>*/}
|
||||
<input
|
||||
type="file"
|
||||
id={`file-${row.id}`}
|
||||
ref={fileMcuInput}
|
||||
style={{ display: 'none' }}
|
||||
onChange={(event) => {
|
||||
handleMcuInputChange(row.id, row.member_id)(event);
|
||||
}}
|
||||
accept="application/pdf"
|
||||
/>
|
||||
<LoadingButton
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
fileMcuInput.current.click();
|
||||
}}
|
||||
>
|
||||
<Iconify icon="eva:plus-fill" />
|
||||
Add Result
|
||||
</LoadingButton>
|
||||
<Stack direction='row' spacing={1}>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Policy Number:</Typography>
|
||||
<Typography variant='body2' sx={{width: '25%'}}>{row.current_policy?.code ? row.current_policy?.code : '-'}</Typography>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Gender:</Typography>
|
||||
<Typography variant='body2' sx={{width: '25%'}}>{row.gender ? row.gender : '-'}</Typography>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Stack direction='row' spacing={1}>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>NRIC:</Typography>
|
||||
<Typography variant='body2' sx={{width: '25%'}}>{row.nric ? row.nric : '-'}</Typography>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Marital Status:</Typography>
|
||||
<Typography variant='body2' sx={{width: '25%'}}>{row.marital_status ? row.marital_status : '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={1}>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>NIK:</Typography>
|
||||
<Typography variant='body2' sx={{width: '25%'}}>{row.employeds[0]?.nik ? row.employeds[0]?.nik : '-'}</Typography>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Language:</Typography>
|
||||
<Typography variant='body2' sx={{width: '25%'}}>{row.language ? row.language : '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={1}>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Email:</Typography>
|
||||
<Typography variant='body2' sx={{width: '25%'}}>{row.email ? row.email : '-'}</Typography>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Race:</Typography>
|
||||
<Typography variant='body2' sx={{width: '25%'}}>{row.race ? row.race : '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={1}>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Phone Number:</Typography>
|
||||
<Typography variant='body2' sx={{width: '25%'}}>{row.person?.phone ? row.person?.phone : '-'}</Typography>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Relationship:</Typography>
|
||||
<Typography variant='body2' sx={{width: '25%'}}>{row.relation_with_principal ? row.relation_with_principal : '-'}</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Typography variant='subtitle1' marginTop={2}>Claim History</Typography>
|
||||
<Stack marginTop={2}>
|
||||
<Stack direction='row' spacing={1}>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Requested:</Typography>
|
||||
<Typography variant='body2' sx={{width: '75%'}}>{row.total_claims?.requested ? row.total_claims?.requested : '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={1}>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Pending:</Typography>
|
||||
<Typography variant='body2' sx={{width: '75%'}}>{row.total_claims?.received ? row.total_claims?.received : '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={1}>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Approved:</Typography>
|
||||
<Typography variant='body2' sx={{width: '75%'}}>{row.total_claims?.approved ? row.total_claims?.approved : '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={1}>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Declined:</Typography>
|
||||
<Typography variant='body2' sx={{width: '75%'}}>{row.total_claims?.declined ? row.total_claims?.declined : '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={1}>
|
||||
<Typography variant='body2' sx={{color: style1.color, width: '25%'}}>Paid:</Typography>
|
||||
<Typography variant='body2' sx={{width: '75%'}}>{row.total_claims?.paid ? row.total_claims?.paid : '-'}</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Typography variant='subtitle1' marginTop={2}>Files History</Typography>
|
||||
<Stack marginTop={2}>
|
||||
|
||||
{row.file_mcu_names
|
||||
? row.file_mcu_names.split(',').map((fileName, index) => (
|
||||
<>
|
||||
<Stack direction='row' spacing={1} alignItems='center'>
|
||||
<InsertDriveFileIcon />
|
||||
<Typography key={index} variant='body2' sx={{width: '100%'}}>{fileName}</Typography>
|
||||
</Stack>
|
||||
</>
|
||||
))
|
||||
: '-'}
|
||||
</Stack>
|
||||
<Stack marginTop={2}>
|
||||
<Stack direction='row' spacing={1} alignItems='center'>
|
||||
<ButtonBase sx={{ p: 4, border: '2px dashed #F9FAFB',
|
||||
bgcolor: '#919EAB52',
|
||||
borderRadius: '8px',
|
||||
width: '100%', height: '60px'}} onClick={() => fileMcuInput.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 Result
|
||||
</Typography>
|
||||
</Box>
|
||||
<input
|
||||
type="file"
|
||||
id={`file-${row.id}`}
|
||||
ref={fileMcuInput}
|
||||
style={{ display: 'none' }}
|
||||
onChange={(event) => {
|
||||
handleMcuInputChange(row.id, row.member_id)(event);
|
||||
}}
|
||||
accept="application/pdf"
|
||||
/>
|
||||
</ButtonBase>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Card>
|
||||
<Stack marginTop={2}>
|
||||
<Stack direction='row' alignItems='center' spacing={1} justifyContent="flex-end">
|
||||
<LoadingButton
|
||||
id="upload-button"
|
||||
sx={{ p: 1.8, color: '#FFFFFF', backgroundColor: '#19BBBB', width: '158px', height: '48px' }}
|
||||
startIcon={<DownloadIcon />}
|
||||
// sx={{ p: 1.8 }}
|
||||
// onClick={() => {handleDownloadLog(row)}}
|
||||
onClick={() => {
|
||||
setDialogLogOpen(true);
|
||||
}}
|
||||
loading={loadingLog}
|
||||
>
|
||||
Download LOG
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<DialogLog
|
||||
title={{
|
||||
name: `Generate LOG - ${row.full_name}`,
|
||||
}}
|
||||
openDialog={dialogLogOpen}
|
||||
setOpenDialog={setDialogLogOpen}
|
||||
data={{ member: row }}
|
||||
></DialogLog>
|
||||
|
||||
<DialogLog
|
||||
title={{
|
||||
name: `Generate LOG - ${row.full_name}`,
|
||||
}}
|
||||
openDialog={dialogLogOpen}
|
||||
setOpenDialog={setDialogLogOpen}
|
||||
data={{ member: row }}
|
||||
></DialogLog>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -746,33 +691,73 @@ export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
const [reasonUpdate,setReasonUpdate] = useState('Agreement changed');
|
||||
const [nameUpdate, setNameUpdate] = useState('');
|
||||
const [memberIdUpdate, setMemberIdUpdate] = useState('');
|
||||
const [activeUpdate, setActiveUpdate] = useState(0);
|
||||
const [idUpdate, setIdUpdate] = useState('');
|
||||
|
||||
const [openDialogStatus, setOpenDialogStatus] = useState(false);
|
||||
|
||||
const handleCloseDialogUpdate = () => {
|
||||
setNameUpdate('');
|
||||
setMemberIdUpdate('');
|
||||
setActiveUpdate(activeUpdate);
|
||||
setIdUpdate('');
|
||||
setOpenDialogStatus(false);
|
||||
}
|
||||
|
||||
const handleSaveUpdateData = () => {
|
||||
let activeValue = 0;
|
||||
if(activeUpdate === 1)
|
||||
{
|
||||
activeValue = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
activeValue = 1;
|
||||
}
|
||||
const updateData = {
|
||||
reason: reasonUpdate,
|
||||
active : activeValue,
|
||||
id: idUpdate,
|
||||
};
|
||||
axios
|
||||
.put('/members/'+idUpdate+'/activation', updateData)
|
||||
.then((response) => {
|
||||
enqueueSnackbar('Data updated successfully', { variant: 'success' });
|
||||
loadDataTableData();
|
||||
handleCloseDialogUpdate();
|
||||
})
|
||||
.catch((error) => {
|
||||
enqueueSnackbar('Failed to add data', { variant: 'error' });
|
||||
});
|
||||
}
|
||||
|
||||
const handleEditDataStatus = (data:any) => {
|
||||
setNameUpdate(data.name);
|
||||
setMemberIdUpdate(data.member_id);
|
||||
setActiveUpdate(data.active);
|
||||
setIdUpdate(data.id);
|
||||
setOpenDialogStatus(true);
|
||||
}
|
||||
return (
|
||||
<Stack>
|
||||
<ImportForm />
|
||||
|
||||
<Card>
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" />
|
||||
{columns.map((column, index) => (
|
||||
<TableCell style={headStyle} key={index} align={column.align}>
|
||||
{column.label}
|
||||
<TableCell style={{ minWidth: column.minWidth, width: column.width }} key={index} align={column.align}>
|
||||
<Typography variant='subtitle2'>{column.label}</Typography>
|
||||
</TableCell>
|
||||
))}
|
||||
<TableCell style={headStyle} align="center">
|
||||
Status
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="center">
|
||||
Action
|
||||
</TableCell>
|
||||
{/* <TableCell style={headStyle} align="center">
|
||||
Action
|
||||
</TableCell> */}
|
||||
<TableCell align="center"></TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</TableHead>
|
||||
{dataTableIsLoading ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
@@ -801,6 +786,62 @@ export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||
</Card>
|
||||
{/* Dialog Update Status */}
|
||||
<Dialog open={openDialogStatus} onClose={handleCloseDialogUpdate} 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">Update Status</Typography>
|
||||
</Stack>
|
||||
<IconButton sx={{ color: '#FFF' }} onClick={handleCloseDialogUpdate}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Stack spacing={2} padding={2}>
|
||||
<Typography variant='body1'>Are you sure to {activeUpdate == 1 ? 'Inactive' : 'Active'} this member ?</Typography>
|
||||
<Card sx={{padding:2}} >
|
||||
<Stack direction='row' spacing={2}>
|
||||
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Member ID</Typography>
|
||||
<Typography variant='subtitle2' sx={{width: '70%'}}>{memberIdUpdate}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2}>
|
||||
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Name</Typography>
|
||||
<Typography variant='subtitle2' sx={{width: '70%'}}>{nameUpdate}</Typography>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Stack>
|
||||
<Stack spacing={2} padding={2}>
|
||||
<Typography variant='subtitle1'>Reason for update*</Typography>
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="reason" required>
|
||||
Reason for update
|
||||
</InputLabel>
|
||||
<Select
|
||||
id="reason"
|
||||
value={reasonUpdate}
|
||||
fullWidth
|
||||
label="Reason for update"
|
||||
onChange={(e) => {
|
||||
setReasonUpdate(e.target.value);
|
||||
}}
|
||||
|
||||
>
|
||||
<MenuItem value="Agreement changed">Agreement changed</MenuItem>
|
||||
<MenuItem value="Endorsement">Endorsement</MenuItem>
|
||||
<MenuItem value="Renewal">Renewal</MenuItem>
|
||||
<MenuItem value="Worng Setting">Worng Setting</MenuItem>
|
||||
</Select>
|
||||
<FormHelperText style={{ color: 'red' }}></FormHelperText>
|
||||
</FormControl>
|
||||
</Stack>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant="outlined" sx={{color: '#212B36'}} onClick={handleCloseDialogUpdate}>Cancel</Button>
|
||||
<Button sx={{backgroundColor: activeUpdate == 0 ? '#19BBBB' : '#FF4842'}} onClick={handleSaveUpdateData} variant="contained">{activeUpdate == 1 ? 'Inactive' : 'Active'}</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
{isDialog === 'edit' && (
|
||||
<DialogLog
|
||||
data={edit}
|
||||
|
||||
@@ -76,6 +76,8 @@ const DialogTopUpLimit = ({ title, openDialog, setOpenDialog, data }: MuiDialogP
|
||||
|
||||
const { id, service_code, status } = data;
|
||||
|
||||
const [memberId, setMemberId] = useState(data.member.id);
|
||||
|
||||
const isEdit = id ? true : false;
|
||||
|
||||
const NewCorporateSchema = Yup.object().shape({
|
||||
@@ -103,10 +105,11 @@ const DialogTopUpLimit = ({ title, openDialog, setOpenDialog, data }: MuiDialogP
|
||||
// const { plan_id } = useParams();
|
||||
const handleActivate = (model: any, status: string) => {
|
||||
axios
|
||||
.put(`/members/${id}/activation`, {
|
||||
.put(`/members/${memberId}/activation`, {
|
||||
// service_code: service.service_code,
|
||||
active: status == 'active',
|
||||
reason: model.reason
|
||||
reason: model.reason,
|
||||
id: memberId,
|
||||
})
|
||||
.then((res) => {
|
||||
// Memuat ulang halaman saat ini
|
||||
@@ -133,7 +136,7 @@ const DialogTopUpLimit = ({ title, openDialog, setOpenDialog, data }: MuiDialogP
|
||||
const data = {
|
||||
service_code : service_code,
|
||||
reason : row.reason,
|
||||
id : id,
|
||||
id : memberId,
|
||||
}
|
||||
handleActivate(data, status)
|
||||
} catch (error: any) {
|
||||
@@ -157,18 +160,18 @@ const DialogTopUpLimit = ({ title, openDialog, setOpenDialog, data }: MuiDialogP
|
||||
<Stack spacing={3}>
|
||||
<Box sx={{ width: '100%', typography: 'body1', p: 2, mt: 1 }}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant='subtitle1' sx={{marginBottom: 2}}>Reason for update*</Typography>
|
||||
<RHFSelect
|
||||
name="reason"
|
||||
label="Reason for update"
|
||||
>
|
||||
<option value=""></option>
|
||||
<option value="Agreement changed">Agreement changed</option>
|
||||
<option value="Endorsement">Endorsement</option>
|
||||
<option value="Renewal">Renewal</option>
|
||||
<option value="Worng Setting">Worng Setting</option>
|
||||
</RHFSelect>
|
||||
name="reason"
|
||||
label="Reason for update"
|
||||
>
|
||||
<option value=""></option>
|
||||
<option value="Agreement changed">Agreement changed</option>
|
||||
<option value="Endorsement">Endorsement</option>
|
||||
<option value="Renewal">Renewal</option>
|
||||
<option value="Worng Setting">Worng Setting</option>
|
||||
</RHFSelect>
|
||||
</Grid>
|
||||
|
||||
<Box sx={{ pt: 5 }}>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
@@ -181,6 +184,7 @@ const DialogTopUpLimit = ({ title, openDialog, setOpenDialog, data }: MuiDialogP
|
||||
<Button
|
||||
sx={{
|
||||
boxShadow: 'none',
|
||||
color: '#212B36'
|
||||
}}
|
||||
variant="outlined"
|
||||
size="medium"
|
||||
@@ -190,7 +194,7 @@ const DialogTopUpLimit = ({ title, openDialog, setOpenDialog, data }: MuiDialogP
|
||||
Cancel
|
||||
</Button>
|
||||
<LoadingButton
|
||||
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)' }}
|
||||
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)', backgroundColor: '#19BBBB' }}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="medium"
|
||||
|
||||
@@ -32,11 +32,11 @@ export default function Divisions() {
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id,
|
||||
href: '/corporates/' + corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Plan',
|
||||
href: '/corporate/' + corporate_id + '/plans',
|
||||
href: '/corporates/' + corporate_id + '/plans',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// @mui
|
||||
import * as Yup from 'yup';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -28,17 +29,22 @@ import {
|
||||
ButtonGroup,
|
||||
Grid,
|
||||
Tooltip,
|
||||
Autocomplete,
|
||||
} from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import SettingsOutlinedIcon from '@mui/icons-material/SettingsOutlined';
|
||||
import CachedOutlinedIcon from '@mui/icons-material/CachedOutlined';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import HistoryIcon from '@mui/icons-material/History';
|
||||
// hooks
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import { Link, useParams, useSearchParams } from 'react-router-dom';
|
||||
import { Form, useNavigate, Link, useParams, useSearchParams } from 'react-router-dom';
|
||||
// components
|
||||
import axios from '../../../utils/axios';
|
||||
import { Plan } from '../../../@types/corporates';
|
||||
@@ -47,6 +53,14 @@ import BasePagination from '../../../components/BasePagination';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import DialogLog from './sections/DialogLog';
|
||||
import { FormProvider, RHFSelect } from '@/components/hook-form';
|
||||
import { Download, Edit } from '@mui/icons-material';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
import Label from '@/components/Label';
|
||||
import DialogUpdateStatus from '@/components/DialogUpdateStatus';
|
||||
import {Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
|
||||
|
||||
export default function CorporatePlanList() {
|
||||
const { themeStretch } = useSettings();
|
||||
@@ -54,6 +68,7 @@ export default function CorporatePlanList() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
|
||||
const navigate = useNavigate()
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const [dialogTitle, setDialogTitle] = useState('');
|
||||
const [isDialog, setIsDialog] = useState('');
|
||||
@@ -69,6 +84,19 @@ export default function CorporatePlanList() {
|
||||
}
|
||||
};
|
||||
|
||||
// filter
|
||||
const defaultValue = [
|
||||
{
|
||||
value: '-',
|
||||
label: '-'
|
||||
}
|
||||
];
|
||||
|
||||
const [serviceCode, setServiceCode] = useState(defaultValue);
|
||||
const [type, setType] = useState(defaultValue);
|
||||
const [code, setCode] = useState(defaultValue);
|
||||
const [codePlan, setCodePlan] = useState(defaultValue);
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
@@ -85,7 +113,6 @@ export default function CorporatePlanList() {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// console.log('Search Input: useEffect')
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
}, [searchParams]);
|
||||
|
||||
@@ -113,6 +140,8 @@ export default function CorporatePlanList() {
|
||||
const [currentImportFileName, setCurrentImportFileName] = useState(null);
|
||||
const [importLoading, setImportLoading] = useState(false);
|
||||
|
||||
const { control } = useForm();
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
@@ -195,6 +224,40 @@ export default function CorporatePlanList() {
|
||||
})
|
||||
}
|
||||
|
||||
const handleFilter = (event: React.SyntheticEvent<Element, Event>, newValue: { value: string, label: string }[], name:string) => { //
|
||||
const serviceCodeArray :string[] = [];
|
||||
const codeArray :string[] = [];
|
||||
const typeArray :string[] = [];
|
||||
const planArray :string[] = [];
|
||||
if (name == 'service_code'){
|
||||
newValue.map(row => {
|
||||
serviceCodeArray.push(row.value);
|
||||
})
|
||||
}
|
||||
if (name == 'code'){
|
||||
newValue.map(row => {
|
||||
codeArray.push(row.value);
|
||||
})
|
||||
}
|
||||
if (name == 'type'){
|
||||
newValue.map(row => {
|
||||
typeArray.push(row.value);
|
||||
})
|
||||
}
|
||||
if (name == 'plan'){
|
||||
newValue.map(row => {
|
||||
planArray.push(row.value);
|
||||
})
|
||||
}
|
||||
let data = {
|
||||
service_code : serviceCodeArray,
|
||||
code : codeArray,
|
||||
type : typeArray,
|
||||
plan : planArray,
|
||||
}
|
||||
loadDataTableDataFilter(data)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<input
|
||||
@@ -207,33 +270,113 @@ export default function CorporatePlanList() {
|
||||
/>
|
||||
{!currentImportFileName && (
|
||||
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
||||
<SearchInput onSearch={applyFilter} />
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={3.5}>
|
||||
<SearchInput onSearch={applyFilter} />
|
||||
</Grid>
|
||||
<Grid item xs={2}>
|
||||
<Autocomplete
|
||||
id="combo-box-demo"
|
||||
options={serviceCode}
|
||||
multiple
|
||||
limitTags={1}
|
||||
onChange={(event, newValue) => handleFilter(event, newValue, 'service_code')}
|
||||
fullWidth
|
||||
getOptionLabel={(option) => option.label}
|
||||
isOptionEqualToValue={(option, value) =>
|
||||
option.value === value.value
|
||||
}
|
||||
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Service" variant="outlined" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={1.5}>
|
||||
<Autocomplete
|
||||
id="combo-box-demo"
|
||||
options={codePlan}
|
||||
onChange={(event, newValue) => handleFilter(event, newValue, 'plan')}
|
||||
multiple
|
||||
limitTags={1}
|
||||
fullWidth
|
||||
getOptionLabel={(option) => option.label}
|
||||
isOptionEqualToValue={(option, value) =>
|
||||
option.value === value.value
|
||||
}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Plan" variant="outlined" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={1.5}>
|
||||
<Autocomplete
|
||||
id="combo-box-demo"
|
||||
options={code}
|
||||
onChange={(event, newValue) => handleFilter(event, newValue, 'code')}
|
||||
multiple
|
||||
limitTags={1}
|
||||
fullWidth
|
||||
getOptionLabel={(option) => option.label}
|
||||
isOptionEqualToValue={(option, value) =>
|
||||
option.value === value.value
|
||||
}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Code" variant="outlined" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={1.5}>
|
||||
<Autocomplete
|
||||
id="combo-box-demo"
|
||||
options={type}
|
||||
multiple
|
||||
limitTags={1}
|
||||
fullWidth
|
||||
getOptionLabel={(option) => option.label}
|
||||
isOptionEqualToValue={(option, value) =>
|
||||
option.value === value.value
|
||||
}
|
||||
onChange={(event, newValue) => handleFilter(event, newValue, 'type')}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Type" variant="outlined" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={1.5}>
|
||||
<Button
|
||||
id="import-button"
|
||||
variant="contained"
|
||||
startIcon={<Download />}
|
||||
fullWidth={true}
|
||||
sx={{ p: 1.8 }}
|
||||
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={createMenu ? 'true' : undefined}
|
||||
onClick={handleClick}
|
||||
>
|
||||
Import
|
||||
</Button>
|
||||
<Menu
|
||||
id="import-button"
|
||||
anchorEl={anchorEl}
|
||||
open={createMenu}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
'aria-labelledby': 'basic-button',
|
||||
}}
|
||||
>
|
||||
<MenuItem onClick={handleImportButton}>Import</MenuItem>
|
||||
<MenuItem onClick={() => {handleGetTemplate('plan-benefit')}}>Download Template</MenuItem>
|
||||
<MenuItem onClick={() => {handleGetData('data-plan-benefit')}}>Download Plans & Benefit</MenuItem>
|
||||
<MenuItem onClick={() => {setDialogDeleteOpen(true)}}>Delete All Import</MenuItem>
|
||||
|
||||
</Menu>
|
||||
</Grid>
|
||||
</Grid>
|
||||
{/* <h1>kjasndkjandskjasndkjansdkjansd</h1> */}
|
||||
<Button
|
||||
id="import-button"
|
||||
variant="outlined"
|
||||
startIcon={<AddIcon />}
|
||||
sx={{ p: 1.8 }}
|
||||
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={createMenu ? 'true' : undefined}
|
||||
onClick={handleClick}
|
||||
>
|
||||
Import
|
||||
</Button>
|
||||
<Menu
|
||||
id="import-button"
|
||||
anchorEl={anchorEl}
|
||||
open={createMenu}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
'aria-labelledby': 'basic-button',
|
||||
}}
|
||||
>
|
||||
<MenuItem onClick={handleImportButton}>Import</MenuItem>
|
||||
<MenuItem onClick={() => {handleGetTemplate('plan-benefit')}}>Download Template</MenuItem>
|
||||
<MenuItem onClick={() => {handleGetData('data-plan-benefit')}}>Download Plans & Benefit</MenuItem>
|
||||
</Menu>
|
||||
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
@@ -286,47 +429,51 @@ export default function CorporatePlanList() {
|
||||
};
|
||||
}
|
||||
|
||||
type DataContent = {
|
||||
code: string;
|
||||
name: string;
|
||||
id: number;
|
||||
status: string|number;
|
||||
};
|
||||
|
||||
type FormValuesProps = {
|
||||
value: string;
|
||||
active: boolean;
|
||||
};
|
||||
|
||||
// Generate the every row of the table
|
||||
const [isDialogOpen, setDialogOpen] = useState(false)
|
||||
let titles = {
|
||||
name: 'Update Status',
|
||||
icon: '-'
|
||||
}
|
||||
const [dataValue, setDataValue] = useState('');
|
||||
const [dataDescription, setDescriptionValue] = useState('');
|
||||
const [url, setUrl] = useState('');
|
||||
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
const handleActivate = (model: any, status: string) => {
|
||||
axios
|
||||
.put(`/plans/${row.id}/activation`, {
|
||||
// service_code: service.service_code,
|
||||
active: status == 'active',
|
||||
})
|
||||
.then((res) => {
|
||||
setDataTableData({
|
||||
...dataTableData,
|
||||
data: dataTableData.data.map((model) => {
|
||||
let updatedModel = model;
|
||||
if (row.id == model.id) {
|
||||
updatedModel.active = res.data.plan.active;
|
||||
}
|
||||
return updatedModel;
|
||||
}),
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
// console.log('asdasd', error.response.data.message)
|
||||
enqueueSnackbar(
|
||||
error.response.data.message ?? error.message ?? 'Failed Processing Request',
|
||||
{ variant: 'error' }
|
||||
);
|
||||
});
|
||||
const handleActivate = (isOpen: boolean, dataValue: DataContent) => {
|
||||
setDialogOpen(isOpen)
|
||||
setDataValue(dataValue)
|
||||
setDescriptionValue('Are you sure to inactive this service ?')
|
||||
setUrl(url)
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell>
|
||||
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||
<TableRow>
|
||||
{/* <TableCell> */}
|
||||
{/* <IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</IconButton> */}
|
||||
{/* </TableCell> */}
|
||||
<TableCell sx={{ borderBottom: '1px solid rgba(145, 158, 171, 0.24)' }} align="left">
|
||||
{row.service_code}
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.service_code}</TableCell>
|
||||
|
||||
<TableCell align="left">{row.corporate_plan_id}</TableCell>
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.type}</TableCell>
|
||||
@@ -334,41 +481,27 @@ export default function CorporatePlanList() {
|
||||
<TableCell align="left">{row.limit_rules}</TableCell>
|
||||
|
||||
<TableCell align="center">
|
||||
{row.active == 1 && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="success"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
// handleActivate(row, 'inactive');
|
||||
clickHandler('edit');
|
||||
setEdit({id: row.id, service_code: row.service_code, status: 'inactive'});
|
||||
}}
|
||||
>
|
||||
Active
|
||||
</Button>
|
||||
)}
|
||||
{row.active != 1 && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="error"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
// handleActivate(row, 'active');
|
||||
clickHandler('edit');
|
||||
setEdit({id: row.id, service_code: row.service_code, status: 'active'});
|
||||
}}
|
||||
>
|
||||
Inactive
|
||||
</Button>
|
||||
)}
|
||||
{row.active == 1 ?
|
||||
<Label color='success'>Active</Label> :
|
||||
<Label color='error'>Inactive</Label>}
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<Tooltip title="History">
|
||||
<Link to={`/corporate/${corporate_id}/plans/${row.id}/history`}>
|
||||
<HistoryIcon />
|
||||
</Link>
|
||||
</Tooltip>
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => navigate(`/corporates/${corporate_id}/corporate-plans/${row.id}/edit`)}>
|
||||
<Edit />
|
||||
Edit
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate(`/corporates/${corporate_id}/plans/${row.id}/history`)}>
|
||||
<HistoryIcon />
|
||||
History
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => handleActivate(true, {code: row.code, name: row.service_code, id:row.id, status: row.active})}>
|
||||
<CachedOutlinedIcon />
|
||||
Update Status
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
@@ -679,16 +812,153 @@ export default function CorporatePlanList() {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const response = await axios.get('/corporates/' + corporate_id + '/plans', { params: filter });
|
||||
// console.log(response.data);
|
||||
|
||||
setDataTableLoading(false);
|
||||
|
||||
setDataTableData(response.data);
|
||||
|
||||
const data = response.data.data;
|
||||
const serviceCodeArray :string[] = [];
|
||||
const codeArray :string[] = [];
|
||||
const typeArray :string[] = [];
|
||||
const planArray :string[] = [];
|
||||
|
||||
data.forEach((row: any) => {
|
||||
if (!serviceCodeArray.includes(row.service_code)) {
|
||||
serviceCodeArray.push(row.service_code);
|
||||
}
|
||||
|
||||
if (!codeArray.includes(row.code)) {
|
||||
codeArray.push(row.code);
|
||||
}
|
||||
|
||||
if (!typeArray.includes(row.type)) {
|
||||
typeArray.push(row.type);
|
||||
}
|
||||
|
||||
if (!planArray.includes(row.corporate_plan_id)) {
|
||||
planArray.push(row.corporate_plan_id);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
const optionServiceCode = serviceCodeArray.map((value) => {
|
||||
return {
|
||||
value: value,
|
||||
label: value
|
||||
};
|
||||
});
|
||||
const optionCode = codeArray.map((value) => {
|
||||
return {
|
||||
value: value,
|
||||
label: value
|
||||
};
|
||||
});
|
||||
const optionType = typeArray.map((value) => {
|
||||
return {
|
||||
value: value,
|
||||
label: value
|
||||
};
|
||||
});
|
||||
const optionPlan = planArray.map((value) => {
|
||||
return {
|
||||
value: value,
|
||||
label: value
|
||||
};
|
||||
});
|
||||
|
||||
setServiceCode(optionServiceCode)
|
||||
setType(optionType)
|
||||
setCode(optionCode)
|
||||
setCodePlan(optionPlan)
|
||||
|
||||
};
|
||||
|
||||
const loadDataTableDataFilter = async (appliedFilter = null) => {
|
||||
setDataTableLoading(true);
|
||||
let filter = appliedFilter
|
||||
|
||||
const response = await axios.post('/corporates/' + corporate_id + '/corporate-plans/filter',filter);
|
||||
|
||||
setDataTableLoading(false);
|
||||
|
||||
setDataTableData(response.data);
|
||||
|
||||
const data = response.data.data;
|
||||
const serviceCodeArray :string[] = [];
|
||||
const codeArray :string[] = [];
|
||||
const typeArray :string[] = [];
|
||||
const planArray :string[] = [];
|
||||
|
||||
// data.forEach((row: any) => {
|
||||
// if (!serviceCodeArray.includes(row.service_code)) {
|
||||
// serviceCodeArray.push(row.service_code);
|
||||
// }
|
||||
|
||||
// if (!codeArray.includes(row.code)) {
|
||||
// codeArray.push(row.code);
|
||||
// }
|
||||
|
||||
// if (!typeArray.includes(row.type)) {
|
||||
// typeArray.push(row.type);
|
||||
// }
|
||||
|
||||
// if (!planArray.includes(row.corporate_plan_id)) {
|
||||
// planArray.push(row.corporate_plan_id);
|
||||
// }
|
||||
|
||||
// });
|
||||
|
||||
// const optionServiceCode = serviceCodeArray.map((value) => {
|
||||
// return {
|
||||
// value: value,
|
||||
// label: value
|
||||
// };
|
||||
// });
|
||||
// const optionCode = codeArray.map((value) => {
|
||||
// return {
|
||||
// value: value,
|
||||
// label: value
|
||||
// };
|
||||
// });
|
||||
// const optionType = typeArray.map((value) => {
|
||||
// return {
|
||||
// value: value,
|
||||
// label: value
|
||||
// };
|
||||
// });
|
||||
// const optionPlan = planArray.map((value) => {
|
||||
// return {
|
||||
// value: value,
|
||||
// label: value
|
||||
// };
|
||||
// });
|
||||
|
||||
// setServiceCode(optionServiceCode)
|
||||
// setType(optionType)
|
||||
// setCode(optionCode)
|
||||
// setCodePlan(optionPlan)
|
||||
|
||||
};
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
|
||||
const onSubmit = async (row : any) => {
|
||||
try {
|
||||
handleUpdate(dataValue.status, dataValue.id, row.reason)
|
||||
} catch (error: any) {
|
||||
console.log('data gagal');
|
||||
}
|
||||
|
||||
const ascent = document?.querySelector('ascent');
|
||||
if (ascent != null) {
|
||||
ascent.innerHTML = '';
|
||||
}
|
||||
};
|
||||
|
||||
const applyFilter = async (searchFilter: string) => {
|
||||
await loadDataTableData({ search: searchFilter });
|
||||
setSearchParams({ search: searchFilter });
|
||||
@@ -704,17 +974,146 @@ export default function CorporatePlanList() {
|
||||
loadDataTableData();
|
||||
}, []);
|
||||
|
||||
const NewCorporateSchema = Yup.object().shape({
|
||||
reason: Yup.string().required('Reason Edit is required'),
|
||||
});
|
||||
|
||||
const methods = useForm<FormValuesProps>({
|
||||
resolver: yupResolver(NewCorporateSchema),
|
||||
});
|
||||
|
||||
|
||||
const {
|
||||
reset,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
} = methods;
|
||||
|
||||
const handleUpdate = (active: number, id: number, reason:string) => {
|
||||
console.log(active)
|
||||
axios
|
||||
.put(`/plans/${id}/activation`, {
|
||||
active: active,
|
||||
reason: reason
|
||||
})
|
||||
.then((res) => {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
const handleDeleteAllImport = () => {
|
||||
axios
|
||||
.post(`/corporates/${corporate_id}/delete-import-plan-benefit`)
|
||||
.then((res) => {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
const [isOpenDialogDelete, setDialogDeleteOpen] = useState(false);
|
||||
const handleCloseDialogDelete = () => {
|
||||
setDialogDeleteOpen(false);
|
||||
};
|
||||
|
||||
const getContent = () => (
|
||||
<>
|
||||
<Stack paddingX={2} paddingY={2}>
|
||||
<Typography variant='subtitle1'>Are you sure to {dataValue?.status == 1 ? 'inactive' : 'active'} this service ?</Typography>
|
||||
</Stack>
|
||||
<Card>
|
||||
<Grid container paddingX={2} paddingY={2}>
|
||||
<Grid item xs={4} md={4}>
|
||||
<Typography variant='inherit'>Code</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
<Typography variant='subtitle1'>{dataValue?.code}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={4} md={4} marginTop={2}>
|
||||
<Typography variant='inherit'>Service Name</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={8} marginTop={2}>
|
||||
<Typography variant='subtitle1'>{dataValue?.name}</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
|
||||
<Typography marginTop={5} marginBottom={3} variant='subtitle1'>
|
||||
Reason for update*
|
||||
</Typography>
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<RHFSelect
|
||||
name="reason"
|
||||
label="Reason for update"
|
||||
>
|
||||
<option value=""></option>
|
||||
<option value="Agreement changed">Agreement changed</option>
|
||||
<option value="Endorsement">Endorsement</option>
|
||||
<option value="Renewal">Renewal</option>
|
||||
<option value="Worng Setting">Worng Setting</option>
|
||||
</RHFSelect>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
justifyContent="flex-end"
|
||||
direction={{ xs: 'column', md: 'row' }}
|
||||
spacing={2}
|
||||
marginTop={5}
|
||||
>
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Button
|
||||
sx={{
|
||||
boxShadow: 'none',
|
||||
}}
|
||||
variant="outlined"
|
||||
size="medium"
|
||||
fullWidth={true}
|
||||
onClick={() => setDialogOpen(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
{dataValue?.status == 1?
|
||||
<LoadingButton
|
||||
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)'}}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="medium"
|
||||
fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
color='error'
|
||||
>
|
||||
Inactive
|
||||
</LoadingButton>
|
||||
:
|
||||
<LoadingButton
|
||||
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)'}}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="medium"
|
||||
fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
color='success'
|
||||
>
|
||||
Active
|
||||
</LoadingButton>
|
||||
|
||||
|
||||
}
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
</FormProvider>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<ImportForm />
|
||||
|
||||
<Card>
|
||||
{/* <Card> */}
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<TableContainer>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" />
|
||||
{/* <TableCell style={headStyle} align="left" /> */}
|
||||
<TableCell style={headStyle} align="left">
|
||||
Service
|
||||
</TableCell>
|
||||
@@ -737,7 +1136,7 @@ export default function CorporatePlanList() {
|
||||
Action
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</TableHead>
|
||||
{dataTableIsLoading ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
@@ -765,7 +1164,7 @@ export default function CorporatePlanList() {
|
||||
</TableContainer>
|
||||
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||
</Card>
|
||||
{/* </Card> */}
|
||||
|
||||
{isDialog === 'edit' && (
|
||||
<DialogLog
|
||||
@@ -775,6 +1174,38 @@ export default function CorporatePlanList() {
|
||||
title={{ name: 'Reason For Update' }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<DialogUpdateStatus
|
||||
openDialog={isDialogOpen}
|
||||
setOpenDialog={setDialogOpen}
|
||||
title={titles}
|
||||
data={dataValue}
|
||||
description={dataDescription}
|
||||
content={getContent()}
|
||||
// maxWidth='50px'
|
||||
/>
|
||||
|
||||
<Dialog open={isOpenDialogDelete} onClose={handleCloseDialogDelete} 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">Delete Import Benefit</Typography>
|
||||
</Stack>
|
||||
<IconButton sx={{ color: '#FFF' }} onClick={handleCloseDialogDelete}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Stack spacing={2} sx={{marginTop: 2, padding: 2}}>
|
||||
<Typography variant='subtitle1'>Are you sure delete all data benefit and plan?</Typography>
|
||||
</Stack>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialogDelete}>Cancel</Button>
|
||||
<Button sx={{backgroundColor: '#19BBBB'}} variant="contained" onClick={() => handleDeleteAllImport()}>Delete</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -121,11 +121,11 @@ export default function CustomizedAccordions() {
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id + '/plans',
|
||||
href: '/corporates/' + corporate_id + '/plans',
|
||||
},
|
||||
{
|
||||
name: 'Audittrail Corporate',
|
||||
href: '/corporate/' + corporate_id + '/plans',
|
||||
name: 'Corporate Dashboard',
|
||||
href: '/corporates/' + corporate_id + '/plans',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,11 +34,11 @@ export default function Divisions() {
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id,
|
||||
href: '/corporates/' + corporate_id,
|
||||
},
|
||||
{
|
||||
name: 'Services',
|
||||
href: '/corporate/' + corporate_id + '/services',
|
||||
href: '/corporates/' + corporate_id + '/services',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -30,17 +30,21 @@ import {
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
Tooltip,
|
||||
Divider,
|
||||
Grid,
|
||||
} from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import SettingsOutlinedIcon from '@mui/icons-material/SettingsOutlined';
|
||||
import CachedOutlinedIcon from '@mui/icons-material/CachedOutlined';
|
||||
import HistoryIcon from '@mui/icons-material/History';
|
||||
// hooks
|
||||
import React, { ChangeEvent, Component, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import { Link, useParams, useSearchParams } from 'react-router-dom';
|
||||
import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
// components
|
||||
import axios from '../../../utils/axios';
|
||||
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||
@@ -48,11 +52,17 @@ import { Icd } from '../../../@types/diagnosis';
|
||||
import BasePagination from '../../../components/BasePagination';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { RHFCheckbox } from '../../../components/hook-form';
|
||||
import { CheckBox } from '@mui/icons-material';
|
||||
import { FormProvider, RHFTextField, RHFSwitch, RHFSelect } from '../../../components/hook-form';
|
||||
import { Add, CheckBox } from '@mui/icons-material';
|
||||
import { CorporateService } from '../../../@types/corporates';
|
||||
import { number } from 'yup/lib/locale';
|
||||
import DialogLog from './sections/DialogLog';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
import Label from '@/components/Label';
|
||||
import DialogUpdateStatus from '@/components/DialogUpdateStatus';
|
||||
import palette from '@/theme/palette';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
|
||||
export default function List() {
|
||||
const { themeStretch } = useSettings();
|
||||
@@ -154,9 +164,39 @@ export default function List() {
|
||||
}
|
||||
|
||||
// Generate the every row of the table
|
||||
type DataContent = {
|
||||
code: string;
|
||||
name: string;
|
||||
id: string;
|
||||
status: string|number;
|
||||
};
|
||||
|
||||
type DataType = {
|
||||
code: string;
|
||||
name: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
type FormValuesProps = {
|
||||
value: string;
|
||||
active: boolean;
|
||||
};
|
||||
|
||||
const [isDialogOpen, setDialogOpen] = useState(false)
|
||||
let titles = {
|
||||
name: 'Update Status',
|
||||
icon: '-'
|
||||
}
|
||||
const [dataValue, setDataValue] = useState('');
|
||||
const [dataDescription, setDescriptionValue] = useState('');
|
||||
const [url, setUrl] = useState('');
|
||||
|
||||
// const { id, service_code, status } = data;
|
||||
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const navigate = useNavigate()
|
||||
|
||||
const handleConfigChange = (event: ChangeEvent<HTMLInputElement>, service: any) => {
|
||||
console.log(event.target.name, event.target.checked, service);
|
||||
@@ -168,85 +208,67 @@ export default function List() {
|
||||
});
|
||||
};
|
||||
|
||||
const handleActivate = (service: any, status: string) => {
|
||||
axios
|
||||
.put(`/corporates/${corporate_id}/services/${service.service_code}`, {
|
||||
service_code: service.service_code,
|
||||
status,
|
||||
reason:service.reason
|
||||
})
|
||||
.then((res) => {
|
||||
setDataTableData({
|
||||
...dataTableData,
|
||||
data: dataTableData.data.map((service) => {
|
||||
let updatedService = service;
|
||||
if (row.id == service.id) {
|
||||
updatedService.status = res.data.status;
|
||||
}
|
||||
return updatedService;
|
||||
}),
|
||||
});
|
||||
});
|
||||
// const handleActivate = (service: any, status: string) => {
|
||||
// axios
|
||||
// .put(`/corporates/${corporate_id}/services/${service.service_code}`, {
|
||||
// service_code: service.service_code,
|
||||
// status,
|
||||
// reason:service.reason
|
||||
// })
|
||||
// .then((res) => {
|
||||
// setDataTableData({
|
||||
// ...dataTableData,
|
||||
// data: dataTableData.data.map((service) => {
|
||||
// let updatedService = service;
|
||||
// if (row.id == service.id) {
|
||||
// updatedService.status = res.data.status;
|
||||
// }
|
||||
// return updatedService;
|
||||
// }),
|
||||
// });
|
||||
// });
|
||||
// };
|
||||
|
||||
const handleActivate = (isOpen: boolean, dataValue: DataContent) => {
|
||||
setDialogOpen(isOpen)
|
||||
setDataValue(dataValue)
|
||||
setDescriptionValue('Are you sure to inactive this service ?')
|
||||
setUrl(url)
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
{/* <TableCell>
|
||||
<IconButton
|
||||
aria-label="expand row"
|
||||
size="small"
|
||||
onClick={() => setOpen(!open)}
|
||||
>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</TableCell> */}
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.service_code}</TableCell>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="left">
|
||||
{row.status == 'active' ?
|
||||
<Label color='success'>{row.status}</Label> :
|
||||
<Label color='error'>{row.status}</Label>}
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="right">
|
||||
{row.status == 'active' && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="success"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
// handleActivate(row, 'inactive', 'test');
|
||||
clickHandler('edit');
|
||||
setEdit({id: row.id, service_code: row.service_code, status: 'inactive'});
|
||||
}}
|
||||
>
|
||||
Active
|
||||
</Button>
|
||||
)}
|
||||
{row.status == 'inactive' && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="error"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
clickHandler('edit');
|
||||
setEdit({id: row.id, service_code: row.service_code, status: 'active'});
|
||||
}}
|
||||
>
|
||||
Inactive
|
||||
</Button>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell align="right" width='10%'>
|
||||
<Link to={`/corporate/${corporate_id}/services/${row.service_code}`}>
|
||||
<Button variant="outlined" color="primary" size="small">
|
||||
Config
|
||||
</Button>
|
||||
</Link>
|
||||
</TableCell>
|
||||
<TableCell width='1%'>
|
||||
<Tooltip title="History">
|
||||
<Link to={`/corporate/${corporate_id}/services/${row.id}/history`} >
|
||||
<HistoryIcon/>
|
||||
</Link>
|
||||
</Tooltip>
|
||||
<TableCell align="right" sx={{borderBottom: 'unset'}}>
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => navigate(`/corporates/${row.corporate_id}/services/${row.service_code}`)}>
|
||||
<SettingsOutlinedIcon />
|
||||
Config
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate(`/corporates/${corporate_id}/services/${row.id}/history`)}>
|
||||
<HistoryIcon />
|
||||
History
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => handleActivate(true, {code: row.service_code, name: row.name, id:corporate_id, status: row.status})}>
|
||||
<CachedOutlinedIcon />
|
||||
Update Status
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</TableCell>
|
||||
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
{false && (
|
||||
@@ -474,7 +496,7 @@ export default function List() {
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell colSpan={4} sx={{ py: 1 }}>
|
||||
Free Admin Fee
|
||||
Admin Fee
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
@@ -682,6 +704,20 @@ export default function List() {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
const onSubmit = async (row : any) => {
|
||||
try {
|
||||
handleUpdate(dataValue.status, dataValue.code, row.reason)
|
||||
} catch (error: any) {
|
||||
console.log('data gagal');
|
||||
}
|
||||
|
||||
const ascent = document?.querySelector('ascent');
|
||||
if (ascent != null) {
|
||||
ascent.innerHTML = '';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const applyFilter = async (searchFilter: any) => {
|
||||
await loadDataTableData({ search: searchFilter });
|
||||
setSearchParams({ search: searchFilter });
|
||||
@@ -697,32 +733,146 @@ export default function List() {
|
||||
loadDataTableData();
|
||||
}, []);
|
||||
|
||||
const NewCorporateSchema = Yup.object().shape({
|
||||
reason: Yup.string().required('Reason Edit is required'),
|
||||
});
|
||||
|
||||
const methods = useForm<FormValuesProps>({
|
||||
resolver: yupResolver(NewCorporateSchema),
|
||||
});
|
||||
|
||||
const {
|
||||
reset,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
} = methods;
|
||||
|
||||
const handleUpdate = (active: string, service_code: string, reason:string) => {
|
||||
console.log(active)
|
||||
axios
|
||||
.put(`/corporates/${corporate_id}/services/${service_code}`, {
|
||||
service_code: service_code,
|
||||
status: active,
|
||||
reason: reason
|
||||
})
|
||||
.then((res) => {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
const getContent = () => (
|
||||
<>
|
||||
<Stack paddingX={2} paddingY={2}>
|
||||
<Typography variant='subtitle1'>Are you sure to {dataValue?.status == 'active' ? 'inactive' : 'active'} this service ?</Typography>
|
||||
</Stack>
|
||||
<Card>
|
||||
<Grid container paddingX={2} paddingY={2}>
|
||||
<Grid item xs={4} md={4}>
|
||||
<Typography variant='inherit'>Code</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={8}>
|
||||
<Typography variant='subtitle1'>{dataValue?.code}</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={4} md={4} marginTop={2}>
|
||||
<Typography variant='inherit'>Service Name</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={8} marginTop={2}>
|
||||
<Typography variant='subtitle1'>{dataValue?.name}</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
|
||||
<Typography marginTop={5} marginBottom={3} variant='subtitle1'>
|
||||
Reason for update*
|
||||
</Typography>
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<RHFSelect
|
||||
name="reason"
|
||||
label="Reason for update"
|
||||
>
|
||||
<option value=""></option>
|
||||
<option value="Agreement changed">Agreement changed</option>
|
||||
<option value="Endorsement">Endorsement</option>
|
||||
<option value="Renewal">Renewal</option>
|
||||
<option value="Worng Setting">Worng Setting</option>
|
||||
</RHFSelect>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
justifyContent="flex-end"
|
||||
direction={{ xs: 'column', md: 'row' }}
|
||||
spacing={2}
|
||||
marginTop={5}
|
||||
>
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Button
|
||||
sx={{
|
||||
boxShadow: 'none',
|
||||
}}
|
||||
variant="outlined"
|
||||
size="medium"
|
||||
fullWidth={true}
|
||||
onClick={() => setDialogOpen(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
{dataValue?.status == 'active' ?
|
||||
<LoadingButton
|
||||
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)'}}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="medium"
|
||||
fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
color='error'
|
||||
>
|
||||
Inactive
|
||||
</LoadingButton>
|
||||
:
|
||||
<LoadingButton
|
||||
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)'}}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="medium"
|
||||
fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
color='success'
|
||||
>
|
||||
Active
|
||||
</LoadingButton>
|
||||
|
||||
|
||||
}
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
</FormProvider>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<SearchForm />
|
||||
|
||||
<Card>
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{/* <TableCell style={headStyle} align="left" width={10}/> */}
|
||||
<TableCell style={headStyle} align="left">
|
||||
<TableCell align="left" width={50} />
|
||||
<TableCell align="left">
|
||||
Code
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
<TableCell align="left">
|
||||
Service
|
||||
</TableCell>
|
||||
|
||||
<TableCell style={headStyle} align="right" width={30}>
|
||||
<TableCell align="left" width={100}>
|
||||
Status
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="center" width={30} colSpan={2}>
|
||||
Action
|
||||
<TableCell align="center" width={100}>
|
||||
{/* Action */}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</TableHead>
|
||||
{dataTableIsLoading ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
@@ -750,16 +900,27 @@ export default function List() {
|
||||
</TableContainer>
|
||||
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||
</Card>
|
||||
|
||||
{isDialog === 'edit' && (
|
||||
{/* {isDialog === 'edit' && (
|
||||
<DialogLog
|
||||
data={edit}
|
||||
openDialog={openDialog}
|
||||
setOpenDialog={setOpenDialog}
|
||||
title={{ name: 'Reason For Update' }}
|
||||
/>
|
||||
)}
|
||||
)} */}
|
||||
|
||||
|
||||
|
||||
<DialogUpdateStatus
|
||||
openDialog={isDialogOpen}
|
||||
setOpenDialog={setDialogOpen}
|
||||
title={titles}
|
||||
data={dataValue}
|
||||
description={dataDescription}
|
||||
content={getContent()}
|
||||
// maxWidth='50px'
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -121,11 +121,11 @@ export default function CustomizedAccordions() {
|
||||
},
|
||||
{
|
||||
name: corporate?.name ?? '-',
|
||||
href: '/corporate/' + corporate_id + '/services',
|
||||
href: '/corporates/' + corporate_id + '/services',
|
||||
},
|
||||
{
|
||||
name: 'Audittrail Corporate',
|
||||
href: '/corporate/' + corporate_id + '/benefits',
|
||||
href: '/corporates/' + corporate_id + '/benefits',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -19,6 +19,10 @@ import HeaderBreadcrumbs from '../../components/HeaderBreadcrumbs';
|
||||
import CorporateTabNavigations from './CorporateTabNavigations';
|
||||
import { fCurrency } from '../../utils/formatNumber';
|
||||
import { ConfiguredCorporateContext } from '@/contexts/ConfiguredCorporateContext';
|
||||
import Iconify from '@/components/Iconify';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { makeFormData } from '@/utils/jsonToFormData';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
|
||||
export default function Corporates() {
|
||||
const { themeStretch } = useSettings();
|
||||
@@ -29,11 +33,95 @@ export default function Corporates() {
|
||||
|
||||
useEffect(() => {
|
||||
setCorporate(configuredCorporateContext.currentCorporate);
|
||||
}, [configuredCorporateContext])
|
||||
getFilesDoc(corporate_id);
|
||||
}, [configuredCorporateContext, corporate_id])
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
};
|
||||
// Upload Docs
|
||||
const fileDocsInput = useRef<HTMLInputElement>(null);
|
||||
const [fileDocs, setFileDocs] = useState([]);
|
||||
const [showAll, setShowAll] = useState(false);
|
||||
const [isActive, setIsActive] = useState(false);
|
||||
const handleDocsInputChange = (corporate_id) => (event) => {
|
||||
if(event.target.files[0] && corporate_id)
|
||||
{
|
||||
const updatedFiles = Array.from(event.target.files).map((file) => ({
|
||||
file
|
||||
}));
|
||||
submitUploadDocs(corporate_id, updatedFiles);
|
||||
}
|
||||
};
|
||||
function submitUploadDocs(corporate_id, files)
|
||||
{
|
||||
if(files.length > 0)
|
||||
{
|
||||
files.map((file, index) => {
|
||||
const formData = makeFormData(
|
||||
{
|
||||
corporate_id : corporate_id,
|
||||
result_files : file['file']
|
||||
}
|
||||
);
|
||||
axios
|
||||
.post('/add-files-doc', formData)
|
||||
.then((response) => {
|
||||
getFilesDoc(corporate_id);
|
||||
enqueueSnackbar(response.data.message, { variant: 'success' });
|
||||
})
|
||||
.catch((error) => {
|
||||
enqueueSnackbar(error.response.data.errors[0], { variant: 'error' });
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
function getFilesDoc(corporate_id)
|
||||
{
|
||||
axios
|
||||
.post('/get-files-doc',{corporate_id:corporate_id})
|
||||
.then((response) => {
|
||||
setFileDocs(response.data.data);
|
||||
if(response.data.data[0]['status_download'] == 1)
|
||||
{
|
||||
setIsActive(!isActive);
|
||||
}
|
||||
else
|
||||
{
|
||||
setIsActive(isActive);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
enqueueSnackbar(error.response.data.errors[0], { variant: 'error' });
|
||||
});
|
||||
}
|
||||
|
||||
const toggleButton = () => {
|
||||
setIsActive(!isActive);
|
||||
let statusDownload = 0;
|
||||
if(!isActive)
|
||||
{
|
||||
statusDownload = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
statusDownload = 0;
|
||||
}
|
||||
axios
|
||||
.post('/update-status-files-doc', {status_download : statusDownload, corporate_id : corporate_id})
|
||||
.then((response) => {
|
||||
enqueueSnackbar(response.data.message, { variant: 'success' });
|
||||
})
|
||||
.catch((error) => {
|
||||
enqueueSnackbar(error.response.data.errors[0], { variant: 'error' });
|
||||
});
|
||||
};
|
||||
// End Upload Docs
|
||||
|
||||
const style1 = {px:4, marginTop: 2};
|
||||
const style2 = {color: '#919EAB', width: '50%'};
|
||||
const style3 = {color: '#212B36', width: '50%'};
|
||||
|
||||
return (
|
||||
<Page title="Dashboard">
|
||||
|
||||
@@ -50,65 +138,140 @@ export default function Corporates() {
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
|
||||
{/* <Container maxWidth={themeStretch ? false : 'xl'}> */}
|
||||
<Card>
|
||||
<Stack spacing="3">
|
||||
<Stack spacing="2">
|
||||
<CorporateTabNavigations position=""/>
|
||||
<Grid container spacing={3}>
|
||||
|
||||
<Grid item md={6} sx={{ p:2 }}>
|
||||
<Typography sx={{...headStyle, px:3, fontSize:'24px'}}>Current Policy </Typography>
|
||||
|
||||
<Table>
|
||||
<TableBody>
|
||||
|
||||
<TableRow>
|
||||
<TableCell sx={headStyle}>Policy Name</TableCell>
|
||||
<TableCell>{corporate?.current_policy?.code}</TableCell>
|
||||
</TableRow>
|
||||
|
||||
<TableRow>
|
||||
<TableCell sx={headStyle}>Total Premi</TableCell>
|
||||
<TableCell>{fCurrency(corporate?.current_policy?.total_premi)}</TableCell>
|
||||
</TableRow>
|
||||
|
||||
<TableRow>
|
||||
<TableCell sx={headStyle}>Stop Service</TableCell>
|
||||
<TableCell>{fCurrency(corporate?.current_policy?.minimal_stop_service_net)}</TableCell>
|
||||
</TableRow>
|
||||
|
||||
<TableRow>
|
||||
<TableCell sx={headStyle}>Balance</TableCell>
|
||||
<TableCell>{fCurrency(corporate?.current_policy?.limit_balance)}</TableCell>
|
||||
</TableRow>
|
||||
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<Grid>
|
||||
<Grid sx={{ p:2 }}>
|
||||
<Typography variant='subtitle1' sx={{...headStyle, px:4, marginTop: 2}}>Current Policy </Typography>
|
||||
<Stack spacing={2} direction='row' sx={{...style1}}>
|
||||
<Typography variant='body2' sx={{...style2}}>Policy Name</Typography>
|
||||
<Typography variant='body2' sx={{...style3}}>{corporate?.current_policy?.code}</Typography>
|
||||
</Stack>
|
||||
<Stack spacing={2} direction='row' sx={{...style1}}>
|
||||
<Typography variant='body2' sx={{...style2}}>Total Premi</Typography>
|
||||
<Typography variant='body2' sx={{...style3}}>{fCurrency(corporate?.current_policy?.total_premi)}</Typography>
|
||||
</Stack>
|
||||
<Stack spacing={2} direction='row' sx={{...style1}}>
|
||||
<Typography variant='body2' sx={{...style2}}>Stop Service</Typography>
|
||||
<Typography variant='body2' sx={{...style3}}>{fCurrency(corporate?.current_policy?.minimal_stop_service_net)}</Typography>
|
||||
</Stack>
|
||||
<Stack spacing={2} direction='row' sx={{...style1}}>
|
||||
<Typography variant='body2' sx={{...style2}}>Balance</Typography>
|
||||
<Typography variant='body2' sx={{...style3}}>{fCurrency(corporate?.current_policy?.limit_balance)}</Typography>
|
||||
</Stack>
|
||||
</Grid>
|
||||
|
||||
<Grid item md={6} sx={{ p:2 }}>
|
||||
<Typography sx={{...headStyle, px:3, fontSize:'24px'}}>Claims</Typography>
|
||||
|
||||
<Table>
|
||||
<TableBody>
|
||||
|
||||
<TableRow>
|
||||
<TableCell sx={headStyle}>Number Of Claim</TableCell>
|
||||
<TableCell>{corporate?.current_policy?.code}</TableCell>
|
||||
</TableRow>
|
||||
|
||||
<TableRow>
|
||||
<TableCell sx={headStyle}>Total Usage This Year</TableCell>
|
||||
<TableCell>{fCurrency((corporate?.current_policy?.total_premi ?? 0) - (corporate?.current_policy?.limit_balance ?? 0))}</TableCell>
|
||||
</TableRow>
|
||||
|
||||
</TableBody>
|
||||
</Table>
|
||||
<Grid sx={{ p:2 }}>
|
||||
<Typography variant='subtitle1' sx={{...headStyle, px:4, marginTop: 2}}>Claims</Typography>
|
||||
<Stack spacing={2} direction='row' sx={{...style1}}>
|
||||
<Typography variant='body2' sx={{...style2}}>Number Of Claim</Typography>
|
||||
<Typography variant='body2' sx={{...style3}}>{corporate?.current_policy?.code}</Typography>
|
||||
</Stack>
|
||||
<Stack spacing={2} direction='row' sx={{...style1}}>
|
||||
<Typography variant='body2' sx={{...style2}}>Total Usage This Year</Typography>
|
||||
<Typography variant='body2' sx={{...style3}}>{fCurrency((corporate?.current_policy?.total_premi ?? 0) - (corporate?.current_policy?.limit_balance ?? 0))}</Typography>
|
||||
</Stack>
|
||||
|
||||
</Grid>
|
||||
<Grid sx={{ p:2 }}>
|
||||
<Typography variant='subtitle1' sx={{...headStyle, px:4, marginTop: 2}}>Docs (Terms & Conditions)</Typography>
|
||||
{fileDocs.length > 0 && (
|
||||
<Stack spacing={2} direction='row' sx={{...style1}} alignItems="center">
|
||||
<Stack direction='row' sx={{width: '50%'}} alignItems="center">
|
||||
<Typography variant='body2' sx={{color: '#919EAB', marginRight: 2}}>ASO members can download or not?</Typography>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color={isActive ? "success" : "error"}
|
||||
size="small"
|
||||
onClick={toggleButton}
|
||||
>
|
||||
<Typography variant='body3' sx={{fontWeight: 'bold'}}>{isActive ? 'Active' : 'Inactive'}</Typography>
|
||||
</Button>
|
||||
</Stack>
|
||||
{!showAll && (
|
||||
<Stack direction='row' sx={{width: '50%'}} alignItems="center">
|
||||
<input
|
||||
type="file"
|
||||
id={`fileDocsID`}
|
||||
ref={fileDocsInput}
|
||||
style={{ display: 'none' }}
|
||||
onChange={(event) => {
|
||||
handleDocsInputChange(corporate_id)(event);
|
||||
}}
|
||||
accept="application/pdf"
|
||||
multiple
|
||||
/>
|
||||
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
fileDocsInput.current.click();
|
||||
}}
|
||||
sx={{ width: 'fit-content', color: '#19BBBB' }}
|
||||
>
|
||||
<Stack alignItems="center" direction="row" spacing={1}>
|
||||
<Iconify icon="icon-park-outline:upload-one" fontSize="2em" sx={{color: '#19BBBB'}} />
|
||||
<Typography variant='body3' sx={{fontWeight: 'bold', color: '#19BBBB'}}>Update File</Typography>
|
||||
</Stack>
|
||||
</Button>
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
)}
|
||||
{fileDocs.slice(0, showAll ? fileDocs.length : 1).map((file, index) => (
|
||||
<Stack spacing={2} direction='row' sx={{...style1}}>
|
||||
<a
|
||||
href={file.path}
|
||||
style={{ cursor: 'pointer', textDecoration: 'underline', color: '#19BBBB' }}
|
||||
target="_blank"
|
||||
>
|
||||
<Typography variant='body2' sx={{color: '#19BBBB'}}>{file.original_name}</Typography>
|
||||
</a>
|
||||
</Stack>
|
||||
))}
|
||||
{!showAll && fileDocs.length > 1 && (
|
||||
<Stack spacing={2} direction='row' sx={{...style1}}>
|
||||
<Typography variant='body2' onClick={() => setShowAll(true)} style={{ color: '#19BBBB', cursor: 'pointer' }}>Lihat Semua Data</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
{showAll && (
|
||||
<Stack spacing={2} direction='row' sx={{...style1}}>
|
||||
<Typography variant='body2' onClick={() => setShowAll(false)} style={{ color: '#19BBBB', cursor: 'pointer' }}>Sembunyikan Data</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
{fileDocs.length <= 0 && (
|
||||
<Stack spacing={2} direction='row' sx={{...style1}} alignItems="center">
|
||||
<Typography variant='body2' sx={{...style2}}>Please add a Terms & Conditions document</Typography>
|
||||
<Stack direction='row' sx={{width: '50%'}} alignItems="center">
|
||||
<input
|
||||
type="file"
|
||||
id={`fileDocsID`}
|
||||
ref={fileDocsInput}
|
||||
style={{ display: 'none' }}
|
||||
onChange={(event) => {
|
||||
handleDocsInputChange(corporate_id)(event);
|
||||
}}
|
||||
accept="application/pdf"
|
||||
// multiple
|
||||
/>
|
||||
<LoadingButton
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
fileDocsInput.current.click();
|
||||
}}
|
||||
>
|
||||
<Stack alignItems="center" direction="row" spacing={1}>
|
||||
<Iconify icon="icon-park-outline:upload-one" fontSize="2em" sx={{color: '#19BBBB'}} />
|
||||
<Typography variant='body3' sx={{fontWeight: 'bold', color: '#19BBBB'}}>Upload File</Typography>
|
||||
</Stack>
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</Stack>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Card>
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { Card, Typography } from "@mui/material";
|
||||
import { Stack } from '@mui/material';
|
||||
import { DetailFinalLogType } from "../FinalLog/Model/Types";
|
||||
import { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime";
|
||||
|
||||
|
||||
type CardDetail = {
|
||||
requestLog: DetailFinalLogType|undefined;
|
||||
}
|
||||
|
||||
const style1 = {
|
||||
color: '#919EAB',
|
||||
width: '30%'
|
||||
}
|
||||
const style2 = {
|
||||
width: '70%'
|
||||
}
|
||||
const marginBottom1 = {
|
||||
marginBottom: 1,
|
||||
}
|
||||
const marginBottom2 = {
|
||||
marginBottom: 2,
|
||||
}
|
||||
|
||||
|
||||
export default function CardDetail({requestLog} : CardDetail ) {
|
||||
return (
|
||||
<Card sx={{padding:2}} >
|
||||
<Typography variant='subtitle1' sx={{color: '#19BBBB', marginBottom: 4}} gutterBottom>Detail</Typography>
|
||||
<Stack direction='row' spacing={2} sx={marginBottom1}>
|
||||
<Typography variant='subtitle2' sx={style1} gutterBottom>Member ID</Typography>
|
||||
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.member_id}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2} sx={marginBottom1}>
|
||||
<Typography variant='subtitle2' sx={style1} gutterBottom>Policy Number</Typography>
|
||||
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.policy_number}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2} sx={marginBottom1}>
|
||||
<Typography variant='subtitle2' sx={style1} gutterBottom>Name</Typography>
|
||||
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.name}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2} sx={marginBottom1}>
|
||||
<Typography variant='subtitle2' sx={style1} gutterBottom>Date Of Birth</Typography>
|
||||
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.date_of_birth ? fDate(requestLog?.date_of_birth) : '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2} sx={marginBottom1}>
|
||||
<Typography variant='subtitle2' sx={style1} gutterBottom>Marital Status</Typography>
|
||||
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.marital_status}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2} sx={marginBottom1}>
|
||||
<Typography variant='subtitle2' sx={style1} gutterBottom>Submission Date</Typography>
|
||||
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : '-'}</Typography>
|
||||
</Stack>
|
||||
</Card>
|
||||
)
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user