Fix Member Plan
This commit is contained in:
@@ -26,7 +26,7 @@ class MemberController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function index(Request $request, $corporate_id)
|
public function index(Request $request, $corporate_id)
|
||||||
{
|
{
|
||||||
$benefits = Member::query()
|
$members = Member::query()
|
||||||
->filter($request->all())
|
->filter($request->all())
|
||||||
// ->where('corporate_id', $corporate_id)
|
// ->where('corporate_id', $corporate_id)
|
||||||
->whereHas('employeds', function ($employeds) use ($corporate_id) {
|
->whereHas('employeds', function ($employeds) use ($corporate_id) {
|
||||||
@@ -40,10 +40,11 @@ class MemberController extends Controller
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
->with('currentPlan')
|
||||||
->paginate()
|
->paginate()
|
||||||
->appends($request->all());
|
->appends($request->all());
|
||||||
|
|
||||||
return $benefits;
|
return $members;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -423,6 +423,15 @@ class MemberEnrollmentService
|
|||||||
]), 0, null, $row);
|
]), 0, null, $row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate If Plan Exist
|
||||||
|
// TODO validate corporate plan
|
||||||
|
$plan = Plan::query()
|
||||||
|
->where('code', $row['plan_id'])
|
||||||
|
->first();
|
||||||
|
if (!$plan) {
|
||||||
|
throw new ImportRowException(__('enrollment.PLAN_NOT_FOUND'), 0, null, $row);
|
||||||
|
}
|
||||||
|
|
||||||
$this->validateRow($row);
|
$this->validateRow($row);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -450,6 +459,13 @@ class MemberEnrollmentService
|
|||||||
'nik' => $row['nik'],
|
'nik' => $row['nik'],
|
||||||
'status' => $row['employment_status']
|
'status' => $row['employment_status']
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$member->memberPlans()->create([
|
||||||
|
'plan_id' => $plan->code,
|
||||||
|
'status' => 'active',
|
||||||
|
'start' => Carbon::parse(strtotime($row['member_effective_date'])),
|
||||||
|
'end' => Carbon::parse(strtotime($row['member_expiry_date'])),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
DB::commit();
|
DB::commit();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
@@ -458,35 +474,65 @@ class MemberEnrollmentService
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "2": // Member Information Update (Without Replacement Card)
|
case "2": // Member Information Update (Without Replacement Card)
|
||||||
$memberPolicy = MemberPolicy::query()
|
$member = Member::query()
|
||||||
->where('policy_id', $row['policy_number'])
|
->where('member_id', $row['member_id'])
|
||||||
->where('member_id', $row['member_id'])
|
->first();
|
||||||
->with('member')
|
|
||||||
->first();
|
// Validate If Exist Member
|
||||||
|
if (!$member) {
|
||||||
|
throw new ImportRowException(__('enrollment.MEMBER_NOT_FOUND', [
|
||||||
|
'member_id' => $row['member_id'],
|
||||||
|
'policy_id' => $row['policy_number']
|
||||||
|
]), 0, null, $row);
|
||||||
|
}
|
||||||
|
|
||||||
if (!$memberPolicy) {
|
try {
|
||||||
throw new ImportRowException(__('enrollment.MEMBER_NOT_EXISTS', [
|
$memberPolicy = MemberPolicy::query()
|
||||||
'member_id' => $row['member_id'],
|
->where('policy_id', $row['policy_number'])
|
||||||
'policy_id' => $row['policy_number']
|
->where('member_id', $row['member_id'])
|
||||||
]), 0, null, $row);
|
->with('member')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$memberPolicy) {
|
||||||
|
throw new ImportRowException(__('enrollment.MEMBER_NOT_EXISTS', [
|
||||||
|
'member_id' => $row['member_id'],
|
||||||
|
'policy_id' => $row['policy_number']
|
||||||
|
]), 0, null, $row);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($memberPolicy->status != 'active') {
|
||||||
|
throw new ImportRowException(__('enrollment.MEMBER_INACTIVE', [
|
||||||
|
'member_id' => $row['member_id'],
|
||||||
|
'policy_id' => $row['policy_number']
|
||||||
|
]), 0, null, $row);
|
||||||
|
}
|
||||||
|
|
||||||
|
$memberPolicy->member->fill($member_data);
|
||||||
|
if (!$memberPolicy->member->isDirty()) {
|
||||||
|
throw new ImportRowException(__('enrollment.MEMBER_NO_CHANGE'), 0, null, $row);
|
||||||
|
}
|
||||||
|
|
||||||
|
$memberPolicy->member->save();
|
||||||
|
DB::commit();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
DB::rollback();
|
||||||
|
throw new ImportRowException($e->getMessage(), $e->getCode(), $e, $row);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($memberPolicy->status != 'active') {
|
|
||||||
throw new ImportRowException(__('enrollment.MEMBER_INACTIVE', [
|
|
||||||
'member_id' => $row['member_id'],
|
|
||||||
'policy_id' => $row['policy_number']
|
|
||||||
]), 0, null, $row);
|
|
||||||
}
|
|
||||||
|
|
||||||
$memberPolicy->member->fill($member_data);
|
|
||||||
if (!$memberPolicy->member->isDirty()) {
|
|
||||||
throw new ImportRowException(__('enrollment.MEMBER_NO_CHANGE'), 0, null, $row);
|
|
||||||
}
|
|
||||||
|
|
||||||
$memberPolicy->member->save();
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "3": // Member Deletion
|
case "3": // Member Deletion
|
||||||
|
$member = Member::query()
|
||||||
|
->where('member_id', $row['member_id'])
|
||||||
|
->first();
|
||||||
|
|
||||||
|
// Validate If Exist Member
|
||||||
|
if (!$member) {
|
||||||
|
throw new ImportRowException(__('enrollment.MEMBER_NOT_FOUND', [
|
||||||
|
'member_id' => $row['member_id'],
|
||||||
|
'policy_id' => $row['policy_number']
|
||||||
|
]), 0, null, $row);
|
||||||
|
}
|
||||||
|
|
||||||
$memberPolicy = MemberPolicy::query()
|
$memberPolicy = MemberPolicy::query()
|
||||||
->where('policy_id', $row['policy_number'])
|
->where('policy_id', $row['policy_number'])
|
||||||
->where('member_id', $row['member_id'])
|
->where('member_id', $row['member_id'])
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ class Member extends Model
|
|||||||
"end_no_claim",
|
"end_no_claim",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function claims()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Claim::class, 'member_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
public function employeds()
|
public function employeds()
|
||||||
{
|
{
|
||||||
return $this->hasMany(CorporateEmployee::class, 'member_id');
|
return $this->hasMany(CorporateEmployee::class, 'member_id');
|
||||||
@@ -68,7 +73,12 @@ class Member extends Model
|
|||||||
|
|
||||||
public function plans()
|
public function plans()
|
||||||
{
|
{
|
||||||
return $this->hasManyThrough(MemberPlan::class, Plan::class, 'member_id', 'plan_id', 'id', 'plan_id');
|
return $this->hasManyThrough(Plan::class, MemberPlan::class, 'member_id', 'code', 'id', 'plan_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function currentPlan()
|
||||||
|
{
|
||||||
|
return $this->hasOneThrough(Plan::class, MemberPlan::class, 'member_id', 'code', 'id', 'plan_id')->latest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function policies()
|
public function policies()
|
||||||
|
|||||||
@@ -12,3 +12,18 @@ export type LaravelPaginatedData = {
|
|||||||
to?: number;
|
to?: number;
|
||||||
total: number;
|
total: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const LaravelPaginatedDataDefault = {
|
||||||
|
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
|
||||||
|
}
|
||||||
241
frontend/dashboard/src/pages/Claims/Create.tsx
Executable file
241
frontend/dashboard/src/pages/Claims/Create.tsx
Executable file
@@ -0,0 +1,241 @@
|
|||||||
|
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 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 DivisionsList from "./List";
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default function Divisions() {
|
||||||
|
const { themeStretch } = useSettings();
|
||||||
|
|
||||||
|
const { corporate_id } = useParams();
|
||||||
|
|
||||||
|
const NewDivisionSchema = 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'),
|
||||||
|
});
|
||||||
|
|
||||||
|
const defaultValues = useMemo(
|
||||||
|
() => ({
|
||||||
|
code: '',
|
||||||
|
}),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const methods = useForm({
|
||||||
|
resolver: yupResolver(NewDivisionSchema),
|
||||||
|
defaultValues,
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
reset,
|
||||||
|
watch,
|
||||||
|
control,
|
||||||
|
setValue,
|
||||||
|
getValues,
|
||||||
|
setError,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { isSubmitting },
|
||||||
|
} = methods;
|
||||||
|
|
||||||
|
const onSubmit = async (data: any) => {
|
||||||
|
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
|
||||||
|
heading={'Create Benefit'}
|
||||||
|
links={[
|
||||||
|
{ name: 'Dashboard', href: '/dashboard' },
|
||||||
|
{
|
||||||
|
name: 'Corporates',
|
||||||
|
href: '/corporates',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Corporate Name',
|
||||||
|
href: '/corporates/'+id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Benefits',
|
||||||
|
href: '/corporates/'+id+'/benefits',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Create',
|
||||||
|
href: '/corporates/'+id+'/benefits/create',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Card sx={{ p: 2 }}>
|
||||||
|
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<Stack spacing={3}>
|
||||||
|
|
||||||
|
<Typography variant="h6">Benefit Detail</Typography>
|
||||||
|
|
||||||
|
<RHFTextField name="name" label="Benefit Name" />
|
||||||
|
|
||||||
|
<RHFTextField name="code" label="Benefit Code" />
|
||||||
|
|
||||||
|
<Typography variant="h6">Benefit Configuration</Typography>
|
||||||
|
|
||||||
|
<Divider orientation="horizontal" flexItem />
|
||||||
|
<Stack spacing={3} divider={<Divider orientation="horizontal" flexItem />}>
|
||||||
|
<Stack spacing={2}>
|
||||||
|
<RHFCheckbox name="a" label='Outpatient'/>
|
||||||
|
{benefits.map(row => (
|
||||||
|
<Collapse in={true} timeout="auto" unmountOnExit >
|
||||||
|
<Typography>{row.category}</Typography>
|
||||||
|
<Grid container>
|
||||||
|
{row.childs.map(benefit => (
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<RHFCheckbox name={benefit.code} label={benefit.name}/>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Collapse>
|
||||||
|
))}
|
||||||
|
<Typography>Admin Fee</Typography>
|
||||||
|
<Grid container>
|
||||||
|
{benefits.map(row => (
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<RHFCheckbox name="cat" label={row.category}/>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
|
||||||
|
<Stack spacing={2}>
|
||||||
|
<RHFCheckbox name="a" label='Inpatient'/>
|
||||||
|
{benefits.map(row => (
|
||||||
|
<Collapse in={true} timeout="auto" unmountOnExit >
|
||||||
|
<Typography>{row.category}</Typography>
|
||||||
|
<Grid container>
|
||||||
|
{row.childs.map(benefit => (
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<RHFCheckbox name={benefit.code} label={benefit.name}/>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Collapse>
|
||||||
|
))}
|
||||||
|
<Typography>Admin Fee</Typography>
|
||||||
|
<Grid container>
|
||||||
|
{benefits.map(row => (
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<RHFCheckbox name="cat" label={row.category}/>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
</Stack>
|
||||||
|
</FormProvider>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
29
frontend/dashboard/src/pages/Claims/Index.tsx
Executable file
29
frontend/dashboard/src/pages/Claims/Index.tsx
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
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 = 'Claim';
|
||||||
|
return (
|
||||||
|
<Page title={ pageTitle } sx={{ mx: 2}}>
|
||||||
|
|
||||||
|
<HeaderBreadcrumbs
|
||||||
|
heading={ pageTitle }
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
name: 'Claim',
|
||||||
|
href: '/claims',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Stack>
|
||||||
|
<List />
|
||||||
|
</Stack>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
}
|
||||||
26
frontend/dashboard/src/pages/Claims/LaravelTable.tsx
Normal file
26
frontend/dashboard/src/pages/Claims/LaravelTable.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { Card, Paper, TableContainer } from "@mui/material";
|
||||||
|
import { LaravelPaginatedData } from "../../@types/paginated-data";
|
||||||
|
import BasePagination from "../../components/BasePagination";
|
||||||
|
|
||||||
|
type LaravelTableProps = {
|
||||||
|
isLoading: boolean;
|
||||||
|
lastRequest: number;
|
||||||
|
data: LaravelPaginatedData;
|
||||||
|
handlePageChange: void;
|
||||||
|
TableContent: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function LaravelTable(props: LaravelTableProps) {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<TableContainer component={Paper}>
|
||||||
|
{ props.TableContent }
|
||||||
|
</TableContainer>
|
||||||
|
|
||||||
|
{ !props.isLoading ?
|
||||||
|
(<BasePagination paginationData={props.data} onPageChange={props.handlePageChange}/>) :
|
||||||
|
(<div></div>)
|
||||||
|
}
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
303
frontend/dashboard/src/pages/Claims/List.tsx
Executable file
303
frontend/dashboard/src/pages/Claims/List.tsx
Executable file
@@ -0,0 +1,303 @@
|
|||||||
|
// @mui
|
||||||
|
import { Box, Button, Card, Collapse, IconButton, MenuItem, Table, TableBody, TableCell, TableRow, TextField, Typography, Stack, Menu, ButtonGroup } 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, useEffect, useRef, useState } from 'react';
|
||||||
|
import { useSearchParams } from 'react-router-dom';
|
||||||
|
// components
|
||||||
|
import axios from '../../utils/axios';
|
||||||
|
import { LaravelPaginatedData, LaravelPaginatedDataDefault } from '../../@types/paginated-data';
|
||||||
|
import DataTable from './LaravelTable';
|
||||||
|
|
||||||
|
export default function List() {
|
||||||
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
|
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({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}/>
|
||||||
|
</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 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])
|
||||||
|
axios.post(`corporates/${corporate_id}/import-plan-benefit`, 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={handleImportButton}>Import</MenuItem>
|
||||||
|
<MenuItem onClick={handleClose}>Download Template</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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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('/master/drugs', { 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadDataTableData();
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const headStyle = {
|
||||||
|
fontWeight: 'bold',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Called on every row to map the data to the columns
|
||||||
|
function createData( data: Icd ): Icd {
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{/* ------------------ TABLE ROW ------------------ */}
|
||||||
|
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.type}</TableCell>
|
||||||
|
<TableCell align="left">{row.code}</TableCell>
|
||||||
|
<TableCell align="left">{row.name}</TableCell>
|
||||||
|
<TableCell align="left">{row.version}</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 style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={99}>
|
||||||
|
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||||
|
<Box sx={{ borderBottom: 1 }}>
|
||||||
|
<Typography variant="body2" gutterBottom component="div">
|
||||||
|
Description : {row.description}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Collapse>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
{/* ------------------ END TABLE ROW ------------------ */}
|
||||||
|
|
||||||
|
function TableContent() {
|
||||||
|
return (
|
||||||
|
<Table aria-label="collapsible table">
|
||||||
|
{/* ------------------ TABLE HEADER ------------------ */}
|
||||||
|
<TableBody>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell style={headStyle} align="left" />
|
||||||
|
<TableCell style={headStyle} align="left">Type</TableCell>
|
||||||
|
<TableCell style={headStyle} align="left">Code</TableCell>
|
||||||
|
<TableCell style={headStyle} align="left">Name</TableCell>
|
||||||
|
<TableCell style={headStyle} align="left">Version</TableCell>
|
||||||
|
<TableCell style={headStyle} align="right">Status</TableCell>
|
||||||
|
<TableCell style={headStyle} align="right">Action</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableBody>
|
||||||
|
{/* ------------------ 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>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<ImportForm />
|
||||||
|
|
||||||
|
<DataTable
|
||||||
|
isLoading={dataTableIsLoading}
|
||||||
|
lastRequest={0}
|
||||||
|
data={dataTableData}
|
||||||
|
handlePageChange={handlePageChange}
|
||||||
|
|
||||||
|
TableContent={<TableContent />}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -268,7 +268,7 @@ export default function CorporatePlanList() {
|
|||||||
<TableCell align="left">{row.name}</TableCell>
|
<TableCell align="left">{row.name}</TableCell>
|
||||||
<TableCell align="left">{row.nric}</TableCell>
|
<TableCell align="left">{row.nric}</TableCell>
|
||||||
<TableCell align="left">{row.email}</TableCell>
|
<TableCell align="left">{row.email}</TableCell>
|
||||||
<TableCell align="left">{row.plan_id}</TableCell>
|
<TableCell align="left">{row.current_plan?.code}</TableCell>
|
||||||
<TableCell align="left">{row.current_policy?.start}</TableCell>
|
<TableCell align="left">{row.current_policy?.start}</TableCell>
|
||||||
<TableCell align="left">{row.current_policy?.end}</TableCell>
|
<TableCell align="left">{row.current_policy?.end}</TableCell>
|
||||||
{( row.active ? (<TableCell align="right"><Button variant="outlined" color="success" size="small">Active</Button></TableCell>)
|
{( row.active ? (<TableCell align="right"><Button variant="outlined" color="success" size="small">Active</Button></TableCell>)
|
||||||
|
|||||||
@@ -205,6 +205,12 @@ export default function Router() {
|
|||||||
path: 'master/formularium/create',
|
path: 'master/formularium/create',
|
||||||
element: <MasterFormulariumCreate />,
|
element: <MasterFormulariumCreate />,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
path: 'claims',
|
||||||
|
element: <Claims />,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
@@ -287,3 +293,5 @@ const CorporateServicesCreate = Loadable(lazy(() => import('../pages/Corporates/
|
|||||||
|
|
||||||
const CorporateHospitals = Loadable(lazy(() => import('../pages/Corporates/Hospital/Index')));
|
const CorporateHospitals = Loadable(lazy(() => import('../pages/Corporates/Hospital/Index')));
|
||||||
const CorporateClaimHistories = Loadable(lazy(() => import('../pages/Corporates/ClaimHistory/Index')));
|
const CorporateClaimHistories = Loadable(lazy(() => import('../pages/Corporates/ClaimHistory/Index')));
|
||||||
|
|
||||||
|
const Claims = Loadable(lazy(() => import('../pages/Claims/Index')));
|
||||||
Reference in New Issue
Block a user