Data Docter dan Hospital dnegan Filter di dashboard
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
namespace Modules\Internal\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Practitioner;
|
||||
use App\Models\PractitionerRole;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -15,9 +16,34 @@ class DoctorController extends Controller
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index()
|
||||
public function index(Request $request)
|
||||
{
|
||||
$doctors = PractitionerRole::active()->with('practitioner.person', 'organization')->paginate();
|
||||
// $doctors = PractitionerRole::active()->with('practitioner.person', 'organization')
|
||||
// ->when($request->search ?? null, function ($query, $search) {
|
||||
// $query->whereHas('practitioner.person', function ($person) use ($search) {
|
||||
// $person->where('name', 'LIKE', '%' . $search . '%');
|
||||
// });
|
||||
// })->paginate();
|
||||
|
||||
$doctors = Practitioner::with('person', 'practitionerRoles.organization', 'practitionerRoles.speciality')
|
||||
->when($request->search ?? null, function ($query, $search) {
|
||||
$query->whereHas('person', function ($person) use ($search) {
|
||||
$person->where('name', 'LIKE', '%' . $search . '%');
|
||||
});
|
||||
})
|
||||
->when($request->organization_id ?? null, function ($query, $organization_id) {
|
||||
$query->whereHas('practitionerRoles', function ($practitionerRole) use ($organization_id) {
|
||||
$practitionerRole->where('organization_id', $organization_id);
|
||||
});
|
||||
})
|
||||
->when($request->speciality_id ?? null, function ($query, $speciality_id) {
|
||||
$query->whereHas('practitionerRoles', function ($practitionerRole) use ($speciality_id) {
|
||||
$practitionerRole->where('speciality_id', $speciality_id);
|
||||
});
|
||||
})
|
||||
->paginate();
|
||||
|
||||
// return $doctors;
|
||||
|
||||
|
||||
return response()->json(Helper::paginateResources(DoctorResource::collection($doctors)));
|
||||
|
||||
@@ -15,12 +15,22 @@ class OrganizationController extends Controller
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index()
|
||||
public function index(Request $request)
|
||||
{
|
||||
$organizations = Organization::active()->hospital()->with('currentAddress')->paginate();
|
||||
$organizations = Organization::hospital()->with('currentAddress')
|
||||
->when($request->search ?? null, function ($query, $search) {
|
||||
$query->where('name', 'LIKE', '%' . $search . '%');
|
||||
})
|
||||
->paginate();
|
||||
return response()->json(Helper::paginateResources(OrganizationResource::collection($organizations)));
|
||||
}
|
||||
|
||||
public function searchOrganization(Request $request)
|
||||
{
|
||||
$organizations = Organization::hospital()->get();
|
||||
return response()->json(OrganizationResource::collection($organizations));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
* @return Renderable
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Internal\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Speciality;
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
|
||||
class SpecialityController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
* @return Renderable
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$specialiy = Speciality::get();
|
||||
return response()->json($specialiy);
|
||||
}
|
||||
|
||||
public function searchSpeciality(Request $request)
|
||||
{
|
||||
$specialiy = Speciality::get();
|
||||
return response()->json($specialiy);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
return view('internal::show');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ use Modules\Internal\Http\Controllers\Api\FormulariumController;
|
||||
use Modules\Internal\Http\Controllers\Api\MemberController;
|
||||
use Modules\Internal\Http\Controllers\Api\OrganizationController;
|
||||
use Modules\Internal\Http\Controllers\Api\PlanController;
|
||||
use Modules\Internal\Http\Controllers\Api\SpecialityController;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -104,10 +105,15 @@ Route::prefix('internal')->group(function () {
|
||||
Route::post('claims', [ClaimController::class, 'store']);
|
||||
Route::get('claims/{id}', [ClaimController::class, 'show']);
|
||||
Route::post('check-limit', [ClaimController::class, 'checkLimit']);
|
||||
|
||||
Route::get('search-organizations', [OrganizationController::class, 'searchOrganization']);
|
||||
Route::get('search-specialities', [SpecialityController::class, 'searchSpeciality']);
|
||||
Route::resource('organizations', OrganizationController::class);
|
||||
Route::resource('doctors', DoctorController::class);
|
||||
});
|
||||
|
||||
Route::resource('organizations', OrganizationController::class);
|
||||
Route::resource('doctors', DoctorController::class);
|
||||
// Route::resource('organizations', OrganizationController::class);
|
||||
// Route::resource('doctors', DoctorController::class);
|
||||
|
||||
// Route::get('something', [DiagnosisExclusionController::class, 'index']);
|
||||
});
|
||||
|
||||
@@ -16,20 +16,35 @@ class DoctorResource extends JsonResource
|
||||
{
|
||||
$doctor = [
|
||||
'id' => $this->id,
|
||||
'his_dokter_id' => $this->meta->DokterID,
|
||||
'name' => $this->practitioner->person->name,
|
||||
'phone' => $this->practitioner->person->phone,
|
||||
'email' => $this->practitioner->person->email,
|
||||
'address' => $this->practitioner->person->currentAddress->text,
|
||||
'organization' => $this->organization->name,
|
||||
'organization_id' => $this->organization->id,
|
||||
'specialty' => $this->speciality->name,
|
||||
'specialtyI_id' => $this->speciality->id,
|
||||
'education' => $this->practitioner->meta->education,
|
||||
'experience' => $this->practitioner->meta->work_experience,
|
||||
'award' => $this->practitioner->meta->award,
|
||||
'keilmuan' => $this->practitioner->meta->Keilmuan,
|
||||
'tipe_dokter' => $this->practitioner->meta->tipeDokter,
|
||||
// 'his_dokter_id' => $this->practitionerRoles->meta,
|
||||
'name' => $this->person->name,
|
||||
'person_id' => $this->person->id,
|
||||
'phone' => $this->person->phone,
|
||||
'email' => $this->person->email,
|
||||
'gender' => $this->person->gender == "L" ? 'Laki-laki' : 'Perempuan',
|
||||
'address' => $this->person->currentAddress->text,
|
||||
'organizations' => $this->practitionerRoles->unique('organization_id')->map(function ($practitionerRole) {
|
||||
return [
|
||||
'organization_id' => $practitionerRole->organization->id,
|
||||
'organization_name' => $practitionerRole->organization->name,
|
||||
];
|
||||
}),
|
||||
"specialties" => $this->practitionerRoles->unique('speciality_id')->map(function ($practitionerRole) {
|
||||
return [
|
||||
'specialty_id' => $practitionerRole->speciality->id,
|
||||
'specialty_name' => $practitionerRole->speciality->name,
|
||||
];
|
||||
}),
|
||||
"departemen" => $this->practitionerRoles->map(function ($practitionerRole) {
|
||||
return [
|
||||
'departemen_id' => $practitionerRole->meta->DepartemenID,
|
||||
];
|
||||
}),
|
||||
'education' => $this->meta->education,
|
||||
'experience' => $this->meta->work_experience,
|
||||
'award' => $this->meta->award,
|
||||
'keilmuan' => $this->meta->Keilmuan,
|
||||
'tipe_dokter' => $this->meta->tipeDokter,
|
||||
|
||||
];
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ class OrganizationResource extends JsonResource
|
||||
public function toArray($request)
|
||||
{
|
||||
$organization = [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'type' => $this->type,
|
||||
'code' => $this->code,
|
||||
|
||||
@@ -17,6 +17,7 @@ class OrganizationSeeder extends Seeder
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
|
||||
$response = Http::get('https://app.primaya.id/temp/organizations');
|
||||
|
||||
foreach ($response->json()['organizations'] as $organization) {
|
||||
|
||||
@@ -33,8 +33,6 @@ class PractitionerSeeder extends Seeder
|
||||
// Meta::query()->where('metaable_type', PractitionerRole::class)->forceDelete();
|
||||
// Address::query()->where('addressable_type', Person::class)->forceDelete();
|
||||
|
||||
|
||||
|
||||
$mapSpecialities = [
|
||||
'Akupunktur' => 'SP027',
|
||||
'Anak' => 'SP001',
|
||||
@@ -125,7 +123,7 @@ class PractitionerSeeder extends Seeder
|
||||
$findSpecialityId = Speciality::where('name', $mapping)->first()->id;
|
||||
|
||||
$newPerson = Person::updateOrCreate([
|
||||
'nik' => $doctor['NIK']
|
||||
'name' => $doctor['Nama'],
|
||||
], [
|
||||
'nik' => (!empty($doctor['NIK'])) ? $doctor['NIK'] : null,
|
||||
'name' => $doctor['Nama'],
|
||||
@@ -195,41 +193,83 @@ class PractitionerSeeder extends Seeder
|
||||
// 'value' => $doctor['Description']
|
||||
// ]);
|
||||
|
||||
$newPractitionerRole = PractitionerRole::updateOrCreate([
|
||||
'practitioner_id' => $newPractitioner->id,
|
||||
'organization_id' => $organization->id,
|
||||
'speciality_id' => $findSpecialityId,
|
||||
'active' => 1,
|
||||
]);
|
||||
$ownedDepartemenIDs = $newPractitioner->practitionerRoles->pluck('meta.DepartemenID');
|
||||
|
||||
$this->command->info('Doctor : ' . $DokterID . '-' . $doctor['Nama'] . ' (Spesialisasi : ' . $mapping . ')');
|
||||
$DepartemenIDs = $doctor['departementIDs'];
|
||||
foreach ($DepartemenIDs as $DepartemenID) {
|
||||
$updatePractitionerRole = $newPractitioner->practitionerRoles->where('meta.DepartemenID', $DepartemenID)->first();
|
||||
|
||||
if (empty($newPractitionerRole->speciality_id)) {
|
||||
$newPractitionerRole->metas()->updateOrCreate([
|
||||
'type' => 'speciality_code',
|
||||
], [
|
||||
'system' => 'primaya-his',
|
||||
'type' => 'speciality_code',
|
||||
'value' => (!empty($doctor['KodeSpesialisasiID']) && $doctor['KodeSpesialisasiID'] != '-') ? $doctor['KodeSpesialisasiID'] : null
|
||||
]);
|
||||
|
||||
$newPractitionerRole->metas()->updateOrCreate([
|
||||
'type' => 'speciality',
|
||||
], [
|
||||
'system' => 'primaya-his',
|
||||
'type' => 'speciality',
|
||||
'value' => (!empty($doctor['spesialisasi']['Nama']) && $doctor['spesialisasi']['Nama'] != '-') ? $doctor['spesialisasi']['Nama'] : null
|
||||
]);
|
||||
if (empty($updatePractitionerRole)) {
|
||||
$updatePractitionerRole = $newPractitioner->practitionerRoles->where('meta.DokterID', $DokterID)->first();
|
||||
|
||||
if (!empty($updatePractitionerRole->meta->DepartemenID) && $updatePractitionerRole->meta->DepartemenID != $DepartemenID) {
|
||||
$updatePractitionerRole = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
isset($updatePractitionerRole)
|
||||
) {
|
||||
|
||||
$updatePractitionerRole->metas()->updateOrCreate([
|
||||
'type' => 'DepartemenID',
|
||||
], [
|
||||
'type' => 'DepartemenID',
|
||||
'system' => 'his',
|
||||
'value' => $DepartemenID
|
||||
]);
|
||||
|
||||
$newPractitioner->load('practitionerRoles');
|
||||
$this->command->info('Updating Practitioner Role : ' . $updatePractitionerRole->id . '-' . $DokterID . '-' . $doctor['Nama'] . '-' . $DepartemenID);
|
||||
} else {
|
||||
|
||||
$newPractitionerRole = PractitionerRole::Create([
|
||||
'practitioner_id' => $newPractitioner->id,
|
||||
'organization_id' => $organization->id,
|
||||
'speciality_id' => $findSpecialityId,
|
||||
'active' => 1,
|
||||
]);
|
||||
|
||||
if (empty($newPractitionerRole->speciality_id)) {
|
||||
$newPractitionerRole->metas()->updateOrCreate([
|
||||
'type' => 'speciality_code',
|
||||
], [
|
||||
'system' => 'primaya-his',
|
||||
'type' => 'speciality_code',
|
||||
'value' => (!empty($doctor['KodeSpesialisasiID']) && $doctor['KodeSpesialisasiID'] != '-') ? $doctor['KodeSpesialisasiID'] : null
|
||||
]);
|
||||
|
||||
$newPractitionerRole->metas()->updateOrCreate([
|
||||
'type' => 'speciality',
|
||||
], [
|
||||
'system' => 'primaya-his',
|
||||
'type' => 'speciality',
|
||||
'value' => (!empty($doctor['spesialisasi']['Nama']) && $doctor['spesialisasi']['Nama'] != '-') ? $doctor['spesialisasi']['Nama'] : null
|
||||
]);
|
||||
}
|
||||
|
||||
$newPractitionerRole->metas()->updateOrCreate([
|
||||
'type' => 'primaya-his',
|
||||
'type' => 'DokterID',
|
||||
], [
|
||||
'system' => 'primaya-his',
|
||||
'type' => 'DokterID',
|
||||
'value' => $DokterID
|
||||
]);
|
||||
|
||||
$newPractitionerRole->metas()->updateOrCreate([
|
||||
'type' => 'primaya-his',
|
||||
'type' => 'DepartemenID',
|
||||
], [
|
||||
'system' => 'primaya-his',
|
||||
'type' => 'DepartemenID',
|
||||
'value' => $DepartemenID
|
||||
]);
|
||||
|
||||
$this->command->info('Creating Practitioner Role : ' . $newPractitionerRole->id . '-' . $DokterID . '-' . $doctor['Nama'] . '-' . $DepartemenID);
|
||||
}
|
||||
}
|
||||
|
||||
$newPractitionerRole->metas()->updateOrCreate([
|
||||
'type' => 'primaya-his',
|
||||
'type' => 'DokterID',
|
||||
], [
|
||||
'system' => 'primaya-his',
|
||||
'type' => 'DokterID',
|
||||
'value' => $DokterID
|
||||
]);
|
||||
}
|
||||
|
||||
$hisOrganizationCode = $organization->meta->KodeRS ?? null;
|
||||
|
||||
51
frontend/dashboard/src/@types/doctor.tsx
Normal file
51
frontend/dashboard/src/@types/doctor.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
export type Organizations = {
|
||||
id: number;
|
||||
code: string;
|
||||
name: string;
|
||||
address: string;
|
||||
type: string;
|
||||
lat: string;
|
||||
lng: string;
|
||||
phone: string;
|
||||
timezone: string;
|
||||
active: boolean | number;
|
||||
};
|
||||
|
||||
export type PractitionerRole = {
|
||||
meta: string;
|
||||
practitioner_id: number;
|
||||
organization_id: number;
|
||||
identifier_id: number;
|
||||
speciality_id: number;
|
||||
period_start: string;
|
||||
period_end: string;
|
||||
active: boolean | number;
|
||||
};
|
||||
|
||||
export type Specialities = {
|
||||
id: number;
|
||||
code: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type Practitioner = {
|
||||
id: number;
|
||||
name: string;
|
||||
name_prefix: string;
|
||||
name_suffix: string;
|
||||
address: string;
|
||||
birth_date: string;
|
||||
birth_place: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
gender: string;
|
||||
description: string;
|
||||
avatar_url: string;
|
||||
doctor_id: string;
|
||||
education: string;
|
||||
experience: string;
|
||||
award: string;
|
||||
active: boolean | number;
|
||||
organizations?: Organizations[];
|
||||
specialities?: Specialities[];
|
||||
};
|
||||
51
frontend/dashboard/src/@types/organization.tsx
Normal file
51
frontend/dashboard/src/@types/organization.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
export type Organizations = {
|
||||
id: number;
|
||||
code: string;
|
||||
name: string;
|
||||
address: string;
|
||||
type: string;
|
||||
lat: string;
|
||||
lng: string;
|
||||
phone: string;
|
||||
timezone: string;
|
||||
active: boolean | number;
|
||||
province_id: number;
|
||||
city_id: number;
|
||||
district_id: number;
|
||||
village_id: number;
|
||||
postal_code: string;
|
||||
description: string;
|
||||
technology: string;
|
||||
support_services: string;
|
||||
merchant_code: string;
|
||||
merchant_key: string;
|
||||
image_url: string;
|
||||
region_groups: string;
|
||||
};
|
||||
|
||||
export type Provinces = {
|
||||
id: number;
|
||||
name: string;
|
||||
code: string;
|
||||
};
|
||||
|
||||
export type Cities = {
|
||||
id: number;
|
||||
name: string;
|
||||
code: string;
|
||||
province_id: number;
|
||||
};
|
||||
|
||||
export type Districts = {
|
||||
id: number;
|
||||
name: string;
|
||||
code: string;
|
||||
city_id: number;
|
||||
};
|
||||
|
||||
export type Villages = {
|
||||
id: number;
|
||||
name: string;
|
||||
code: string;
|
||||
district_id: number;
|
||||
};
|
||||
@@ -19,9 +19,7 @@ const navConfig = [
|
||||
// GENERAL
|
||||
// ----------------------------------------------------------------------
|
||||
{
|
||||
items: [
|
||||
{ title: 'Dashboard', path: '/dashboard', icon: ICONS.dashboard },
|
||||
],
|
||||
items: [{ title: 'Dashboard', path: '/dashboard', icon: ICONS.dashboard }],
|
||||
},
|
||||
|
||||
// Membership
|
||||
@@ -37,8 +35,8 @@ const navConfig = [
|
||||
{
|
||||
title: 'DOCTORS & HOSPITALS',
|
||||
children: [
|
||||
{ title: 'Doctors', path: '/doctors' },
|
||||
{ title: 'Hospitals', path: '/hospitals' },
|
||||
{ title: 'Doctors', path: '/master/doctors' },
|
||||
{ title: 'Hospitals', path: '/master/hospitals' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -62,16 +60,14 @@ const navConfig = [
|
||||
},
|
||||
{
|
||||
title: 'CASE MANAGEMENT',
|
||||
path: '/claims',
|
||||
path: '/claims',
|
||||
// children: [
|
||||
// { title: 'Request', path: '/case-request' },
|
||||
// ],
|
||||
},
|
||||
{
|
||||
title: 'CUSTOMER SERVICES',
|
||||
children: [
|
||||
{ title: 'Request', path: '/cs-request' },
|
||||
],
|
||||
children: [{ title: 'Request', path: '/cs-request' }],
|
||||
},
|
||||
{
|
||||
title: 'USER MANAGEMENT',
|
||||
|
||||
93
frontend/dashboard/src/pages/Master/Doctors/Create.tsx
Normal file
93
frontend/dashboard/src/pages/Master/Doctors/Create.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { paramCase } from 'change-case';
|
||||
import { useParams, useLocation } from 'react-router-dom';
|
||||
// @mui
|
||||
import { Container, Stack } from '@mui/material';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import Page from '../../../components/Page';
|
||||
import Form from './Form';
|
||||
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
|
||||
import axios from '../../../utils/axios';
|
||||
import { Practitioner } from '../../../@types/doctor';
|
||||
import ButtonBack from '../../../components/ButtonBack';
|
||||
|
||||
export default function Create() {
|
||||
const { themeStretch } = useSettings();
|
||||
const { id } = useParams();
|
||||
|
||||
const isEdit = id ? true : false;
|
||||
|
||||
const [currentPractitioner, setCurrentPractitioner] = useState<Practitioner>();
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit) {
|
||||
axios.get('/doctors/' + id).then((res) => {
|
||||
setCurrentPractitioner(res.data);
|
||||
});
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<Page title="Membership: Create a new Dokter">
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<Stack direction="row" alignItems="center">
|
||||
<ButtonBack />
|
||||
<HeaderBreadcrumbs
|
||||
heading={!isEdit ? 'Manage a new Dokter' : 'Manage Dokter'}
|
||||
links={[
|
||||
{ name: 'Master', href: '/master' },
|
||||
{
|
||||
name: 'Doctors',
|
||||
href: '/master/doctors',
|
||||
},
|
||||
{ name: !isEdit ? 'Create' : currentPractitioner?.name ?? '' },
|
||||
]}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
<Form
|
||||
// isSubmitting={isSubmitting}
|
||||
isEdit={isEdit}
|
||||
currentPractitioner={currentPractitioner}
|
||||
/>
|
||||
</Container>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
// const pageTitle = 'Create Data Dokter';
|
||||
// return (
|
||||
// <Page title={pageTitle}>
|
||||
// <Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
// <HeaderBreadcrumbs
|
||||
// heading={pageTitle}
|
||||
// links={[
|
||||
// {
|
||||
// name: 'Master',
|
||||
// href: '/master',
|
||||
// },
|
||||
// {
|
||||
// name: 'Dokter',
|
||||
// href: '/master/organizations/',
|
||||
// },
|
||||
// {
|
||||
// name: 'Create',
|
||||
// href: '/master/organizations/create/',
|
||||
// },
|
||||
// ]}
|
||||
// />
|
||||
|
||||
// <Grid container spacing={2}>
|
||||
// <Grid item xs={12}>
|
||||
// <Card sx={{ p: 2 }}>
|
||||
// <Form
|
||||
// isSubmitting={isSubmitting}
|
||||
// isEdit={isEdit}
|
||||
// currentOrganizations={currentOrganizations}
|
||||
// />
|
||||
// </Card>
|
||||
// </Grid>
|
||||
// </Grid>
|
||||
// </Container>
|
||||
// </Page>
|
||||
// );
|
||||
// }
|
||||
260
frontend/dashboard/src/pages/Master/Doctors/Form.tsx
Normal file
260
frontend/dashboard/src/pages/Master/Doctors/Form.tsx
Normal file
@@ -0,0 +1,260 @@
|
||||
import * as Yup from 'yup';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
|
||||
import Select, { SelectChangeEvent } from '@mui/material/Select';
|
||||
import * as React from 'react';
|
||||
|
||||
// form
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
// @mui
|
||||
import { styled } from '@mui/material/styles';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import {
|
||||
Box,
|
||||
Avatar,
|
||||
Button,
|
||||
ButtonGroup,
|
||||
Card,
|
||||
FormHelperText,
|
||||
Grid,
|
||||
Stack,
|
||||
Typography,
|
||||
TextField,
|
||||
Chip,
|
||||
} from '@mui/material';
|
||||
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
|
||||
// components
|
||||
import {
|
||||
FormProvider,
|
||||
RHFTextField,
|
||||
RHFRadioGroup,
|
||||
RHFUploadAvatar,
|
||||
RHFSwitch,
|
||||
RHFEditor,
|
||||
RHFDatepicker,
|
||||
RHFMultiCheckbox,
|
||||
RHFCheckbox,
|
||||
RHFCustomMultiCheckbox,
|
||||
} from '../../../components/hook-form';
|
||||
import axios from '../../../utils/axios';
|
||||
import { fCurrency } from '../../../utils/formatNumber';
|
||||
import { Practitioner } from '../../../@types/doctor';
|
||||
|
||||
import { Label, Rowing } from '@mui/icons-material';
|
||||
|
||||
const LabelStyle = styled(Typography)(({ theme }) => ({
|
||||
...theme.typography.subtitle2,
|
||||
color: theme.palette.text.secondary,
|
||||
marginBottom: theme.spacing(1),
|
||||
}));
|
||||
|
||||
const HeaderStyle = styled('header')(({ theme }) => ({
|
||||
paddingBottom: theme.spacing(5),
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
}));
|
||||
|
||||
const Title = styled(Typography)(({ theme }) => ({
|
||||
...theme.typography.h4,
|
||||
boxShadow: 'none',
|
||||
// paddingBottom: theme.spacing(3),
|
||||
fontWeight: 700,
|
||||
color: '#005B7F',
|
||||
}));
|
||||
|
||||
interface FormValuesProps extends Partial<Practitioner> {
|
||||
taxes: boolean;
|
||||
inStock: boolean;
|
||||
}
|
||||
|
||||
type Props = {
|
||||
isEdit: boolean;
|
||||
currentPractitioner?: Practitioner;
|
||||
};
|
||||
|
||||
const Span = styled(Typography)(({ theme }) => ({
|
||||
boxShadow: 'none',
|
||||
paddingBottom: theme.spacing(1),
|
||||
}));
|
||||
|
||||
const Text = styled(Typography)(({ theme }) => ({
|
||||
boxShadow: 'none',
|
||||
paddingBottom: theme.spacing(3),
|
||||
}));
|
||||
|
||||
export default function PractitionerForm({ isEdit, currentPractitioner }: Props) {
|
||||
const navigate = useNavigate();
|
||||
const [practitioner_group, setPractitionerGroups] = useState([]);
|
||||
|
||||
// const [ errors, setErrors ] = useState<{ [key: string]: string }>({});
|
||||
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const NewCorporateSchema = Yup.object().shape({
|
||||
name: Yup.string().required('Name is required'),
|
||||
// file: Yup.boolean().required('Corporate Status is required'),
|
||||
});
|
||||
|
||||
const defaultValues = useMemo(
|
||||
() => ({
|
||||
id: currentPractitioner?.id,
|
||||
name: currentPractitioner?.name || '',
|
||||
address: currentPractitioner?.address || '',
|
||||
birth_date: currentPractitioner?.birth_date || '',
|
||||
gender: currentPractitioner?.gender || '',
|
||||
description: currentPractitioner?.description || '',
|
||||
birth_place: currentPractitioner?.birth_place || '',
|
||||
active: currentPractitioner?.active === 1 ? true : false,
|
||||
avatar_url: currentPractitioner?.avatar_url || '',
|
||||
doctor_id: currentPractitioner?.doctor_id || '',
|
||||
organizations: currentPractitioner?.organizations || [],
|
||||
specialities: currentPractitioner?.specialities || [],
|
||||
}),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[currentPractitioner]
|
||||
);
|
||||
|
||||
console.log('defaultValues', defaultValues);
|
||||
|
||||
function StatusLabel({ value }: { value: boolean }) {
|
||||
return (
|
||||
<Chip
|
||||
label={value ? 'Aktif' : 'Tidak Aktif'}
|
||||
size="medium"
|
||||
sx={{
|
||||
backgroundColor: value ? 'rgba(84, 214, 44, 0.16)' : 'rgba(255, 72, 66, 0.16)',
|
||||
color: value ? '#229A16' : '#B72136',
|
||||
padding: '1 8 1 8 px',
|
||||
borderRadius: '4px',
|
||||
fontSize: '12px',
|
||||
fontWeight: 'bold',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
const methods = useForm<FormValuesProps>({
|
||||
resolver: yupResolver(NewCorporateSchema),
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
const {
|
||||
reset,
|
||||
watch,
|
||||
control,
|
||||
setValue,
|
||||
getValues,
|
||||
setError,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
} = methods;
|
||||
|
||||
const values = watch();
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit && currentPractitioner) {
|
||||
reset(defaultValues);
|
||||
}
|
||||
if (!isEdit) {
|
||||
reset(defaultValues);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isEdit, currentPractitioner]);
|
||||
|
||||
const handleActivate = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setValue('active', event.target.checked);
|
||||
|
||||
console.log('event.target.checked', event.target.checked);
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('active', event.target.checked ? '1' : '0');
|
||||
formData.append('_method', 'PUT');
|
||||
axios.post('/doctors/' + currentPractitioner?.id ?? '', formData);
|
||||
|
||||
enqueueSnackbar('active Updated Successfully!', { variant: 'success' });
|
||||
};
|
||||
|
||||
return (
|
||||
<FormProvider methods={methods}>
|
||||
<Stack spacing={3}>
|
||||
<Box sx={{ width: '100%' }}>
|
||||
{/* <Stack spacing={3}> */}
|
||||
<Card sx={{ p: 5 }}>
|
||||
<HeaderStyle>
|
||||
<Grid item xs={6} md={6}>
|
||||
<Title>Data Dokter</Title>
|
||||
</Grid>
|
||||
<Grid item xs={6} md={6}>
|
||||
{/* <Typography>Status Rumah Sakit</Typography> */}
|
||||
<RHFSwitch name="active" label="" onClick={handleActivate} />
|
||||
<StatusLabel value={values.active} />
|
||||
</Grid>
|
||||
</HeaderStyle>
|
||||
<Title variant="h5">Informasi Umum</Title>
|
||||
<Avatar
|
||||
alt="Remy Sharp"
|
||||
src={currentPractitioner?.avatar_url}
|
||||
sx={{ width: 120, height: 120, marginBottom: 2 }}
|
||||
/>
|
||||
|
||||
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||
<Grid item xs={7}>
|
||||
<Span style={{ fontWeight: 'bold' }}>Nama Dokter</Span>
|
||||
<Text>{currentPractitioner?.name ? currentPractitioner?.name : '-'}</Text>
|
||||
<Span style={{ fontWeight: 'bold' }}>No Telp</Span>
|
||||
<Text>{currentPractitioner?.phone ? currentPractitioner?.phone : '-'}</Text>
|
||||
<Span style={{ fontWeight: 'bold' }}>Tempat Lahir</Span>
|
||||
<Text>
|
||||
{currentPractitioner?.birth_place ? currentPractitioner?.birth_place : '-'}
|
||||
</Text>
|
||||
<Span style={{ fontWeight: 'bold' }}>Alamat</Span>
|
||||
<Text>{currentPractitioner?.address ? currentPractitioner?.address : '-'}</Text>
|
||||
</Grid>
|
||||
<Grid item xs={5} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||
<Span style={{ fontWeight: 'bold' }}>Jenis Kelamin</Span>
|
||||
<Text>{currentPractitioner?.gender ? currentPractitioner?.gender : '-'}</Text>
|
||||
<Span style={{ fontWeight: 'bold' }}>Email</Span>
|
||||
<Text>{currentPractitioner?.email ? currentPractitioner?.email : '-'}</Text>
|
||||
<Span style={{ fontWeight: 'bold' }}>Tanggal Lahir</Span>
|
||||
<Text>
|
||||
{currentPractitioner?.birth_date ? currentPractitioner?.birth_date : '-'}
|
||||
</Text>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Card>
|
||||
<Card sx={{ p: 5, marginTop: 2 }}>
|
||||
<Title variant="h5">Tempat Praktik</Title>
|
||||
{currentPractitioner?.organizations?.map((item, index) => (
|
||||
<Box key={index} sx={{ mt: 3 }}>
|
||||
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||
<Grid item xs={7}>
|
||||
<Text>{item.name}</Text>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
))}
|
||||
</Card>
|
||||
<Card sx={{ p: 5, marginTop: 2 }}>
|
||||
<Title variant="h5">Spesialisasi</Title>
|
||||
{currentPractitioner?.specialities?.map((item, index) => (
|
||||
<Box key={index} sx={{ mt: 3 }}>
|
||||
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||
<Grid item xs={7}>
|
||||
<Text>{item.name}</Text>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
))}
|
||||
</Card>
|
||||
</Box>
|
||||
</Stack>
|
||||
</FormProvider>
|
||||
);
|
||||
}
|
||||
35
frontend/dashboard/src/pages/Master/Doctors/Index.tsx
Normal file
35
frontend/dashboard/src/pages/Master/Doctors/Index.tsx
Normal file
@@ -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 Doctors() {
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const { id } = useParams();
|
||||
|
||||
const pageTitle = 'Manage Dokter';
|
||||
return (
|
||||
<Page title={pageTitle}>
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<HeaderBreadcrumbs
|
||||
heading={pageTitle}
|
||||
links={[
|
||||
{
|
||||
name: 'Master',
|
||||
href: '/master',
|
||||
},
|
||||
{
|
||||
name: 'Dokter',
|
||||
href: '/master/doctors',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<List />
|
||||
</Container>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
552
frontend/dashboard/src/pages/Master/Doctors/List.tsx
Normal file
552
frontend/dashboard/src/pages/Master/Doctors/List.tsx
Normal file
@@ -0,0 +1,552 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
Collapse,
|
||||
Paper,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
Stack,
|
||||
ButtonGroup,
|
||||
Grid,
|
||||
Chip,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogActions,
|
||||
FormControl,
|
||||
Autocomplete,
|
||||
InputAdornment,
|
||||
IconButton,
|
||||
} from '@mui/material';
|
||||
|
||||
import {
|
||||
Link,
|
||||
NavLink as RouterLink,
|
||||
useSearchParams,
|
||||
useNavigate,
|
||||
useParams,
|
||||
} from 'react-router-dom';
|
||||
// hooks
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
// components
|
||||
import axios from '../../../utils/axios';
|
||||
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||
import { Icd } from '../../../@types/diagnosis';
|
||||
import BasePagination from '../../../components/BasePagination';
|
||||
import { Practitioner } from '../../../@types/doctor';
|
||||
import CreateIcon from '@mui/icons-material/Create';
|
||||
import { Props } from '../../../components/editor/index';
|
||||
import { red } from '@mui/material/colors';
|
||||
import { margin, padding } from '@mui/system';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { Controller } from 'react-hook-form';
|
||||
|
||||
import SvgIconStyle from '../../../components/SvgIconStyle';
|
||||
import { GridSearchIcon } from '@mui/x-data-grid';
|
||||
import { Search } from '@mui/icons-material';
|
||||
import { Icon } from '@iconify/react';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function List() {
|
||||
// Generate the every row of the table
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { organization_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [searchParamsOrganizations, setSearchParamsOrganizations] = useSearchParams();
|
||||
const [searchParamsSpecialities, setSearchParamsSpecialities] = useSearchParams();
|
||||
const [searchParamsFilter, setSearchParamsFilter] = useSearchParams();
|
||||
|
||||
function Filter(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
const [seacrhOrganizations, setSearchOrganizations] = useState('');
|
||||
const [searchSpecialities, setSearchSpecialities] = useState('');
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
||||
//handle search
|
||||
const handleSearchChange = (event: any) => {
|
||||
const newSearchText = event.target.value ?? '';
|
||||
setSearchText(newSearchText);
|
||||
};
|
||||
|
||||
const handleSearchOrganizations = (event: any) => {
|
||||
const newSearchOrganizations = event.id ?? '';
|
||||
console.log(newSearchOrganizations);
|
||||
setSearchOrganizations(newSearchOrganizations);
|
||||
};
|
||||
|
||||
const handleSearchSpecialities = (event: any) => {
|
||||
const newSearchSpecialities = event.id ?? '';
|
||||
setSearchSpecialities(newSearchSpecialities);
|
||||
};
|
||||
|
||||
const handleSearchSubmit = (event: any) => {
|
||||
event.preventDefault();
|
||||
|
||||
props.onSearch(searchText, seacrhOrganizations, searchSpecialities);
|
||||
};
|
||||
|
||||
const [organization, setOrganization] = useState<any>([]);
|
||||
const [specialities, setSpecialities] = useState<any>([]);
|
||||
|
||||
useEffect(() => {
|
||||
axios.get(`/search-organizations`).then((response) => {
|
||||
setOrganization(response.data);
|
||||
});
|
||||
|
||||
axios.get(`/search-specialities`).then((response) => {
|
||||
setSpecialities(response.data);
|
||||
});
|
||||
|
||||
// Trigger First Search
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
setSearchOrganizations(searchParamsOrganizations.get('organization_id') ?? '');
|
||||
setSearchSpecialities(searchParamsSpecialities.get('speciality_id') ?? '');
|
||||
}, []);
|
||||
|
||||
const item = [
|
||||
{
|
||||
id: '',
|
||||
value: '',
|
||||
name: 'Semua',
|
||||
},
|
||||
];
|
||||
|
||||
//item search
|
||||
const dataOrganizations = item.concat(organization);
|
||||
const dataSpecialities = item.concat(specialities);
|
||||
|
||||
return (
|
||||
<form style={{ width: '100%' }}>
|
||||
<Grid container spacing={2} sx={{ justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Grid item xs={12} sm={12} md={8} lg={8}>
|
||||
<TextField
|
||||
id="search-input"
|
||||
ref={searchInput}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
onChange={handleSearchChange}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
handleSearchSubmit(event);
|
||||
}
|
||||
}}
|
||||
value={searchText}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<Search />
|
||||
</InputAdornment>
|
||||
),
|
||||
placeholder: 'Search',
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={4} md={2} lg={2}>
|
||||
<Autocomplete
|
||||
id="organizations"
|
||||
options={dataOrganizations}
|
||||
value={dataOrganizations.find((v) => v.id == seacrhOrganizations)}
|
||||
getOptionLabel={(option) => option.name}
|
||||
onChange={(event, value) => {
|
||||
handleSearchOrganizations(value);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
handleSearchSubmit(event);
|
||||
}
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Rumah Sakit" variant="outlined" fullWidth />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={4} md={2} lg={2}>
|
||||
<Autocomplete
|
||||
id="specialities"
|
||||
options={dataSpecialities}
|
||||
getOptionLabel={(option) => option.name}
|
||||
value={dataSpecialities.find((v) => v.id == searchSpecialities)}
|
||||
onChange={(event, value) => handleSearchSpecialities(value)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
handleSearchSubmit(event);
|
||||
}
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Spesialis" variant="outlined" fullWidth />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
function FilterForm(props: any) {
|
||||
// IMPORT
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
spacing={2}
|
||||
sx={{ p: 2, justifyContent: 'space-between', alignItems: 'center' }}
|
||||
>
|
||||
<Grid item xs={12} md={12} lg={12}>
|
||||
<Filter onSearch={applyItems} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
function createData(doctor: Practitioner): Practitioner {
|
||||
return {
|
||||
...doctor,
|
||||
};
|
||||
}
|
||||
|
||||
function CheckStatus(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
if (row.active === 1) {
|
||||
return (
|
||||
<Chip
|
||||
label="Aktif"
|
||||
size="small"
|
||||
sx={{
|
||||
backgroundColor: 'rgba(84, 214, 44, 0.16)',
|
||||
color: '#229A16',
|
||||
padding: '1 8 1 8 px',
|
||||
borderRadius: '4px',
|
||||
fontSize: '12px',
|
||||
fontWeight: 'bold',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Chip
|
||||
label="Tidak Aktif"
|
||||
size="small"
|
||||
sx={{
|
||||
backgroundColor: 'rgba(255, 72, 66, 0.16)',
|
||||
color: '#B72136',
|
||||
padding: '1 8 1 8 px',
|
||||
borderRadius: '4px',
|
||||
fontSize: '12px',
|
||||
fontWeight: 'bold',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [openDialog, setOpenDialog] = React.useState(false);
|
||||
|
||||
const handleDelete = (model: any) => {
|
||||
axios
|
||||
.delete(`/doctors/${row.id}`)
|
||||
.then((res) => {
|
||||
setDataTableData({
|
||||
...dataTableData,
|
||||
data: dataTableData.data.filter((model) => model.id != row.id),
|
||||
});
|
||||
enqueueSnackbar('Data berhasil dihapus', { variant: 'success' });
|
||||
})
|
||||
.catch((error) => {
|
||||
enqueueSnackbar(
|
||||
error.response.data.message ?? error.message ?? 'Failed Processing Request',
|
||||
{ variant: 'error' }
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.name ? row.name : '-'}</TableCell>
|
||||
|
||||
<TableCell align="left">
|
||||
{row.organizations?.map((org) => org.organization_name).join(', ') ?? '-'}
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
{row.specialties ? row.specialties.map((spec) => spec.specialty_name).join(', ') : '-'}
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.address ? row.address : '-'}</TableCell>
|
||||
{/* <TableCell align="left">
|
||||
<CheckStatus row={row} />
|
||||
</TableCell> */}
|
||||
|
||||
{/* <TableCell align="center">
|
||||
<ButtonGroup variant="text" aria-label="text button group">
|
||||
<Link to={'/master/doctors/' + row.id}>
|
||||
<Button>
|
||||
<Icon icon="ph:eye-bold" style={{ width: '24px', height: '24px' }} />
|
||||
</Button>
|
||||
</Link>
|
||||
</ButtonGroup>
|
||||
</TableCell> */}
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
<TableCell
|
||||
style={{ paddingBottom: 0, paddingTop: 0, backgroundColor: 'rgba(244, 246, 248, 0.5)' }}
|
||||
colSpan={9999}
|
||||
>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ margin: 1, pb: 2, pl: 4 }}>
|
||||
<Grid container>
|
||||
<Grid item xs={6} sx={{ padding: 2 }}>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
Pendidikan
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.education ? row.education : '-'}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
Pengalaman Kerja
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.experience ? row.experience : '-'}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
Jenis Kelamin
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.gender ? row.gender : '-'}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={6} sx={{ padding: 2 }}>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
Email
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.email ? row.email : '-'}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
No. Telp
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.phone ? row.phone : '-'}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
Penghargaan
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.award ? row.award : '-'}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
{/* END COLLAPSIBLE ROW */}
|
||||
|
||||
<Dialog
|
||||
open={openDialog}
|
||||
onClose={() => {
|
||||
setOpenDialog(false);
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogContent sx={{ p: 5 }}>
|
||||
<Icon
|
||||
icon="eva:trash-2-outline"
|
||||
style={{
|
||||
width: '100px',
|
||||
height: '100px',
|
||||
color: '#FF0000',
|
||||
margin: 'auto',
|
||||
display: 'block',
|
||||
marginBottom: '20px',
|
||||
alignContent: 'center',
|
||||
}}
|
||||
/>
|
||||
<DialogContentText sx={{ fontWeight: 'bold', pb: 1 }} id="alert-dialog-title">
|
||||
Apakah anda yakin ingin menghapus
|
||||
</DialogContentText>
|
||||
<Typography sx={{ fontWeight: 'bold' }} id="alert-dialog-title">
|
||||
{row.name}?
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setOpenDialog(false);
|
||||
}}
|
||||
color="primary"
|
||||
>
|
||||
Batal
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleDelete(row.id);
|
||||
}}
|
||||
color="primary"
|
||||
autoFocus
|
||||
>
|
||||
Hapus
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
// Dummy Default Data
|
||||
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||
const [dataTableLastRequest, setDataTableLastRequest] = useState(0);
|
||||
const [dataTableResponseState, setDataTableResponseState] = useState('idle');
|
||||
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>({
|
||||
current_page: 1,
|
||||
data: [],
|
||||
path: '',
|
||||
first_page_url: '',
|
||||
last_page: 1,
|
||||
last_page_url: '',
|
||||
next_page_url: '',
|
||||
prev_page_url: '',
|
||||
per_page: 10,
|
||||
from: 0,
|
||||
to: 0,
|
||||
total: 0,
|
||||
});
|
||||
const [dataTablePage, setDataTablePage] = useState(5);
|
||||
|
||||
const loadDataTableData = async (appliedFilter: any | null = null) => {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const response = await axios.get('/doctors', {
|
||||
params: filter,
|
||||
});
|
||||
setDataTableLoading(false);
|
||||
setDataTableData(response.data);
|
||||
};
|
||||
|
||||
// const applyFilter = async (searchFilter: string) => {
|
||||
// await loadDataTableData({ search: searchFilter });
|
||||
// setSearchParams({ search: searchFilter });
|
||||
// };
|
||||
|
||||
const applyItems = async (
|
||||
searchFilter: string,
|
||||
searchFilterOrganization: string,
|
||||
searchFilterSpecialities: string
|
||||
) => {
|
||||
await loadDataTableData({
|
||||
search: searchFilter,
|
||||
organization_id: searchFilterOrganization,
|
||||
speciality_id: searchFilterSpecialities,
|
||||
});
|
||||
setSearchParamsFilter({
|
||||
search: searchFilter,
|
||||
organization_id: searchFilterOrganization,
|
||||
speciality_id: searchFilterSpecialities,
|
||||
});
|
||||
};
|
||||
|
||||
const handlePageChange = (event: ChangeEvent, value: number) => {
|
||||
const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]);
|
||||
loadDataTableData(filter);
|
||||
setSearchParams(filter);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
{/* <Ambulace /> */}
|
||||
|
||||
<Card sx={{ marginTop: '30px' }}>
|
||||
<FilterForm sx={{ marginTop: '100px' }} />
|
||||
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" />
|
||||
<TableCell style={headStyle} align="left">
|
||||
Nama Dokter
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Rumah Sakit
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Spesialis
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Alamat
|
||||
</TableCell>
|
||||
{/* <TableCell style={headStyle} align="center">
|
||||
Aksi
|
||||
</TableCell> */}
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
{dataTableIsLoading ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">
|
||||
Loading
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : dataTableData.data.length == 0 ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">
|
||||
No Data
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody>
|
||||
{dataTableData.data.map((row) => (
|
||||
<Row key={row.id} row={row} />
|
||||
))}
|
||||
</TableBody>
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||
</Card>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
56
frontend/dashboard/src/pages/Master/Hospitals/Create.tsx
Normal file
56
frontend/dashboard/src/pages/Master/Hospitals/Create.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { paramCase } from 'change-case';
|
||||
import { useParams, useLocation } from 'react-router-dom';
|
||||
// @mui
|
||||
import { Container, Stack } from '@mui/material';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import Page from '../../../components/Page';
|
||||
import Form from './Form';
|
||||
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
|
||||
import axios from '../../../utils/axios';
|
||||
import { Organizations } from '../../../@types/organization';
|
||||
import ButtonBack from '../../../components/ButtonBack';
|
||||
|
||||
export default function Create() {
|
||||
const { themeStretch } = useSettings();
|
||||
const { id } = useParams();
|
||||
|
||||
const isEdit = id ? true : false;
|
||||
|
||||
const [currentOrganizations, setCurrentOrganizations] = useState<Organizations>();
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit) {
|
||||
axios.get('/organizations/' + id + '/edit').then((res) => {
|
||||
setCurrentOrganizations(res.data);
|
||||
});
|
||||
}
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<Page title="Membership: Create a new Rumah Sakit">
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<Stack direction="row" alignItems="center">
|
||||
<ButtonBack />
|
||||
<HeaderBreadcrumbs
|
||||
heading={!isEdit ? 'Create a new Rumah Sakit' : 'Edit Rumah Sakit'}
|
||||
links={[
|
||||
{ name: 'Master', href: '/master' },
|
||||
{
|
||||
name: 'Organizations',
|
||||
href: '/master/organizations',
|
||||
},
|
||||
{ name: !isEdit ? 'Create' : currentOrganizations?.name ?? '' },
|
||||
]}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
<Form
|
||||
// isSubmitting={isSubmitting}
|
||||
isEdit={isEdit}
|
||||
currentOrganizations={currentOrganizations}
|
||||
/>
|
||||
</Container>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
778
frontend/dashboard/src/pages/Master/Hospitals/Form.tsx
Normal file
778
frontend/dashboard/src/pages/Master/Hospitals/Form.tsx
Normal file
@@ -0,0 +1,778 @@
|
||||
import * as Yup from 'yup';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
|
||||
import Select, { SelectChangeEvent } from '@mui/material/Select';
|
||||
import * as React from 'react';
|
||||
|
||||
// form
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
// @mui
|
||||
import { styled } from '@mui/material/styles';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
ButtonGroup,
|
||||
Card,
|
||||
Grid,
|
||||
Stack,
|
||||
Typography,
|
||||
TextField,
|
||||
Tab,
|
||||
Chip,
|
||||
Autocomplete,
|
||||
} from '@mui/material';
|
||||
|
||||
import TabContext from '@mui/lab/TabContext';
|
||||
import TabList from '@mui/lab/TabList';
|
||||
import TabPanel from '@mui/lab/TabPanel';
|
||||
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
|
||||
// components
|
||||
import {
|
||||
FormProvider,
|
||||
RHFTextField,
|
||||
RHFRadioGroup,
|
||||
RHFUploadAvatar,
|
||||
RHFSwitch,
|
||||
RHFSelect,
|
||||
RHFEditor,
|
||||
RHFDatepicker,
|
||||
RHFMultiCheckbox,
|
||||
RHFCheckbox,
|
||||
RHFCustomMultiCheckbox,
|
||||
} from '../../../components/hook-form';
|
||||
import axios from '../../../utils/axios';
|
||||
import { fCurrency } from '../../../utils/formatNumber';
|
||||
import { Organizations } from '../../../@types/organization';
|
||||
import { Provinces } from '../../../@types/organization';
|
||||
import { Cities } from '../../../@types/organization';
|
||||
import { Districts } from '../../../@types/organization';
|
||||
import { Villages } from '../../../@types/organization';
|
||||
|
||||
import { Label } from '@mui/icons-material';
|
||||
import MyDropzone from '../../../components/MyDropzone';
|
||||
|
||||
const LabelStyle = styled(Typography)(({ theme }) => ({
|
||||
...theme.typography.h6,
|
||||
marginBottom: theme.spacing(2),
|
||||
marginTop: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const HeaderStyle = styled('header')(({ theme }) => ({
|
||||
padding: theme.spacing(5),
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
}));
|
||||
|
||||
const Title = styled(Typography)(({ theme }) => ({
|
||||
...theme.typography.h4,
|
||||
boxShadow: 'none',
|
||||
// paddingBottom: theme.spacing(3),
|
||||
fontWeight: 700,
|
||||
color: '#005B7F',
|
||||
}));
|
||||
|
||||
// const [timezone, setTimezone] = React.useState('');
|
||||
|
||||
// const selectInput = (event: SelectChangeEvent) => {
|
||||
// setTimezone(event.target.value as string);
|
||||
// const name = event.target.name;
|
||||
// const value = event.target.value;
|
||||
// setInputs((values) => ({ ...values, [name]: value }));
|
||||
// };
|
||||
// const [inputs, setInputs] = useState({});
|
||||
|
||||
interface FormValuesProps extends Partial<Organizations> {
|
||||
taxes: boolean;
|
||||
inStock: boolean;
|
||||
}
|
||||
|
||||
type Props = {
|
||||
isEdit: boolean;
|
||||
currentOrganizations?: Organizations;
|
||||
};
|
||||
|
||||
export default function OrganizationsForm({ isEdit, currentOrganizations }: Props) {
|
||||
const navigate = useNavigate();
|
||||
const [organizations_group, setOrganizationsGroups] = useState([]);
|
||||
|
||||
// const [ errors, setErrors ] = useState<{ [key: string]: string }>({});
|
||||
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const NewCorporateSchema = Yup.object().shape({
|
||||
name: Yup.string().required('Name is required'),
|
||||
code: Yup.string().required('Corporate Code is required'),
|
||||
active: Yup.boolean().required('Corporate Status is required'),
|
||||
lat: Yup.string().required('Latitude is required'),
|
||||
lng: Yup.string().required('Longitude is required'),
|
||||
timezone: Yup.string().required('Timezone is required'),
|
||||
// file: Yup.boolean().required('Corporate Status is required'),
|
||||
});
|
||||
|
||||
const defaultValues = useMemo(
|
||||
() => ({
|
||||
name: currentOrganizations?.name || '',
|
||||
code: currentOrganizations?.code || '',
|
||||
phone: currentOrganizations?.phone || '',
|
||||
lat: currentOrganizations?.lat || '',
|
||||
lng: currentOrganizations?.lng || '',
|
||||
address: currentOrganizations?.address || '',
|
||||
timezone: currentOrganizations?.timezone || '',
|
||||
active: currentOrganizations?.active === 1 ? true : false,
|
||||
province_id: currentOrganizations?.province_id || '',
|
||||
city_id: currentOrganizations?.city_id || '',
|
||||
district_id: currentOrganizations?.district_id || '',
|
||||
village_id: currentOrganizations?.village_id || '',
|
||||
postal_code: currentOrganizations?.postal_code || '',
|
||||
description: currentOrganizations?.description || '',
|
||||
technology: currentOrganizations?.technology || '',
|
||||
support_services: currentOrganizations?.support_services || '',
|
||||
merchant_code: currentOrganizations?.merchant_code || '',
|
||||
merchant_key: currentOrganizations?.merchant_key || '',
|
||||
image_url: currentOrganizations?.image_url || '',
|
||||
region_groups: currentOrganizations?.region_groups || '',
|
||||
}),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[currentOrganizations]
|
||||
);
|
||||
|
||||
console.log('defaultValues', defaultValues);
|
||||
|
||||
function StatusLabel({ value }: { value: boolean }) {
|
||||
return (
|
||||
<Chip
|
||||
label={value ? 'Aktif' : 'Tidak Aktif'}
|
||||
size="medium"
|
||||
sx={{
|
||||
backgroundColor: value ? 'rgba(84, 214, 44, 0.16)' : 'rgba(255, 72, 66, 0.16)',
|
||||
color: value ? '#229A16' : '#B72136',
|
||||
padding: '1 8 1 8 px',
|
||||
borderRadius: '4px',
|
||||
fontSize: '12px',
|
||||
fontWeight: 'bold',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const methods = useForm<FormValuesProps>({
|
||||
resolver: yupResolver(NewCorporateSchema),
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
const {
|
||||
reset,
|
||||
watch,
|
||||
control,
|
||||
setValue,
|
||||
getValues,
|
||||
setError,
|
||||
handleSubmit,
|
||||
formState: { isSubmitting },
|
||||
} = methods;
|
||||
|
||||
const values = watch();
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit && currentOrganizations) {
|
||||
reset(defaultValues);
|
||||
}
|
||||
if (!isEdit) {
|
||||
reset(defaultValues);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isEdit, currentOrganizations]);
|
||||
|
||||
const currentImage = currentOrganizations?.image_url;
|
||||
console.log('currentImage', currentImage);
|
||||
|
||||
console.log('current_image', currentImage);
|
||||
|
||||
const [file, setFile] = useState(null);
|
||||
console.log('file', file);
|
||||
|
||||
const onSubmit = async (data: FormValuesProps) => {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
console.log('data', data);
|
||||
formData.append('name', data.name);
|
||||
formData.append('code', data.code);
|
||||
formData.append('phone', data.phone);
|
||||
formData.append('lat', data.lat);
|
||||
formData.append('lng', data.lng);
|
||||
formData.append('address', data.address);
|
||||
formData.append('timezone', data.timezone);
|
||||
formData.append('active', data.active ? '1' : '0');
|
||||
if (data.province_id === currentOrganizations?.province_id) {
|
||||
formData.append('province_id', data.province_id);
|
||||
} else {
|
||||
formData.append('province_id', data.province_id?.value ?? '');
|
||||
}
|
||||
|
||||
if (data.city_id === currentOrganizations?.city_id) {
|
||||
formData.append('city_id', data.city_id);
|
||||
} else {
|
||||
formData.append('city_id', data.city_id?.value ?? '');
|
||||
}
|
||||
|
||||
if (data.district_id === currentOrganizations?.district_id) {
|
||||
formData.append('district_id', data.district_id);
|
||||
} else {
|
||||
formData.append('district_id', data.district_id?.value ?? '');
|
||||
}
|
||||
|
||||
if (data.village_id === currentOrganizations?.village_id) {
|
||||
formData.append('village_id', data.village_id);
|
||||
} else {
|
||||
formData.append('village_id', data.village_id?.value ?? '');
|
||||
}
|
||||
if (data.region_groups === currentOrganizations?.region_groups) {
|
||||
formData.append('region_groups', data.region_groups);
|
||||
} else {
|
||||
formData.append('region_groups', data.region_groups?.value ?? '');
|
||||
}
|
||||
|
||||
formData.append('postal_code', data.postal_code);
|
||||
formData.append('description', data.description);
|
||||
formData.append('technology', data.technology);
|
||||
formData.append('support_services', data.support_services);
|
||||
formData.append('merchant_code', data.merchant_code);
|
||||
formData.append('merchant_key', data.merchant_key);
|
||||
formData.append('image', file);
|
||||
|
||||
if (!isEdit) {
|
||||
const response = await axios.post('/organizations', formData);
|
||||
} else {
|
||||
formData.append('_method', 'PUT');
|
||||
const response = await axios.post(
|
||||
'/organizations/' + currentOrganizations?.id ?? '',
|
||||
formData
|
||||
);
|
||||
}
|
||||
reset();
|
||||
enqueueSnackbar(
|
||||
!isEdit ? 'Organizations Created Successfully!' : 'Organizations Udpated Successfully!',
|
||||
{ variant: 'success' }
|
||||
);
|
||||
navigate('/master/organizations');
|
||||
} catch (error: any) {
|
||||
if (error && error.response.status === 422) {
|
||||
for (const [key, value] of Object.entries(error.response.data.errors)) {
|
||||
setError(key, { message: value[0] });
|
||||
enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' });
|
||||
}
|
||||
} else {
|
||||
enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' });
|
||||
}
|
||||
}
|
||||
|
||||
const ascent = document?.querySelector('ascent');
|
||||
if (ascent != null) {
|
||||
ascent.innerHTML = '';
|
||||
}
|
||||
};
|
||||
|
||||
const [valueTab, setValueTab] = React.useState('1');
|
||||
|
||||
const handleChangeTab = (event: React.SyntheticEvent, newValueTab: string) => {
|
||||
setValueTab(newValueTab);
|
||||
};
|
||||
|
||||
const handleDrop = useCallback(
|
||||
(acceptedFiles) => {
|
||||
setValue(
|
||||
'logo',
|
||||
acceptedFiles.map((file: Blob | MediaSource) =>
|
||||
Object.assign(file, {
|
||||
preview: URL.createObjectURL(file),
|
||||
})
|
||||
)
|
||||
);
|
||||
},
|
||||
[setValue]
|
||||
);
|
||||
|
||||
const handleRemove = (file: File | string) => {
|
||||
setValue('logo', null);
|
||||
};
|
||||
|
||||
const [province, setProvince] = useState<any>([]);
|
||||
const [city, setCity] = useState<any>([]);
|
||||
const [district, setDistrict] = useState<any>([]);
|
||||
// const [village, setVillage] = useState<any>([]);
|
||||
|
||||
useEffect(() => {
|
||||
axios.get('/province').then((res) => {
|
||||
setProvince(res.data.data.map((item: any) => ({ value: item.id, label: item.name })));
|
||||
});
|
||||
|
||||
const loadCity = async () => {
|
||||
if (values.province_id == currentOrganizations?.province_id) {
|
||||
const res = await axios.get('/city?province_id=' + values.province_id);
|
||||
setCity(res.data.data.map((item: any) => ({ value: item.id, label: item.name })));
|
||||
} else {
|
||||
const res = await axios.get('/city?province_id=' + values.province_id?.value);
|
||||
setCity(res.data.data.map((item: any) => ({ value: item.id, label: item.name })));
|
||||
}
|
||||
};
|
||||
|
||||
const loadDistrict = async () => {
|
||||
if (values.city_id == currentOrganizations?.city_id) {
|
||||
const res = await axios.get('/district?city_id=' + values.city_id);
|
||||
setDistrict(res.data.data.map((item: any) => ({ value: item.id, label: item.name })));
|
||||
} else {
|
||||
const res = await axios.get('/district?city_id=' + values.city_id?.value);
|
||||
setDistrict(res.data.data.map((item: any) => ({ value: item.id, label: item.name })));
|
||||
}
|
||||
};
|
||||
|
||||
// if (values.province_id) {
|
||||
// if (values.city_id) {
|
||||
// loadDistrict();
|
||||
// } else {
|
||||
// loadCity();
|
||||
// }
|
||||
// } else {
|
||||
// axios.get('/province').then((res) => {
|
||||
// setProvince(res.data.data.map((item: any) => ({ value: item.id, label: item.name })));
|
||||
// });
|
||||
// }
|
||||
|
||||
if (values.province_id) {
|
||||
loadCity();
|
||||
}
|
||||
|
||||
if (values.city_id) {
|
||||
loadDistrict();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [values.province_id, values.city_id, values.district_id]);
|
||||
|
||||
console.log('province', values.province_id);
|
||||
console.log('city', values.city_id);
|
||||
console.log('district', values.district_id);
|
||||
|
||||
const findValueProvince = province.find(
|
||||
(item: any) => item.value === currentOrganizations?.province_id
|
||||
);
|
||||
const findValueCity = city.find((item: any) => item.value === currentOrganizations?.city_id);
|
||||
const findValueDistrict = district.find(
|
||||
(item: any) => item.value === currentOrganizations?.district_id
|
||||
);
|
||||
|
||||
console.log('findValueProvince', findValueProvince);
|
||||
console.log('findValueCity', findValueCity);
|
||||
console.log('findValueDistrict', findValueDistrict);
|
||||
const timezone = [
|
||||
{
|
||||
value: 'WIB',
|
||||
label: 'WIB',
|
||||
},
|
||||
{
|
||||
value: 'WITA',
|
||||
label: 'WITA',
|
||||
},
|
||||
{
|
||||
value: 'WIT',
|
||||
label: 'WIT',
|
||||
},
|
||||
];
|
||||
const region_groups = [
|
||||
{
|
||||
value: 'Jabodetabek',
|
||||
label: 'Jabodetabek',
|
||||
},
|
||||
{
|
||||
value: 'Jawa',
|
||||
label: 'Jawa',
|
||||
},
|
||||
{
|
||||
value: 'Kalimantan',
|
||||
label: 'Kalimantan',
|
||||
},
|
||||
{
|
||||
value: 'Papua',
|
||||
label: 'Papua',
|
||||
},
|
||||
{
|
||||
value: 'Sulawesi',
|
||||
label: 'Sulawesi',
|
||||
},
|
||||
{
|
||||
value: 'Sumatera',
|
||||
label: 'Sumatera',
|
||||
},
|
||||
];
|
||||
|
||||
const findVaalueGroupWilayah = region_groups.find(
|
||||
(item: any) => item.value === currentOrganizations?.region_groups
|
||||
);
|
||||
|
||||
return (
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<Stack spacing={3}>
|
||||
<Card sx={{ p: 5 }}>
|
||||
<HeaderStyle>
|
||||
<Grid item xs={6} md={6}>
|
||||
<Title>Data Rumah Sakit</Title>
|
||||
</Grid>
|
||||
<Grid item xs={6} md={6}>
|
||||
{/* <Typography>Status Rumah Sakit</Typography> */}
|
||||
<RHFSwitch name="active" label="" />
|
||||
<StatusLabel value={values.active} />
|
||||
</Grid>
|
||||
</HeaderStyle>
|
||||
<Box sx={{ width: '100%', typography: 'body1' }}>
|
||||
<TabContext value={valueTab}>
|
||||
<Box
|
||||
sx={{
|
||||
borderBottom: 1,
|
||||
borderColor: 'divider',
|
||||
backgroundColor: '#F4F6F8',
|
||||
pl: 5,
|
||||
pr: 5,
|
||||
}}
|
||||
>
|
||||
<TabList onChange={handleChangeTab} aria-label="lab API tabs example">
|
||||
<Tab label="Rumah Sakit" value="1" sx={{ pr: 5, pl: 5 }} />
|
||||
<Tab label="Informasi" value="2" sx={{ pr: 5, pl: 5 }} />
|
||||
<Tab label="Duitku Setting" value="3" sx={{ pr: 5, pl: 5 }} />
|
||||
</TabList>
|
||||
</Box>
|
||||
<TabPanel value="1">
|
||||
<Box sx={{ width: '100%', p: 5 }}>
|
||||
<Grid container rowSpacing={4} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||
<Grid item xs={12}>
|
||||
<LabelStyle>Nama Rumah Sakit</LabelStyle>
|
||||
<RHFTextField name="name" placeholder="Tuliskan Nama Rumah Sakit" />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<LabelStyle>Pilih Foto Rumah Sakit</LabelStyle>
|
||||
<Box sx={{ width: '100%' }}>
|
||||
<MyDropzone setFile={setFile} currentImage={currentImage} />
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<LabelStyle>Nomor IGD</LabelStyle>
|
||||
<RHFTextField name="phone" placeholder="Tuliskan No IGD" />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<LabelStyle>Code Rumah Sakit</LabelStyle>
|
||||
<RHFTextField name="code" placeholder="Tuliskan Code Rumah Sakit" />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<LabelStyle>Group Wilayah</LabelStyle>
|
||||
<Controller
|
||||
name="region_groups"
|
||||
control={control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Autocomplete
|
||||
id="combo-box-demo"
|
||||
options={region_groups}
|
||||
getOptionLabel={(option) =>
|
||||
option.label ?? findVaalueGroupWilayah?.label ?? ''
|
||||
}
|
||||
value={value}
|
||||
onChange={(event: any, newValue: any) => {
|
||||
console.log('newValue', newValue);
|
||||
setValue('region_groups', newValue?.value);
|
||||
onChange(newValue);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="Group Wilayah"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<LabelStyle>Alamat</LabelStyle>
|
||||
<RHFTextField name="address" placeholder="Tuliskan Alamat" />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<LabelStyle>Provinsi</LabelStyle>
|
||||
{/*
|
||||
<Controller
|
||||
name="province_id"
|
||||
control={control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Select
|
||||
className="input-container"
|
||||
size="medium"
|
||||
disabled={!province?.length}
|
||||
value={value}
|
||||
onChange={(e: any) => {
|
||||
onChange(e);
|
||||
}}
|
||||
fullWidth
|
||||
MenuProps={{
|
||||
PaperProps: {
|
||||
sx: {
|
||||
maxHeight: 224,
|
||||
width: 250,
|
||||
p: 1,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{province?.map((item: any) => (
|
||||
<MenuItem key={item.value} value={item.value}>
|
||||
{item.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
/> */}
|
||||
|
||||
<Controller
|
||||
name="province_id"
|
||||
control={control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Autocomplete
|
||||
id="combo-box-demo"
|
||||
options={province}
|
||||
getOptionLabel={(option) =>
|
||||
option.label ?? findValueProvince?.label ?? ''
|
||||
}
|
||||
value={value}
|
||||
onChange={(event: any, newValue: any) => {
|
||||
console.log('newValue', newValue);
|
||||
setValue('province_id', newValue?.value);
|
||||
onChange(newValue);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="Provinsi"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<LabelStyle>Kabupaten / Kota</LabelStyle>
|
||||
{/* <Controller
|
||||
name="city_id"
|
||||
control={control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Select
|
||||
className="input-container"
|
||||
size="medium"
|
||||
disabled={!city?.length}
|
||||
value={value}
|
||||
onChange={(e: any) => {
|
||||
onChange(e);
|
||||
}}
|
||||
fullWidth
|
||||
MenuProps={{
|
||||
PaperProps: {
|
||||
sx: {
|
||||
maxHeight: 224,
|
||||
width: 250,
|
||||
p: 1,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{city?.map((item: any) => (
|
||||
<MenuItem key={item.value} value={item.value}>
|
||||
{item.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
/> */}
|
||||
<Controller
|
||||
name="city_id"
|
||||
control={control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Autocomplete
|
||||
id="combo-box-demo"
|
||||
options={city}
|
||||
getOptionLabel={(option) => option.label ?? findValueCity?.label ?? ''}
|
||||
value={value}
|
||||
onChange={(event: any, newValue: any) => {
|
||||
console.log('newValue', newValue);
|
||||
setValue('city_id', newValue?.value);
|
||||
onChange(newValue);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="Kabupaten / Kota"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={6}>
|
||||
<LabelStyle>Kecamatan</LabelStyle>
|
||||
|
||||
{/* <Controller
|
||||
name="district_id"
|
||||
control={control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Select
|
||||
className="input-container"
|
||||
size="medium"
|
||||
disabled={!district?.length}
|
||||
value={value}
|
||||
onChange={(e: any) => {
|
||||
onChange(e);
|
||||
}}
|
||||
fullWidth
|
||||
MenuProps={{
|
||||
PaperProps: {
|
||||
sx: {
|
||||
maxHeight: 224,
|
||||
width: 250,
|
||||
p: 1,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{district?.map((item: any) => (
|
||||
<MenuItem key={item.value} value={item.value}>
|
||||
{item.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
/> */}
|
||||
|
||||
<Controller
|
||||
name="district_id"
|
||||
control={control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<Autocomplete
|
||||
id="combo-box-demo"
|
||||
options={district}
|
||||
getOptionLabel={(option) =>
|
||||
option.label ?? findValueDistrict?.label ?? ''
|
||||
}
|
||||
value={value}
|
||||
onChange={(event: any, newValue: any) => {
|
||||
console.log('newValue', newValue);
|
||||
setValue('district_id', newValue?.value);
|
||||
onChange(newValue);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="Kecamatan"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={6}>
|
||||
<LabelStyle>Kode Pos</LabelStyle>
|
||||
<RHFTextField name="postal_code" placeholder="Tuliskan Kode Pos" />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<LabelStyle>Latitude</LabelStyle>
|
||||
<RHFTextField name="lat" placeholder="Tuliskan Lattitude" />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<LabelStyle>Longitude</LabelStyle>
|
||||
<RHFTextField name="lng" placeholder="Tuliskan Longitude" />
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<LabelStyle>Timezone</LabelStyle>
|
||||
{/* <RHFTextField name="timezone" /> */}
|
||||
<RHFSelect name="timezone" label="Pilih Timezone">
|
||||
<option value="" />
|
||||
{timezone.map((option, index) => (
|
||||
<option key={index} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</RHFSelect>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</TabPanel>
|
||||
<TabPanel value="2">
|
||||
<Box sx={{ width: '100%', p: 5 }}>
|
||||
<Grid container rowSpacing={4} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||
<Grid item xs={12}>
|
||||
<LabelStyle>Deskripsi</LabelStyle>
|
||||
<RHFEditor name="description" placeholder="Tuliskan Deskripsi" />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<LabelStyle>Teknologi</LabelStyle>
|
||||
<RHFEditor name="technology" placeholder="Tuliskan Teknologi" />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<LabelStyle>Layanan Penunjang</LabelStyle>
|
||||
<RHFEditor name="support_services" placeholder="Tuliskan Layanan Penunjang" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</TabPanel>
|
||||
<TabPanel value="3">
|
||||
<Box sx={{ width: '100%', p: 5 }}>
|
||||
<Grid container rowSpacing={4} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
|
||||
<Grid item xs={12}>
|
||||
<LabelStyle>Merchant Code</LabelStyle>
|
||||
<RHFTextField name="merchant_code" placeholder="Tuliskan Merchant Code" />
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<LabelStyle>Merchant Key</LabelStyle>
|
||||
<RHFTextField name="merchant_key" placeholder="Tuliskan Merchant Key" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</TabPanel>
|
||||
</TabContext>
|
||||
</Box>
|
||||
<Box sx={{ width: '100%', p: 5 }}>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
justifyContent="end"
|
||||
direction={{ xs: 'column', md: 'row' }}
|
||||
sx={{ width: 1, textAlign: { xs: 'center', md: 'left' } }}
|
||||
>
|
||||
<Grid item xs={12} md={4}>
|
||||
<LoadingButton
|
||||
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)' }}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="large"
|
||||
// fullWidth={true}
|
||||
loading={isSubmitting}
|
||||
>
|
||||
{!isEdit ? 'Simpan' : 'Simpan Perubahan'}
|
||||
</LoadingButton>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Card>
|
||||
</Stack>
|
||||
</FormProvider>
|
||||
);
|
||||
}
|
||||
35
frontend/dashboard/src/pages/Master/Hospitals/Index.tsx
Normal file
35
frontend/dashboard/src/pages/Master/Hospitals/Index.tsx
Normal file
@@ -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 Organizations() {
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
const { id } = useParams();
|
||||
|
||||
const pageTitle = 'Rumah Sakit';
|
||||
return (
|
||||
<Page title={pageTitle}>
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<HeaderBreadcrumbs
|
||||
heading={pageTitle}
|
||||
links={[
|
||||
{
|
||||
name: 'Master',
|
||||
href: '/master',
|
||||
},
|
||||
{
|
||||
name: 'Rumah Sakit',
|
||||
href: '/master/organizations',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<List />
|
||||
</Container>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
485
frontend/dashboard/src/pages/Master/Hospitals/List.tsx
Normal file
485
frontend/dashboard/src/pages/Master/Hospitals/List.tsx
Normal file
@@ -0,0 +1,485 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
Collapse,
|
||||
IconButton,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
OutlinedInput,
|
||||
Paper,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
Badge,
|
||||
Tab,
|
||||
Tabs,
|
||||
CardHeader,
|
||||
Stack,
|
||||
Menu,
|
||||
ButtonGroup,
|
||||
Pagination,
|
||||
Grid,
|
||||
Chip,
|
||||
styled,
|
||||
DialogTitle,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogActions,
|
||||
InputAdornment,
|
||||
} from '@mui/material';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
|
||||
import {
|
||||
Link,
|
||||
NavLink as RouterLink,
|
||||
useSearchParams,
|
||||
useNavigate,
|
||||
useParams,
|
||||
} from 'react-router-dom';
|
||||
// hooks
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
// components
|
||||
import axios from '../../../utils/axios';
|
||||
import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||
import { Icd } from '../../../@types/diagnosis';
|
||||
import BasePagination from '../../../components/BasePagination';
|
||||
import { Organizations } from '../../../@types/organization';
|
||||
import CreateIcon from '@mui/icons-material/Create';
|
||||
import { Props } from '../../../components/editor/index';
|
||||
import { red } from '@mui/material/colors';
|
||||
import { margin, padding } from '@mui/system';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import SvgIconStyle from '../../../components/SvgIconStyle';
|
||||
// import ButtonCreate from '../../../components/ButtonCreate';
|
||||
import { Search } from '@mui/icons-material';
|
||||
import { Icon } from '@iconify/react';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const getIcon = (name: string) => (
|
||||
<SvgIconStyle src={`/icons/${name}.svg`} sx={{ width: 1, height: 1 }} />
|
||||
);
|
||||
|
||||
const ICONS = {
|
||||
show: getIcon('ic_show'),
|
||||
edit: getIcon('ic_edit'),
|
||||
delete: getIcon('ic_delete'),
|
||||
};
|
||||
|
||||
export default function List() {
|
||||
// Generate the every row of the table
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { organization_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
const Item = styled(Paper)(({ theme }) => ({
|
||||
textAlign: 'left',
|
||||
}));
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
||||
const handleSearchChange = (event: any) => {
|
||||
const newSearchText = event.target.value ?? '';
|
||||
setSearchText(newSearchText);
|
||||
};
|
||||
|
||||
const handleSearchSubmit = (event: any) => {
|
||||
event.preventDefault();
|
||||
props.onSearch(searchText); // Trigger to Parent
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// Trigger First Search
|
||||
setSearchText(searchParams.get('search') ?? '');
|
||||
}, [searchParams]);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '100%' }}>
|
||||
<TextField
|
||||
id="search-input"
|
||||
ref={searchInput}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
onChange={handleSearchChange}
|
||||
value={searchText}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<Search />
|
||||
</InputAdornment>
|
||||
),
|
||||
placeholder: 'Search',
|
||||
}}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
function ImportForm(props: any) {
|
||||
// IMPORT
|
||||
// Create Button Menu
|
||||
|
||||
return (
|
||||
<Stack
|
||||
direction={'row'}
|
||||
spacing={2}
|
||||
sx={{ p: 2, justifyContent: 'flex-end', alignItems: 'center' }}
|
||||
>
|
||||
<SearchInput onSearch={applyFilter} />
|
||||
|
||||
{/* <Link to="/master/organizations/create/" style={{ textDecoration: 'none' }}>
|
||||
<ButtonCreate />
|
||||
</Link> */}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
function createData(organization: Organizations): Organizations {
|
||||
return {
|
||||
...organization,
|
||||
};
|
||||
}
|
||||
|
||||
function CheckStatus(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
if (row.active === 1) {
|
||||
return (
|
||||
<Chip
|
||||
label="Aktif"
|
||||
size="small"
|
||||
sx={{
|
||||
backgroundColor: 'rgba(84, 214, 44, 0.16)',
|
||||
color: '#229A16',
|
||||
padding: '1 8 1 8 px',
|
||||
borderRadius: '4px',
|
||||
fontSize: '12px',
|
||||
fontWeight: 'bold',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Chip
|
||||
label="Tidak Aktif"
|
||||
size="small"
|
||||
sx={{
|
||||
backgroundColor: 'rgba(255, 72, 66, 0.16)',
|
||||
color: '#B72136',
|
||||
padding: '1 8 1 8 px',
|
||||
borderRadius: '4px',
|
||||
fontSize: '12px',
|
||||
fontWeight: 'bold',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function Row(props: { row: ReturnType<typeof createData> }) {
|
||||
const { row } = props;
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [openDialog, setOpenDialog] = React.useState(false);
|
||||
|
||||
const handleActivate = (model: any, status: string) => {
|
||||
axios
|
||||
.put(`/organizations/${row.id}/activation`, {
|
||||
// service_code: service.service_code,
|
||||
active: status == 'active',
|
||||
})
|
||||
.then((res) => {
|
||||
setDataTableData({
|
||||
...dataTableData,
|
||||
data: dataTableData.data.map((model) => {
|
||||
let updatedModel = model;
|
||||
if (row.id == model.id) {
|
||||
updatedModel.active = res.data.data.active;
|
||||
}
|
||||
return updatedModel;
|
||||
}),
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
enqueueSnackbar(
|
||||
error.response.data.message ?? error.message ?? 'Failed Processing Request',
|
||||
{ variant: 'error' }
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = (model: any) => {
|
||||
axios
|
||||
.delete(`/organizations/${row.id}`)
|
||||
.then((res) => {
|
||||
setDataTableData({
|
||||
...dataTableData,
|
||||
data: dataTableData.data.filter((model) => model.id != row.id),
|
||||
});
|
||||
enqueueSnackbar('Data berhasil dihapus', { variant: 'success' });
|
||||
})
|
||||
.catch((error) => {
|
||||
enqueueSnackbar(
|
||||
error.response.data.message ?? error.message ?? 'Failed Processing Request',
|
||||
{ variant: 'error' }
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow
|
||||
sx={{
|
||||
backgroundColor: open ? 'rgba(244, 246, 248, 0.5)' : '#fff',
|
||||
'& > *': { borderBottom: 'unset' },
|
||||
}}
|
||||
>
|
||||
<TableCell>
|
||||
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
||||
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="left">{row.phone}</TableCell>
|
||||
<TableCell align="left">{row.address?.text}</TableCell>
|
||||
|
||||
{/* <TableCell align="left">
|
||||
<Stack direction="row">
|
||||
<ButtonGroup variant="text" aria-label="text button group">
|
||||
<Link to={'/master/organizations/' + row.id + '/edit'}>
|
||||
<Button>
|
||||
<Icon icon="ph:pencil-simple-fill" style={{ width: '24px', height: '24px' }} />
|
||||
</Button>
|
||||
</Link>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setOpenDialog(true);
|
||||
}}
|
||||
>
|
||||
<Icon icon="eva:trash-2-outline" style={{ width: '24px', height: '24px' }} />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Stack>
|
||||
</TableCell> */}
|
||||
</TableRow>
|
||||
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
<TableCell
|
||||
style={{ paddingBottom: 0, paddingTop: 0, backgroundColor: 'rgba(244, 246, 248, 0.5)' }}
|
||||
colSpan={6}
|
||||
>
|
||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
||||
<Box sx={{ margin: 1, pb: 2, pl: 4 }}>
|
||||
<Grid container>
|
||||
<Grid item xs={6} sx={{ padding: 2 }}>
|
||||
<Grid container>
|
||||
<Grid item xs={6}>
|
||||
Kode Rumah Sakit
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.code ? row.code : '-'}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
Longitude
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.lng ? row.lng : '-'}
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
Latittude
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
: {row.lat ? row.lat : '-'}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
{/* END COLLAPSIBLE ROW */}
|
||||
|
||||
<Dialog
|
||||
open={openDialog}
|
||||
onClose={() => {
|
||||
setOpenDialog(false);
|
||||
}}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
{/* <DialogTitle id="alert-dialog-title">{'Hapus Dokter'}</DialogTitle> */}
|
||||
<DialogContent sx={{ p: 5 }}>
|
||||
<Icon
|
||||
icon="eva:trash-2-outline"
|
||||
style={{
|
||||
width: '100px',
|
||||
height: '100px',
|
||||
color: '#FF0000',
|
||||
margin: 'auto',
|
||||
display: 'block',
|
||||
marginBottom: '20px',
|
||||
alignContent: 'center',
|
||||
}}
|
||||
/>
|
||||
<DialogContentText sx={{ fontWeight: 'bold', pb: 1 }} id="alert-dialog-title">
|
||||
Apakah anda yakin ingin menghapus
|
||||
</DialogContentText>
|
||||
<Typography sx={{ fontWeight: 'bold' }} id="alert-dialog-title">
|
||||
{row.name}?
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setOpenDialog(false);
|
||||
}}
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
>
|
||||
Batal
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleDelete(row.id);
|
||||
}}
|
||||
color="primary"
|
||||
variant="contained"
|
||||
autoFocus
|
||||
>
|
||||
Hapus
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
const headStyle = {
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
// Dummy Default Data
|
||||
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
||||
const [dataTableLastRequest, setDataTableLastRequest] = useState(0);
|
||||
const [dataTableResponseState, setDataTableResponseState] = useState('idle');
|
||||
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>({
|
||||
current_page: 1,
|
||||
data: [],
|
||||
path: '',
|
||||
first_page_url: '',
|
||||
last_page: 1,
|
||||
last_page_url: '',
|
||||
next_page_url: '',
|
||||
prev_page_url: '',
|
||||
per_page: 10,
|
||||
from: 0,
|
||||
to: 0,
|
||||
total: 0,
|
||||
});
|
||||
const [dataTablePage, setDataTablePage] = useState(5);
|
||||
|
||||
const loadDataTableData = async (appliedFilter: any | null = null) => {
|
||||
setDataTableLoading(true);
|
||||
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
||||
const response = await axios.get('/organizations', {
|
||||
params: filter,
|
||||
});
|
||||
console.log(response.data);
|
||||
setDataTableLoading(false);
|
||||
setDataTableData(response.data);
|
||||
};
|
||||
|
||||
const applyFilter = async (searchFilter: string) => {
|
||||
await loadDataTableData({ search: searchFilter });
|
||||
setSearchParams({ search: searchFilter });
|
||||
};
|
||||
|
||||
const handlePageChange = (event: ChangeEvent, value: number) => {
|
||||
const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]);
|
||||
loadDataTableData(filter);
|
||||
setSearchParams(filter);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
{/* <Ambulace /> */}
|
||||
|
||||
<Card sx={{ marginTop: '30px' }}>
|
||||
<ImportForm sx={{ marginTop: '100px' }} />
|
||||
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell style={headStyle} align="left" />
|
||||
<TableCell style={headStyle} align="left">
|
||||
Rumah Sakit
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Nomor IGD
|
||||
</TableCell>
|
||||
<TableCell style={headStyle} align="left">
|
||||
Alamat
|
||||
</TableCell>
|
||||
{/* <TableCell style={headStyle} align="center">
|
||||
Aksi
|
||||
</TableCell> */}
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
{dataTableIsLoading ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">
|
||||
Loading
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : dataTableData.data.length == 0 ? (
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} align="center">
|
||||
No Data
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody>
|
||||
{dataTableData.data.map((row) => (
|
||||
<Row key={row.id} row={row} />
|
||||
))}
|
||||
</TableBody>
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||
</Card>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -68,8 +68,9 @@ export default function Router() {
|
||||
<AuthGuard>
|
||||
<DashboardLayout />
|
||||
</AuthGuard>
|
||||
</AuthProvider>),
|
||||
children:[
|
||||
</AuthProvider>
|
||||
),
|
||||
children: [
|
||||
{ element: <Navigate to="/dashboard" replace />, index: true },
|
||||
{
|
||||
path: 'dashboard',
|
||||
@@ -187,6 +188,14 @@ export default function Router() {
|
||||
element: <CorporateClaimHistories />,
|
||||
},
|
||||
|
||||
{
|
||||
path: 'master/doctors',
|
||||
element: <MasterDoctors />,
|
||||
},
|
||||
{
|
||||
path: 'master/hospitals',
|
||||
element: <MasterHospitals />,
|
||||
},
|
||||
{
|
||||
path: 'master/diagnosis',
|
||||
element: <MasterDiagnosis />,
|
||||
@@ -206,31 +215,30 @@ export default function Router() {
|
||||
element: <MasterFormulariumCreate />,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
path: 'claims',
|
||||
element: <Claims />,
|
||||
},
|
||||
{
|
||||
path: 'claims/create',
|
||||
element: <ClaimsCreate />
|
||||
element: <ClaimsCreate />,
|
||||
},
|
||||
{
|
||||
path: 'claims/:id',
|
||||
element: <ClaimsCreate />
|
||||
}
|
||||
]
|
||||
element: <ClaimsCreate />,
|
||||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
// path: '/dashboard',
|
||||
// element: <DashboardLayout />,
|
||||
// children: [
|
||||
// { element: <Navigate to="/dashboard/one" replace />, index: true },
|
||||
// { path: 'one', element:
|
||||
// { path: 'one', element:
|
||||
// <AuthProvider><PageOne /></AuthProvider> },
|
||||
// { path: 'two', element:
|
||||
// { path: 'two', element:
|
||||
// <AuthProvider><PageTwo /></AuthProvider> },
|
||||
// { path: 'three', element:
|
||||
// { path: 'three', element:
|
||||
// <AuthProvider><PageThree /></AuthProvider> },
|
||||
// {
|
||||
// path: 'user',
|
||||
@@ -269,27 +277,39 @@ const CorporateCreate = Loadable(lazy(() => import('../pages/Corporates/CreateUp
|
||||
const CorporateShow = Loadable(lazy(() => import('../pages/Corporates/Show')));
|
||||
|
||||
const CorporateDivisions = Loadable(lazy(() => import('../pages/Corporates/Division/Index')));
|
||||
const CorporateDivisionsCreate = Loadable(lazy(() => import('../pages/Corporates/Division/CreateUpdate')));
|
||||
const CorporateDivisionsCreate = Loadable(
|
||||
lazy(() => import('../pages/Corporates/Division/CreateUpdate'))
|
||||
);
|
||||
|
||||
const CorporateMembers = Loadable(lazy(() => import('../pages/Corporates/Member/Index')));
|
||||
|
||||
const BenefitCreate = Loadable(lazy(() => import('../pages/Corporates/Benefit/Create')));
|
||||
const Benefits = Loadable(lazy(() => import('../pages/Corporates/Benefit/Index')));
|
||||
|
||||
const CorporateBenefitsCreate = Loadable(lazy(() => import('../pages/Corporates/CorporateBenefit/CreateUpdate')));
|
||||
const CorporateBenefits = Loadable(lazy(() => import('../pages/Corporates/CorporateBenefit/Index')));
|
||||
const CorporateBenefitsCreate = Loadable(
|
||||
lazy(() => import('../pages/Corporates/CorporateBenefit/CreateUpdate'))
|
||||
);
|
||||
const CorporateBenefits = Loadable(
|
||||
lazy(() => import('../pages/Corporates/CorporateBenefit/Index'))
|
||||
);
|
||||
|
||||
const CorporatePlanCreate = Loadable(lazy(() => import('../pages/Corporates/CorporatePlan/CreateUpdate')));
|
||||
const CorporatePlanCreate = Loadable(
|
||||
lazy(() => import('../pages/Corporates/CorporatePlan/CreateUpdate'))
|
||||
);
|
||||
const CorporatePlans = Loadable(lazy(() => import('../pages/Corporates/CorporatePlan/Index')));
|
||||
|
||||
const PlanCreate = Loadable(lazy(() => import('../pages/Corporates/Plan/Create')));
|
||||
const Plans = Loadable(lazy(() => import('../pages/Corporates/Plan/Index')));
|
||||
|
||||
const DiagnosisExclusions = Loadable(lazy(() => import('../pages/Corporates/DiagnosisExclusion/Index')));
|
||||
const DiagnosisExclusions = Loadable(
|
||||
lazy(() => import('../pages/Corporates/DiagnosisExclusion/Index'))
|
||||
);
|
||||
|
||||
const CorporateFormularium = Loadable(lazy(() => import('../pages/Corporates/Formularium/Index')));
|
||||
|
||||
const MasterDiagnosis = Loadable(lazy(() => import('../pages/Master/Diagnosis/Index')));
|
||||
const MasterDoctors = Loadable(lazy(() => import('../pages/Master/Doctors/Index')));
|
||||
const MasterHospitals = Loadable(lazy(() => import('../pages/Master/Hospitals/Index')));
|
||||
|
||||
const MasterDrug = Loadable(lazy(() => import('../pages/Master/Drug/Index')));
|
||||
|
||||
@@ -300,7 +320,9 @@ const CorporateServices = Loadable(lazy(() => import('../pages/Corporates/Servic
|
||||
const CorporateServicesCreate = Loadable(lazy(() => import('../pages/Corporates/Services/Create')));
|
||||
|
||||
const CorporateHospitals = Loadable(lazy(() => import('../pages/Corporates/Hospital/Index')));
|
||||
const CorporateClaimHistories = Loadable(lazy(() => import('../pages/Corporates/ClaimHistory/Index')));
|
||||
const CorporateClaimHistories = Loadable(
|
||||
lazy(() => import('../pages/Corporates/ClaimHistory/Index'))
|
||||
);
|
||||
|
||||
const Claims = Loadable(lazy(() => import('../pages/Claims/Index')));
|
||||
const ClaimsCreate = Loadable(lazy(() => import('../pages/Claims/CreateUpdate')));
|
||||
const ClaimsCreate = Loadable(lazy(() => import('../pages/Claims/CreateUpdate')));
|
||||
|
||||
Reference in New Issue
Block a user