Base Template
This commit is contained in:
319
frontend/dashboard/src/pages/Members/Index.tsx
Normal file
319
frontend/dashboard/src/pages/Members/Index.tsx
Normal file
@@ -0,0 +1,319 @@
|
||||
// @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 } from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import PublishIcon from '@mui/icons-material/Publish';
|
||||
// hooks
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
// components
|
||||
import Page from '../../components/Page';
|
||||
import axios from '../../utils/axios';
|
||||
import useAuth from '../../hooks/useAuth';
|
||||
import { Link } from 'react-router-dom';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { Theme, useTheme } from '@mui/material/styles';
|
||||
|
||||
export default function Members() {
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const { logout } = useAuth();
|
||||
|
||||
const loadSomething = () => {
|
||||
console.log('Loading Something')
|
||||
}
|
||||
|
||||
type Member = {
|
||||
id: number;
|
||||
code: string;
|
||||
nik: string;
|
||||
name: string;
|
||||
plan_code: string;
|
||||
number_of_families: number;
|
||||
number_of_claim: number;
|
||||
active: boolean;
|
||||
history: any[];
|
||||
}
|
||||
|
||||
function createData( member: Member ): Member {
|
||||
return {
|
||||
...member,
|
||||
history: [
|
||||
{
|
||||
date: '2020-01-05',
|
||||
customerId: '11091700',
|
||||
amount: 3,
|
||||
},
|
||||
{
|
||||
date: '2020-01-02',
|
||||
customerId: 'Anonymous',
|
||||
amount: 1,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
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.name}</TableCell>
|
||||
<TableCell align="right">{row.nik}</TableCell>
|
||||
<TableCell align="right">{row.plan_code}</TableCell>
|
||||
<TableCell align="right">{row.number_of_claim}</TableCell>
|
||||
<TableCell align="right">{row.number_of_families}</TableCell>
|
||||
<TableCell align="right"><Button variant="outlined" color="success" size="small">Active</Button></TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ margin: 1 }}>
|
||||
<Typography variant="h6" gutterBottom component="div">
|
||||
History
|
||||
</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={historyRow?.date}>
|
||||
<TableCell component="th" scope="row">
|
||||
{historyRow?.date}
|
||||
</TableCell>
|
||||
<TableCell>{historyRow?.customerId}</TableCell>
|
||||
<TableCell align="right">{historyRow?.amount}</TableCell>
|
||||
<TableCell align="right">
|
||||
{Math.round(historyRow?.amount * 1000 * 100) / 100}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
: (
|
||||
<TableRow>
|
||||
<TableCell colSpan={8}>No Data</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
// Dummy Default Data
|
||||
const [memberLoading, setMemberLoading] = React.useState(true);
|
||||
const [members, setMembers] = React.useState<Member[]>([]);
|
||||
|
||||
const loadMembers = async () => {
|
||||
setMemberLoading(true)
|
||||
const response = await axios.get('/members');
|
||||
setMemberLoading(false)
|
||||
setMembers(response.data.map(createData));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadMembers();
|
||||
}, [])
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
// FILTER SELECT
|
||||
const ITEM_HEIGHT = 48;
|
||||
const ITEM_PADDING_TOP = 8;
|
||||
const MenuProps = {
|
||||
PaperProps: {
|
||||
style: {
|
||||
maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
|
||||
width: 250,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const names = [
|
||||
'PLAN001',
|
||||
'PLAN002',
|
||||
'PLAN003',
|
||||
'PLAN004',
|
||||
'PLAN005',
|
||||
];
|
||||
function getStyles(name: string, personName: string[], theme: Theme) {
|
||||
return {
|
||||
fontWeight:
|
||||
personName.indexOf(name) === -1
|
||||
? theme.typography.fontWeightRegular
|
||||
: theme.typography.fontWeightMedium,
|
||||
};
|
||||
}
|
||||
|
||||
const theme = useTheme();
|
||||
const [planIdFilter, setPlanIdFilter] = React.useState<string[]>([]);
|
||||
|
||||
const handleChangePlanID = (event: SelectChangeEvent<typeof planIdFilter>) => {
|
||||
const {
|
||||
target: { value },
|
||||
} = event;
|
||||
setPlanIdFilter(
|
||||
// On autofill we get a stringified value.
|
||||
typeof value === 'string' ? value.split(',') : value,
|
||||
);
|
||||
};
|
||||
|
||||
const [statusFilter, setStatusFilter] = React.useState<string[]>([]);
|
||||
const handleChangeStatus = (event: SelectChangeEvent<typeof statusFilter>) => {
|
||||
const {
|
||||
target: { value },
|
||||
} = event;
|
||||
setStatusFilter(
|
||||
// On autofill we get a stringified value.
|
||||
typeof value === 'string' ? value.split(',') : value,
|
||||
);
|
||||
};
|
||||
// END FILTER SELECT
|
||||
|
||||
// IMPORT
|
||||
const importMember = React.useRef(null);
|
||||
const handleImportButton = (event: any) => {
|
||||
if (importMember?.current)
|
||||
importMember.current.click()
|
||||
else
|
||||
alert('No file selected')
|
||||
}
|
||||
|
||||
return (
|
||||
<Page title="Member List">
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<Typography variant="h3" component="h1" paragraph>
|
||||
Member List
|
||||
</Typography>
|
||||
|
||||
<Grid container spacing={2} sx={{ mb: 2 }} justifyContent="flex-end">
|
||||
<Grid item>
|
||||
<TextField id="outlined-basic" label="Search" variant="outlined" sx={{ width: 400 }}/>
|
||||
</Grid>
|
||||
|
||||
<Grid item>
|
||||
<FormControl sx={{ width: 200 }}>
|
||||
<InputLabel id="plan-id-label">PlanID</InputLabel>
|
||||
<Select
|
||||
labelId="plan-id-label"
|
||||
id="plan-id"
|
||||
multiple
|
||||
value={planIdFilter}
|
||||
onChange={handleChangePlanID}
|
||||
input={<OutlinedInput label="PlanID" />}
|
||||
MenuProps={MenuProps}
|
||||
>
|
||||
{names.map((name) => (
|
||||
<MenuItem
|
||||
key={name}
|
||||
value={name}
|
||||
style={getStyles(name, planIdFilter, theme)}
|
||||
>
|
||||
{name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
<Grid item>
|
||||
<FormControl sx={{ width: 200 }}>
|
||||
<InputLabel id="status-filter-label">Status</InputLabel>
|
||||
<Select
|
||||
labelId="status-filter-label"
|
||||
id="status-filter"
|
||||
multiple
|
||||
value={statusFilter}
|
||||
onChange={handleChangeStatus}
|
||||
input={<OutlinedInput label="Status" />}
|
||||
MenuProps={MenuProps}
|
||||
>
|
||||
{['Active', 'Suspended'].map((name) => (
|
||||
<MenuItem
|
||||
key={name}
|
||||
value={name}
|
||||
style={getStyles(name, statusFilter, theme)}
|
||||
>
|
||||
{name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
<Grid item>
|
||||
<input id="importMember" ref={importMember} style={{ display: 'none' }} type="file" accept='.csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, text/plain' />
|
||||
<Button variant="outlined" startIcon={<PublishIcon />} sx={{ p: 1.8 }} onClick={handleImportButton}>
|
||||
Import
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Card>
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<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="right">NIK</TableCell>
|
||||
<TableCell style={headStyle} align="right">PlanID</TableCell>
|
||||
<TableCell style={headStyle} align="right">Claim (time)</TableCell>
|
||||
<TableCell style={headStyle} align="right">Family (person)</TableCell>
|
||||
<TableCell style={headStyle} align="right">Status</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
{memberLoading ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">Loading</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
members.length == 0 ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">No Data</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody>
|
||||
{members.map(row => (
|
||||
<Row key={row.code} row={row} />
|
||||
))}
|
||||
</TableBody>
|
||||
)
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Card>
|
||||
</Container>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user