update
This commit is contained in:
@@ -13,10 +13,14 @@ class MemberController extends Controller
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index()
|
||||
public function index(Request $request)
|
||||
{
|
||||
return Member::query()
|
||||
->with('currentPlan')
|
||||
->when($request->search, function ($query, $search) {
|
||||
return $query->where('name', 'LIKE', '%' . $search . '%')
|
||||
->orWhere('member_id', 'LIKE', '%' . $search . '%');
|
||||
})
|
||||
->with('currentPlan', 'currentCorporate')
|
||||
->paginate();
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ class MemberResource extends JsonResource
|
||||
'code' => $currentMemberPlan->plan->code ?? null,
|
||||
'start' => $currentMemberPlan->start,
|
||||
'end' => $currentMemberPlan->end,
|
||||
'limit' => $this->currentPlan->limit_rules
|
||||
'limit' => $this->currentPlan->limit_rules,
|
||||
'limit_consultation' => 6
|
||||
] : null,
|
||||
'policy_code' => $this->currentPolicy?->code ?? null,
|
||||
'corporate' => [
|
||||
|
||||
@@ -224,6 +224,7 @@ class Plan extends Model
|
||||
return $this->belongsTo(CorporatePlan::class);
|
||||
}
|
||||
|
||||
|
||||
// public function Corporate()
|
||||
// {
|
||||
// return $this->belongsTo(Corporate::class);
|
||||
|
||||
@@ -16,7 +16,7 @@ return new class extends Migration
|
||||
Schema::table('claim_requests', function (Blueprint $table) {
|
||||
//
|
||||
$table->string('service_code')->after('payment_type')->nullable();
|
||||
$table->string('policy_id')->after('service_code')->nullable();
|
||||
$table->unsignedBigInteger('policy_id')->after('service_code')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,10 @@ const navConfig = [
|
||||
},
|
||||
{
|
||||
title: 'CUSTOMER SERVICES',
|
||||
children: [{ title: 'Request', path: '/cs-request' }],
|
||||
children: [
|
||||
{ title: 'Request', path: '/cs-request' },
|
||||
{ title: 'Membership', path: '/cs-membership' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'REPORT',
|
||||
|
||||
@@ -84,7 +84,7 @@ export default function List() {
|
||||
onChange={handleSearchChange}
|
||||
value={searchText}
|
||||
/>
|
||||
<Tooltip title="Export Excel">
|
||||
<Tooltip title="Benefit Usage Report">
|
||||
<Button variant="outlined" startIcon={<AssessmentIcon />} sx={{ p: 1.8 }} onClick={handleGetData}/>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
|
||||
267
frontend/dashboard/src/pages/Service/Membership/List.tsx
Executable file
267
frontend/dashboard/src/pages/Service/Membership/List.tsx
Executable file
@@ -0,0 +1,267 @@
|
||||
// @mui
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
Collapse,
|
||||
IconButton,
|
||||
MenuItem,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
Stack,
|
||||
Menu,
|
||||
ButtonGroup,
|
||||
Tooltip,
|
||||
} 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 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';
|
||||
// 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 { Chip } from '@mui/material';
|
||||
import Iconify from '@/components/Iconify';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
|
||||
export default function List() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(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
|
||||
};
|
||||
|
||||
const handleGetData = (type :string) => {
|
||||
axios.get(`members`)
|
||||
.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();
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// Trigger First Search
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '100%' }}>
|
||||
<Stack direction={'row'} spacing={2} sx={{ mb: 2 }}>
|
||||
<TextField
|
||||
id="search-input"
|
||||
ref={searchInput}
|
||||
label="Search"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
onChange={handleSearchChange}
|
||||
value={searchText}
|
||||
/>
|
||||
</Stack>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
function ImportForm(props: any) {
|
||||
// IMPORT
|
||||
// Create Button Menu
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
|
||||
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>
|
||||
</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('/members', { 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: any): any {
|
||||
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.member_id}</TableCell>
|
||||
<TableCell align="left">{row.person?.name}</TableCell>
|
||||
<TableCell align="left">{row.current_corporate?.name}</TableCell>
|
||||
<TableCell align="left">{row.person?.nik}</TableCell>
|
||||
<TableCell align="left">{row.current_plan?.code}</TableCell>
|
||||
<TableCell align="left">{row.active == 1 ? 'Active' : 'Inactive'}</TableCell>
|
||||
<TableCell align="center">
|
||||
{row.member_id == 'draft' && (<Chip label='Draft' color="default" variant="outlined" />)}
|
||||
{row.member_id == 'requested' && (<Chip label='Requested' color="primary" />)}
|
||||
{row.member_id == 'received' && (<Chip label='Received' color="success" variant='outlined' />)}
|
||||
{row.member_id == 'approved' && (<Chip label='Approved' color="success" />)}
|
||||
{row.member_id == 'postpone' && (<Chip label='Postpone' color="primary" variant="outlined" />)}
|
||||
{row.member_id == 'paid' && (<Chip label='Paid' color="warning" />)}
|
||||
{row.member_id == 'declined' && (<Chip label='Declined' color="error" />)}
|
||||
</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">Detail</TableCell> */}
|
||||
<TableCell style={headStyle} align="left">MemberID</TableCell>
|
||||
<TableCell style={headStyle} align="left">Name</TableCell>
|
||||
<TableCell style={headStyle} align="left">Corporate Name</TableCell>
|
||||
<TableCell style={headStyle} align="left">NIK</TableCell>
|
||||
<TableCell style={headStyle} align="left">Plan</TableCell>
|
||||
<TableCell style={headStyle} align="left">Status</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>
|
||||
);
|
||||
}
|
||||
30
frontend/dashboard/src/pages/Service/Membership/index.tsx
Normal file
30
frontend/dashboard/src/pages/Service/Membership/index.tsx
Normal file
@@ -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 = 'Claim Request';
|
||||
return (
|
||||
<Page title={ pageTitle } sx={{ mx: 2}}>
|
||||
|
||||
<HeaderBreadcrumbs
|
||||
heading={ pageTitle }
|
||||
links={[
|
||||
{ name: 'Dashboard', href: '/dashboard' },
|
||||
{
|
||||
name: 'Claim Request',
|
||||
href: '/claim-requests',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
{/* <Stack> */}
|
||||
<List />
|
||||
{/* </Stack> */}
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -310,6 +310,10 @@ export default function Router() {
|
||||
path: 'profile',
|
||||
element: <Profile />,
|
||||
},
|
||||
{
|
||||
path: 'cs-membership',
|
||||
element: <Membership />,
|
||||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
@@ -440,4 +444,7 @@ const Claims = Loadable(lazy(() => import('../pages/Claims/Index')));
|
||||
const ClaimsCreate = Loadable(lazy(() => import('../pages/Claims/CreateUpdate')));
|
||||
const ClaimShow = Loadable(lazy(() => import('../pages/Claims/Show')));
|
||||
|
||||
const ClaimRequests = Loadable(lazy(() => import('../pages/ClaimRequests/Index')));
|
||||
const ClaimRequests = Loadable(lazy(() => import('../pages/ClaimRequests/Index')));
|
||||
|
||||
|
||||
const Membership = Loadable(lazy(() => import('../pages/Service/Membership/index')));
|
||||
Reference in New Issue
Block a user