diff --git a/Modules/Internal/Http/Controllers/Api/DoctorOnlineController.php b/Modules/Internal/Http/Controllers/Api/DoctorOnlineController.php new file mode 100755 index 00000000..d7571212 --- /dev/null +++ b/Modules/Internal/Http/Controllers/Api/DoctorOnlineController.php @@ -0,0 +1,239 @@ +where('nID', $id); + } + + $doctorRatings = $query->with([ + 'user' => function ($query) { + $query->select('nID', 'sFirstName'); // Select only necessary columns + } + ]) + ->select('nIDUser', 'sDate', 'sStatus') + ->get(); + + + // $prescriptions->toArray(); + // dd($prescriptions); + + return response()->json($doctorRatings); + // return response()->json(Helper::paginateResources(LivechatResource::collection($livechat))); + } + + public function getData(Request $request) + { + $limit = $request->has('per_page') ? $request->input('per_page') : 50; + $results = DB::connection('oldlms')->table('tx_users_online') + ->leftJoin('tm_users', 'tx_users_online.nIDUser', '=', 'tm_users.nID') + ->leftJoin('tm_dokter', 'tx_users_online.nIDUser', '=', 'tm_dokter.nIDUser') + ->when($request->input('search'), function ($query, $search) { + $query->where(function ($query) use ($search) { + $query->orWhere('tm_users.sFirstname', 'like', "%" . $search . "%"); + $query->orWhere('tx_users_online.sStatus', 'like', "%" . $search . "%"); + }); + }) + ->when($request->has('orderBy'), function ($query) use ($request) { + $orderBy = $request->orderBy; + $direction = $request->order ?? 'asc'; + + $query->orderBy($orderBy, $direction); + }) + ->when($request->input('start_date') , function ($query, $start_date) { + $query->where(function ($query) use ($start_date) { + $query->where('tx_users_online.sDate', '>=', $start_date. ' 00:00:00'); + }); + }) + ->when($request->input('end_date') , function ($query, $end_date) { + $query->where(function ($query) use ($end_date) { + $query->where('tx_users_online.sDate', '<=', $end_date. ' 23:59:59'); + }); + }) + ->select( + DB::connection('oldlms')->raw("CONCAT('dr. ', tm_users.sFirstName, ' ', IFNULL(tm_users.sMiddleName, ''), ' ', IFNULL(tm_users.sLastName, '')) as nama_dokter"), + 'tx_users_online.sStatus', + 'tx_users_online.sDate' + ) + ->paginate($limit); + + return response()->json(Helper::paginateResources($results)); + } + + public function export(Request $request) + { + // Menyimpan tanggal mulai dan tanggal selesai dari request + $start_date = $request->input('start_date') ? $request->input('start_date') : 'all'; + $end_date = $request->input('end_date') ? $request->input('end_date') : 'all'; + + // Membuat writer untuk file XLSX + $writer = WriterEntityFactory::createXLSXWriter(); + + // Pastikan folder 'files' ada dan bisa ditulis + $filePath = public_path('files'); + if (!is_dir($filePath)) { + mkdir($filePath, 0755, true); // Membuat folder jika belum ada + } + + // Menyimpan file Excel ke folder yang sesuai + $fileName = 'Report-Data-Rating-Dokter-' . $start_date . '-' . $end_date . '.xlsx'; + $writer->openToFile(public_path('files/' . $fileName)); + + // Header Excel + $header = [ + 'No', + 'Nama Dokter', + 'Date', + 'Status', + ]; + + // Styling untuk header (bold) + $headerStyle = (new StyleBuilder()) + ->setFontBold() // Menambahkan font bold hanya pada header + ->setCellAlignment(CellAlignment::LEFT) + ->build(); + + // Menambahkan header ke dalam file + $headerRow = WriterEntityFactory::createRowFromArray($header, $headerStyle); + $writer->addRow($headerRow); + + // Query untuk mengambil data dari database + $results = DB::connection('oldlms')->table('tx_users_online') + ->leftJoin('tm_users', 'tx_users_online.nIDUser', '=', 'tm_users.nID') + ->when($request->input('search'), function ($query, $search) { + $query->where(function ($query) use ($search) { + $query->orWhere('tm_users.sFirstname', 'like', "%" . $search . "%"); + $query->orWhere('tm_users.sLastname', 'like', "%" . $search . "%"); + }); + }) + ->when($request->has('orderBy'), function ($query) use ($request) { + $orderBy = $request->orderBy; + $direction = $request->order ?? 'asc'; + $query->orderBy($orderBy, $direction); + }) + ->when($request->input('start_date'), function ($query, $start_date) { + $query->where('tx_users_online.sDate', '>=', $start_date . ' 00:00:00'); + }) + ->when($request->input('end_date'), function ($query, $end_date) { + $query->where('tx_users_online.sDate', '<=', $end_date . ' 23:59:59'); + }) + ->select( + DB::connection('oldlms')->raw("CONCAT('dr. ', tm_users.sFirstName, ' ', IFNULL(tm_users.sMiddleName, ''), ' ', IFNULL(tm_users.sLastName, '')) as nama_dokter"), + 'tx_users_online.sStatus', + 'tx_users_online.sDate' + ) + ->get(); + + // Styling untuk baris data (tidak ada bold) + $dataStyle = (new StyleBuilder()) + ->setCellAlignment(CellAlignment::LEFT) + ->build(); + + // Menambahkan data baris ke dalam file + $no = 0; + foreach ($results as $item) { + $no++; + $rowData = [ + $no, + $item->nama_dokter, + $item->sDate, + $item->sStatus + ]; + + $row = WriterEntityFactory::createRowFromArray($rowData, $dataStyle); + $writer->addRow($row); + } + + // Menutup writer setelah selesai menulis file + $writer->close(); + + // Mengirimkan response JSON + return Helper::responseJson([ + 'file_name' => $fileName, + 'file_url' => url('files/' . $fileName), + ]); + } + + + + /** + * Show the form for creating a new resource. + * @return Renderable + */ + public function create() + { + return view('internal::create'); + } + + /** + * Store a newly created resource in storage. + * @param Request $request + * @return Renderable + */ + public function store(Request $request) + { + } + + /** + * Show the specified resource. + * @param int $id + * @return Renderable + */ + public function show($id) + { + + } + + /** + * Show the form for editing the specified resource. + * @param int $id + * @return Renderable + */ + public function edit($id) + { + return view('internal::edit'); + } + + /** + * Update the specified resource in storage. + * @param Request $request + * @param int $id + * @return Renderable + */ + public function update(Request $request, $id) + { + // + } + + /** + * Remove the specified resource from storage. + * @param int $id + * @return Renderable + */ + public function destroy($id) + { + // + } +} diff --git a/Modules/Internal/Routes/api.php b/Modules/Internal/Routes/api.php index 327e07b0..3fde67d7 100755 --- a/Modules/Internal/Routes/api.php +++ b/Modules/Internal/Routes/api.php @@ -26,6 +26,7 @@ use Modules\Internal\Http\Controllers\Api\DivisionController; use Modules\Internal\Http\Controllers\Api\HospitalController; use Modules\Internal\Http\Controllers\Api\DoctorController; use Modules\Internal\Http\Controllers\Api\DoctorRatingController; +use Modules\Internal\Http\Controllers\Api\DoctorOnlineController; use Modules\Internal\Http\Controllers\Api\DrugController; use Modules\Internal\Http\Controllers\Api\FormulariumController; use Modules\Internal\Http\Controllers\Api\FormulariumTemplateController; @@ -350,6 +351,9 @@ Route::prefix('internal')->group(function () { Route::get('get-doctorrating', [DoctorRatingController::class, 'getData']); Route::get('export-doctorrating', [DoctorRatingController::class, 'export']); + Route::get('get-doctoronline', [DoctorOnlineController::class, 'getData']); + Route::get('export-doctoronline', [DoctorOnlineController::class, 'export']); + Route::get('get-dokter-katalog', [KatalogDokterController::class, 'getData']); Route::get('export-dokter-katalog', [KatalogDokterController::class, 'export']); diff --git a/app/Models/OLDLMS/DoctorOnline.php b/app/Models/OLDLMS/DoctorOnline.php new file mode 100755 index 00000000..db9dbc11 --- /dev/null +++ b/app/Models/OLDLMS/DoctorOnline.php @@ -0,0 +1,35 @@ +belongsTo(User::class, 'nIDUser'); + } + + // Include additional fields in the model's JSON form + protected $appends = [ + 'user_first_name', // Include the attribute for user's first name + ]; + + // Define an accessor to get the first name of the related user + public function getUserFirstNameAttribute() + { + return $this->user ? $this->user->sFirstName : null; + } +} diff --git a/database/seeders/NavigationSeeder.php b/database/seeders/NavigationSeeder.php index bf11ef17..a6464788 100755 --- a/database/seeders/NavigationSeeder.php +++ b/database/seeders/NavigationSeeder.php @@ -187,6 +187,11 @@ class NavigationSeeder extends Seeder 'path' => '/report/doctor-rating', 'permission' => 'report-doctor-rating' ], + [ + 'title' => 'Doctor Online', + 'path' => '/report/doctor-online', + 'permission' => 'report-doctor-online' + ], [ 'title' => 'Katalog Dokter', 'path' => '/report/katalog-dokter', diff --git a/database/seeders/PermissionTableSeeder.php b/database/seeders/PermissionTableSeeder.php index cecb8f9e..f2d6af41 100755 --- a/database/seeders/PermissionTableSeeder.php +++ b/database/seeders/PermissionTableSeeder.php @@ -69,6 +69,7 @@ class PermissionTableSeeder extends Seeder 'report-livechat-list', 'report-livechat-payment', 'report-doctor-rating', + 'report-doctor-online', 'user-role-list', 'user-access-list', 'report-katalog-dokter' diff --git a/frontend/dashboard/src/pages/Report/DoctorOnline/Index.tsx b/frontend/dashboard/src/pages/Report/DoctorOnline/Index.tsx new file mode 100755 index 00000000..e93d773f --- /dev/null +++ b/frontend/dashboard/src/pages/Report/DoctorOnline/Index.tsx @@ -0,0 +1,35 @@ +import { Card, Grid, Container } from '@mui/material'; +import { useParams } from 'react-router-dom'; +import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs'; +import Page from '../../../components/Page'; +import useSettings from '../../../hooks/useSettings'; +import List from './List'; + +export default function Index() { + const { themeStretch } = useSettings(); + + const { id } = useParams(); + + const pageTitle = 'Doctor Online'; + return ( + + + + + + + + ); +} diff --git a/frontend/dashboard/src/pages/Report/DoctorOnline/List.tsx b/frontend/dashboard/src/pages/Report/DoctorOnline/List.tsx new file mode 100755 index 00000000..4c5f3114 --- /dev/null +++ b/frontend/dashboard/src/pages/Report/DoctorOnline/List.tsx @@ -0,0 +1,1012 @@ +// @mui +import { + Box, + Grid, + Button, + Card, + Collapse, + IconButton, + MenuItem, + Table, + TableBody, + TableCell, + TableRow, + TextField, + Typography, + Stack, + Menu, + ButtonGroup, + Tooltip, + TableHead, + Checkbox, + InputAdornment, + TableSortLabel, + FormControl + } from '@mui/material'; + import { visuallyHidden } from '@mui/utils'; + + import { DesktopDatePicker, LocalizationProvider } from '@mui/x-date-pickers'; + import { fDateOnly } from '@/utils/formatTime'; + + import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; + import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined'; + import AssessmentIcon from '@mui/icons-material/Assessment'; + // hooks + import React, { ChangeEvent, useEffect, useRef, useState } from 'react'; + import { Link, Navigate, useNavigate, useSearchParams } from 'react-router-dom'; + + import { LoadingButton } from '@mui/lab'; + // 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'; + import { fDate, fDateTime } from '../../../utils/formatTime'; + import { Claims } from '@/@types/claims'; + import Label from '@/components/Label'; + import { capitalizeFirstLetter } from '@/utils/formatString'; + import TableMoreMenu from '@/components/table/TableMoreMenu'; + import Edit from '@mui/icons-material/Edit'; + import { Download } from '@mui/icons-material'; + import { Add, Search } from '@mui/icons-material'; + import Autocomplete from '@mui/material/Autocomplete'; + + import DownloadIcon from '@mui/icons-material/Download'; + + import UploadIcon from '@mui/icons-material/Upload'; + import CancelIcon from '@mui/icons-material/Cancel'; + import CheckCircleIcon from '@mui/icons-material/CheckCircle'; + + import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material'; + import CloseIcon from '@mui/icons-material/Close'; + + + export default function List() { + const [selectAll, setSelectAll] = useState(false); + const [selectedRows, setSelectedRows] = useState([]); + const [providers, setProviders] = useState(null); + // const [searchText, setSearchText] = useState(''); + const [order, setOrder] = useState('desc'); + const [orderBy, setOrderBy] = useState('sDate'); + const [perPage, setPerPage] = useState(0); + + const handleChange = (event, newValue) => { + // Jika newValue tidak undefined, atur nilai dataProvider + if (newValue !== undefined) { + setDataProvider(newValue.service_code); + } else { + // Jika tidak ada yang dipilih, set dataProvider menjadi string kosong + setDataProvider(null); + } + }; + // Dummy data + const dummyServices = [ + { service_code: '1', name: 'Service 1' }, + { service_code: '2', name: 'Service 2' }, + { service_code: '3', name: 'Service 3' }, + // tambahkan data lain sesuai kebutuhan + ]; + + + + const handleSelectAll = () => { + setSelectAll(!selectAll); + if (!selectAll) { + const requestedIds = dataTableData.data + .filter(row => row.status === 'approved') // Memfilter baris dengan status 'requested' + .map(row => row.id); // Mengambil hanya ID dari baris-baris yang memenuhi kondisi + setSelectedRows(requestedIds); + } else { + setSelectedRows([]); + } + }; + + const handleRowSelect = (id) => { + if (selectedRows.includes(id)) { + setSelectedRows(selectedRows.filter(rowId => rowId !== id)); + } else { + setSelectedRows([...selectedRows, id]); + } + }; + + const [searchParams, setSearchParams] = useSearchParams(); + const [startDate, setStartDate] = useState(null); + const [searchText, setSearchText] = useState(''); + const [endDate, setEndDate] = useState(null); + const navigate = useNavigate(); + const [dataProvider, setDataProvider] = useState(null); + + useEffect(() => { + if (startDate !== null || endDate !== null || dataProvider !== null + || order !== null || orderBy !== null || perPage !== 0) { + loadDataTableData(); + getProvider(); + } + }, [startDate, endDate, dataProvider, order, orderBy, perPage]); + + const [isLoading, setIsLoading] = useState(false); + const [isLoadingImport, setIsLoadingImport] = useState(false); + const handleExportReport = async () => { + + + const year = startDate?.getFullYear(); + const month = (startDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit + const day = startDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit + + const formattedDate = year && month && day ? `${year}-${month}-${day}` : ''; + + const year1 = endDate?.getFullYear(); + const month1 = (endDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit + const day1 = endDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit + + const formattedDate1 = year1 && month1 && day1 ? `${year1}-${month1}-${day1}` : ''; + + + + var filter = Object.fromEntries([...searchParams.entries()]); + setIsLoading(true) + await axios + .get('/export-doctoronline',{ + params: { + search: searchText, + start_date: formattedDate ? formattedDate : null, + end_date:formattedDate1, + provider: dataProvider, + order: order, + orderBy: orderBy, + page: perPage, + } + }) + .then((res) => { + enqueueSnackbar('Data berhasil di Export', { + variant: 'success', + anchorOrigin: { horizontal: 'right', vertical: 'top' }, + }); + setIsLoading(false) + + document.location.href = res.data.data.file_url; + }) + .catch((err) => + enqueueSnackbar('Data Gagal di Export', { + variant: 'error', + anchorOrigin: { horizontal: 'right', vertical: 'top' }, + }) + + ); + }; + + + function SearchInput(props: any) { + // SEARCH + const searchInput = useRef(null); + + + + 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(`claims/1/data-claim`) + .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 ( +
+ + + + +
+ ); + } + + function ImportForm(props: any) { + // IMPORT + // Create Button Menu + const [anchorEl, setAnchorEl] = React.useState(null); + + return ( +
+ + + {/* */} + +
+ ); + } + + const searchInput = useRef(null); + + + //handle search + const handleSearchChange = (event: any) => { + const newSearchText = event.target.value ?? ''; + setSearchText(newSearchText); + }; + + const handleSearchSubmit = (event: any) => { + event.preventDefault(); + loadDataTableData(); + }; + + + + useEffect(() => { + // Trigger First Search + //setSearchText(searchText); + }, []); + + const item = [ + { + id: '', + value: '', + name: 'Semua', + }, + ]; + + // const handleClick = () => { + + // } + + + + // Dummy Default Data + const [dataTableIsLoading, setDataTableLoading] = useState(true); + const [dataTableData, setDataTableData] = useState( + LaravelPaginatedDataDefault + ); + + + + const loadDataTableData = async (appliedFilter: any | null = null) => { + setDataTableLoading(true); + const year = startDate?.getFullYear(); + const month = (startDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit + const day = startDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit + + const formattedDate = year && month && day ? `${year}-${month}-${day}` : ''; + + const year1 = endDate?.getFullYear(); + const month1 = (endDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit + const day1 = endDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit + + const formattedDate1 = year1 && month1 && day1 ? `${year1}-${month1}-${day1}` : ''; + + const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]); + const response = await axios.get('/get-doctoronline', { + params: { + search: searchText, + start_date: formattedDate ? formattedDate : null, + end_date:formattedDate1, + provider: dataProvider, + order: order, + orderBy: orderBy, + page: perPage, + } + }); + + setDataTableLoading(false); + + setDataTableData(response.data); + }; + + const getProvider = async () => { + const response = await axios.get('/claims/get-provider'); + setProviders(response.data) + } + + const applyFilter = async (searchFilter: { search: string }) => { + await loadDataTableData(searchFilter); + setSearchParams(searchFilter); + }; + + const handlePageChange = (event: ChangeEvent, value: number): void => { + setPerPage(value); + }; + + const [openDialogSubmit, setOpenDialogSubmit] = useState(false); + const handleCloseDialogSubmit = () => { + setOpenDialogSubmit(false); + } + + function toTitleCase(str: string | null) { + return str.replace(/\w\S*/g, function(txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + }); + } + + const [approve, setApprove] = useState(''); + + const [reasonDecline, setReasonDecline] = useState(''); + + const handleReasonDeclineChange = (event) => { + setReasonDecline(event.target.value); + // Tambahkan logika yang diperlukan di sini + }; + + const handleSubmitData = async () => { + try { + const response = await axios.post('download-zip', { selectedRows: selectedRows }); + const fileUrl = response.data.file_url; // Perbaikan disini + enqueueSnackbar('Data berhasil di download', { variant: 'success' }); + window.open(fileUrl, '_blank'); + setOpenDialogSubmit(false); + setTimeout(() => { + window.location.reload(); + }, 5000); // Reload the page after 5 seconds + } catch (error) { + enqueueSnackbar('Data Gagal di download', { variant: 'error' }); + } + }; + + const handleSubmitData1 = () => { + //approve or decline + if (!reasonDecline && approve == 'decline') { + enqueueSnackbar('Mohon isi alasan', { variant: 'warning' }); + return false; + } + Promise.all(selectedRows.map(send_bulk)) + .then(() => { + enqueueSnackbar('All requests processed successfully', { variant: 'success' }); + setOpenDialogSubmit(false); + setTimeout(() => { + window.location.reload(); + }, 5000); // Reload the page after 5 seconds + }) + .catch((error) => { + enqueueSnackbar(error.response?.data?.message ?? 'Something went wrong!', { variant: 'error' }); + }); + }; + + function send_bulk(id) { + return axios.post(`claims/${id}/${approve}`, { reasonDecline: reasonDecline }); + } + + + const [anchorEl, setAnchorEl] = React.useState(null); + const createMenu = Boolean(anchorEl); + const importClaimManagement = useRef(null); + const [currentImportFileName, setCurrentImportFileName] = useState(null); + const [importLoading, setImportLoading] = useState(false); + const [importResult, setImportResult] = useState(null); + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + }; + const handleImportButton = () => { + if (importClaimManagement?.current) { + handleClose(); + importClaimManagement.current ? importClaimManagement.current.click() : console.log('No File selected'); + } else { + alert('No file selected'); + } + }; + const handleCancelImportButton = () => { + if(importClaimManagement.current) + { + importClaimManagement.current.value = ''; + importClaimManagement.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(importClaimManagement.current && importClaimManagement.current.files) + { + if (importClaimManagement.current?.files.length) { + const formData = new FormData(); + formData.append('file', importClaimManagement.current?.files[0]); + setImportLoading(true); + axios + .post('claims/import', formData) + .then((response) => { + handleCancelImportButton(); + loadDataTableData(); + setImportResult(response.data); + setImportLoading(false); + enqueueSnackbar('Success Import Claim Managemenet', { variant: 'success' }); + }) + .catch((response) => { + enqueueSnackbar( + 'Looks like something went wrong. Please check your data and try again. ' + + response.message, + { variant: 'error' } + ); + setImportLoading(false); + }); + } else { + enqueueSnackbar('No File Selected', { variant: 'warning' }); + } + } + }; + const handleGetTemplate = () => { + axios.get('claims/download-template').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(); + handleClose(); + }); + + + }; + + const handleExportReportFiled = async () => { + + await axios + .post('claims/exportFiled', { params: importResult?.data.result_rows }) + .then((res) => { + enqueueSnackbar('Data berhasil di Export', { + variant: 'success', + anchorOrigin: { horizontal: 'right', vertical: 'top' }, + }); + setIsLoading(false) + + document.location.href = res.data.data.file_url; + }) + .catch((err) => + enqueueSnackbar('Data Gagal di Export', { + variant: 'error', + anchorOrigin: { horizontal: 'right', vertical: 'top' }, + }) + + ); + }; + + + // useEffect(() => { + // loadDataTableData(); + // getProvider(); + // }, []); + + const headStyle = { + fontWeight: 'bold', + }; + // const headCells = [ + // { + // id: 'dCreateOn', + // align: 'left', + // label: 'Date Submission', + // isSort: true, + // }, + // { + // id: 'code', + // align: 'left', + // label: 'Code', + // isSort: true, + // }, + // { + // id: 'name', + // align: 'left', + // label: 'Name', + // isSort: false, + // }, + // { + // id: 'provider', + // align: 'left', + // label: 'Provider', + // isSort: false, + // }, + // { + // id: 'files', + // align: 'left', + // label: 'Nama File', + // isSort: false, + // }, + // ]; + const headCells = [ + { + id: 'nama_dokter', + align: 'left', + label: 'Nama Dokter', + isSort: true, + }, + { + id: 'sDate', + align: 'left', + label: 'Date', + isSort: true, + }, + { + id: 'sStatus', + align: 'left', + label: 'Status', + isSort: false, + } + ]; + + const orders = { + order: order, + setOrder: setOrder, + orderBy: orderBy, + setOrderBy: setOrderBy, + }; + const createSortHandler = (property: string) => (event: React.MouseEvent) => { + handleRequestSort(event, property); + }; + const handleRequestSort = async (event: React.MouseEvent, property: string) => { + const isAsc = orders?.orderBy === property && orders?.order === 'asc'; + + orders?.setOrder(isAsc ? 'desc' : 'asc'); + orders?.setOrderBy(property); + }; + // Called on every row to map the data to the columns + function createData(data: Claims): Claims { + return { + ...data, + }; + } + + { + /* ------------------ TABLE ROW ------------------ */ + } + function Row(props: { row: ReturnType, isSelected: boolean, onSelect: (id: string) => void }) { + const { row, isSelected, onSelect } = props; + // Memperbaiki destrukturisasi props + + const handleRowCheckboxChange = () => { + onSelect(row.id); // Panggil fungsi onSelect dari komponen induk dengan id baris saat checkbox di baris diklik + }; + + const [open, setOpen] = React.useState(false); + + const test = 1000; + + return ( + + *': { borderBottom: 'unset' } }}> + {/* + setOpen(!open)}> + {open ? : } + + */} + {/* + + */} + {row?.nama_dokter} + {row?.sDate ? fDateTime(row?.sDate) : ''} + {row?.sStatus == 'Offline' ? : } + {/* {row?.dCreateOn ? fDateTime(row?.dCreateOn) : ''} */} + {/* {row?.code} */} + {/* {row.code} */} + {/* {row?.provider} */} + + {/* COLLAPSIBLE ROW */} + + + + {/* + + Description : {row.description} + + */} + + + + + ); + } + { + /* ------------------ END TABLE ROW ------------------ */ + } + + + + function TableContent() { + return ( + + {/* ------------------ TABLE HEADER ------------------ */} + + + {selectedRows.length > 0 ? ( + <> + + + + {selectedRows.length > 0 ? selectedRows.length : '0'}  Selected + + + + + + {/* + + */} + + + + + + ) : ( + <> + {/* + + */} + {headCells && + headCells.map((headCell, index) => ( + + {headCell.isSort ? ( + + {headCell.label} + {orders?.orderBy === headCell.id ? ( + + {orders.order === 'desc' ? 'sorted descending' : 'sorted ascending'} + + ) : null} + + ) : ( + headCell.label + )} + + ))} + + + )} + + + + + {/* ------------------ END TABLE HEADER ------------------ */} + + {/* ------------------ TABLE ROW ------------------ */} + {dataTableIsLoading ? ( + + + + Loading + + + + ) : dataTableData.data.length === 0 ? ( + + + + No Data + + + + ) : ( + + {dataTableData.data.map((row) => ( + + ))} + + )} + {/* ------------------ END TABLE ROW ------------------ */} +
+ ); + } + + return ( + + + +
+ + + {!currentImportFileName && ( + <> + + { + if (event.key === 'Enter') { + handleSearchSubmit(event); + } + }} + InputProps={{ + startAdornment: ( + + + + ), + placeholder: 'Search Name', + }} + /> + + + + { + + // loadDataTableData(); + setStartDate(value); + }} + renderInput={(params) => } + /> + + + + { + setEndDate(value); + }} + renderInput={(params) => ( + + )} + /> + + + {/* + { + providers ? ( + option.name || ''} + value={providers.find((item) => item.id === dataProvider) || null} + onChange={(event, value) => { + if (value) { + setDataProvider(value.id); + } else { + setDataProvider(null); + } + }} + renderInput={(params) => ( + + )} + /> + ):( + <> + Loading... + + ) + } + */} + + {/* + } + sx={{ p: 1.8 }} + loading={isLoadingImport} + onClick={handleClick} + > + + Import + + + + + Import + + { + handleGetTemplate(); + }} + > + Download Template + + + */} + + } + sx={{ p: 1.8 }} + onClick={handleExportReport} + loading={isLoading} + > + + Export to Excel + + + + + + )} + {currentImportFileName && ( + + + + + + + + } + sx={{ p: 1.8 }} + onClick={handleUpload} + loading={importLoading} + > + Upload + + + + )} + {importResult && ( + + + Last Import Result :{' '} + + {importResult.data.total_success_row ?? 0} + {' '} + Row Processed,{' '} + + {importResult.data.total_failed_row} + {' '} + Failed, + {/* {importResult.data.failed_rows.map((row, index) => ( + [Code={row.code ? row.code : 'Required'}] + ))} */} +  Report: +  Download Data Result Import + + + )} + +
+
+
+ + } + /> + + + + + Confirmation + + + + + + + + + + Are you sure to Download this files selected ? + {approve == "decline" ? ( + + + + ): ''} + + + + + + + +
+ ); + } diff --git a/frontend/dashboard/src/pages/Report/Rujukan/Index.tsx b/frontend/dashboard/src/pages/Report/Rujukan/Index.tsx old mode 100644 new mode 100755 diff --git a/frontend/dashboard/src/pages/Report/Rujukan/List.tsx b/frontend/dashboard/src/pages/Report/Rujukan/List.tsx old mode 100644 new mode 100755 diff --git a/frontend/dashboard/src/routes/index.tsx b/frontend/dashboard/src/routes/index.tsx index 2fa32d41..c29ee22d 100755 --- a/frontend/dashboard/src/routes/index.tsx +++ b/frontend/dashboard/src/routes/index.tsx @@ -13,6 +13,7 @@ import { AuthProvider } from '../contexts/LaravelAuthContext'; import AuthGuard from '../guards/AuthGuard'; import { Link, useParams, useSearchParams } from 'react-router-dom'; import DoctorRating from '@/pages/Report/DoctorRating_v2/Index'; +import DoctorOnline from '@/pages/Report/DoctorOnline/Index'; import KatalogDokter from '@/pages/Report/KatalogDokter/Index'; // ---------------------------------------------------------------------- @@ -446,6 +447,10 @@ export default function Router() { path: 'report/doctor-rating', element: , }, + { + path: 'report/doctor-online', + element: , + }, { path: 'report/katalog-dokter', element: , diff --git a/public/files/Report-Data-Dokter-Online-all-all.xlsx b/public/files/Report-Data-Dokter-Online-all-all.xlsx new file mode 100644 index 00000000..5a487229 Binary files /dev/null and b/public/files/Report-Data-Dokter-Online-all-all.xlsx differ