Merge branch 'feature/dashboard-create-claim-request' into staging

This commit is contained in:
korospace
2023-11-02 20:05:41 +07:00
28 changed files with 1162 additions and 131 deletions

View File

@@ -0,0 +1,98 @@
import { RefObject, useEffect, useRef, useState } from 'react';
interface FetchFunction<T> {
(page: number): Promise<T[]>;
}
const useLoadOnScroll = <T>(executeFetch: FetchFunction<T>) => {
const [data, setData] = useState<T[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [page, setPage] = useState<number>(1);
const [listener, setListener] = useState<number>(1);
const [lastPage, setLastPage] = useState<boolean>(false);
const fetchData = async (isSearch?: boolean) => {
if (!lastPage || isSearch === true)
if (isLoading === false) {
setIsLoading(true);
if (isSearch === true) {
const newData = await executeFetch(1);
if (newData.length > 0) {
setData(newData);
setPage((prevPage) => 2);
} else {
setLastPage(true);
setData([]);
}
} else {
const newData = await executeFetch(page);
if (newData.length > 0) {
setData((prevData) => [...prevData, ...newData]);
setPage((prevPage) => prevPage + 1);
} else {
setLastPage(true);
}
}
setIsLoading(false);
}
};
const refetchData = () => {
setPage(1);
setListener((prev) => prev + 1);
};
const resetLastPage = () => {
setLastPage(false);
};
useEffect(() => {
fetchData();
}, [listener]);
// useEffect(() => {
// if (data.length === 0) {
// fetchData();
// }
// }, [data]);
const handleScroll = () => {
const { scrollTop, clientHeight, scrollHeight } = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight - 1) {
setListener((prevListener) => prevListener + 1);
}
};
const resetSearch = () => {
console.log('reset search');
fetchData(true);
resetLastPage();
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
const onClose = () => {
setData([]);
setPage(1);
setLastPage(false);
};
const onOpen = () => {
setData([]);
setLastPage(false);
fetchData(true);
};
// setData and setPage to reset when the dialog closed
return { data, isLoading, setPage, setData, resetSearch, resetLastPage, onClose, onOpen, refetchData };
};
export default useLoadOnScroll;

View File

@@ -32,12 +32,6 @@ export default function Claim() {
const [memberDetail, setMemberDetail] = useState<MemberDetailType>();
const [claimList, setClaimList] = useState<ClaimListType[]>();
// Use Effect
// --------------------
useEffect(() => {
loadDataTableData();
}, [])
// Load Data
// -------------------
const loadDataTableData = async () => {
@@ -47,6 +41,10 @@ export default function Claim() {
setClaimList(response.claim_list);
}
useEffect(() => {
loadDataTableData();
}, [])
return (
<Page title={ `claims | ${memberDetail?.name??'_ _ _'}` } sx={{ px: 2 }}>
<Grid container gap={6}>

View File

@@ -37,7 +37,7 @@ export default function ClaimListRow ({ ...props }: Props) {
<TableRow hover sx={{ '& > td': { borderBottom: '1' } }}>
<TableCell align="left" />
<TableCell align="left">
{props.row.admission_dates == "0000-00-00 00:00:00" ?
{props.row.admission_date == "0000-00-00 00:00:00" ?
('-')
:
(
@@ -45,12 +45,12 @@ export default function ClaimListRow ({ ...props }: Props) {
variant="ghost"
color="default"
>
{fDate(props.row.admission_dates)}
{fDate(props.row.admission_date)}
</Label>
)}
</TableCell>
<TableCell align="left">
{props.row.discharge_dates == "0000-00-00 00:00:00" ?
{props.row.discharge_date == "0000-00-00 00:00:00" ?
('-')
:
(
@@ -58,7 +58,7 @@ export default function ClaimListRow ({ ...props }: Props) {
variant="ghost"
color="default"
>
{fDate(props.row.discharge_dates)}
{fDate(props.row.discharge_date)}
</Label>
)}
</TableCell>

View File

@@ -25,12 +25,6 @@ export default function DailyMonitoringList() {
fontWeight: 'bold',
};
// Use Effect
// --------------------
useEffect(() => {
loadDataTableData();
}, [])
// Load Data
// -------------------
const loadDataTableData = async () => {
@@ -42,6 +36,10 @@ export default function DailyMonitoringList() {
setDataTableData(response);
}
useEffect(() => {
loadDataTableData();
}, [])
return (
<Box>
<TableContainer component={Paper}>

View File

@@ -30,8 +30,8 @@ export type MemberDetailType = {
*/
export type ClaimListType = {
claim_id : number,
admission_dates : string,
discharge_dates : string,
admission_date : string,
discharge_date : string,
claim_code : string,
claim_status : string,
service_type : string,

View File

@@ -37,7 +37,7 @@ export default function ClaimListRow ({ ...props }: Props) {
<TableRow hover sx={{ '& > td': { borderBottom: '1' } }}>
<TableCell align="left" />
<TableCell align="left">
{props.row.admission_dates == "0000-00-00 00:00:00" ?
{props.row.admission_date == "0000-00-00 00:00:00" ?
('-')
:
(
@@ -45,12 +45,12 @@ export default function ClaimListRow ({ ...props }: Props) {
variant="ghost"
color="default"
>
{fDate(props.row.admission_dates)}
{fDate(props.row.admission_date)}
</Label>
)}
</TableCell>
<TableCell align="left">
{props.row.discharge_dates == "0000-00-00 00:00:00" ?
{props.row.discharge_date == "0000-00-00 00:00:00" ?
('-')
:
(
@@ -58,7 +58,7 @@ export default function ClaimListRow ({ ...props }: Props) {
variant="ghost"
color="default"
>
{fDate(props.row.discharge_dates)}
{fDate(props.row.discharge_date)}
</Label>
)}
</TableCell>

View File

@@ -30,8 +30,8 @@ export type MemberDetailType = {
*/
export type ClaimListType = {
claim_id : number,
admission_dates : string,
discharge_dates : string,
admission_date : string,
discharge_date : string,
claim_code : string,
claim_status : string,
service_type : string,

View File

@@ -0,0 +1,361 @@
/**
* 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';
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}>
<Grid item xs={6}>
<Button
sx={{ padding: 2, width: '100%',border: row.patien_type === 'IP' ? '1px solid #19BBBB' : '1px solid #919EAB52' }}
variant="outlined"
color={row.patien_type === 'IP' ? 'primary' : 'inherit'}
onClick={() => {
handleChoosePatienType(row, 'IP')
}}
>
Inpatient
</Button>
</Grid>
<Grid item xs={6}>
<Button
sx={{ padding: 2, width: '100%',border: row.patien_type === 'OP' ? '1px solid #19BBBB' : '1px solid #919EAB52' }}
variant="outlined"
color={row.patien_type === 'OP' ? 'primary' : 'inherit'}
onClick={() => {
handleChoosePatienType(row, 'OP')
}}
>
Outpatient
</Button>
</Grid>
</Grid>
</Grid>
{/* File Kondisi */}
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="h6">Condition Document</Typography>
</Grid>
{row.file_kondisi && row.file_kondisi.map((file, index) => (
<Grid item xs={12} key={index}>
<FormCreateFilesUpload file={file} handleRemoveFileProp={() => handleRemoveFile(row, 'kondisi', index)} />
</Grid>
))}
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<FormCreateBtnUpload handleChangeInputProp={(file) => handleChangeInput(row, 'kondisi', file)} />
</Grid>
</Grid>
</Grid>
{/* File Diagnosa */}
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="h6">Diagnosis Document</Typography>
</Grid>
{row.file_diagnosa && row.file_diagnosa.map((file, index) => (
<Grid item xs={12} key={index}>
<FormCreateFilesUpload file={file} handleRemoveFileProp={() => handleRemoveFile(row, 'diagnosa', index)} />
</Grid>
))}
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<FormCreateBtnUpload handleChangeInputProp={(file) => handleChangeInput(row, 'diagnosa', file)} />
</Grid>
</Grid>
</Grid>
{/* File Penunjang */}
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="h6">Supporting Result Document</Typography>
</Grid>
{row.file_penunjang && row.file_penunjang.map((file, index) => (
<Grid item xs={12} key={index}>
<FormCreateFilesUpload file={file} handleRemoveFileProp={() => handleRemoveFile(row, 'penunjang', index)} />
</Grid>
))}
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<FormCreateBtnUpload handleChangeInputProp={(file) => handleChangeInput(row, 'penunjang', file)} />
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
)
})
}
<Grid item xs={12} sx={{ display: 'flex', justifyContent: 'flex-end' }}>
<Box display="flex" gap={1}>
<Button variant="outlined" color="inherit" onClick={() => clearForm()}>
Cancel
</Button>
<LoadingButton disabled={isDirty} type="submit" variant="contained" loading={formIsLoading} onClick={() => handleSubmit()}>
Save Changes
</LoadingButton>
</Box>
</Grid>
</Grid>
</Box>
)
}

View File

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

View File

@@ -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=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf"
/>
</ButtonBase>
)
}

View File

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

View File

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

View File

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

View File

@@ -4,8 +4,8 @@ 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 axios from '../../../utils/axios';
import { FormProvider, RHFTextField } from '../../../components/hook-form';
import { makeFormData } from '@/utils/jsonToFormData';
import {
@@ -32,12 +32,12 @@ import {
ButtonBase,
Box,
} from '@mui/material';
import Iconify from '../../components/Iconify';
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, DeleteOutline } from '@mui/icons-material';
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';
@@ -51,7 +51,7 @@ type Props = {
currentClaim?: ClaimRequest;
};
export default function ClaimForm({ isEdit, currentClaim }: Props) {
export default function FormEdit({ isEdit, currentClaim }: Props) {
const navigate = useNavigate();
const { enqueueSnackbar } = useSnackbar();
@@ -90,7 +90,7 @@ export default function ClaimForm({ isEdit, currentClaim }: Props) {
resolver: yupResolver(EditClaimSchema),
defaultValues,
});
const {
reset,
watch,
@@ -188,8 +188,8 @@ export default function ClaimForm({ isEdit, currentClaim }: Props) {
_method: 'PUT'
});
const response = await axios.post(`/claim-requests/${data.id}`, formData);
const response = await axios.put(`/claim-requests/${data.id}`, formData);
reset();
enqueueSnackbar('Claim Request Updated Successfully!', { variant: 'success' });
navigate('/claim-requests');
@@ -208,6 +208,18 @@ export default function ClaimForm({ isEdit, currentClaim }: Props) {
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}>
@@ -224,7 +236,7 @@ export default function ClaimForm({ isEdit, currentClaim }: Props) {
</Grid>
{/* <input type="hidden" name="id"/> */}
<Grid item xs={12}></Grid>
<Grid item xs={3}>
@@ -246,7 +258,7 @@ export default function ClaimForm({ isEdit, currentClaim }: Props) {
<InputAdornment position="end">
<CalendarTodayIcon />
</InputAdornment>
), }}
), }}
name="date" label="Date of Submission" disabled/>
</Grid>
<Grid item xs={3}>
@@ -310,7 +322,7 @@ export default function ClaimForm({ isEdit, currentClaim }: Props) {
</ButtonBase>
</Grid>
</React.Fragment>
{/* -------------------------------Upload Dokumen Diagnosa------------------------------- */}
{/* -------------------------------Upload Dokumen Diagnosa------------------------------- */}
<React.Fragment>
<Grid item xs={12}>
<Typography variant='h6'> Diagnosis Document</Typography>
@@ -360,7 +372,7 @@ export default function ClaimForm({ isEdit, currentClaim }: Props) {
</ButtonBase>
</Grid>
</React.Fragment>
{/* -------------------------------Upload Result Hasil Penunjang------------------------------- */}
{/* -------------------------------Upload Result Hasil Penunjang------------------------------- */}
<React.Fragment>
<Grid item xs={12}>
<Typography variant='h6'> Supporting Result Document</Typography>

View File

@@ -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';
@@ -16,46 +18,45 @@ import { LoadingButton } from '@mui/lab';
import { fCurrency } from '../../utils/formatNumber';
import Iconify from '../../components/Iconify';
import { ClaimRequest } from '@/@types/claims';
import Form from './Form';
import FormEdit from './Components/FormEdit';
import FormCreate from './Components/FormCreate';
export default function ClaimsCreateUpdate() {
const { themeStretch } = useSettings();
const { id } = useParams();
const { themeStretch } = useSettings();
const { id } = useParams();
const isEdit = id ? true : false;
const isEdit = id ? true : false;
const [currentClaim, setCurrentClaim] = useState<ClaimRequest>();
const [currentClaim, setCurrentClaim] = useState<ClaimRequest>();
useEffect(() => {
if (isEdit) {
axios.get('/claim-requests/' + id).then((res) => {
console.log('Yeet', res.data);
setCurrentClaim(res.data.data);
});
useEffect(() => {
if (isEdit) {
axios.get('/claim-requests/' + id).then((res) => {
console.log('Yeet', res.data);
setCurrentClaim(res.data.data);
});
console.log(currentClaim)
}
}, [id]);
console.log(currentClaim)
}
}, [id]);
return (
<Page title={isEdit ? `Edit Claim Request` : "Create New Claim"}>
<Container maxWidth={themeStretch ? false : 'xl'}>
<Stack direction="row" alignItems="center">
<HeaderBreadcrumbs
heading={'Edit Claim Request'}
links={[
{ name: 'Dashboard', href: '/dashboard' },
{
name: 'Claim Request',
},
]}
/>
</Stack>
{
id == undefined
?
(
<FormCreate />
)
:
(
<FormEdit isEdit={isEdit} currentClaim={currentClaim} />
)
}
<Form isEdit={isEdit} currentClaim={currentClaim} />
</Container>
</Page>
);

View File

@@ -135,7 +135,7 @@ export default function List() {
if (importForm.current?.files.length) {
const formData = new FormData();
formData.append('file', importForm.current?.files[0]);
setImportLoading(true);
axios
.post(`claim-requests/import`, formData)
@@ -222,7 +222,7 @@ export default function List() {
startIcon={<AddIcon />}
sx={{ p: 1.8 }}
onClick={() => {
navigate('/claims/create');
navigate('/claim-requests/create');
}}
>
Create
@@ -356,8 +356,8 @@ export default function List() {
<TableCell align="left">{row.service_name}</TableCell>
<TableCell align="left">{row.payment_type_name}</TableCell>
<TableCell align="left">
{ row.status == "requested" ?
(<Label variant='ghost' color='primary'>{capitalizeFirstLetter(row.status)}</Label>) :
{ row.status == "requested" ?
(<Label variant='ghost' color='primary'>{capitalizeFirstLetter(row.status)}</Label>) :
(<Label color='success'> {capitalizeFirstLetter(row.status)}</Label>)
}
</TableCell>
@@ -376,7 +376,7 @@ export default function List() {
} />
</TableCell>
{/* <TableCell>
<IconButton
onClick={() => {
handleShowClaim(row);
@@ -398,7 +398,7 @@ export default function List() {
>
<Box>
<Typography fontWeight={600}>Berkas Hasil Penunjang</Typography>
{/* {row.files_by_type?.claim_kondisi &&
{/* {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>{' '}
@@ -412,7 +412,7 @@ export default function List() {
<>
<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}
@@ -426,7 +426,7 @@ export default function List() {
<>
<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}
@@ -440,7 +440,7 @@ export default function List() {
<>
<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}

View File

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

View File

@@ -0,0 +1,19 @@
/**
* Search Type
*/
export type SearchType = {
keyword: string,
}
/**
* Member List
*/
export type MemberListType = {
id : string,
member_id : string,
name : string,
patien_type? : string,
file_kondisi? : any[],
file_diagnosa? : any[],
file_penunjang? : any[]
}

View File

@@ -430,18 +430,6 @@ export default function Router() {
path: 'claims',
element: <Claims />,
},
{
path: 'claim-requests',
element: <ClaimRequests />,
},
{
path: 'claim-requests/edit/:id',
element: <ClaimRequestsCreate />,
},
{
path: 'claim-requests/detail/:id',
element: <ClaimRequestsDetail />,
},
{
path: 'claims/create',
element: <ClaimsCreate />,
@@ -458,6 +446,22 @@ export default function Router() {
path: 'claims/:id',
element: <ClaimShow />,
},
{
path: 'claim-requests',
element: <ClaimRequests />,
},
{
path: 'claim-requests/create',
element: <ClaimRequestsCreate />,
},
{
path: 'claim-requests/edit/:id',
element: <ClaimRequestsCreate />,
},
{
path: 'claim-requests/detail/:id',
element: <ClaimRequestsDetail />,
},
{
path: 'profile',
element: <Profile />,

View File

@@ -62,11 +62,11 @@ declare module '@mui/material' {
// SETUP COLORS
const PRIMARY = {
lighter: '#D0FBEC',
light: '#70EAD5',
main: '#19BBBB',
dark: '#0C7186',
darker: '#043C59',
lighter: '#D1F1F1',
light: '#70EAD5',
main: '#19BBBB',
dark: '#0C7186',
darker: '#043C59',
};
const SECONDARY = {
lighter: '#D6E4FF',