Display Uploaded Files
This commit is contained in:
@@ -4,6 +4,7 @@ namespace Modules\HospitalPortal\Http\Controllers\Api;
|
|||||||
|
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Models\ClaimRequest;
|
use App\Models\ClaimRequest;
|
||||||
|
use App\Models\File;
|
||||||
use Illuminate\Contracts\Support\Renderable;
|
use Illuminate\Contracts\Support\Renderable;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Routing\Controller;
|
use Illuminate\Routing\Controller;
|
||||||
@@ -17,7 +18,6 @@ class ClaimRequestController extends Controller
|
|||||||
public function index(request $request)
|
public function index(request $request)
|
||||||
{
|
{
|
||||||
$claimRequests = ClaimRequest::query()
|
$claimRequests = ClaimRequest::query()
|
||||||
->with(['member'])
|
|
||||||
->when($request->search, function ($q, $search) {
|
->when($request->search, function ($q, $search) {
|
||||||
$q->where('code', 'LIKE', "%".$search."%");
|
$q->where('code', 'LIKE', "%".$search."%");
|
||||||
})
|
})
|
||||||
@@ -29,6 +29,7 @@ class ClaimRequestController extends Controller
|
|||||||
->when($request->status, function($q, $status) {
|
->when($request->status, function($q, $status) {
|
||||||
$q->where('status', $status);
|
$q->where('status', $status);
|
||||||
})
|
})
|
||||||
|
->with(['member'])
|
||||||
->paginate();
|
->paginate();
|
||||||
|
|
||||||
return Helper::responseJson($claimRequests);
|
return Helper::responseJson($claimRequests);
|
||||||
@@ -64,11 +65,19 @@ class ClaimRequestController extends Controller
|
|||||||
|
|
||||||
if ($request->hasFile('result_files')) {
|
if ($request->hasFile('result_files')) {
|
||||||
foreach ($request->result_files as $file) {
|
foreach ($request->result_files as $file) {
|
||||||
// $newClaimRequest->files()->create()
|
$pathFile = File::storeFile('claim', $newClaimRequest->id, $file);
|
||||||
|
$newClaimRequest->files()->updateOrCreate([
|
||||||
|
'type' => 'result',
|
||||||
|
'name' => File::getFileName('claim', $newClaimRequest->id, $file),
|
||||||
|
'original_name' => $file->getClientOriginalName(),
|
||||||
|
'extension' => $file->getClientOriginalExtension(),
|
||||||
|
'path' => $pathFile,
|
||||||
|
'created_by' => auth()->user()->id,
|
||||||
|
'updated_by' => auth()->user()->id,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ($request->files_result[0]->getClientOriginalName());
|
return ($request->result_files[0]->getClientOriginalName());
|
||||||
die('asdasd');
|
|
||||||
|
|
||||||
return Helper::responseJson(data: $request->toArray(), message: 'Claim Request berhasil ajukan!');
|
return Helper::responseJson(data: $request->toArray(), message: 'Claim Request berhasil ajukan!');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use App\Models\ClaimRequest;
|
|||||||
use Illuminate\Contracts\Support\Renderable;
|
use Illuminate\Contracts\Support\Renderable;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Routing\Controller;
|
use Illuminate\Routing\Controller;
|
||||||
|
use Modules\Internal\Transformers\ClaimRequestResource;
|
||||||
|
|
||||||
class ClaimRequestController extends Controller
|
class ClaimRequestController extends Controller
|
||||||
{
|
{
|
||||||
@@ -14,13 +15,27 @@ class ClaimRequestController extends Controller
|
|||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
* @return Renderable
|
* @return Renderable
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$claimRequests = ClaimRequest::query()
|
$claimRequests = ClaimRequest::query()
|
||||||
->with(['member'])
|
->when($request->search, function ($q, $search) {
|
||||||
|
$q->where('code', 'LIKE', "%".$search."%");
|
||||||
|
})
|
||||||
|
->when($request->orderBy, function ($q, $orderBy) use ($request) {
|
||||||
|
if (in_array($orderBy, ['submission_date', 'code'])) {
|
||||||
|
$q->orderBy($orderBy, $request->order);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->when(empty($request->orderBy), function ($q) {
|
||||||
|
$q->orderBy('created_at', 'desc');
|
||||||
|
})
|
||||||
|
->when($request->status, function($q, $status) {
|
||||||
|
$q->where('status', $status);
|
||||||
|
})
|
||||||
|
->with(['member', 'files'])
|
||||||
->paginate();
|
->paginate();
|
||||||
|
|
||||||
return $claimRequests;
|
return Helper::paginateResources(ClaimRequestResource::collection($claimRequests));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
33
Modules/Internal/Transformers/ClaimRequestResource.php
Normal file
33
Modules/Internal/Transformers/ClaimRequestResource.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Internal\Transformers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class ClaimRequestResource extends JsonResource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the resource into an array.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function toArray($request)
|
||||||
|
{
|
||||||
|
$filesGroupByType = $this->files->mapToGroups(function($file) {
|
||||||
|
return [$file->type => $file];
|
||||||
|
});
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'id' => $this->id,
|
||||||
|
'code' => $this->code,
|
||||||
|
'submission_date' => $this->submission_date,
|
||||||
|
'member' => $this->member,
|
||||||
|
'status' => $this->status ?? 'unknown',
|
||||||
|
'service_type' => $this->service_type,
|
||||||
|
'files_by_type' => $filesGroupByType
|
||||||
|
];
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,10 +16,20 @@ class File extends Model
|
|||||||
'fileable_id',
|
'fileable_id',
|
||||||
'type',
|
'type',
|
||||||
'name',
|
'name',
|
||||||
|
'original_name',
|
||||||
'extension',
|
'extension',
|
||||||
'path',
|
'path',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected $hidden = [
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at',
|
||||||
|
'created_by',
|
||||||
|
'updated_by',
|
||||||
|
'deleted_by',
|
||||||
|
];
|
||||||
|
|
||||||
public $appends = [
|
public $appends = [
|
||||||
'url'
|
'url'
|
||||||
];
|
];
|
||||||
@@ -28,7 +38,7 @@ class File extends Model
|
|||||||
'import-temp' => 'import-temp/',
|
'import-temp' => 'import-temp/',
|
||||||
'avatar' => 'user-avatar/',
|
'avatar' => 'user-avatar/',
|
||||||
'dataDiri' => 'data-diri/',
|
'dataDiri' => 'data-diri/',
|
||||||
''
|
'claim' => 'claim/'
|
||||||
];
|
];
|
||||||
|
|
||||||
public function fileable()
|
public function fileable()
|
||||||
@@ -46,6 +56,11 @@ class File extends Model
|
|||||||
return $type . '-' . $id . '-' . Str::random(10);
|
return $type . '-' . $id . '-' . Str::random(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getNameAttribute($value)
|
||||||
|
{
|
||||||
|
return !empty($this->original_name) ? $this->original_name : ($value . '.' . $this->extension);
|
||||||
|
}
|
||||||
|
|
||||||
public function getUrlAttribute()
|
public function getUrlAttribute()
|
||||||
{
|
{
|
||||||
return url(Storage::url($this->path));
|
return url(Storage::url($this->path));
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ return new class extends Migration
|
|||||||
$table->dateTime('submission_date')->nullable();
|
$table->dateTime('submission_date')->nullable();
|
||||||
$table->foreignId('member_id');
|
$table->foreignId('member_id');
|
||||||
$table->string('status')->nullable();
|
$table->string('status')->nullable();
|
||||||
|
$table->foreignId('claim_id')->nullable()->comment('After Claim is Created');
|
||||||
|
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
$table->softDeletes();
|
$table->softDeletes();
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('files', function (Blueprint $table) {
|
||||||
|
$table->string('original_name')->nullable()->after('name');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('files', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('original_name');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -34,6 +34,8 @@ import { fCurrency } from '../../utils/formatNumber';
|
|||||||
import EditRoundedIcon from '@mui/icons-material/EditRounded';
|
import EditRoundedIcon from '@mui/icons-material/EditRounded';
|
||||||
import { LoadingButton } from '@mui/lab';
|
import { LoadingButton } from '@mui/lab';
|
||||||
import { enqueueSnackbar } from 'notistack';
|
import { enqueueSnackbar } from 'notistack';
|
||||||
|
import { Divider } from '@mui/material';
|
||||||
|
import Iconify from '@/components/Iconify';
|
||||||
// import LoadingButton from '@/theme/overrides/LoadingButton';
|
// import LoadingButton from '@/theme/overrides/LoadingButton';
|
||||||
|
|
||||||
export default function List() {
|
export default function List() {
|
||||||
@@ -179,6 +181,7 @@ export default function List() {
|
|||||||
<TableCell align="left">{row.code}</TableCell>
|
<TableCell align="left">{row.code}</TableCell>
|
||||||
<TableCell align="left">{row.member?.full_name}</TableCell>
|
<TableCell align="left">{row.member?.full_name}</TableCell>
|
||||||
<TableCell align="left">{row.submission_date}</TableCell>
|
<TableCell align="left">{row.submission_date}</TableCell>
|
||||||
|
<TableCell align="left">{row.service_type}</TableCell>
|
||||||
<TableCell align="right"><Chip label={row.status}/></TableCell>
|
<TableCell align="right"><Chip label={row.status}/></TableCell>
|
||||||
<TableCell align="right">{ row.status == 'requested' && (<LoadingButton loading={loadingApprove} variant="outlined" onClick={() => {handleApprove(row)}}>Approve</LoadingButton> )}</TableCell>
|
<TableCell align="right">{ row.status == 'requested' && (<LoadingButton loading={loadingApprove} variant="outlined" onClick={() => {handleApprove(row)}}>Approve</LoadingButton> )}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -187,9 +190,25 @@ export default function List() {
|
|||||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={99}>
|
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={99}>
|
||||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||||
<Box sx={{ borderBottom: 1 }}>
|
<Box sx={{ borderBottom: 1 }}>
|
||||||
<Typography variant="body2" gutterBottom component="div">
|
<Stack
|
||||||
Description : {row.description}
|
divider={<Divider orientation="horizontal" flexItem />}
|
||||||
</Typography>
|
spacing={1}
|
||||||
|
sx={{ marginY: 2 }}
|
||||||
|
>
|
||||||
|
<Box>
|
||||||
|
<Typography fontWeight={600}>Berkas Hasil Penunjang</Typography>
|
||||||
|
{row.files_by_type?.result &&
|
||||||
|
row.files_by_type?.result.map((file, index) => (
|
||||||
|
<Stack direction="row" key={index}>
|
||||||
|
<Typography sx={{marginRight: 2}}>-</Typography> <a href={file.url} target="_blank">{file.name}</a>
|
||||||
|
</Stack>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{ !row.files_by_type?.result && (
|
||||||
|
<Typography>Tidak ada berkas</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
@@ -217,6 +236,9 @@ export default function List() {
|
|||||||
<TableCell style={headStyle} align="left">
|
<TableCell style={headStyle} align="left">
|
||||||
Submission Date
|
Submission Date
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell style={headStyle} align="left">
|
||||||
|
Jenis Layanan
|
||||||
|
</TableCell>
|
||||||
<TableCell style={headStyle} align="left">
|
<TableCell style={headStyle} align="left">
|
||||||
Status
|
Status
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
6
frontend/hospital-portal/pnpm-lock.yaml
generated
6
frontend/hospital-portal/pnpm-lock.yaml
generated
@@ -48,7 +48,6 @@ specifiers:
|
|||||||
framer-motion: ^6.5.1
|
framer-motion: ^6.5.1
|
||||||
highlight.js: ^11.7.0
|
highlight.js: ^11.7.0
|
||||||
history: ^5.3.0
|
history: ^5.3.0
|
||||||
json2formdata: ^1.0.4
|
|
||||||
jsx-runtime: ^1.2.0
|
jsx-runtime: ^1.2.0
|
||||||
lodash: ^4.17.21
|
lodash: ^4.17.21
|
||||||
notistack: 3.0.0-alpha.11
|
notistack: 3.0.0-alpha.11
|
||||||
@@ -100,7 +99,6 @@ dependencies:
|
|||||||
framer-motion: 6.5.1_sfoxds7t5ydpegc3knd667wn6m
|
framer-motion: 6.5.1_sfoxds7t5ydpegc3knd667wn6m
|
||||||
highlight.js: 11.7.0
|
highlight.js: 11.7.0
|
||||||
history: 5.3.0
|
history: 5.3.0
|
||||||
json2formdata: 1.0.4
|
|
||||||
jsx-runtime: 1.2.0
|
jsx-runtime: 1.2.0
|
||||||
lodash: 4.17.21
|
lodash: 4.17.21
|
||||||
notistack: 3.0.0-alpha.11_pwge5r66yg44rq5pj4ruhckhdm
|
notistack: 3.0.0-alpha.11_pwge5r66yg44rq5pj4ruhckhdm
|
||||||
@@ -4653,10 +4651,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
|
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/json2formdata/1.0.4:
|
|
||||||
resolution: {integrity: sha512-caobS2W+raW3Fg3mt2ANGTPryLOUANxukjdfwkWKHY2pam9G1Ns3tifnaVzctMaqKevxhf7NIycFnTEXWYggdg==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/json5/1.0.2:
|
/json5/1.0.2:
|
||||||
resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
|
resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ export default function Dashboard() {
|
|||||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={12} lg={6} md={6}>
|
<Grid item xs={12} lg={6} md={6}>
|
||||||
<CardSearchMember></CardSearchMember>
|
<CardSearchMember handleSubmitSuccess={() => {console.log('submit success')}}></CardSearchMember>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} lg={6} md={6}>
|
<Grid item xs={12} lg={6} md={6}>
|
||||||
<CardNotification data={itemList} />
|
<CardNotification data={itemList} />
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const ItemNotificationStyle = styled(Card)(({ theme }) => ({
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
export default function CardSearchMember() {
|
export default function CardSearchMember(handleSubmitSuccess) {
|
||||||
const {enqueueSnackbar} = useSnackbar();
|
const {enqueueSnackbar} = useSnackbar();
|
||||||
|
|
||||||
const [noPolis, setNoPolis] = useState('AW001-01');
|
const [noPolis, setNoPolis] = useState('AW001-01');
|
||||||
@@ -145,7 +145,7 @@ export default function CardSearchMember() {
|
|||||||
title={{name: "Member"}}
|
title={{name: "Member"}}
|
||||||
openDialog={openDialogBenefit}
|
openDialog={openDialogBenefit}
|
||||||
setOpenDialog={setOpenDialogBenefit}
|
setOpenDialog={setOpenDialogBenefit}
|
||||||
content={DialogMember(currentMember, () => {setOpenDialogBenefit(false)})}
|
content={DialogMember(currentMember, () => {setOpenDialogBenefit(false); handleSubmitSuccess()})}
|
||||||
maxWidth="md"
|
maxWidth="md"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { Avatar } from '@mui/material';
|
|||||||
import Iconify from '@/components/Iconify';
|
import Iconify from '@/components/Iconify';
|
||||||
import FormRequestClaim from './FormRequestClaim';
|
import FormRequestClaim from './FormRequestClaim';
|
||||||
|
|
||||||
export default function DialogMember(member, closeDialog) {
|
export default function DialogMember(member, handleSubmitSuccess) {
|
||||||
const [currentTab, setCurrentTab] = useState('request')
|
const [currentTab, setCurrentTab] = useState('request')
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
@@ -92,7 +92,7 @@ export default function DialogMember(member, closeDialog) {
|
|||||||
|
|
||||||
|
|
||||||
<TabPanel value={currentTab} index={'request'}>
|
<TabPanel value={currentTab} index={'request'}>
|
||||||
<FormRequestClaim member={member} handleSubmitSuccess={closeDialog} />
|
<FormRequestClaim member={member} handleSubmitSuccess={handleSubmitSuccess} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export default function FormRequestClaim({ member, handleSubmitSuccess }) {
|
|||||||
.post('/claim-requests', formData)
|
.post('/claim-requests', formData)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
enqueueSnackbar(response.data.message ?? 'Berhasil membuat data', { variant: 'success' });
|
enqueueSnackbar(response.data.message ?? 'Berhasil membuat data', { variant: 'success' });
|
||||||
// handleSubmitSuccess();
|
handleSubmitSuccess();
|
||||||
})
|
})
|
||||||
.catch(({ response }) => {
|
.catch(({ response }) => {
|
||||||
enqueueSnackbar(response.data.message ?? 'Something Went Wrong', { variant: 'error' });
|
enqueueSnackbar(response.data.message ?? 'Something Went Wrong', { variant: 'error' });
|
||||||
@@ -120,15 +120,15 @@ export default function FormRequestClaim({ member, handleSubmitSuccess }) {
|
|||||||
spacing={1}
|
spacing={1}
|
||||||
sx={{ marginY: 2 }}
|
sx={{ marginY: 2 }}
|
||||||
>
|
>
|
||||||
{filesResult &&
|
{fileHasilPenunjangs &&
|
||||||
filesResult.map((file, index) => (
|
fileHasilPenunjangs.map((file, index) => (
|
||||||
<Stack direction="row" justifyContent={'space-between'} key={index}>
|
<Stack direction="row" justifyContent={'space-between'} key={index}>
|
||||||
<Typography>{file.name}</Typography>
|
<Typography>{file.name}</Typography>
|
||||||
<Iconify
|
<Iconify
|
||||||
icon="eva:trash-2-outline"
|
icon="eva:trash-2-outline"
|
||||||
color={'darkred'}
|
color={'darkred'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
removeFiles(filesResult, index);
|
removeFiles(fileHasilPenunjangs, index);
|
||||||
}}
|
}}
|
||||||
></Iconify>
|
></Iconify>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -357,8 +357,8 @@ export default function TableList(props: any) {
|
|||||||
sx={{ width: '100%' }}
|
sx={{ width: '100%' }}
|
||||||
>
|
>
|
||||||
{statusOptions &&
|
{statusOptions &&
|
||||||
statusOptions.map((option) => (
|
statusOptions.map((option, index) => (
|
||||||
<MenuItem value={option} sx={{ textTransform: 'capitalize' }}>
|
<MenuItem value={option} sx={{ textTransform: 'capitalize' }} key={index}>
|
||||||
{option}
|
{option}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user