progress 1 dashboard-create-claim-request
This commit is contained in:
@@ -129,7 +129,7 @@ class ClaimRequestController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
$updateClaimRequest = ClaimRequestService::updateClaimRequest(organization_id: $organization->id, claim_request_id: $id);
|
$updateClaimRequest = ClaimRequestService::updateClaimRequest(organization_id: $organization->id, claim_request_id: $id);
|
||||||
|
|
||||||
ClaimRequested::dispatch($updateClaimRequest);
|
ClaimRequested::dispatch($updateClaimRequest);
|
||||||
// Log History
|
// Log History
|
||||||
$updateClaimRequest->histories()->create([
|
$updateClaimRequest->histories()->create([
|
||||||
@@ -185,9 +185,9 @@ class ClaimRequestController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'error' => false,
|
'error' => false,
|
||||||
'message' => 'Update succses',
|
'message' => 'Update succses',
|
||||||
'data' => $updateClaimRequest],
|
'data' => $updateClaimRequest],
|
||||||
200);
|
200);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -206,17 +206,17 @@ class ClaimRequestController extends Controller
|
|||||||
{
|
{
|
||||||
$claimRequest = ClaimRequest::findOrFail($id);
|
$claimRequest = ClaimRequest::findOrFail($id);
|
||||||
$member = $claimRequest->member;
|
$member = $claimRequest->member;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// Create New Claim
|
// Create New Claim
|
||||||
$newClaim = ClaimService::storeClaim(member: $member, status: 'received', claimRequest: $claimRequest);
|
$newClaim = ClaimService::storeClaim(member: $member, status: 'received', claimRequest: $claimRequest);
|
||||||
|
|
||||||
// Update Claim Request Status & Link with Claim
|
// Update Claim Request Status & Link with Claim
|
||||||
$claimRequest->status = 'approved';
|
$claimRequest->status = 'approved';
|
||||||
$claimRequest->claim_id = $newClaim->id;
|
$claimRequest->claim_id = $newClaim->id;
|
||||||
$claimRequest->save();
|
$claimRequest->save();
|
||||||
|
|
||||||
// Store Generated Documents LOG
|
// Store Generated Documents LOG
|
||||||
$logContent = view('pdf.guaranted_leter', compact('member', 'claimRequest'));
|
$logContent = view('pdf.guaranted_leter', compact('member', 'claimRequest'));
|
||||||
$claimRequest->generatedDocuments()->create([
|
$claimRequest->generatedDocuments()->create([
|
||||||
@@ -269,7 +269,7 @@ class ClaimRequestController extends Controller
|
|||||||
{
|
{
|
||||||
return Helper::responseJson(data: $request->toArray(), message: 'Tidak ada file member yang ditambahkan');
|
return Helper::responseJson(data: $request->toArray(), message: 'Tidak ada file member yang ditambahkan');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function importClaim(Request $request)
|
public function importClaim(Request $request)
|
||||||
@@ -323,24 +323,24 @@ class ClaimRequestController extends Controller
|
|||||||
$claimRequestService = new ClaimRequestService();
|
$claimRequestService = new ClaimRequestService();
|
||||||
|
|
||||||
$claimRequestService->handleClaimRequestRow($row_data);
|
$claimRequestService->handleClaimRequestRow($row_data);
|
||||||
|
|
||||||
// Write Success Result to File
|
// Write Success Result to File
|
||||||
// $import->read($fileRead);
|
// $import->read($fileRead);
|
||||||
// $import->write($fileWrite, 'xsls');
|
// $import->write($fileWrite, 'xsls');
|
||||||
$result_headers = array_merge($row_data, ['Ingest Code' =>200, 'Ingest Note' => 'Success']);
|
$result_headers = array_merge($row_data, ['Ingest Code' =>200, 'Ingest Note' => 'Success']);
|
||||||
|
|
||||||
$import->addArrayToRow($result_headers, $sheet->getName());
|
$import->addArrayToRow($result_headers, $sheet->getName());
|
||||||
|
|
||||||
} catch (ImportRowException $e) {
|
} catch (ImportRowException $e) {
|
||||||
// Write Data Validation Error to File
|
// Write Data Validation Error to File
|
||||||
// $import->read($fileRead);
|
// $import->read($fileRead);
|
||||||
// $import->write($fileWrite, 'xsls');
|
// $import->write($fileWrite, 'xsls');
|
||||||
|
|
||||||
$import->addArrayToRow(array_merge($row_data, [
|
$import->addArrayToRow(array_merge($row_data, [
|
||||||
'Ingest Code' => $e->getCode(),
|
'Ingest Code' => $e->getCode(),
|
||||||
'Ingest Note' => $e->getMessage(),
|
'Ingest Note' => $e->getMessage(),
|
||||||
]), $sheet->getName());
|
]), $sheet->getName());
|
||||||
}
|
}
|
||||||
// catch (\Exception $e) {
|
// catch (\Exception $e) {
|
||||||
// // throw new \Exception($e);
|
// // throw new \Exception($e);
|
||||||
// // Write Server Error to File
|
// // Write Server Error to File
|
||||||
@@ -380,16 +380,16 @@ class ClaimRequestController extends Controller
|
|||||||
->where('claim_requests.id', '=', $claimRequestId)
|
->where('claim_requests.id', '=', $claimRequestId)
|
||||||
->select(
|
->select(
|
||||||
'claim_requests.submission_date',
|
'claim_requests.submission_date',
|
||||||
'claim_requests.code',
|
'claim_requests.code',
|
||||||
DB::raw('
|
DB::raw('
|
||||||
CASE
|
CASE
|
||||||
WHEN claim_requests.status = "requested" THEN "requested"
|
WHEN claim_requests.status = "requested" THEN "requested"
|
||||||
WHEN claim_requests.status = "approved" AND claims.status = "approved" THEN "approved"
|
WHEN claim_requests.status = "approved" AND claims.status = "approved" THEN "approved"
|
||||||
WHEN claim_requests.status = "approved" AND claims.status = "declined" THEN "declined"
|
WHEN claim_requests.status = "approved" AND claims.status = "declined" THEN "declined"
|
||||||
WHEN claim_requests.status = "approved" AND claims.status = "disbrusmented" THEN "disbrusmented"
|
WHEN claim_requests.status = "approved" AND claims.status = "disbrusmented" THEN "disbrusmented"
|
||||||
/*WHEN claim_requests.status = "approved" AND claims.status = "received" THEN "pending"*/
|
/*WHEN claim_requests.status = "approved" AND claims.status = "received" THEN "pending"*/
|
||||||
WHEN claim_requests.status = "approved" AND claims.status = "received" THEN "reviewed"
|
WHEN claim_requests.status = "approved" AND claims.status = "received" THEN "reviewed"
|
||||||
ELSE ""
|
ELSE ""
|
||||||
END AS status
|
END AS status
|
||||||
')
|
')
|
||||||
)
|
)
|
||||||
@@ -477,4 +477,37 @@ class ClaimRequestController extends Controller
|
|||||||
}
|
}
|
||||||
return Helper::responseJson(data: $request->toArray(), message: 'Invoice Success Uploaded');
|
return Helper::responseJson(data: $request->toArray(), message: 'Invoice Success Uploaded');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Claim Member - Infinite Scroll
|
||||||
|
*
|
||||||
|
* Bagaskoro, BSD 31 Oktober 2023
|
||||||
|
*/
|
||||||
|
public function getClaimMemberInfiniteScroll(Request $request)
|
||||||
|
{
|
||||||
|
$offset = 0;
|
||||||
|
$limit = 10;
|
||||||
|
$page = $request->get('page');
|
||||||
|
$keyword = $request->get('keyword');
|
||||||
|
|
||||||
|
if ($page > 1) {
|
||||||
|
$offset = ($page*$limit)-$limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$memberList = DB::table('members')
|
||||||
|
->select('id','member_id','name')
|
||||||
|
->where("name", "like", "%$keyword%")
|
||||||
|
->orderBy('created_at', 'asc')
|
||||||
|
->offset($offset)
|
||||||
|
->limit($limit)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'error' => false,
|
||||||
|
'message' => "success",
|
||||||
|
'data' => [
|
||||||
|
'member_list'=> $memberList,
|
||||||
|
]
|
||||||
|
],200);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ Route::prefix('internal')->group(function () {
|
|||||||
Route::post('files-mcu', 'filesMcu');
|
Route::post('files-mcu', 'filesMcu');
|
||||||
});
|
});
|
||||||
Route::get('claim-requests', [ClaimRequestController::class, 'index'])->name('claim-requests.index');
|
Route::get('claim-requests', [ClaimRequestController::class, 'index'])->name('claim-requests.index');
|
||||||
|
Route::get('claim-requests/list-member', [ClaimRequestController::class, 'getClaimMemberInfiniteScroll']); // Bagaskoro, BSD 31 Oktober 2023
|
||||||
Route::post('claim-requests/{id}/approve', [ClaimRequestController::class, 'approve'])->name('claim-requests.approve');
|
Route::post('claim-requests/{id}/approve', [ClaimRequestController::class, 'approve'])->name('claim-requests.approve');
|
||||||
Route::get('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show');
|
Route::get('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show');
|
||||||
Route::put('claim-requests/{id}', [ClaimRequestController::class, 'update'])->name('claim-requests.update');
|
Route::put('claim-requests/{id}', [ClaimRequestController::class, 'update'])->name('claim-requests.update');
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export default function Drugs() {
|
|||||||
setIsLoading: setIsLoading,
|
setIsLoading: setIsLoading,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------ handle params ----------------------------- */
|
/* ------------------------------ handle params ----------------------------- */
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
@@ -121,7 +121,7 @@ export default function Drugs() {
|
|||||||
setOrderBy: setOrderBy,
|
setOrderBy: setOrderBy,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* ---------------------------- Get Current Date ---------------------------- */
|
/* ---------------------------- Get Current Date ---------------------------- */
|
||||||
const current = new Date();
|
const current = new Date();
|
||||||
const date = fDateSuffix(current);
|
const date = fDateSuffix(current);
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ export default function DialogClaimSubmitMember({
|
|||||||
<Stack marginTop={2} spacing={1}>
|
<Stack marginTop={2} spacing={1}>
|
||||||
{data.map((row: DataContentType, key) => (
|
{data.map((row: DataContentType, key) => (
|
||||||
<Card
|
<Card
|
||||||
|
|
||||||
key={key}
|
key={key}
|
||||||
sx={{bgcolor: (theme) => {
|
sx={{bgcolor: (theme) => {
|
||||||
return selectedData.some((item) => item.memberId === row.memberId) ? theme.palette.primary.lighter : theme.palette.background.default
|
return selectedData.some((item) => item.memberId === row.memberId) ? theme.palette.primary.lighter : theme.palette.background.default
|
||||||
|
|||||||
10
frontend/dashboard/pnpm-lock.yaml
generated
10
frontend/dashboard/pnpm-lock.yaml
generated
@@ -149,6 +149,9 @@ dependencies:
|
|||||||
vite-plugin-svgr:
|
vite-plugin-svgr:
|
||||||
specifier: ^2.4.0
|
specifier: ^2.4.0
|
||||||
version: 2.4.0(rollup@2.79.1)(vite@3.2.7)
|
version: 2.4.0(rollup@2.79.1)(vite@3.2.7)
|
||||||
|
yarn:
|
||||||
|
specifier: ^1.22.19
|
||||||
|
version: 1.22.19
|
||||||
yup:
|
yup:
|
||||||
specifier: ^0.32.11
|
specifier: ^0.32.11
|
||||||
version: 0.32.11
|
version: 0.32.11
|
||||||
@@ -7889,6 +7892,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
|
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
|
/yarn@1.22.19:
|
||||||
|
resolution: {integrity: sha512-/0V5q0WbslqnwP91tirOvldvYISzaqhClxzyUKXYxs07yUILIs5jx/k6CFe8bvKSkds5w+eiOqta39Wk3WxdcQ==}
|
||||||
|
engines: {node: '>=4.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
/yocto-queue@0.1.0:
|
/yocto-queue@0.1.0:
|
||||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|||||||
98
frontend/dashboard/src/hooks/useLoadOnScroll.ts
Normal file
98
frontend/dashboard/src/hooks/useLoadOnScroll.ts
Normal 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;
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
|
import { Box, IconButton } from '@mui/material';
|
||||||
|
import { ArrowBackIosNew } from '@mui/icons-material';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
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 { 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 { Controller, useForm } from 'react-hook-form';
|
||||||
@@ -17,45 +19,57 @@ import { fCurrency } from '../../utils/formatNumber';
|
|||||||
import Iconify from '../../components/Iconify';
|
import Iconify from '../../components/Iconify';
|
||||||
import { ClaimRequest } from '@/@types/claims';
|
import { ClaimRequest } from '@/@types/claims';
|
||||||
import Form from './Form';
|
import Form from './Form';
|
||||||
|
import FormCreate from './FormCreate';
|
||||||
|
|
||||||
export default function ClaimsCreateUpdate() {
|
export default function ClaimsCreateUpdate() {
|
||||||
|
|
||||||
|
const navigate = useNavigate()
|
||||||
const { themeStretch } = useSettings();
|
const { themeStretch } = useSettings();
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
|
||||||
const isEdit = id ? true : false;
|
const isEdit = id ? true : false;
|
||||||
|
|
||||||
const [currentClaim, setCurrentClaim] = useState<ClaimRequest>();
|
const [currentClaim, setCurrentClaim] = useState<ClaimRequest>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
axios.get('/claim-requests/' + id).then((res) => {
|
axios.get('/claim-requests/' + id).then((res) => {
|
||||||
console.log('Yeet', res.data);
|
console.log('Yeet', res.data);
|
||||||
setCurrentClaim(res.data.data);
|
setCurrentClaim(res.data.data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(currentClaim)
|
||||||
|
}
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
console.log(currentClaim)
|
|
||||||
}
|
|
||||||
}, [id]);
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page title={isEdit ? `Edit Claim Request` : "Create New Claim"}>
|
<Page title={isEdit ? `Edit Claim Request` : "Create New Claim"}>
|
||||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||||
<Stack direction="row" alignItems="center">
|
<Stack direction="row" alignItems="center" sx={{ mb: 5 }}>
|
||||||
<HeaderBreadcrumbs
|
<Box sx={{ display: 'flex', alignItems: 'center'}}>
|
||||||
heading={'Edit Claim Request'}
|
<IconButton size='large' color='inherit' onClick={() => navigate(`/claim-requests`)} >
|
||||||
links={[
|
<ArrowBackIosNew/>
|
||||||
{ name: 'Dashboard', href: '/dashboard' },
|
</IconButton>
|
||||||
{
|
|
||||||
name: 'Claim Request',
|
<Typography variant="h5" sx={{ marginLeft: '24px' }}>
|
||||||
},
|
{id == undefined ? 'Create Claim Requests' : 'Edit Claim Requests'}
|
||||||
]}
|
</Typography>
|
||||||
/>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Form isEdit={isEdit} currentClaim={currentClaim} />
|
{
|
||||||
|
id == undefined
|
||||||
|
?
|
||||||
|
(
|
||||||
|
<FormCreate />
|
||||||
|
)
|
||||||
|
:
|
||||||
|
(
|
||||||
|
<Form isEdit={isEdit} currentClaim={currentClaim} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
|
|||||||
110
frontend/dashboard/src/pages/ClaimRequests/FormCreate.tsx
Normal file
110
frontend/dashboard/src/pages/ClaimRequests/FormCreate.tsx
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/**
|
||||||
|
* Core
|
||||||
|
* ============================================
|
||||||
|
*/
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { Box, FormControlLabel, Grid, Checkbox, Typography, CircularProgress , Button, styled} from '@mui/material';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Components
|
||||||
|
* ============================================
|
||||||
|
*/
|
||||||
|
// - Global -
|
||||||
|
import Label from '@/components/Label';
|
||||||
|
// - Local -
|
||||||
|
import FormCreateSearch from './FormCreateSearch';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Icon, Utils, Types, Functions, theme, hook
|
||||||
|
* ============================================
|
||||||
|
*/
|
||||||
|
import { MemberListType } from './Model/Types';
|
||||||
|
import { getMemberList } from './Model/Functions';
|
||||||
|
import useLoadOnScroll from '@/hooks/useLoadOnScroll';
|
||||||
|
import FormCreateListChoose from './FormCreateListChoose';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom Style
|
||||||
|
* ============================================
|
||||||
|
*/
|
||||||
|
const DivCustom1 = styled('div')(({ theme }) => ({
|
||||||
|
left: '350px',
|
||||||
|
[theme.breakpoints.between('sm', 'lg')]: {
|
||||||
|
left: '0px',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function FormCreate() {
|
||||||
|
// State
|
||||||
|
// -------------------------
|
||||||
|
const [keyword, setKeyword] = useState<string>('');
|
||||||
|
const [listChoosed, setListChoosed] = useState<MemberListType[]>([]);
|
||||||
|
const [isChoosed, setIsChoosed] = useState<boolean>(false);
|
||||||
|
|
||||||
|
// List Choose - auto Scroll
|
||||||
|
// -------------------------
|
||||||
|
const fetchFunction = async (page: number): Promise<MemberListType[]> => getMemberList(page, keyword)
|
||||||
|
const {data: MemberList, isLoading, setData, resetLastPage, refetchData} = useLoadOnScroll<MemberListType>(fetchFunction);
|
||||||
|
|
||||||
|
// List Choose - Search
|
||||||
|
// -------------------------
|
||||||
|
const handleSearch = (keyword: string) => {
|
||||||
|
setData([])
|
||||||
|
resetLastPage()
|
||||||
|
setKeyword(keyword)
|
||||||
|
refetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ position: 'relative' }}>
|
||||||
|
{/* Choose Section */}
|
||||||
|
<Grid container spacing={4} sx={{ px: 2, 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: isLoading === false ? 'none' : 'flex', justifyContent: 'center', marginTop: '40px' }}>
|
||||||
|
<CircularProgress />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* Submit List */}
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<DivCustom1 sx={{ position: 'fixed', bottom: 0, right: 0, background: 'white', px: 4, pt: 4, pb: 6}}>
|
||||||
|
<Button variant="contained" color="primary" disabled={listChoosed.length==0} sx={{ width: '100%', p: '11px' }} onClick={() => {setIsChoosed(true)}}>
|
||||||
|
Create Number Batch ({listChoosed.length})
|
||||||
|
</Button>
|
||||||
|
</DivCustom1>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* Input Section */}
|
||||||
|
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -135,7 +135,7 @@ export default function List() {
|
|||||||
if (importForm.current?.files.length) {
|
if (importForm.current?.files.length) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', importForm.current?.files[0]);
|
formData.append('file', importForm.current?.files[0]);
|
||||||
|
|
||||||
setImportLoading(true);
|
setImportLoading(true);
|
||||||
axios
|
axios
|
||||||
.post(`claim-requests/import`, formData)
|
.post(`claim-requests/import`, formData)
|
||||||
@@ -222,7 +222,7 @@ export default function List() {
|
|||||||
startIcon={<AddIcon />}
|
startIcon={<AddIcon />}
|
||||||
sx={{ p: 1.8 }}
|
sx={{ p: 1.8 }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigate('/claims/create');
|
navigate('/claim-requests/create');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Create
|
Create
|
||||||
@@ -356,8 +356,8 @@ export default function List() {
|
|||||||
<TableCell align="left">{row.service_name}</TableCell>
|
<TableCell align="left">{row.service_name}</TableCell>
|
||||||
<TableCell align="left">{row.payment_type_name}</TableCell>
|
<TableCell align="left">{row.payment_type_name}</TableCell>
|
||||||
<TableCell align="left">
|
<TableCell align="left">
|
||||||
{ row.status == "requested" ?
|
{ row.status == "requested" ?
|
||||||
(<Label variant='ghost' color='primary'>{capitalizeFirstLetter(row.status)}</Label>) :
|
(<Label variant='ghost' color='primary'>{capitalizeFirstLetter(row.status)}</Label>) :
|
||||||
(<Label color='success'> {capitalizeFirstLetter(row.status)}</Label>)
|
(<Label color='success'> {capitalizeFirstLetter(row.status)}</Label>)
|
||||||
}
|
}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
@@ -376,7 +376,7 @@ export default function List() {
|
|||||||
} />
|
} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
{/* <TableCell>
|
{/* <TableCell>
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleShowClaim(row);
|
handleShowClaim(row);
|
||||||
@@ -398,7 +398,7 @@ export default function List() {
|
|||||||
>
|
>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography fontWeight={600}>Berkas Hasil Penunjang</Typography>
|
<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) => (
|
row.files_by_type?.claim_kondisi.map((file, index) => (
|
||||||
<Stack direction="row" key={index}>
|
<Stack direction="row" key={index}>
|
||||||
<Typography sx={{ marginRight: 2 }}>-</Typography>{' '}
|
<Typography sx={{ marginRight: 2 }}>-</Typography>{' '}
|
||||||
@@ -412,7 +412,7 @@ export default function List() {
|
|||||||
<>
|
<>
|
||||||
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Kondisi</Typography>
|
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Kondisi</Typography>
|
||||||
{row.files_by_type?.claim_kondisi.map((file, index) => (
|
{row.files_by_type?.claim_kondisi.map((file, index) => (
|
||||||
|
|
||||||
<Stack direction="row" key={index}>
|
<Stack direction="row" key={index}>
|
||||||
<a href={file.url} target="_blank">
|
<a href={file.url} target="_blank">
|
||||||
{file.name}
|
{file.name}
|
||||||
@@ -426,7 +426,7 @@ export default function List() {
|
|||||||
<>
|
<>
|
||||||
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Diagnosa</Typography>
|
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Diagnosa</Typography>
|
||||||
{row.files_by_type?.claim_diagnosis.map((file, index) => (
|
{row.files_by_type?.claim_diagnosis.map((file, index) => (
|
||||||
|
|
||||||
<Stack direction="row" key={index}>
|
<Stack direction="row" key={index}>
|
||||||
<a href={file.url} target="_blank">
|
<a href={file.url} target="_blank">
|
||||||
{file.name}
|
{file.name}
|
||||||
@@ -440,7 +440,7 @@ export default function List() {
|
|||||||
<>
|
<>
|
||||||
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Hasil</Typography>
|
<Typography fontWeight={600} sx={{ marginRight: 4 }}> - Hasil</Typography>
|
||||||
{row.files_by_type?.claim_result.map((file, index) => (
|
{row.files_by_type?.claim_result.map((file, index) => (
|
||||||
|
|
||||||
<Stack direction="row" key={index}>
|
<Stack direction="row" key={index}>
|
||||||
<a href={file.url} target="_blank">
|
<a href={file.url} target="_blank">
|
||||||
{file.name}
|
{file.name}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import axios from '@/utils/axios';
|
||||||
|
import { enqueueSnackbar } from 'notistack';
|
||||||
|
import { MemberListType } from './Types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
};
|
||||||
15
frontend/dashboard/src/pages/ClaimRequests/Model/Types.tsx
Normal file
15
frontend/dashboard/src/pages/ClaimRequests/Model/Types.tsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* Search Type
|
||||||
|
*/
|
||||||
|
export type SearchType = {
|
||||||
|
keyword: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Member List
|
||||||
|
*/
|
||||||
|
export type MemberListType = {
|
||||||
|
id : string,
|
||||||
|
member_id : string,
|
||||||
|
name : string,
|
||||||
|
}
|
||||||
@@ -430,18 +430,6 @@ export default function Router() {
|
|||||||
path: 'claims',
|
path: 'claims',
|
||||||
element: <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',
|
path: 'claims/create',
|
||||||
element: <ClaimsCreate />,
|
element: <ClaimsCreate />,
|
||||||
@@ -458,6 +446,22 @@ export default function Router() {
|
|||||||
path: 'claims/:id',
|
path: 'claims/:id',
|
||||||
element: <ClaimShow />,
|
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',
|
path: 'profile',
|
||||||
element: <Profile />,
|
element: <Profile />,
|
||||||
|
|||||||
@@ -62,11 +62,11 @@ declare module '@mui/material' {
|
|||||||
|
|
||||||
// SETUP COLORS
|
// SETUP COLORS
|
||||||
const PRIMARY = {
|
const PRIMARY = {
|
||||||
lighter: '#D0FBEC',
|
lighter: '#D1F1F1',
|
||||||
light: '#70EAD5',
|
light: '#70EAD5',
|
||||||
main: '#19BBBB',
|
main: '#19BBBB',
|
||||||
dark: '#0C7186',
|
dark: '#0C7186',
|
||||||
darker: '#043C59',
|
darker: '#043C59',
|
||||||
};
|
};
|
||||||
const SECONDARY = {
|
const SECONDARY = {
|
||||||
lighter: '#D6E4FF',
|
lighter: '#D6E4FF',
|
||||||
|
|||||||
Reference in New Issue
Block a user