62 Commits

Author SHA1 Message Date
R
bcf6662db6 Update Generate Log 2023-02-21 17:01:57 +07:00
R
912edcdae7 [Build] Dashboard Production 2023-02-15 10:47:39 +07:00
R
5a7695b404 Add Appointment Type 2023-02-15 10:46:37 +07:00
R
5f05f191c6 [Build] Dashboard Prod 2023-02-15 10:14:20 +07:00
R
46af57b17c Show additional patient information in Dashboard Appointment 2023-02-15 10:13:07 +07:00
R
016bd3f605 [Hotfix] No PaymentDetail 2023-02-15 10:02:49 +07:00
R
093f8160d2 [Build] Additional Information 2023-02-15 10:00:53 +07:00
R
d8f493103c Add Additional Information 2023-02-15 09:57:00 +07:00
R
7f77deb09e Order Appointment & Livechat by newset 2023-02-15 09:10:22 +07:00
R
d38bc8dbfc [Build] Dashboard 2023-02-15 09:07:33 +07:00
R
b225084991 Update OLDLMS Appointment & Livechat Status 2023-02-15 09:03:13 +07:00
R
d8a98f4648 Merge remote-tracking branch 'origin/feature/appointment' 2023-02-15 08:08:51 +07:00
pajri
f309f4039c list dan show appointment 2023-02-10 16:55:24 +07:00
pajri
387658a992 CRUD Doctor Hospital 2023-02-09 13:15:45 +07:00
R
6491f4d3e3 Add corporate Manager soft delete 2023-02-04 08:48:52 +07:00
R
5028b2d82b Fix Division by Zero 2023-02-04 08:46:44 +07:00
R
5d56434aa2 [Build] Client Portal 2023-02-04 08:38:46 +07:00
R
8e05280b7d Fix Name & User Avatar 2023-02-04 08:36:59 +07:00
R
e3de0a3c04 Hide Burger 2023-02-04 08:14:51 +07:00
R
c3a425c93d Fix Error on opening Add Claim Modal 2023-02-04 08:12:53 +07:00
R
431070efc3 Fix OTP Client Portal to 4444 2023-02-04 08:05:03 +07:00
R
e8c3decf85 Change Title 2023-02-01 20:27:53 +07:00
R
99c488baf3 Update Guaranted Letter 2023-02-01 20:21:03 +07:00
R
0b50e4c980 Update Guaranted Letter Styling 2023-02-01 20:17:32 +07:00
R
ba310a21c1 [Build] Both 2023-02-01 19:39:33 +07:00
R
5a0136acf8 Fix Download Blob Pdf 2023-02-01 19:35:30 +07:00
R
75c9781a22 [Build] Staging 2023-02-01 19:20:09 +07:00
R
2a1f0c854a [Build] Production 2023-02-01 19:16:50 +07:00
R
f0c787fede Add Download LOG 2023-02-01 19:15:31 +07:00
R
8d5f4bb0bd Fix Import Benefit selecting wrong plan from another corporate 2023-02-01 01:37:53 +07:00
R
248047006e [Build] Staging 2023-02-01 01:16:44 +07:00
R
2c535b4021 [Build] Production 2023-02-01 00:56:17 +07:00
R
59dd63a78f Add name,dob linking tools 2023-02-01 00:51:14 +07:00
R
21282be7b3 Merge remote-tracking branch 'origin/feature/prices' 2023-02-01 00:42:44 +07:00
pajri
8cbfb1929b update csv 2023-02-01 11:52:19 +07:00
R
b8152e6b3f Fix Date Time Write 2023-01-30 12:40:04 +07:00
R
cfbe108629 Remove error sting 2023-01-30 12:20:14 +07:00
R
a8821dfb3c Fix Seeder 2023-01-30 12:08:49 +07:00
pajri
1ce2655b65 update schedule dokter 2023-01-28 09:44:14 +07:00
pajri
335e24b17c add biaya admin 2023-01-27 13:26:42 +07:00
pajri
4776eb5b0a seeder prices jadwal dokter 2023-01-27 09:52:31 +07:00
R
17daf20167 Add MCU 2023-01-26 14:51:32 +07:00
R
18ace75fc7 Add OLDLMS .env.example 2023-01-26 07:35:08 +07:00
R
ad743de98d Fix Bug Member Import 2023-01-19 15:09:32 +07:00
R
96a40842bd [Build] Import Loading Button 2023-01-19 14:43:16 +07:00
R
137fd07a28 Add Loading Button when Import 2023-01-19 14:41:56 +07:00
R
21dc0b1fc1 [Build] Frontend Dashboard 2023-01-19 10:15:55 +07:00
R
f56361de62 [Build] Frontend Dashboard 2023-01-19 10:15:00 +07:00
R
85f319878a Fix Regex Kode Corporate 2023-01-19 10:09:53 +07:00
R
23436164c2 Fix Corporate Create & Update Validation remove allow spaces 2023-01-17 12:40:15 +07:00
R
b19e0876e5 Change Specialities Button 2023-01-15 12:19:31 +07:00
R
704c5ecc44 [Bug Fix] Update Validation : Is there laravel validation update ? 2023-01-15 12:07:44 +07:00
R
9087580138 Add File Import Example Download 2023-01-15 11:28:07 +07:00
R
7ff199a3c1 [Fix] Member Benefit Specific 2023-01-13 14:48:15 +07:00
R
08a2502fb1 Enable Claim Softdeletes 2023-01-13 12:19:00 +07:00
R
65c9153fee [Build] Frontend 2023-01-13 12:14:00 +07:00
R
775f471a07 [WIP] Update Postponed 2023-01-13 12:08:57 +07:00
R
f09eaef5ad [Fix] Display Claim Postponed 2023-01-13 11:50:31 +07:00
R
e116fb814a [WIP] Fix Medicine 2023-01-13 08:19:43 +07:00
R
2f10f913c0 [WIP] Change Check Coverage Appointment 2023-01-13 00:43:58 +07:00
R
3a2dd84500 Fix Breadcrumbs Links 2023-01-12 15:10:59 +07:00
R
7d1872ef1e [Build] Update 2023-01-11 14:49:16 +07:00
380 changed files with 10324 additions and 3883 deletions

View File

@@ -15,6 +15,13 @@ DB_DATABASE=laravel
DB_USERNAME=root DB_USERNAME=root
DB_PASSWORD= DB_PASSWORD=
OLDLMS_DB_CONNECTION=mysql
OLDLMS_DB_HOST=127.0.0.1
OLDLMS_DB_PORT=3306
OLDLMS_DB_DATABASE=linksehat
OLDLMS_DB_USERNAME=mysql
OLDLMS_DB_PASSWORD=password
BROADCAST_DRIVER=log BROADCAST_DRIVER=log
CACHE_DRIVER=file CACHE_DRIVER=file
FILESYSTEM_DISK=local FILESYSTEM_DISK=local

View File

@@ -35,13 +35,13 @@ class AuthController extends Controller
if (filter_var($request->phoneOrEmail, FILTER_VALIDATE_EMAIL)) { if (filter_var($request->phoneOrEmail, FILTER_VALIDATE_EMAIL)) {
User::query()->find($user->id)->update([ User::query()->find($user->id)->update([
'email' => $request->phoneOrEmail, 'email' => $request->phoneOrEmail,
'otp' => rand(1000, 9999), 'otp' => 4444, //rand(1000, 9999),
'otp_created_at' => now() 'otp_created_at' => now()
]); ]);
} else { } else {
User::query()->find($user->id)->update([ User::query()->find($user->id)->update([
'phone' => $request->phoneOrEmail, 'phone' => $request->phoneOrEmail,
'otp' => rand(1000, 9999), 'otp' => 4444,//rand(1000, 9999),
'otp_created_at' => now() 'otp_created_at' => now()
]); ]);
} }

View File

@@ -26,7 +26,7 @@ class DashboardResources extends JsonResource
'myLimit' => [ 'myLimit' => [
'balance' => $myLimitBalance, 'balance' => $myLimitBalance,
'total' => $myLimitTotal, 'total' => $myLimitTotal,
'percentage' => ($myLimitBalance / $myLimitTotal) * 100, 'percentage' => $myLimitTotal ? (($myLimitBalance / $myLimitTotal) * 100) : 0,
], ],
'lockLimit' => [ 'lockLimit' => [
'balance' => $lockBalance, 'balance' => $lockBalance,

View File

@@ -0,0 +1,89 @@
<?php
namespace Modules\Internal\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Models\OLDLMS\Appointment;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Modules\Internal\Transformers\AppointmentResource;
class AppointmentController extends Controller
{
/**
* Display a listing of the resource.
* @return Renderable
*/
public function index()
{
$appointments = Appointment::query()
->with('doctor.user', 'doctor.speciality', 'appointmentDetail', 'healthCare', 'user', 'user.detail')
->latest()
->paginate(15);
return response()->json(Helper::paginateResources(AppointmentResource::collection($appointments)));
}
/**
* 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)
{
$appointments = Appointment::query()
->with('doctor.user', 'doctor.speciality', 'appointmentDetail', 'healthCare')
->where('nID', $id)
->first();
return response()->json(new AppointmentResource($appointments));
}
/**
* 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)
{
//
}
}

View File

@@ -0,0 +1,86 @@
<?php
namespace Modules\Internal\Http\Controllers\Api;
use App\Models\City;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class CityController extends Controller
{
/**
* Display a listing of the resource.
* @return Renderable
*/
public function index(Request $request)
{
$city = City::where('province_id', $request->province_id)->orderBy('name', 'asc')->get();
if (!$city) {
return response(['message' => 'Tidak ada data'], 404);
} else {
return response(['message' => 'Data ditemukan', 'data' => $city]);
}
}
/**
* 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)
{
//
}
}

View File

@@ -3,6 +3,7 @@
namespace Modules\Internal\Http\Controllers\Api; namespace Modules\Internal\Http\Controllers\Api;
use App\Exceptions\ImportRowException; use App\Exceptions\ImportRowException;
use App\Helpers\Helper;
use App\Imports\PlansImport; use App\Imports\PlansImport;
use App\Models\Benefit; use App\Models\Benefit;
use App\Models\Claim; use App\Models\Claim;
@@ -19,7 +20,8 @@ use Illuminate\Routing\Controller;
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Facades\Excel;
use Box\Spout\Reader\Common\Creator\ReaderEntityFactory; use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
use App\Models\File; use App\Models\File;
use Illuminate\Support\Facades\File as FacadesFile;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Modules\Internal\Services\CorporateService; use Modules\Internal\Services\CorporateService;
@@ -76,7 +78,7 @@ class CorporateController extends Controller
public function store(Request $request) public function store(Request $request)
{ {
$request->validate([ $request->validate([
'code' => 'required', 'code' => 'required|regex:/^[a-zA-Z0-9]+$/',
'name' => 'required', 'name' => 'required',
// 'logo' => 'required', // 'logo' => 'required',
'policy_code' => 'required_with:policy_id', 'policy_code' => 'required_with:policy_id',
@@ -144,6 +146,12 @@ class CorporateController extends Controller
'code' => 'OPT', 'code' => 'OPT',
'description' => 'Optical', 'description' => 'Optical',
], ],
[
'id' => 6,
'name' => 'Medical Check Up',
'code' => 'MCU',
'description' => 'Medical Check Up',
],
]; ];
foreach ($services as $service) { foreach ($services as $service) {
@@ -293,7 +301,7 @@ class CorporateController extends Controller
public function update(Request $request, $id) public function update(Request $request, $id)
{ {
$request->validate([ $request->validate([
'code' => 'required', 'code' => 'required|regex:/^[a-zA-Z0-9]+$/',
'name' => 'required', 'name' => 'required',
'policy_code' => 'required_with:policy_id', 'policy_code' => 'required_with:policy_id',
'policy_total_premi' => 'required_with:policy_code', 'policy_total_premi' => 'required_with:policy_code',
@@ -486,4 +494,31 @@ class CorporateController extends Controller
] ]
]; ];
} }
public function importDocumentExample($document_type)
{
switch ($document_type) {
case 'plan-benefit':
return Helper::responseJson([
'file_name' => "Corporate Plan & Benefit Import.xlsx",
"file_url" => url('files/Corporate Plan & Benefit Import.xlsx')
]);
break;
case 'member':
return Helper::responseJson([
'file_name' => "Corporate Membership Import.xlsx",
"file_url" => url('files/Corporate Membership Import.xlsx')
]);
break;
case 'diagnosis-exclusion':
return Helper::responseJson([
'file_name' => "Corporate Exclusion Import.xlsx",
"file_url" => url('files/Corporate Exclusion Import.xlsx')
]);
break;
default:
return Helper::responseJson([], 'error', 404);
break;
}
}
} }

View File

@@ -10,11 +10,13 @@ use App\Models\Member;
use Box\Spout\Reader\Common\Creator\ReaderEntityFactory; use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
use Box\Spout\Writer\Common\Creator\WriterEntityFactory; use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
use Box\Spout\Common\Entity\Row; use Box\Spout\Common\Entity\Row;
use Carbon\Carbon;
use Illuminate\Contracts\Support\Renderable; use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Routing\Controller; use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Modules\Internal\Services\MemberEnrollmentService; use Modules\Internal\Services\MemberEnrollmentService;
use PDF;
class CorporateMemberController extends Controller class CorporateMemberController extends Controller
{ {
@@ -41,10 +43,10 @@ class CorporateMemberController extends Controller
'claims' => function ($claim) { 'claims' => function ($claim) {
// return $claim->whereBetween('requested_at', [now()->startOfYear(), now()->endOfYear()]); // return $claim->whereBetween('requested_at', [now()->startOfYear(), now()->endOfYear()]);
// return $claim->used(now()->startOfYear(), now()->endOfYear()); // return $claim->used(now()->startOfYear(), now()->endOfYear());
} },
'currentPlan',
'currentPlan.benefits'
]) ])
->with('currentPlan')
// ->with
->paginate() ->paginate()
->appends($request->all()); ->appends($request->all());
@@ -192,9 +194,12 @@ class CorporateMemberController extends Controller
'ingestion_code' => $e->getCode(), 'ingestion_code' => $e->getCode(),
'ingestion_status' => $e->getMessage(), 'ingestion_status' => $e->getMessage(),
]); ]);
$singleRow = WriterEntityFactory::createRow($this->memberEnrollmentService->makeResultRowWithResultFormat($new_member_data)); // try {
$writer->addRow($singleRow); $singleRow = WriterEntityFactory::createRow($this->memberEnrollmentService->makeResultRowWithResultFormat($new_member_data));
$failed_member_data[] = ['row_number' => $index, 'error' => $e->getMessage()]; $writer->addRow($singleRow);
// } catch (\Exception $e) {
$failed_member_data[] = ['row_number' => $index, 'error' => $e->getMessage(), 'data' => $new_member_data];
// }
} catch (\Exception $e) { } catch (\Exception $e) {
// Write Server Error to File // Write Server Error to File
$new_member_data = array_merge($new_member_data, [ $new_member_data = array_merge($new_member_data, [
@@ -225,4 +230,25 @@ class CorporateMemberController extends Controller
] ]
]; ];
} }
public function generateLog(Request $request, $member_id)
{
$member = Member::findOrFail($member_id)
->load([
'currentPlan',
'currentPolicy',
'currentPlan.corporateBenefits' => function ($benefit) use ($request) {
return $benefit->when($request->benefit_ids, function ($q, $ids) {
return $q->whereIn('id', $ids);
});
},
'currentPlan.corporateBenefits.benefit']);
$dateOfAdmission = $request->date_of_admission ? Carbon::parse($request->date_of_admission) : now();
// return view('pdf.guaranted_leter', compact('member'));
$pdf = PDF::loadView('pdf.guaranted_leter', compact(['member', 'dateOfAdmission']));
return $pdf->download('Guaranted Letter - '.$member->full_name.'.pdf');
}
} }

View File

@@ -0,0 +1,85 @@
<?php
namespace Modules\Internal\Http\Controllers\Api;
use App\Models\District;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class DistrictController extends Controller
{
/**
* Display a listing of the resource.
* @return Renderable
*/
public function index(Request $request)
{
$district = District::where('city_id', $request->city_id)->orderBy('name', 'asc')->get();
if (!$district) {
return response(['message' => 'Tidak ada data'], 404);
} else {
return response(['message' => 'Data ditemukan', 'data' => $district]);
}
}
/**
* 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)
{
//
}
}

View File

@@ -3,6 +3,7 @@
namespace Modules\Internal\Http\Controllers\Api; namespace Modules\Internal\Http\Controllers\Api;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Models\Person;
use App\Models\Practitioner; use App\Models\Practitioner;
use App\Models\PractitionerRole; use App\Models\PractitionerRole;
use Illuminate\Contracts\Support\Renderable; use Illuminate\Contracts\Support\Renderable;
@@ -18,12 +19,6 @@ class DoctorController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
// $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') $doctors = Practitioner::with('person', 'practitionerRoles.organization', 'practitionerRoles.speciality')
->when($request->search ?? null, function ($query, $search) { ->when($request->search ?? null, function ($query, $search) {
@@ -31,6 +26,9 @@ class DoctorController extends Controller
$person->where('name', 'LIKE', '%' . $search . '%'); $person->where('name', 'LIKE', '%' . $search . '%');
}); });
}) })
->when($request->id ?? null, function ($query, $id) {
$query->where('id', $id);
})
->when($request->organization_id ?? null, function ($query, $organization_id) { ->when($request->organization_id ?? null, function ($query, $organization_id) {
$query->whereHas('practitionerRoles', function ($practitionerRole) use ($organization_id) { $query->whereHas('practitionerRoles', function ($practitionerRole) use ($organization_id) {
$practitionerRole->where('organization_id', $organization_id); $practitionerRole->where('organization_id', $organization_id);
@@ -65,7 +63,58 @@ class DoctorController extends Controller
*/ */
public function store(Request $request) public function store(Request $request)
{ {
// $data_person = [
'name' => $request->name,
'gender' => $request->gender,
'address' => $request->address,
'phone' => $request->phone,
'email' => $request->email,
'birth_date' => date('Y-m-d', strtotime($request->birth_date)),
'birth_place' => $request->birth_place,
];
$person = Person::create($data_person);
$address = $person->addresses()->create([
'use' => 'both',
'type' => 'physical',
'text' => $request->address,
]);
$person->main_address_id = $address->id;
$person->save();
$practitioner = $person->practitioner()->create();
$practices = $request->practices;
if ($practices[0]['organization_id'] !== null) {
foreach ($practices as $key => $practice) {
if (isset($practice['specialities'])) {
//jika input spesialis
foreach ($practice['specialities'] as $key => $speciality) {
$speciality_id = $speciality['speciality_id'];
$organization_id = $practice['organization_id'];
$practitionerRole = $practitioner->practitionerRoles()->create([
'organization_id' => $organization_id,
'speciality_id' => $speciality_id,
]);
}
} else {
//jika tidak input spesialis
$speciality_id = null;
$organization_id = $practice['organization_id'];
$practitionerRole = $practitioner->practitionerRoles()->create([
'organization_id' => $organization_id,
'speciality_id' => $speciality_id,
]);
}
}
}
return response()->json([
'status' => 'success',
'message' => 'Data berhasil disimpan',
]);
} }
/** /**
@@ -75,7 +124,8 @@ class DoctorController extends Controller
*/ */
public function show($id) public function show($id)
{ {
return view('internal::show'); $practitioner = Practitioner::with('person', 'practitionerRoles.organization', 'practitionerRoles.speciality')->find($id);
return response()->json(DoctorResource::make($practitioner));
} }
/** /**
@@ -85,7 +135,8 @@ class DoctorController extends Controller
*/ */
public function edit($id) public function edit($id)
{ {
return view('internal::edit'); $practitioner = Practitioner::with('person', 'practitionerRoles.organization', 'practitionerRoles.speciality')->find($id);
return response()->json(DoctorResource::make($practitioner));
} }
/** /**
@@ -96,7 +147,81 @@ class DoctorController extends Controller
*/ */
public function update(Request $request, $id) public function update(Request $request, $id)
{ {
// $practitioner = Practitioner::find($id);
$data_person = [
'name' => $request->name,
'gender' => $request->gender,
'address' => $request->address,
'phone' => $request->phone,
'email' => $request->email,
'birth_date' => date('Y-m-d', strtotime($request->birth_date)),
'birth_place' => $request->birth_place,
];
$person = $practitioner->person;
$person->update($data_person);
$address = $practitioner->person->addresses()->updateOrCreate([
'use' => 'both',
'type' => 'physical',
'text' => $request->address,
]);
$practitioner->person->main_address_id = $address->id;
$practitioner->person->save();
$practices = $request->practices;
$practitionerRole = $practitioner->practitionerRoles()->get() ?? null;
foreach ($practices as $practice) {
$organization_id = $practice['organization_id'];
foreach ($practice['specialities'] as $speciality) {
$speciality_id = $speciality['speciality_id'];
$cek = $practitionerRole->where('organization_id', $organization_id)
->where('speciality_id', $speciality_id)->first() ?? null;
if (!$cek || $practitionerRole->isEmpty()) {
// Create new practitioner role if not found
$practitioner->practitionerRoles()->create([
'organization_id' => $organization_id,
'speciality_id' => $speciality_id,
]);
}
}
}
if ($practitionerRole) {
// Remove practitioner roles that are no longer exists
$currentRoleIds = $practitionerRole->pluck('id')->toArray();
$newRoleIds = [];
foreach ($practices as $practice) {
$organization_id = $practice['organization_id'];
foreach ($practice['specialities'] as $speciality) {
$speciality_id = $speciality['speciality_id'];
$newPractitionerRole = $practitionerRole->where('organization_id', $organization_id)
->where('speciality_id', $speciality_id)
->first();
if ($newPractitionerRole) {
$newRoleIds[] = $newPractitionerRole->id;
}
}
}
$deletedRoleIds = array_diff($currentRoleIds, $newRoleIds);
if (count($deletedRoleIds) > 0) {
// Delete practitioner roles that are no longer exists
$data = $practitionerRole->whereIn('id', $deletedRoleIds);
$data->each(function ($item) {
$item->delete();
});
}
}
return response()->json([
'status' => 'success',
'message' => 'Data berhasil disimpan',
]);
} }
/** /**
@@ -106,6 +231,14 @@ class DoctorController extends Controller
*/ */
public function destroy($id) public function destroy($id)
{ {
// $practitioner = Practitioner::find($id);
$person = $practitioner->person->delete();
$address = $practitioner->person->addresses()->delete();
$practitionerRole = $practitioner->practitionerRoles()->delete();
$practitioner->delete();
return response()->json([
'status' => 'success',
'message' => 'Data berhasil dihapus',
]);
} }
} }

View File

@@ -0,0 +1,90 @@
<?php
namespace Modules\Internal\Http\Controllers\Api;
use App\Helpers\Helper;
use App\Models\OLDLMS\Livechat;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Modules\Internal\Transformers\LivechatResource;
class LivechatController extends Controller
{
/**
* Display a listing of the resource.
* @return Renderable
*/
public function index()
{
$livechat = Livechat::with('doctor.user', 'doctor.speciality', 'appointment.appointmentDetail', 'healthCare')
->where('nIDAppointment', '!=', null)->where('nIDAppointment', '!=', '')
->latest()
->paginate(15);
return response()->json(Helper::paginateResources(LivechatResource::collection($livechat)));
}
/**
* 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)
{
$livechat = Livechat::with('doctor.user', 'doctor.speciality', 'appointment.appointmentDetail', 'healthCare')
->where('nIDAppointment', '!=', null)->where('nIDAppointment', '!=', '')
->where('nID', $id)
->first();
return response()->json(new LivechatResource($livechat));
}
/**
* 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)
{
//
}
}

View File

@@ -47,7 +47,44 @@ class OrganizationController extends Controller
*/ */
public function store(Request $request) public function store(Request $request)
{ {
// $organization = [
'code' => $request->code,
'name' => $request->name,
'type' => 'hospital',
'status' => $request->active == 1 ? 'active' : 'inactive',
'description' => $request->description,
];
$create_organization = Organization::create($organization);
if ($request->phone != null) {
$create_organization->metas()->create([
'system' => 'default',
'type' => 'phone',
'value' => $request->phone,
]);
}
$address = $create_organization->addresses()->create([
'use' => 'both',
'type' => 'physical',
'text' => $request->address,
'province_id' => $request->province_id,
'city_id' => $request->city_id,
'district_id' => $request->district_id,
'village_id' => $request->village_id,
'postal_code' => $request->postal_code,
'lat' => $request->lat,
'lng' => $request->lng,
]);
$create_organization->main_address_id = $address->id;
$create_organization->save();
return response()->json([
'message' => 'Data berhasil disimpan',
'data' => new OrganizationResource($create_organization)
]);
} }
/** /**
@@ -57,7 +94,7 @@ class OrganizationController extends Controller
*/ */
public function show($id) public function show($id)
{ {
return view('internal::show'); return response()->json(OrganizationResource::make(Organization::find($id)));
} }
/** /**
@@ -67,7 +104,7 @@ class OrganizationController extends Controller
*/ */
public function edit($id) public function edit($id)
{ {
return view('internal::edit'); return response()->json(OrganizationResource::make(Organization::find($id)));
} }
/** /**
@@ -78,7 +115,46 @@ class OrganizationController extends Controller
*/ */
public function update(Request $request, $id) public function update(Request $request, $id)
{ {
// $update_organization = Organization::find($id);
$update_organization->update([
'code' => $request->code,
'name' => $request->name,
'type' => 'hospital',
'status' => $request->active == 1 ? 'active' : 'inactive',
'description' => $request->description,
]);
if ($request->phone != null) {
$update_organization->metas()->updateOrCreate([
'system' => 'default',
'type' => 'phone',
], [
'system' => 'default',
'type' => 'phone',
'value' => $request->phone,
]);
}
$update_organization->addresses()->updateOrCreate([
'id' => $update_organization->main_address_id
], [
'use' => 'both',
'type' => 'physical',
'text' => $request->address,
'province_id' => $request->province_id,
'city_id' => $request->city_id,
'district_id' => $request->district_id,
'village_id' => $request->village_id,
'postal_code' => $request->postal_code,
'lat' => $request->lat,
'lng' => $request->lng,
]);
return response()->json([
'message' => 'Data berhasil diubah',
'data' => new OrganizationResource($update_organization)
]);
} }
/** /**
@@ -88,6 +164,12 @@ class OrganizationController extends Controller
*/ */
public function destroy($id) public function destroy($id)
{ {
// $delete_organization = Organization::find($id);
$delete_organization->addresses()->delete();
$delete_organization->delete();
return response()->json([
'message' => 'Data berhasil dihapus',
'data' => new OrganizationResource($delete_organization)
]);
} }
} }

View File

@@ -0,0 +1,86 @@
<?php
namespace Modules\Internal\Http\Controllers\Api;
use App\Models\Province;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class ProvinceController extends Controller
{
/**
* Display a listing of the resource.
* @return Renderable
*/
public function index(Request $request)
{
$province = Province::orderBy('name', 'ASC')->get();
if (empty($province)) {
return response(['message' => 'Tidak ada data'], 404);
} else {
return response(['message' => 'Data ditemukan', 'data' => $province]);
}
}
/**
* 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)
{
//
}
}

View File

@@ -0,0 +1,86 @@
<?php
namespace Modules\Internal\Http\Controllers\Api;
use App\Models\Village;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
class VillageController extends Controller
{
/**
* Display a listing of the resource.
* @return Renderable
*/
public function index(Request $request)
{
$villages = Village::where('district_id', $request->district_id)->orderBy('name', 'asc')->get();
if (!$villages) {
return response(['message' => 'Tidak ada data'], 404);
} else {
return response(['message' => 'Data ditemukan', 'data' => $villages]);
}
}
/**
* 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)
{
//
}
}

View File

@@ -3,7 +3,9 @@
use App\Http\Controllers\Api\MemberController as ApiMemberController; use App\Http\Controllers\Api\MemberController as ApiMemberController;
use Modules\Internal\Http\Controllers\Api\AuthController; use Modules\Internal\Http\Controllers\Api\AuthController;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Modules\Internal\Http\Controllers\Api\AppointmentController;
use Modules\Internal\Http\Controllers\Api\BenefitController; use Modules\Internal\Http\Controllers\Api\BenefitController;
use Modules\Internal\Http\Controllers\Api\CityController;
use Modules\Internal\Http\Controllers\Api\ClaimController; use Modules\Internal\Http\Controllers\Api\ClaimController;
use Modules\Internal\Http\Controllers\Api\CorporateBenefitController; use Modules\Internal\Http\Controllers\Api\CorporateBenefitController;
use Modules\Internal\Http\Controllers\Api\CorporateController; use Modules\Internal\Http\Controllers\Api\CorporateController;
@@ -13,14 +15,18 @@ use Modules\Internal\Http\Controllers\Api\CorporatePlanController;
use Modules\Internal\Http\Controllers\Api\CorporateServiceController; use Modules\Internal\Http\Controllers\Api\CorporateServiceController;
use Modules\Internal\Http\Controllers\Api\DiagnosisController; use Modules\Internal\Http\Controllers\Api\DiagnosisController;
use Modules\Internal\Http\Controllers\Api\DiagnosisExclusionController; use Modules\Internal\Http\Controllers\Api\DiagnosisExclusionController;
use Modules\Internal\Http\Controllers\Api\DistrictController;
use Modules\Internal\Http\Controllers\Api\DivisionController; use Modules\Internal\Http\Controllers\Api\DivisionController;
use Modules\Internal\Http\Controllers\Api\DoctorController; use Modules\Internal\Http\Controllers\Api\DoctorController;
use Modules\Internal\Http\Controllers\Api\DrugController; use Modules\Internal\Http\Controllers\Api\DrugController;
use Modules\Internal\Http\Controllers\Api\FormulariumController; use Modules\Internal\Http\Controllers\Api\FormulariumController;
use Modules\Internal\Http\Controllers\Api\LivechatController;
use Modules\Internal\Http\Controllers\Api\MemberController; use Modules\Internal\Http\Controllers\Api\MemberController;
use Modules\Internal\Http\Controllers\Api\OrganizationController; use Modules\Internal\Http\Controllers\Api\OrganizationController;
use Modules\Internal\Http\Controllers\Api\PlanController; use Modules\Internal\Http\Controllers\Api\PlanController;
use Modules\Internal\Http\Controllers\Api\ProvinceController;
use Modules\Internal\Http\Controllers\Api\SpecialityController; use Modules\Internal\Http\Controllers\Api\SpecialityController;
use Modules\Internal\Http\Controllers\Api\VillageController;
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@@ -51,6 +57,7 @@ Route::prefix('internal')->group(function () {
Route::resource('corporates', CorporateController::class); Route::resource('corporates', CorporateController::class);
Route::get('corporates/import-document-example/{document_type}', [CorporateController::class, 'importDocumentExample']);
Route::put('corporates/{corporate_id}/activation', [CorporateController::class, 'activation']); Route::put('corporates/{corporate_id}/activation', [CorporateController::class, 'activation']);
Route::post('corporates/{corporate_id}/import-plan-benefit', [CorporateController::class, 'importPlanBenefit']); Route::post('corporates/{corporate_id}/import-plan-benefit', [CorporateController::class, 'importPlanBenefit']);
@@ -118,11 +125,19 @@ Route::prefix('internal')->group(function () {
Route::get('search-organizations', [OrganizationController::class, 'searchOrganization']); Route::get('search-organizations', [OrganizationController::class, 'searchOrganization']);
Route::get('search-specialities', [SpecialityController::class, 'searchSpeciality']); Route::get('search-specialities', [SpecialityController::class, 'searchSpeciality']);
Route::resource('organizations', OrganizationController::class); Route::resource('organizations', OrganizationController::class);
Route::resource('appointments', AppointmentController::class);
Route::resource('live-chat', LivechatController::class);
Route::resource('doctors', DoctorController::class); Route::resource('doctors', DoctorController::class);
Route::post('generate-log/{member_id}', [CorporateMemberController::class, 'generateLog']);
Route::get('claim-requests', [ClaimRequestController::class, 'index'])->name('claim-requests.index');
Route::post('claim-requests/{id}/approve', [ClaimRequestController::class, 'approve'])->name('claim-requests.approve');
}); });
// Route::resource('organizations', OrganizationController::class); Route::get('province', [ProvinceController::class, 'index']);
// Route::resource('doctors', DoctorController::class); Route::get('city', [CityController::class, 'index']);
Route::get('district', [DistrictController::class, 'index']);
// Route::get('something', [DiagnosisExclusionController::class, 'index']); Route::get('village', [VillageController::class, 'index']);
}); });

View File

@@ -11,6 +11,8 @@
| |
*/ */
use Modules\Internal\Http\Controllers\Api\CorporateMemberController;
Route::prefix('internal')->group(function() { Route::prefix('internal')->group(function() {
Route::get('/', 'InternalController@index'); Route::get('/', 'InternalController@index');
}); });

View File

@@ -42,10 +42,8 @@ class CorporateService
$this->validatePlanRow($plan_data); $this->validatePlanRow($plan_data);
$plan = Plan::updateOrCreate([ $plan = $corporate->plans()->updateOrCreate([
'service_code' => $plan_data['service_code'], 'service_code' => $plan_data['service_code'],
'corporate_id' => $corporate->id,
'code' => $plan_data['code'],
], $plan_data); ], $plan_data);
return $plan; return $plan;
@@ -91,7 +89,9 @@ class CorporateService
$this->validateBenefitRow($benefit_data); $this->validateBenefitRow($benefit_data);
$plan = Plan::where('corporate_plan_id', $benefit_data['plan_code'])->first(); $plan = $corporate->plans()
->where('corporate_plan_id', $benefit_data['plan_code'])
->first();
// $corporate->plans->where('corporate_plan_id', $benefit_data['plan_code'])->first(); // $corporate->plans->where('corporate_plan_id', $benefit_data['plan_code'])->first();
$benefit_data['plan_code'] = $plan->id; $benefit_data['plan_code'] = $plan->id;

View File

@@ -15,6 +15,7 @@ use App\Models\Plan;
use Box\Spout\Writer\Common\Creator\WriterEntityFactory; use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
use Box\Spout\Common\Entity\Row; use Box\Spout\Common\Entity\Row;
use Carbon\Carbon; use Carbon\Carbon;
use DateTime;
use DB; use DB;
class MemberEnrollmentService class MemberEnrollmentService
@@ -45,6 +46,7 @@ class MemberEnrollmentService
"The Right Classes Room of BPJS Participants" => "bpjs_class", "The Right Classes Room of BPJS Participants" => "bpjs_class",
"Name of Faskes" => "faskes_name", "Name of Faskes" => "faskes_name",
"Rule_BPJSK ('Y' or 'N')" => "bpjsk", "Rule_BPJSK ('Y' or 'N')" => "bpjsk",
"Rule BPJSK" => "bpjsk",
"Agent Code / intermediary code" => "agent_code", "Agent Code / intermediary code" => "agent_code",
"Member Name" => "name", "Member Name" => "name",
"Address1" => "address1", "Address1" => "address1",
@@ -123,7 +125,7 @@ class MemberEnrollmentService
"faskes_fkrtl" => "Faskes FKRTL (Next Level Provider) or Individual group preferred provider", "faskes_fkrtl" => "Faskes FKRTL (Next Level Provider) or Individual group preferred provider",
"bpjs_class" => "The Right Classes Room of BPJS Participants", "bpjs_class" => "The Right Classes Room of BPJS Participants",
"faskes_name" => "Name of Faskes", "faskes_name" => "Name of Faskes",
"bpjsk" => "Rule_BPJSK ('Y' or 'N')", "bpjsk" => "Rule BPJSK",
"agent_code" => "Agent Code / intermediary code", "agent_code" => "Agent Code / intermediary code",
"name" => "Member Name", "name" => "Member Name",
"address1" => "Address1", "address1" => "Address1",
@@ -195,8 +197,8 @@ class MemberEnrollmentService
"Faskes FKRTL (Next Level Provider) or Individual group preferred provider", "Faskes FKRTL (Next Level Provider) or Individual group preferred provider",
"The Right Classes Room of BPJS Participants", "The Right Classes Room of BPJS Participants",
"Name of Faskes", "Name of Faskes",
"Rule_BPJSK ('Y' or 'N')", "Rule BPJSK",
"Agent Code / intermediary code", "Internal Use",
"Member Name", "Member Name",
"Address1", "Address1",
"Address 1", "Address 1",
@@ -247,6 +249,10 @@ class MemberEnrollmentService
$this->member = $member; $this->member = $member;
} }
public function dateParser($date_from_row) {
return is_string($date_from_row) ? Carbon::parse(strtotime($date_from_row)) : Carbon::parse($date_from_row);
}
protected function validateRow($row) protected function validateRow($row)
{ {
if (empty($row['record_type'])) { if (empty($row['record_type'])) {
@@ -360,7 +366,7 @@ class MemberEnrollmentService
"member_id" => $row['member_id'] ?? null, "member_id" => $row['member_id'] ?? null,
"payor_id" => $row['payor_id'] ?? null, "payor_id" => $row['payor_id'] ?? null,
"nik" => $row['nik'] ?? null, "nik" => $row['nik'] ?? null,
"birth_date" => Carbon::parse(strtotime($row['date_of_birth'])), "birth_date" => $this->dateParser($row['date_of_birth']),
"gender" => Helper::genderNormalization($row['sex']), "gender" => Helper::genderNormalization($row['sex']),
// "language" => $row['language'] ?? null, // "language" => $row['language'] ?? null,
// "race" => $row['race'] ?? null, // "race" => $row['race'] ?? null,
@@ -415,7 +421,7 @@ class MemberEnrollmentService
], ],
[ [
'name' => $row['name'] ?? null, 'name' => $row['name'] ?? null,
'birth_date' => Carbon::parse(strtotime($row['date_of_birth'])), 'birth_date' => $this->dateParser($row['date_of_birth']),
'gender' => Helper::genderPerson($row['sex']), 'gender' => Helper::genderPerson($row['sex']),
'language' => $row['language'] ?? null, 'language' => $row['language'] ?? null,
'race' => $row['race'] ?? null, 'race' => $row['race'] ?? null,
@@ -462,7 +468,7 @@ class MemberEnrollmentService
$person = Person::create([ $person = Person::create([
'name' => $row['name'], 'name' => $row['name'],
'birth_date' => Carbon::parse(strtotime($row['date_of_birth'])), 'birth_date' => $this->dateParser($row['date_of_birth']),
'gender' => Helper::genderPerson($row['sex']), 'gender' => Helper::genderPerson($row['sex']),
'language' => $row['language'] ?? null, 'language' => $row['language'] ?? null,
'race' => $row['race'] ?? null, 'race' => $row['race'] ?? null,
@@ -474,8 +480,8 @@ class MemberEnrollmentService
$memberPolicy->fill([ $memberPolicy->fill([
'member_id' => $member->member_id, 'member_id' => $member->member_id,
'policy_id' => $row['policy_number'], 'policy_id' => $row['policy_number'],
'start' => Carbon::parse(strtotime($row['member_effective_date'])), 'start' => $this->dateParser($row['member_effective_date']),
'end' => Carbon::parse(strtotime($row['member_expiry_date'])), 'end' => $this->dateParser($row['member_expiry_date']),
'status' => 'active' 'status' => 'active'
]); ]);
$memberPolicy->save(); $memberPolicy->save();
@@ -505,8 +511,8 @@ class MemberEnrollmentService
$member->memberPlans()->create([ $member->memberPlans()->create([
'plan_id' => $plan->id, 'plan_id' => $plan->id,
'status' => 'active', 'status' => 'active',
'start' => Carbon::parse(strtotime($row['member_effective_date'])), 'start' => $this->dateParser($row['member_effective_date']),
'end' => Carbon::parse(strtotime($row['member_expiry_date'])), 'end' => $this->dateParser($row['member_expiry_date']),
]); ]);
} }
DB::commit(); DB::commit();
@@ -620,13 +626,13 @@ class MemberEnrollmentService
} }
if (Carbon::parse(strtotime($row['member_effective_date'])) > Carbon::parse(strtotime($row['member_expiry_date']))) { if ($this->dateParser($row['member_effective_date']) > $this->dateParser($row['member_expiry_date'])) {
throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row);
} }
if ( if (
Carbon::parse($memberPolicy->end) > Carbon::parse(strtotime($row['member_expiry_date'])) Carbon::parse($memberPolicy->end) > $this->dateParser($row['member_expiry_date'])
|| $memberPolicy->end > Carbon::parse(strtotime($row['member_expiry_date'])) || $memberPolicy->end > $this->dateParser($row['member_expiry_date'])
) { ) {
throw new ImportRowException(__('enrollment.MEMBER_RENEWAL_STILL_ACTIVE'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_RENEWAL_STILL_ACTIVE'), 0, null, $row);
} }
@@ -663,13 +669,13 @@ class MemberEnrollmentService
]), 0, null, $row); ]), 0, null, $row);
} }
if (Carbon::parse(strtotime($row['member_effective_date'])) > Carbon::parse(strtotime($row['member_expiry_date']))) { if ($this->dateParser($row['member_effective_date']) > $this->dateParser($row['member_expiry_date'])) {
throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row);
} }
if ( if (
Carbon::parse($memberPolicy->end) > Carbon::parse(strtotime($row['member_expiry_date'])) Carbon::parse($memberPolicy->end) > $this->dateParser($row['member_expiry_date'])
|| $memberPolicy->end > Carbon::parse(strtotime($row['member_expiry_date'])) || $memberPolicy->end > $this->dateParser($row['member_expiry_date'])
) { ) {
throw new ImportRowException(__('enrollment.MEMBER_RENEWAL_STILL_ACTIVE'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_RENEWAL_STILL_ACTIVE'), 0, null, $row);
} }
@@ -850,11 +856,11 @@ class MemberEnrollmentService
]), 0, null, $row); ]), 0, null, $row);
} }
if (Carbon::parse(strtotime($row['member_effective_date'])) < now() || Carbon::parse(strtotime($row['member_expiry_date'])) < now()) { if ($this->dateParser($row['member_effective_date']) < now() || $this->dateParser($row['member_expiry_date']) < now()) {
throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_MUST_BE_AFTER_TODAY'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_MUST_BE_AFTER_TODAY'), 0, null, $row);
} }
if (Carbon::parse(strtotime($row['member_effective_date'])) > Carbon::parse(strtotime($row['member_expiry_date']))) { if ($this->dateParser($row['member_effective_date']) > $this->dateParser($row['member_expiry_date'])) {
throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row);
} }
@@ -889,8 +895,8 @@ class MemberEnrollmentService
$newMemberPolicy->fill([ $newMemberPolicy->fill([
'member_id' => $row['member_id'], 'member_id' => $row['member_id'],
'policy_id' => $row['policy_number'], 'policy_id' => $row['policy_number'],
'start' => Carbon::parse(strtotime($row['member_effective_date'])), 'start' => $this->dateParser($row['member_effective_date']),
'end' => Carbon::parse(strtotime($row['member_expiry_date'])), 'end' => $this->dateParser($row['member_expiry_date']),
'status' => 'active' 'status' => 'active'
]); ]);
$newMemberPolicy->save(); $newMemberPolicy->save();
@@ -931,7 +937,7 @@ class MemberEnrollmentService
throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_NO_CHANGE'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_NO_CHANGE'), 0, null, $row);
} }
if (Carbon::parse(strtotime($row['member_effective_date'])) > Carbon::parse(strtotime($row['member_expiry_date']))) { if ($this->dateParser($row['member_effective_date']) > $this->dateParser($row['member_expiry_date'])) {
throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row); throw new ImportRowException(__('enrollment.MEMBER_EXPIRY_DATE_INVALID'), 0, null, $row);
} }
@@ -1016,7 +1022,15 @@ class MemberEnrollmentService
$cells = []; $cells = [];
foreach ($this->result_doc_headers as $header) { foreach ($this->result_doc_headers as $header) {
$value = $row_data[$this->doc_headers_to_field_map[$header]] ?? null; $value = $row_data[$this->doc_headers_to_field_map[$header]] ?? null;
$cells[] = WriterEntityFactory::createCell($value); if (is_string($value)) {
$cells[] = WriterEntityFactory::createCell($value);
}
else if ($value instanceof DateTime) {
$cells[] = WriterEntityFactory::createCell(Carbon::parse($value)->format('Ymd'));
}
else {
$cells[] = WriterEntityFactory::createCell(null);
}
} }
return $cells; return $cells;

View File

@@ -0,0 +1,53 @@
<?php
namespace Modules\Internal\Transformers;
use Carbon\Carbon;
use Illuminate\Http\Resources\Json\JsonResource;
class AppointmentResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
{
$appointment = [
'id' => $this->nID,
'patient_name' => $this->user ? $this->user->full_name : '',
'doctor_name' => $this->doctor ? $this->doctor->user?->full_name : '',
'speciality' => $this->doctor->speciality->sKeterangan,
'date_appointment' => Carbon::parse($this->appointmentDetail->dTanggalAppointment)->format('d-m-Y') . ' ' . $this->appointmentDetail->tTimeAppointment,
'date_created' => Carbon::parse($this->dCreateOn)->format('d-m-Y H:i:s') ?? null,
'appointment_media' => $this->sMedia,
'status' => $this->status_name,
'health_care' => $this->healthCare->sHealthCare ?? null,
'payment_method' => $this->payment_method ?? null,
'patient' => $this->user,
'booking_code' => $this->sBookingCode,
'his_detail' => [
'RegID' => $this->sRegID,
'Medrec' => $this->sNomorRekamMedis
],
'type' => $this->type
];
$payment_detail = null;
if ($this->appointmentDetail->sPaymentDetails != null) {
$payment_detail = [
'payment_type' => $this->appointmentDetail->sPaymentDetails['payment_type'] ?? '',
'transaction_time' => $this->appointmentDetail->sPaymentDetails['transaction_time'] ?? '',
'gross_amount' => $this->appointmentDetail->sPaymentDetails['gross_amount'] ?? '',
'currency' => $this->appointmentDetail->sPaymentDetails['currency'] ?? '',
'status_message' => $this->appointmentDetail->sPaymentDetails['status_message'] ?? '',
];
}
$appointment['payment_detail'] = $payment_detail;
return $appointment;
}
}

View File

@@ -20,8 +20,8 @@ class CorporateServiceConfigResource extends JsonResource
'corporate_id' => $this->corporate_id, 'corporate_id' => $this->corporate_id,
'service_code' => $this->service_code, 'service_code' => $this->service_code,
'status' => $this->status, 'status' => $this->status,
'name' => $this->service->name, 'name' => $this->service->name ?? '-',
'description' => $this->service->description, 'description' => $this->service->description ?? '-',
'configurations' => $this->configs->pluck('value', 'name'), 'configurations' => $this->configs->pluck('value', 'name'),
'selected_specialities' => $this->corporateServiceSpecialities->where('active', true)->pluck('speciality.name', 'speciality_id'), 'selected_specialities' => $this->corporateServiceSpecialities->where('active', true)->pluck('speciality.name', 'speciality_id'),
'exclusions' => $this->corporateServiceSpecialities->map(function ($speciality) { 'exclusions' => $this->corporateServiceSpecialities->map(function ($speciality) {

View File

@@ -4,6 +4,8 @@ namespace Modules\Internal\Transformers;
use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Http\Resources\Json\JsonResource;
use function PHPSTORM_META\map;
class DoctorResource extends JsonResource class DoctorResource extends JsonResource
{ {
/** /**
@@ -19,35 +21,51 @@ class DoctorResource extends JsonResource
// 'his_dokter_id' => $this->practitionerRoles->meta, // 'his_dokter_id' => $this->practitionerRoles->meta,
'name' => $this->person->name, 'name' => $this->person->name,
'person_id' => $this->person->id, 'person_id' => $this->person->id,
'phone' => $this->person->phone, 'phone' => $this->person->phone ?? null,
'email' => $this->person->email, 'email' => $this->person->email ?? null,
'gender' => $this->person->gender == "L" ? 'Laki-laki' : 'Perempuan', 'birth_date' => $this->person->birth_date ?? null,
'address' => $this->person->currentAddress->text, 'birth_place' => $this->person->birth_place ?? null,
'gender' => $this->person->gender == "L" || $this->person->gender == "male" ? 'male' : 'female',
'address' => $this->person->currentAddress->text ?? null,
'organizations' => $this->practitionerRoles->unique('organization_id')->map(function ($practitionerRole) { 'organizations' => $this->practitionerRoles->unique('organization_id')->map(function ($practitionerRole) {
return [ return [
'organization_id' => $practitionerRole->organization->id, 'organization_id' => $practitionerRole->organization->id,
'organization_name' => $practitionerRole->organization->name, 'organization_name' => $practitionerRole->organization->name,
]; ];
}), })->values(),
"specialties" => $this->practitionerRoles->unique('speciality_id')->map(function ($practitionerRole) { "specialties" => $this->practitionerRoles->unique('speciality_id')->map(function ($practitionerRole) {
return [ return [
'specialty_id' => $practitionerRole->speciality->id, 'specialty_id' => $practitionerRole->speciality->id,
'specialty_name' => $practitionerRole->speciality->name, 'specialty_name' => $practitionerRole->speciality->name,
]; ];
}), }),
"departemen" => $this->practitionerRoles->map(function ($practitionerRole) { // "departemen" => $this->practitionerRoles->map(function ($practitionerRole) {
return [ // return [
'departemen_id' => $practitionerRole->meta->DepartemenID, // 'departemen_id' => $practitionerRole->meta->DepartemenID ?? null,
]; // ];
}), // }) ?? null,
'education' => $this->meta->education, 'education' => $this->meta->education ?? null,
'experience' => $this->meta->work_experience, 'experience' => $this->meta->work_experience ?? null,
'award' => $this->meta->award, 'award' => $this->meta->award ?? null,
'keilmuan' => $this->meta->Keilmuan, 'keilmuan' => $this->meta->Keilmuan ?? null,
'tipe_dokter' => $this->meta->tipeDokter, 'tipe_dokter' => $this->meta->tipeDokter ?? null,
]; ];
$grouped = $this->collection($this->practitionerRoles)->groupBy('organization_id');
$grouped->transform(function ($items, $key) {
return [
'organization_id' => $key,
'specialities' => $items->map(function ($item) {
return [
'speciality_id' => $item->speciality->id,
];
}),
];
});
$doctor['practices'] = $grouped->toArray();
return $doctor; return $doctor;
} }
} }

View File

@@ -0,0 +1,62 @@
<?php
namespace Modules\Internal\Transformers;
use Carbon\Carbon;
use Illuminate\Http\Resources\Json\JsonResource;
class LivechatResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
{
$livechat = [
'id' => $this->nID,
'doctor_name' => isset($this->doctor->user->sFirstName) ? $this->doctor->user->sFirstName . ' ' . $this->doctor->user->sLastName : null,
'speciality' => $this->doctor->speciality->sKeterangan ?? null,
'health_care' => $this->healthCare->sHealthCare ?? null,
'date_appointment' => Carbon::parse($this->appointment->appointmentDetail->dTanggalAppointment)->format('d-m-Y')
. ' ' . $this->appointment->appointmentDetail->tTimeAppointment ?? null,
'status_appointment' => $this->appointment->status_name ?? null,
'date_created' => Carbon::parse($this->appointment->dCreateOn)->format('d-m-Y H:i:s') ?? null,
'patient_media' => $this->sMedia ?? null,
'doctor_media' => $this->sMediaDokter ?? null,
'appointment_media' => $this->appointment->sMedia ?? null,
'status_chat' => $this->status_name ?? null,
'payment_method' => $this->appointment->payment_method ?? null,
];
$start_time = $this->dStartTime;
$end_time = $this->dEndTime;
$data_duration = 0 . ' jam ' . 0 . ' menit ' . 0 . ' detik';
if ($start_time != null && $end_time != null) {
$duration = Carbon::parse($start_time)->diffInMinutes(Carbon::parse($end_time));
$hours = floor($duration / 60);
$minutes = $duration % 60;
$seconds = ($duration - ($hours * 60) - $minutes) * 60;
$data_duration = $hours . ' jam ' . $minutes . ' menit ' . $seconds . ' detik';
}
$livechat['duration'] = $data_duration;
$payment_detail = null;
if ($this->appointment->appointmentDetail->sPaymentDetails != null) {
$payment_detail = [
'payment_type' => $this->appointment->appointmentDetail->sPaymentDetails['payment_type'],
'transaction_time' => $this->appointment->appointmentDetail->sPaymentDetails['transaction_time'],
'gross_amount' => $this->appointment->appointmentDetail->sPaymentDetails['gross_amount'],
'currency' => $this->appointment->appointmentDetail->sPaymentDetails['currency'],
'status_message' => $this->appointment->appointmentDetail->sPaymentDetails['status_message'],
];
}
$livechat['payment_detail'] = $payment_detail;
return $livechat;
}
}

View File

@@ -14,17 +14,24 @@ class OrganizationResource extends JsonResource
*/ */
public function toArray($request) public function toArray($request)
{ {
$organization = [ $organization = [
'id' => $this->id, 'id' => $this->id,
'name' => $this->name, 'name' => $this->name,
'type' => $this->type, 'type' => $this->type,
'code' => $this->code, 'code' => $this->code,
'description' => $this->description, 'description' => $this->description,
'kodeRs' => $this->meta->kodeRs ?? null, 'kodeRs' => $this->meta->KodeRS ?? null,
'phone' => $this->meta->phone ?? null, 'phone' => $this->meta->phone ?? null,
'lat' => $this->currentAddress->lat ?? null, 'lat' => $this->currentAddress->lat ?? null,
'lng' => $this->currentAddress->lng ?? null, 'lng' => $this->currentAddress->lng ?? null,
'address' => $this->currentAddress ?? null, 'address' => $this->currentAddress->text ?? null,
'province_id' => $this->currentAddress->province_id ?? null,
'city_id' => $this->currentAddress->city_id ?? null,
'district_id' => $this->currentAddress->district_id ?? null,
'village_id' => $this->currentAddress->village_id ?? null,
'postal_code' => $this->currentAddress->postal_code ?? null,
'active' => $this->status == 'active' ? 1 : 0,
]; ];
return $organization; return $organization;

View File

@@ -6,8 +6,11 @@ use App\Helpers\Helper;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Icd; use App\Models\Icd;
use App\Models\Member; use App\Models\Member;
use App\Models\Claim;
use App\Models\Speciality;
use App\Services\ClaimService; use App\Services\ClaimService;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class ClaimController extends Controller class ClaimController extends Controller
{ {
@@ -16,19 +19,23 @@ class ClaimController extends Controller
$request->validate([ $request->validate([
'member_id' => 'required', 'member_id' => 'required',
'user_id' => 'required', 'user_id' => 'required',
'type' => 'required|in:consultation-gp,consultation-specialist,medicine', 'type' => 'required|in:consultation,teleconsultation,medicine',
// 'speciality_code' => 'required',
'total_claim' => 'required', 'total_claim' => 'required',
'detail' => 'required', 'detail' => 'required',
]); ]);
if ($request->type == 'consultation-gp') { $currentSpeciality = Speciality::where('code', $request->speciality_code)->first();
$benefitCode = 'OPCONS1';
} $gpSpecialityName = config('aso.general_practitioner_speciality_name', 'Umum');
if ($request->type == 'consultation-specialist') { $isGp = $gpSpecialityName == ($currentSpeciality ? $currentSpeciality->name : false);
$benefitCode = 'OPCONS2';
}
if ($request->type == 'medicine') { if ($request->type == 'medicine') {
$benefitCode = 'OPMEDI1'; $benefitCode = 'OPMEDI1';
} else if ($isGp) {
$benefitCode = 'OPCONS1';
} else {
$benefitCode = 'OPCONS2';
} }
$member = Member::query() $member = Member::query()
@@ -38,7 +45,6 @@ class ClaimController extends Controller
]) ])
->firstOrFail(); ->firstOrFail();
$benefit = $member->currentPlan->benefits()->where('code', $benefitCode)->first(); $benefit = $member->currentPlan->benefits()->where('code', $benefitCode)->first();
// $diagnosis = Icd::first();
$claim = ClaimService::storeClaim($member, null, $request->total_claim, $benefit, 'requested'); $claim = ClaimService::storeClaim($member, null, $request->total_claim, $benefit, 'requested');
$claim->status = 'approved'; $claim->status = 'approved';
@@ -54,7 +60,29 @@ class ClaimController extends Controller
'icd_codes' => 'required' 'icd_codes' => 'required'
]); ]);
// dd($request->toArray()); $claim = Claim::where('code', $request->claim_code)->firstOrFail();
return $request->toArray();
try {
DB::beginTransaction();
$claim->fill(['status' => 'postpone'])->update();
$icds = Icd::whereIn('code', $request['icd_codes'])->get();
$icds = $icds->map(function($icd) use ($claim) {
return [
'claim_id' => $claim->id,
'type' => 'primary',
'diagnosis_id' => $icd->id,
'note' => 'HIS Summary',
'description'=> ''
];
})->toArray();
return $claim->diagnoses()->insert($icds);
DB::commit();
} catch (\Exception $e) {
DB::rollback();
return Helper::responseJson($e, 500);
};
} }
} }

View File

@@ -25,7 +25,7 @@ class MembershipController extends Controller
} }
if (!$member->active) { if (!$member->active) {
return Helper::responseJson(statusCode: 406, message: 'The Member '.$request->member_id.' is Inactive.', status: 'error'); return Helper::responseJson(statusCode: 406, message: 'The Member ' . $request->member_id . ' is Inactive.', status: 'error');
} }
return Helper::responseJson(data: $member, message: 'Member Found'); return Helper::responseJson(data: $member, message: 'Member Found');
@@ -35,68 +35,30 @@ class MembershipController extends Controller
{ {
$request->validate([ $request->validate([
'member_id' => 'required', 'member_id' => 'required',
'type' => 'required|in:consultation-gp,consultation-specialist,medicine', 'type' => 'required|in:consultation,teleconsultation,medicine',
// 'speciality_code' => 'sometimes' // 'speciality_code' => 'sometimes'
]); ]);
if ($request->type == 'consultation-gp') { $member = Member::query()
$benefitCode = 'OPCONS1'; ->where('member_id', $request->member_id)
} ->with(['currentCorporate', 'currentPolicy', 'currentPlan', 'postponedClaims'])
if ($request->type == 'consultation-specialist') { ->first();
$benefitCode = 'OPCONS2';
}
if ($request->type == 'medicine') {
$benefitCode = 'OPMEDI1';
}
$member = Member::where('member_id', $request->member_id)->with(['currentCorporate', 'currentPolicy', 'currentPlan', 'postponedClaims'])->first(); $corporateService = $member->currentCorporate->corporateServices()
$limits = ClaimService::showMemberBenefitLimit($member, $benefitCode);
$limits['postponed_claims'] = $member->postponedClaims;
$limits['postponed_claims_payment_url'] = route('postpone-pay', $member->member_id);
$limits['postponed_claims_unpaid_total'] = $member->postponedClaims->sum('total_claim');
$corporateService = $member->currentCorporate
->corporateServices()
->active() ->active()
->where('service_code', 'OP') ->where('service_code', 'OP')
->with([ ->with([
'configs', 'configs',
'specialities' => function ($speciality) use ($request) { 'specialities' => function ($speciality) use ($request) {
$speciality->where('code', $request->speciality_code) $speciality->where('code', $request->speciality_code ?? null)
->wherePivot('active', 1); ->wherePivot('active', 1);
}]) }
])
->first(); ->first();
$configs = $corporateService->configs->mapWithKeys(function ($config) { $currentSpeciality = $corporateService->specialities->first();
return [$config->name => $config];
});
$coverage = [ if ($currentSpeciality) {
'benefit' => false,
'admin_fee' => false,
'medicine_benefit' => true, // TODO Make this into setting ?
'medicine_delivery_fee' => false
];
$coverage['medicine_delivery_fee'] = (($configs['delivery_fee']['value'] ?? 1) == 1);
$coverage['gp_benefit'] = (($configs['gp_internal_doctor_online']['value'] ?? 1) == 1);
$coverage['gp_admin_fee'] = (($configs['general_practitioner_fee']['value'] ?? 1) == 1);
$coverage['sp_benefit'] = (($configs['sp_internal_doctor_online']['value'] ?? 1) == 1);
$coverage['sp_admin_fee'] = (($configs['specialist_practitioner_fee']['value'] ?? 1) == 1);
if ($request->has('speciality_code') && !empty($request->speciality_code)) {
if (empty($corporateService) || empty($corporateService->specialities)) {
$coverage['benefit'] = false;
$coverage['admin_fee'] = false;
$limits['coverage'] = $coverage;
return Helper::responseJson(data: $limits);
}
$currentSpeciality = $corporateService->specialities->first();
// Load the Relation Data after speciality check is supported
$corporateService->load([ $corporateService->load([
'corporateServiceSpecialities' => function ($corporateServiceSpeciality) use ($currentSpeciality) { 'corporateServiceSpecialities' => function ($corporateServiceSpeciality) use ($currentSpeciality) {
$corporateServiceSpeciality->where('speciality_id', $currentSpeciality->id); $corporateServiceSpeciality->where('speciality_id', $currentSpeciality->id);
@@ -106,94 +68,105 @@ class MembershipController extends Controller
}, },
'corporateServiceSpecialities.exclusions.rules' 'corporateServiceSpecialities.exclusions.rules'
]); ]);
}
$serviceSpeciality = $corporateService->corporateServiceSpecialities->first() ?? null; $corporateServiceSpeciality = $corporateService->corporateServiceSpecialities->first() ?? null;
$serviceSpecialityRules = $serviceSpeciality->exclusions->first()->rules ?? collect([]);
$serviceSpecialityRules = $serviceSpecialityRules->mapWithKeys(function ($rule) {
return [$rule->name => $rule];
});
$gpSpecialityName = config('aso.general_practitioner_speciality_name', 'Umum'); $serviceSpecialityRules = $corporateServiceSpeciality->exclusions->first()->rules ?? collect([]);
$serviceSpecialityRules = $serviceSpecialityRules->mapWithKeys(function ($rule) {
return [$rule->name => $rule];
});
if ($gpSpecialityName == $currentSpeciality->name) { $configs = $corporateService->configs->mapWithKeys(function ($config) {
// To General Practitioner return [$config->name => $config];
if (($configs['gp_internal_doctor_online']['value'] ?? 1) == 1) { });
$coverage['benefit'] = true;
}
if (($configs['general_practitioner_fee']['value'] ?? 1) == 1) { $gpSpecialityName = config('aso.general_practitioner_speciality_name', 'Umum');
$coverage['admin_fee'] = true; $isGp = $gpSpecialityName == ($currentSpeciality ? $currentSpeciality->name : false);
}
if ($serviceSpeciality->active == 1) { if ($request->type == 'medicine') {
$coverage['benefit'] = true; $benefitCode = 'OPMEDI1';
} } else if ($isGp) {
$benefitCode = 'OPCONS1';
} else {
$benefitCode = 'OPCONS2';
}
} else { $limits = ClaimService::showMemberBenefitLimit($member, $benefitCode);
// To Specialist $limits['postponed_claims'] = $member->postponedClaims;
if (($configs['sp_internal_doctor_online']['value'] ?? 1) == 1) { $limits['postponed_claims_payment_url'] = route('postpone-pay', $member->member_id);
$coverage['benefit'] = true; $limits['postponed_claims_unpaid_total'] = $member->postponedClaims->sum('total_claim');
}
// dd($configs['specialist_practitioner_fee']['value'], $configs['specialist_practitioner_fee']['value'] ?? 1, ($configs['specialist_practitioner_fee']['value'] ?? 1) == 1);
if (($configs['specialist_practitioner_fee']['value'] ?? 1) == 1) { $coverage['medicine_benefit'] = false;
$coverage['admin_fee'] = true; if ($benefitCode = 'OPMEDI1') {
} $medicineBenefit = $member->currentPlan->benefits()->where('code', $benefitCode)->wherePivot('active', 1)->first();
$coverage['medicine_benefit'] = !empty($medicineBenefit);
}
$coverage['medicine_delivery_fee'] = (($configs['delivery_fee']['value'] ?? 1) == 1);
if ($serviceSpeciality->active == 1) { if ($currentSpeciality) {
$coverage['benefit'] = true; $xCoverage['sp_consultation_benefit'] = (($configs['sp_internal_doctor_offline']['value'] ?? 1) == 1);
} $xCoverage['sp_teleconsultation_benefit'] = (($configs['sp_internal_doctor_online']['value'] ?? 1) == 1);
} $xCoverage['gp_consultation_benefit'] = (($configs['gp_internal_doctor_offline']['value'] ?? 1) == 1);
$xCoverage['gp_teleconsultation_benefit'] = (($configs['gp_internal_doctor_online']['value'] ?? 1) == 1);
$coverage['consultation_benefit'] = ($isGp)
// TODO THIS EXCLUSION IS USED AS INCLUSION NOW, MUST BE CHANGE TO USED AS EXCLUSION AND MAYBE MOVE THE TABLE ? $xCoverage['gp_consultation_benefit']
$excluded = []; : $xCoverage['sp_consultation_benefit'];
foreach ($serviceSpecialityRules as $ruleName => $rule) { $coverage['teleconsultation_benefit'] = ($isGp)
if ($ruleName == 'msc') { ? $xCoverage['gp_teleconsultation_benefit']
$values = explode(',', $rule->values); : $xCoverage['sp_teleconsultation_benefit'];
if (!in_array(strtolower($member->marital_status), $values)) {
$excluded[] = $rule;
}
}
if ($ruleName == 'gender') {
$values = explode(',', $rule->values);
if (!in_array(strtolower($member->gender), $values)) {
$excluded[] = $rule;
}
}
if ($ruleName == 'min_age') {
if (!empty($rule->values) && $member->age < $rule->values) {
$excluded[] = $rule;
}
}
if ($ruleName == 'max_age') {
if (!empty($rule->values) && $member->age > $rule->values) {
$excluded[] = $rule;
}
}
if ($ruleName == 'plan') {
$values = explode(',', $rule->values);
if (!in_array($member->currentPlan->code, $values)) {
$excluded[] = $rule;
}
}
}
if ( count($excluded) ) {
$coverage['benefit'] = false;
$coverage['benefit_exclusion'] = $excluded;
} else {
$coverage['benefit'] = true;
}
$xCoverage['sp_admin_fee'] = (($configs['specialist_practitioner_fee']['value'] ?? 1) == 1);
$xCoverage['gp_admin_fee'] = (($configs['general_practitioner_fee']['value'] ?? 1) == 1);
$coverage['admin_fee'] = ($isGp)
? $xCoverage['gp_admin_fee']
: $xCoverage['sp_admin_fee'];
} else {
// Not Supported
$coverage['consultation_benefit'] = false;
$coverage['teleconsultation_benefit'] = false;
$coverage['admin_fee'] = false;
} }
$limits['coverage'] = $coverage; $limits['coverage'] = $coverage;
// TODO THIS EXCLUSION IS USED AS INCLUSION NOW, MUST BE CHANGE TO USED AS EXCLUSION AND MAYBE MOVE THE TABLE
$excluded = [];
foreach ($serviceSpecialityRules as $ruleName => $rule) {
if ($ruleName == 'msc') {
$values = explode(',', $rule->values);
if (!in_array(strtolower($member->marital_status), $values)) {
$excluded[] = $rule;
}
}
if ($ruleName == 'gender') {
$values = explode(',', $rule->values);
if (!in_array(strtolower($member->gender), $values)) {
$excluded[] = $rule;
}
}
if ($ruleName == 'min_age') {
if (!empty($rule->values) && $member->age < $rule->values) {
$excluded[] = $rule;
}
}
if ($ruleName == 'max_age') {
if (!empty($rule->values) && $member->age > $rule->values) {
$excluded[] = $rule;
}
}
if ($ruleName == 'plan') {
$values = explode(',', $rule->values);
if (!in_array($member->currentPlan->code, $values)) {
$excluded[] = $rule;
}
}
}
return Helper::responseJson(data: $limits); return Helper::responseJson(data: $limits);
} }
} }

View File

@@ -11,12 +11,13 @@ use App\Events\ClaimRequested;
use App\Traits\Blameable; use App\Traits\Blameable;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str; use Illuminate\Support\Str;
class Claim extends Model class Claim extends Model
{ {
use HasFactory, Blameable; use HasFactory, Blameable, SoftDeletes;
protected $fillable = [ protected $fillable = [
'code', 'code',

View File

@@ -215,6 +215,11 @@ class CorporateBenefit extends Model
return $this->belongsTo(Plan::class); return $this->belongsTo(Plan::class);
} }
public function scopeActive($query)
{
$query->where('active', 1);
}
public function scopeFilter($query, array $filters) public function scopeFilter($query, array $filters)
{ {
$query->when($filters['search'] ?? false, function ($query, $search) { $query->when($filters['search'] ?? false, function ($query, $search) {

View File

@@ -4,10 +4,11 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class CorporateManager extends Model class CorporateManager extends Model
{ {
use HasFactory; use HasFactory, SoftDeletes;
protected $table = 'corporate_manager'; protected $table = 'corporate_manager';
} }

View File

@@ -2,6 +2,7 @@
namespace App\Models\OLDLMS; namespace App\Models\OLDLMS;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
@@ -14,12 +15,99 @@ class Appointment extends Model
const UPDATED_AT = 'dUpdateOn'; const UPDATED_AT = 'dUpdateOn';
const DELETED_AT = 'dDeleteOn'; const DELETED_AT = 'dDeleteOn';
public $sStatusNames = [
0 => 'Menunggu Pembayaran',
1 => 'Pembayaran Terkonfirmasi', // Pembayaran Diterima
2 => 'Ditolak',
3 => 'Dibatalkan', // Canceled
4 => 'Expired',
];
public $sPaymentMethodName = [
1 => 'Pribadi',
2 => 'On-Site Payment',
3 => 'OVO',
4 => 'Asuransi',
5 => 'Voucher',
];
public $nIDJenisBookingNames = [
1 => 'Rawat Jalan',
2 => 'Telekonsultasi',
3 => 'Chat Sekarang'
];
protected $connection = 'oldlms'; protected $connection = 'oldlms';
protected $table = 'tx_appointment'; protected $table = 'tx_appointment';
public function detail() protected $primaryKey = 'nID';
public $incrementing = false;
protected $keyType = 'string';
protected $fillable = [
'nID',
'nIDDokter',
'nIDUser',
'sStatus',
'dCreateOn',
'dUpdateOn',
'dDeleteOn',
];
protected $appends = [
'status_name',
'payment_method',
'type'
];
protected function statusName(): Attribute
{ {
return $this->hasOne(AppointmentDetail::class, ''); return Attribute::make(
get: function ($value) {
return $this->sStatusNames[$this->sStatus] ?? '-';
},
);
}
protected function paymentMethod(): Attribute
{
return Attribute::make(
get: function ($value) {
return $this->sPaymentMethodName[$this->sPaymentMethod] ?? '-';
},
);
}
protected function type(): Attribute
{
return Attribute::make(
get: function($value) {
return $this->nIDJenisBookingNames[$this->nIDJenisBooking] ?? '-';
}
);
}
public function appointmentDetail()
{
return $this->hasOne(AppointmentDetail::class, 'nIDAppointment', 'nID');
}
public function doctor()
{
return $this->belongsTo(Dokter::class, 'nIDDokter', 'nID');
}
public function user()
{
return $this->belongsTo(User::class, 'nIDUser', 'nID');
}
public function healthCare()
{
return $this->belongsTo(Healthcare::class, 'nIDHealthCare', 'nID');
} }
} }

View File

@@ -8,4 +8,19 @@ use Illuminate\Database\Eloquent\Model;
class AppointmentDetail extends Model class AppointmentDetail extends Model
{ {
use HasFactory; use HasFactory;
const CREATED_AT = 'dCreateOn';
const UPDATED_AT = 'dUpdateOn';
const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms';
protected $table = 'tx_appointment_detail';
protected $casts = [
'sPaymentDetails' => 'array',
];
public function appointment()
{
return $this->belongsTo(Appointment::class, 'nIDAppointment', 'nID');
}
} }

View File

@@ -0,0 +1,37 @@
<?php
namespace App\Models\OLDLMS;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Dokter extends Model
{
use HasFactory, SoftDeletes;
const CREATED_AT = 'dCreateOn';
const UPDATED_AT = 'dUpdateOn';
const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms';
protected $table = 'tm_dokter';
protected $primaryKey = 'nID';
public function jadwalDokter()
{
return $this->hasMany(JadwalDokter::class, 'nIDDokter', 'nID');
}
public function user()
{
return $this->belongsTo(User::class, 'nIDUser', 'nID');
}
public function speciality()
{
return $this->belongsTo(Speciality::class, 'nIDSpesialis', 'nID');
}
}

View File

@@ -4,8 +4,24 @@ namespace App\Models\OLDLMS;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Healthcare extends Model class Healthcare extends Model
{ {
use HasFactory; use HasFactory, SoftDeletes;
const CREATED_AT = 'dCreateOn';
const UPDATED_AT = 'dUpdateOn';
const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms';
protected $table = 'tm_healthcare';
protected $primaryKey = 'nID';
public function jadwalDokter()
{
return $this->hasMany(JadwalDokter::class, 'nIDHealthCare', 'nID');
}
} }

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Models\OLDLMS;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class JadwalDokter extends Model
{
use HasFactory, SoftDeletes;
const CREATED_AT = 'dCreateOn';
const UPDATED_AT = 'dUpdateOn';
const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms';
protected $table = 'tx_jadwal_dokter';
protected $primaryKey = 'nID';
public function jadwalDokterDay()
{
return $this->hasMany(JadwalDokterDay::class, 'nIDJadwalDokter', 'nID');
}
public function healthcare()
{
return $this->belongsTo(Healthcare::class, 'nIDHealthCare', 'nID');
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Models\OLDLMS;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class JadwalDokterDay extends Model
{
use HasFactory, SoftDeletes;
const CREATED_AT = 'dCreateOn';
const UPDATED_AT = 'dUpdateOn';
const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms';
protected $table = 'tx_jadwal_dokter_detail';
protected $primaryKey = 'nID';
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Models\OLDLMS;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
class Livechat extends Model
{
use HasFactory;
public $sStatusNames = [
0 => 'Menunggu Konfirmasi',
1 => 'Diterima',
2 => 'Ditolak',
3 => 'Selesai',
4 => 'Expired',
];
const CREATED_AT = 'dCreateOn';
const UPDATED_AT = 'dUpdateOn';
const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms';
protected $table = 'tx_livechat';
protected $appends = [
'status_name',
];
protected function statusName(): Attribute
{
return Attribute::make(
get: function ($value) {
return $this->sStatusNames[$this->sStatus] ?? '-';
},
);
}
public function user()
{
return $this->belongsTo(User::class, 'nIDUser', 'nID');
}
public function doctor()
{
return $this->belongsTo(Dokter::class, 'nIDDokter', 'nID');
}
public function appointment()
{
return $this->belongsTo(Appointment::class, 'nIDAppointment', 'nID');
}
public function healthCare()
{
return $this->belongsTo(Healthcare::class, 'nIDHealthCare', 'nID');
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Models\OLDLMS;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Speciality extends Model
{
use HasFactory;
const CREATED_AT = 'dCreateOn';
const UPDATED_AT = 'dUpdateOn';
const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms';
protected $table = 'tm_spesialis';
protected $primaryKey = 'nID';
public function dokter()
{
return $this->hasMany(Dokter::class, 'nIDSpesialis', 'nID');
}
}

View File

@@ -2,10 +2,46 @@
namespace App\Models\OLDLMS; namespace App\Models\OLDLMS;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Model class User extends Model
{ {
use HasFactory; use HasFactory, SoftDeletes;
const CREATED_AT = 'dCreateOn';
const UPDATED_AT = 'dUpdateOn';
const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms';
protected $table = 'tm_users';
protected $appends = [
'full_name',
];
protected function fullName(): Attribute
{
return Attribute::make(
get: function ($value) {
$names = [];
if (!empty($this->sFirstName)) {
array_push($names, $this->sFirstName);
}
if (!empty($this->sLastName)) {
array_push($names, $this->sLastName);
}
return implode(' ', $names);
}
);
}
public function detail()
{
return $this->hasOne(UserDetail::class, 'nIDUser', 'nID');
}
} }

View File

@@ -8,4 +8,13 @@ use Illuminate\Database\Eloquent\Model;
class UserDetail extends Model class UserDetail extends Model
{ {
use HasFactory; use HasFactory;
const CREATED_AT = 'dCreateOn';
const UPDATED_AT = 'dUpdateOn';
const DELETED_AT = 'dDeleteOn';
protected $connection = 'oldlms';
protected $table = 'tm_users_detail';
} }

View File

@@ -114,6 +114,11 @@ class Person extends Model
return $this->hasOne(User::class, 'person_id'); return $this->hasOne(User::class, 'person_id');
} }
public function practitioner()
{
return $this->hasOne(Practitioner::class, 'person_id');
}
public function appointmentParticipantables() public function appointmentParticipantables()
{ {
return $this->morphMany(AppointmentParticipant::class, 'participantable'); return $this->morphMany(AppointmentParticipant::class, 'participantable');

View File

@@ -48,13 +48,26 @@ class User extends Authenticatable
]; ];
public $with = [ public $with = [
'metas' 'metas',
'person'
]; ];
public $appends = [ public $appends = [
'meta' 'meta',
'avatar_url',
'full_name'
]; ];
public function getAvatarUrlAttribute()
{
return asset('images/specialities/anak.png');
}
public function getFullNameAttribute()
{
return $this->person?->full_name;
}
public function getMetaAttribute() public function getMetaAttribute()
{ {
$orgMeta = []; $orgMeta = [];

View File

@@ -112,8 +112,12 @@ class ClaimService{
// $policy = $member->currentPolicy; // $policy = $member->currentPolicy;
// $corporate = $member->currentCorporate; // $corporate = $member->currentCorporate;
$benefit = $member->currentPlan->benefits()->where('code', $benefit_code)->first(); $benefit = $member->currentPlan->benefits()->where('code', $benefit_code)->first();
// dd($member->currentPlan->benefits->toArray()); $corporateBenefit = $member->currentPlan
$corporateBenefit = $member->currentPlan->corporateBenefits()->where('benefit_id', $benefit->id)->first(); ->corporateBenefits()
->where('benefit_id', $benefit->id ?? null)
->where('plan_id', $member->currentPlan->id)
->active()
->first();
// dd($benefit->toArray()); // dd($benefit->toArray());
// dd(compact(['plan', 'policy', 'corporate', 'benefit'])); // dd(compact(['plan', 'policy', 'corporate', 'benefit']));
@@ -129,7 +133,7 @@ class ClaimService{
'usage_yearly' => null 'usage_yearly' => null
]; ];
switch ($corporateBenefit->max_frequency_period) { switch ($corporateBenefit->max_frequency_period ?? 0) {
case(0) : case(0) :
$limits['usage_yearly'] = $member->claims()->used(Carbon::now()->firstOfYear(), now())->count(); $limits['usage_yearly'] = $member->claims()->used(Carbon::now()->firstOfYear(), now())->count();
$limits['total_claim'] = $member->claims()->used(Carbon::now()->firstOfYear(), now())->sum('total_claim'); $limits['total_claim'] = $member->claims()->used(Carbon::now()->firstOfYear(), now())->sum('total_claim');
@@ -154,7 +158,7 @@ class ClaimService{
// return null; // return null;
break; break;
} }
$limits['remaining_limit'] = $corporateBenefit->limit_amount - $limits['total_claim']; $limits['remaining_limit'] = ($corporateBenefit->limit_amount ?? 0) - $limits['total_claim'];
return $limits; return $limits;
} }

View File

@@ -39,19 +39,36 @@ class LmsApi
$data['channel'] = 'Website'; $data['channel'] = 'Website';
} }
$res = self::http()->post( self::baseUrl() . '/jadwaldokter', $data)->json(); $res = self::http()->post(self::baseUrl() . '/jadwaldokter', $data)->json();
// Reformat Jam Data // Reformat Jam Data
$res['data'] = collect($res['data'])->map(function($day) { $res['data'] = collect($res['data'])->map(function ($day) {
$day['Jam'] = !empty($day['Jam']) ? explode(', ', $day['Jam']) : null; $day['Jam'] = !empty($day['Jam']) ? explode(', ', $day['Jam']) : null;
return $day; return $day;
})->toArray(); })->toArray();
return $res; return $res;
} }
/**
* dokter
*
*
*/
public static function dokter($kodeRs, $channel = 'hospitaloka', $timeout = 30)
{
$data = [
'rs' => $kodeRs,
'channel' => $channel,
];
$res = self::http()->timeout($timeout)->post('http://lmsapi.primaya.id/dokter', $data)->json();
return $res;
}
/** /**
* jadwalDokterTersedia * jadwalDokterTersedia
* *
@@ -72,16 +89,15 @@ class LmsApi
$data['channel'] = 'Website'; $data['channel'] = 'Website';
} }
$res = self::http()->post( self::baseUrl() . '/jadwaldoktertersedia', $data)->json(); $res = self::http()->post(self::baseUrl() . '/jadwaldoktertersedia', $data)->json();
// Reformat Jam Data // Reformat Jam Data
$res['data'] = collect($res['data'])->map(function($day) { $res['data'] = collect($res['data'])->map(function ($day) {
// Change jam to Jam to Standarize // Change jam to Jam to Standarize
$day['Jam'] = !empty($day['jam']) ? explode(', ', $day['jam']) : null; $day['Jam'] = !empty($day['jam']) ? explode(', ', $day['jam']) : null;
unset($day['jam']); unset($day['jam']);
return $day; return $day;
})->toArray(); })->toArray();
return $res; return $res;
@@ -113,7 +129,7 @@ class LmsApi
throw new Exception('name, birth_date, nik, phone are required in $patientData'); throw new Exception('name, birth_date, nik, phone are required in $patientData');
} }
$res = self::http()->post( self::baseUrl() . '/medrec_nama', $data)->json(); $res = self::http()->post(self::baseUrl() . '/medrec_nama', $data)->json();
return $res; return $res;
} }
@@ -141,7 +157,7 @@ class LmsApi
throw new Exception('name, birth_date are required in $patientData'); throw new Exception('name, birth_date are required in $patientData');
} }
$res = self::http()->post( self::baseUrl() . '/cek_gantung', $data)->json(); $res = self::http()->post(self::baseUrl() . '/cek_gantung', $data)->json();
return $res; return $res;
} }
@@ -156,7 +172,7 @@ class LmsApi
* @param string $type HIS Slot Type walkin, teleconsultation * @param string $type HIS Slot Type walkin, teleconsultation
* @return void * @return void
*/ */
public static function checkSlot( $HISKodeRS, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $type ) public static function checkSlot($HISKodeRS, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $type)
{ {
$data = [ $data = [
@@ -169,7 +185,7 @@ class LmsApi
$data['channel'] = 'Website'; $data['channel'] = 'Website';
} }
$res = self::http()->post( self::baseUrl() . '/cek_slot', $data)->json(); $res = self::http()->post(self::baseUrl() . '/cek_slot', $data)->json();
return $res; return $res;
} }
@@ -189,7 +205,8 @@ class LmsApi
* @param mixed $userId * @param mixed $userId
* @return void * @return void
*/ */
public static function appointmentBaru( $HISKodeRS, $HISKodeDep, $HISKodeDokter, $jenisTC, $tanggalAppointment, $jamAppointment, $jumlahBayar, $kodePembayaran, $patientData, $userId ) { public static function appointmentBaru($HISKodeRS, $HISKodeDep, $HISKodeDokter, $jenisTC, $tanggalAppointment, $jamAppointment, $jumlahBayar, $kodePembayaran, $patientData, $userId)
{
$data = [ $data = [
'rs' => $HISKodeRS, 'rs' => $HISKodeRS,
'dep' => $HISKodeDep, 'dep' => $HISKodeDep,
@@ -220,7 +237,7 @@ class LmsApi
'jam' => $jamAppointment, 'jam' => $jamAppointment,
]; ];
$res = self::http()->post( self::baseUrl() . '/appointment_baru', $data)->json(); $res = self::http()->post(self::baseUrl() . '/appointment_baru', $data)->json();
return $res; return $res;
} }
@@ -241,7 +258,8 @@ class LmsApi
* @param mixed $userId * @param mixed $userId
* @return void * @return void
*/ */
public static function appointment( $HISKodeRS, $HISKodeDep, $HISKodeDokter, $jenisTC, $tanggalAppointment, $jamAppointment, $jumlahBayar, $kodePembayaran, $HISMedrec, $patientData, $userId ) { public static function appointment($HISKodeRS, $HISKodeDep, $HISKodeDokter, $jenisTC, $tanggalAppointment, $jamAppointment, $jumlahBayar, $kodePembayaran, $HISMedrec, $patientData, $userId)
{
$data = [ $data = [
'rs' => $HISKodeRS, 'rs' => $HISKodeRS,
'dep' => $HISKodeDep, 'dep' => $HISKodeDep,
@@ -259,7 +277,7 @@ class LmsApi
'jam' => $jamAppointment, 'jam' => $jamAppointment,
]; ];
$res = self::http()->post( self::baseUrl() . '/appointment', $data)->json(); $res = self::http()->post(self::baseUrl() . '/appointment', $data)->json();
return $res; return $res;
} }
@@ -277,7 +295,7 @@ class LmsApi
* @param mixed $patientData * @param mixed $patientData
* @return void * @return void
*/ */
public static function appointmentEdit( $HISRegid, $HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $HISMedrec, $patientData ) public static function appointmentEdit($HISRegid, $HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $HISMedrec, $patientData)
{ {
$data = [ $data = [
'regid' => $HISRegid, 'regid' => $HISRegid,
@@ -293,7 +311,7 @@ class LmsApi
'jam' => $jamAppointment, 'jam' => $jamAppointment,
]; ];
$res = self::http()->post( self::baseUrl() . '/appointment_edit', $data)->json(); $res = self::http()->post(self::baseUrl() . '/appointment_edit', $data)->json();
return $res; return $res;
} }
@@ -314,7 +332,8 @@ class LmsApi
* @param mixed $nomorRujukanBPJS * @param mixed $nomorRujukanBPJS
* @return void * @return void
*/ */
public static function booking( $HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $HISMedrec, $patientData, $jenisPenjamin = 0, $namaPenjamin = '', $nomorKartuBPJS = null, $nomorRujukanBPJS = null ) { public static function booking($HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $HISMedrec, $patientData, $jenisPenjamin = 0, $namaPenjamin = '', $nomorKartuBPJS = null, $nomorRujukanBPJS = null)
{
$data = [ $data = [
'rs' => $HISKodeRS, 'rs' => $HISKodeRS,
'dep' => $HISKodeDep, 'dep' => $HISKodeDep,
@@ -334,7 +353,7 @@ class LmsApi
'norujukan' => $nomorRujukanBPJS 'norujukan' => $nomorRujukanBPJS
]; ];
$res = self::http()->post( self::baseUrl() . '/booking', $data)->json(); $res = self::http()->post(self::baseUrl() . '/booking', $data)->json();
return $res; return $res;
} }
@@ -354,7 +373,8 @@ class LmsApi
* @param mixed $nomorRujukanBPJS * @param mixed $nomorRujukanBPJS
* @return void * @return void
*/ */
public static function bookingBaru( $HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $patientData, $jenisPenjamin = 0, $namaPenjamin = '', $nomorKartuBPJS = null, $nomorRujukanBPJS = null) { public static function bookingBaru($HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $patientData, $jenisPenjamin = 0, $namaPenjamin = '', $nomorKartuBPJS = null, $nomorRujukanBPJS = null)
{
$data = [ $data = [
'rs' => $HISKodeRS, 'rs' => $HISKodeRS,
'dep' => $HISKodeDep, 'dep' => $HISKodeDep,
@@ -386,7 +406,7 @@ class LmsApi
'norujukan' => $nomorRujukanBPJS 'norujukan' => $nomorRujukanBPJS
]; ];
$res = self::http()->post( self::baseUrl() . '/booking_baru', $data)->json(); $res = self::http()->post(self::baseUrl() . '/booking_baru', $data)->json();
return $res; return $res;
} }
@@ -409,7 +429,8 @@ class LmsApi
* @param mixed $nomorRujukanBPJS * @param mixed $nomorRujukanBPJS
* @return void * @return void
*/ */
public static function bookingEdit( $kodeBooking, $HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $tanggalAppointmentBaru, $jamAppointmentBaru, $jenisPenjamin = 0, $namaPenjamin = '', $nomorKartuBPJS = null, $nomorRujukanBPJS = null ) { public static function bookingEdit($kodeBooking, $HISKodeRS, $HISKodeDep, $HISKodeDokter, $tanggalAppointment, $jamAppointment, $tanggalAppointmentBaru, $jamAppointmentBaru, $jenisPenjamin = 0, $namaPenjamin = '', $nomorKartuBPJS = null, $nomorRujukanBPJS = null)
{
$data = [ $data = [
'kodebooking' => $kodeBooking, 'kodebooking' => $kodeBooking,
'rs' => $HISKodeRS, 'rs' => $HISKodeRS,
@@ -425,7 +446,7 @@ class LmsApi
'jambaru' => $jamAppointmentBaru, 'jambaru' => $jamAppointmentBaru,
]; ];
$res = self::http()->post( self::baseUrl() . '/booking_edit', $data)->json(); $res = self::http()->post(self::baseUrl() . '/booking_edit', $data)->json();
return $res; return $res;
} }
@@ -558,7 +579,7 @@ class LmsApi
return $url; return $url;
} }
public static function bookingBayar( $kodeBooking, $HISKodeRS, $tanggalBooking, $jumlahBayar, $merchantCode, $merchantOrderId, $reference) public static function bookingBayar($kodeBooking, $HISKodeRS, $tanggalBooking, $jumlahBayar, $merchantCode, $merchantOrderId, $reference)
{ {
$data = [ $data = [
"rs" => $HISKodeRS, "rs" => $HISKodeRS,
@@ -571,7 +592,7 @@ class LmsApi
'reference' => $reference, 'reference' => $reference,
]; ];
$res = self::http()->post( self::baseUrl() . '/booking_bayar', $data)->json(); $res = self::http()->post(self::baseUrl() . '/booking_bayar', $data)->json();
return $res; return $res;
} }

View File

@@ -6,9 +6,11 @@
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^8.0.2", "php": "^8.0.2",
"barryvdh/laravel-snappy": "^1.0",
"box/spout": "^3.3", "box/spout": "^3.3",
"duitkupg/duitku-php": "dev-master", "duitkupg/duitku-php": "dev-master",
"guzzlehttp/guzzle": "^7.2", "guzzlehttp/guzzle": "^7.2",
"h4cc/wkhtmltopdf-amd64": "0.12.x",
"laravel/framework": "^9.11", "laravel/framework": "^9.11",
"laravel/sanctum": "^2.15", "laravel/sanctum": "^2.15",
"laravel/socialite": "^5.5", "laravel/socialite": "^5.5",

203
composer.lock generated
View File

@@ -4,8 +4,86 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "bce7c2a0879fd09f793f1bfa9aeb0a68", "content-hash": "001e5beb4f35e725aaab5763c69eaeed",
"packages": [ "packages": [
{
"name": "barryvdh/laravel-snappy",
"version": "v1.0.0",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-snappy.git",
"reference": "2c18a3602981bc6f25b32908cf8aaa05952ab2f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-snappy/zipball/2c18a3602981bc6f25b32908cf8aaa05952ab2f7",
"reference": "2c18a3602981bc6f25b32908cf8aaa05952ab2f7",
"shasum": ""
},
"require": {
"illuminate/filesystem": "^6|^7|^8|^9",
"illuminate/support": "^6|^7|^8|^9",
"knplabs/knp-snappy": "^1",
"php": ">=7.2"
},
"require-dev": {
"orchestra/testbench": "^4|^5|^6|^7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
},
"laravel": {
"providers": [
"Barryvdh\\Snappy\\ServiceProvider"
],
"aliases": {
"PDF": "Barryvdh\\Snappy\\Facades\\SnappyPdf",
"SnappyImage": "Barryvdh\\Snappy\\Facades\\SnappyImage"
}
}
},
"autoload": {
"psr-4": {
"Barryvdh\\Snappy\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "Snappy PDF/Image for Laravel",
"keywords": [
"image",
"laravel",
"pdf",
"snappy",
"wkhtmltoimage",
"wkhtmltopdf"
],
"support": {
"issues": "https://github.com/barryvdh/laravel-snappy/issues",
"source": "https://github.com/barryvdh/laravel-snappy/tree/v1.0.0"
},
"funding": [
{
"url": "https://fruitcake.nl",
"type": "custom"
},
{
"url": "https://github.com/barryvdh",
"type": "github"
}
],
"time": "2022-01-29T19:36:49+00:00"
},
{ {
"name": "box/spout", "name": "box/spout",
"version": "v3.3.0", "version": "v3.3.0",
@@ -1199,6 +1277,129 @@
], ],
"time": "2022-10-26T14:07:24+00:00" "time": "2022-10-26T14:07:24+00:00"
}, },
{
"name": "h4cc/wkhtmltopdf-amd64",
"version": "0.12.4",
"source": {
"type": "git",
"url": "https://github.com/h4cc/wkhtmltopdf-amd64.git",
"reference": "4e2ab2d032a5d7fbe2a741de8b10b8989523c95b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/h4cc/wkhtmltopdf-amd64/zipball/4e2ab2d032a5d7fbe2a741de8b10b8989523c95b",
"reference": "4e2ab2d032a5d7fbe2a741de8b10b8989523c95b",
"shasum": ""
},
"bin": [
"bin/wkhtmltopdf-amd64"
],
"type": "library",
"autoload": {
"psr-4": {
"h4cc\\WKHTMLToPDF\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL Version 3"
],
"authors": [
{
"name": "Julius Beckmann",
"email": "github@h4cc.de"
}
],
"description": "Convert html to pdf using webkit (qtwebkit). Static linked linux binary for amd64 systems.",
"homepage": "http://wkhtmltopdf.org/",
"keywords": [
"binary",
"convert",
"pdf",
"snapshot",
"thumbnail",
"wkhtmltopdf"
],
"support": {
"issues": "https://github.com/h4cc/wkhtmltopdf-amd64/issues",
"source": "https://github.com/h4cc/wkhtmltopdf-amd64/tree/master"
},
"time": "2018-01-15T06:57:33+00:00"
},
{
"name": "knplabs/knp-snappy",
"version": "v1.4.1",
"source": {
"type": "git",
"url": "https://github.com/KnpLabs/snappy.git",
"reference": "5126fb5b335ec929a226314d40cd8dad497c3d67"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/KnpLabs/snappy/zipball/5126fb5b335ec929a226314d40cd8dad497c3d67",
"reference": "5126fb5b335ec929a226314d40cd8dad497c3d67",
"shasum": ""
},
"require": {
"php": ">=7.1",
"psr/log": "^1.0||^2.0||^3.0",
"symfony/process": "~3.4||~4.3||~5.0||~6.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.16||^3.0",
"pedrotroller/php-cs-custom-fixer": "^2.19",
"phpstan/phpstan": "^0.12.7",
"phpstan/phpstan-phpunit": "^0.12.6",
"phpunit/phpunit": "~7.4||~8.5"
},
"suggest": {
"h4cc/wkhtmltoimage-amd64": "Provides wkhtmltoimage-amd64 binary for Linux-compatible machines, use version `~0.12` as dependency",
"h4cc/wkhtmltoimage-i386": "Provides wkhtmltoimage-i386 binary for Linux-compatible machines, use version `~0.12` as dependency",
"h4cc/wkhtmltopdf-amd64": "Provides wkhtmltopdf-amd64 binary for Linux-compatible machines, use version `~0.12` as dependency",
"h4cc/wkhtmltopdf-i386": "Provides wkhtmltopdf-i386 binary for Linux-compatible machines, use version `~0.12` as dependency",
"wemersonjanuario/wkhtmltopdf-windows": "Provides wkhtmltopdf executable for Windows, use version `~0.12` as dependency"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Knp\\Snappy\\": "src/Knp/Snappy"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "KNP Labs Team",
"homepage": "http://knplabs.com"
},
{
"name": "Symfony Community",
"homepage": "http://github.com/KnpLabs/snappy/contributors"
}
],
"description": "PHP library allowing thumbnail, snapshot or PDF generation from a url or a html page. Wrapper for wkhtmltopdf/wkhtmltoimage.",
"homepage": "http://github.com/KnpLabs/snappy",
"keywords": [
"knp",
"knplabs",
"pdf",
"snapshot",
"thumbnail",
"wkhtmltopdf"
],
"support": {
"issues": "https://github.com/KnpLabs/snappy/issues",
"source": "https://github.com/KnpLabs/snappy/tree/v1.4.1"
},
"time": "2022-01-07T13:03:38+00:00"
},
{ {
"name": "laravel/framework", "name": "laravel/framework",
"version": "v9.47.0", "version": "v9.47.0",

View File

@@ -187,6 +187,7 @@ return [
*/ */
Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class, Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,
Maatwebsite\Excel\ExcelServiceProvider::class, Maatwebsite\Excel\ExcelServiceProvider::class,
Barryvdh\Snappy\ServiceProvider::class,
/* /*
* Application Service Providers... * Application Service Providers...
@@ -218,6 +219,8 @@ return [
'Duitku' => App\Services\Duitku::class, 'Duitku' => App\Services\Duitku::class,
'Excel' => Maatwebsite\Excel\Facades\Excel::class, 'Excel' => Maatwebsite\Excel\Facades\Excel::class,
'LmsApi' => App\Services\LmsApi::class, 'LmsApi' => App\Services\LmsApi::class,
'PDF' => Barryvdh\Snappy\Facades\SnappyPdf::class,
'SnappyImage' => Barryvdh\Snappy\Facades\SnappyImage::class,
])->toArray(), ])->toArray(),
]; ];

52
config/snappy.php Normal file
View File

@@ -0,0 +1,52 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Snappy PDF / Image Configuration
|--------------------------------------------------------------------------
|
| This option contains settings for PDF generation.
|
| Enabled:
|
| Whether to load PDF / Image generation.
|
| Binary:
|
| The file path of the wkhtmltopdf / wkhtmltoimage executable.
|
| Timout:
|
| The amount of time to wait (in seconds) before PDF / Image generation is stopped.
| Setting this to false disables the timeout (unlimited processing time).
|
| Options:
|
| The wkhtmltopdf command options. These are passed directly to wkhtmltopdf.
| See https://wkhtmltopdf.org/usage/wkhtmltopdf.txt for all options.
|
| Env:
|
| The environment variables to set while running the wkhtmltopdf process.
|
*/
'pdf' => [
'enabled' => true,
'binary' => env('WKHTML_PDF_BINARY', '/usr/local/bin/wkhtmltopdf'),
'timeout' => false,
'options' => [],
'env' => [],
],
'image' => [
'enabled' => true,
'binary' => env('WKHTML_IMG_BINARY', '/usr/local/bin/wkhtmltoimage'),
'timeout' => false,
'options' => [],
'env' => [],
],
];

View File

@@ -0,0 +1,143 @@
<?php
namespace Database\Seeders;
use App\Models\OLDLMS\Healthcare;
use App\Models\OLDLMS\JadwalDokter;
use App\Models\OLDLMS\JadwalDokterDay;
use App\Services\LmsApi;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class JadwalDokterSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$mapHealthcare = [
'Q',
'C',
'D',
'E',
'F',
'M',
'O',
'P',
'Q',
'N',
'SG',
'BW',
'SK',
'PK',
'CK',
'DE'
];
$healthcares = Healthcare::whereIn('sKodeRS', $mapHealthcare)->get();
foreach ($healthcares as $healthcare) {
$jadwalDokterDay = LmsApi::dokter($healthcare->sKodeRS, 'hospitaloka', 300);
if (empty($jadwalDokterDay['data'])) {
continue;
}
$listDokter = $jadwalDokterDay['data'];
foreach ($listDokter as $dokter) {
$jadwalDokter = JadwalDokter::where('sIDDokter', $dokter['id'])->where('sDepartmenID', $dokter['DepartemenID'])->first() ?? null;
if ($jadwalDokter == null) {
continue;
}
// if ($jadwalDokter->nID != 1901) {
// continue;
// }
$jadwalDokterDay = $jadwalDokter->jadwalDokterDay()->get() ?? null;
// JadwalDokterDay::where('nIDJadwalDokter', $jadwalDokter->nID)->get() ?? null;
if ($jadwalDokterDay == null) {
continue;
}
// dd($dokter);
$listShcedule = $dokter['JadwalDokter'];
foreach ($jadwalDokterDay as $day) {
$NewJam = "";
foreach ($listShcedule as $key => $schedule) {
$jam = $schedule['Jam'];
$cek = $schedule['Jam'];
//jika jam memiliki hurug A-Z
if (preg_match('/[A-Z]/', $jam)) {
$jam = $jam;
} else {
//jika terdapat titik
if (strpos($jam, ".") !== false) {
//ganti titik dengan : dan tambahkan 00
$jam = str_replace(".", ":", $jam);
//jika jam nya terdapat strip
if (strpos($jam, "-") !== false) {
//jika didepan strip dan belakang strip ada spasi
if (strpos($jam, " ") !== false) {
//hapus spasi
$jam = str_replace(" ", "", $jam);
}
// try{
$jam = explode("-", $jam);
$jam = $jam[0] . " - " . $jam[1];
// } catch (\Exception $e) {
// $this->command->error($cek . "Id dokter : " . $jadwalDokter->nID);
// }
} else {
$jam = $jam;
}
} else {
//jika terdapat strip
if (strpos($jam, "-") !== false) {
//jika hanya ada strip tidak ada yang lain
if (strlen($jam) > 1) {
//jika sudah ada : maka diabaikan
if (strpos($jam, ":") !== false) {
$jam = explode("-", $jam);
$jam = $jam[0] . " - " . $jam[1];
} else {
//jika didepan strip ada spasi
if (strpos($jam, " ") !== false) {
//hapus spasi
$jam = str_replace(" ", "", $jam);
}
$jam = explode("-", $jam);
$jam = $jam[0] . ":00 - " . $jam[1] . ":00";
}
}
} else if (strpos($jam, ":") !== false) {
$jam = $jam;
} else {
$jam = $jam . ":00";
}
}
}
if ($day->sHari == $schedule['Hari']) {
if ($schedule['Jam'] == null) {
$NewJam = "";
} else {
$NewJam = $jam;
}
} else {
continue;
}
}
$day->sJam = $NewJam;
$day->save();
}
}
}
}
}

View File

@@ -0,0 +1,110 @@
<?php
namespace Database\Seeders;
use App\Models\OLDLMS\Healthcare;
use App\Models\OLDLMS\JadwalDokter;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class PricesJadwalDokter extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// $healthcare_primaya = Healthcare::where('nIDHealthCareGroup', 1)->get();
// PHSM = semarang
// PHBU = Bekasi Utara
// PHMA = makasar
// PHPK = pasar kemis
// PHPC = cikini
// PHBW = Bakti wara
// PEVH = evasari
// PHTA = tangerang
// PHSB = sukabumi
// PHKA = karawang
// PHBB = bekasi barat
// PHBT = bekasi timur
$mapHealthcare = [
'SG' => 'PHSM',
'P' => 'PHBU',
'F' => 'PHMA',
'PK' => 'PHPK',
'CK' => 'PHPC',
'BW' => 'PHBW',
'E' => 'PEVH',
'C' => 'PHTA',
'SK' => 'PHSB',
'Q' => 'PHKA',
'D' => 'PHBB',
'M' => 'PHBT',
];
$file = fopen(public_path("files/Tarif Konsultasi Primaya 2023.csv"), "r");
$data = [];
while ($row = fgetcsv($file)) {
for ($i = 0; $i < count($row); $i++) {
$data[$i][] = $row[$i];
}
}
fclose($file);
// foreach ($healthcare_primaya as $healthcare) {
$jadwalDokter = JadwalDokter::get();
foreach ($jadwalDokter as $jadwal) {
$id_healthcare_jadwal = $jadwal->nIDHealthCare;
$healthcare = Healthcare::where('nID', $id_healthcare_jadwal)->first() ?? null;
if ($healthcare == null) {
continue;
}
$mapValue = $mapHealthcare[$healthcare->sKodeRS] ?? null;
if ($mapValue == null) {
continue;
}
foreach ($data as $value) {
if ($value[0] == "") {
continue;
}
$codeValue = $value[0];
$codeValue = substr($codeValue, 1, 4);
if ($codeValue == $mapValue) {
if ($jadwal->nIDSpesialis == 1) {
//umum
$jadwal->nBiaya = (int)str_replace(",", "", $value[2]) + (int)str_replace(",", "", $value[1]);
$jadwal->nBiayaTC = (int)str_replace(",", "", $value[5]);
$jadwal->nBiayaATC = (int)str_replace(",", "", $value[5]);
$jadwal->save();
} else if ($jadwal->nIDSpesialis !== 1 && $jadwal->sIsSubSpesialis == 1) {
//sub spesialis
$jadwal->nBiaya = (int)str_replace(",", "", $value[4]) + (int)str_replace(",", "", $value[1]);
$jadwal->nBiayaTC = (int)str_replace(",", "", $value[7]);
$jadwal->nBiayaATC = (int)str_replace(",", "", $value[7]);
$jadwal->save();
} else if ($jadwal->nIDSpesialis !== 1) {
//spesialis
$jadwal->nBiaya = (int)str_replace(",", "", $value[3]) + (int)str_replace(",", "", $value[1]);
$jadwal->nBiayaTC = (int)str_replace(",", "", $value[6]);
$jadwal->nBiayaATC = (int)str_replace(",", "", $value[6]);
$jadwal->save();
}
} else {
continue;
}
}
}
// }
}
}

View File

@@ -47,6 +47,12 @@ class ServiceSeeder extends Seeder
'code' => 'OPT', 'code' => 'OPT',
'description' => 'Optical', 'description' => 'Optical',
], ],
[
'id' => 6,
'name' => 'Medical Check Up',
'code' => 'MCU',
'description' => 'Medical Check Up',
],
]; ];
@@ -56,12 +62,14 @@ class ServiceSeeder extends Seeder
$service = Service::updateOrCreate(['id' => $service['id']], $service); $service = Service::updateOrCreate(['id' => $service['id']], $service);
foreach ($corporates as $corporate) { foreach ($corporates as $corporate) {
$corporateService = $corporate->corporateServices()->create([ $corporateService = $corporate->corporateServices()->firstOrCreate([
'service_code' => $service->code
],[
'service_code' => $service->code, 'service_code' => $service->code,
'status' => 'active' 'status' => 'inactive'
]); ]);
$corporateService->configs()->insert([ $corporate_service_configs_data = [
[ [
'corporate_service_id' => $corporateService->id, 'corporate_service_id' => $corporateService->id,
'name' => 'gp_external_doctor_online', 'name' => 'gp_external_doctor_online',
@@ -122,7 +130,14 @@ class ServiceSeeder extends Seeder
'name' => 'specialist_practitioner_fee', 'name' => 'specialist_practitioner_fee',
'value' => false, 'value' => false,
], ],
]); ];
foreach ($corporate_service_configs_data as $config) {
$corporateService->configs()->firstOrCreate([
'corporate_service_id' => $config['corporate_service_id'],
'name' => $config['name']
], $config);
}
} }
} }
} }

View File

@@ -1,4 +1,12 @@
<IfModule mod_rewrite.c> <IfModule mod_rewrite.c>
RewriteEngine On RewriteEngine On
RewriteBase / RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /index.html [QSA,L]
</IfModule>
<IfModule pagespeed_module>
ModPagespeed off
</IfModule> </IfModule>

View File

@@ -32,7 +32,7 @@ const MENU_OPTIONS = [
export default function AccountPopover() { export default function AccountPopover() {
const [open, setOpen] = useState<HTMLElement | null>(null); const [open, setOpen] = useState<HTMLElement | null>(null);
const navigate = useNavigate(); const navigate = useNavigate();
const { logout } = useAuth(); const { logout, user } = useAuth();
const handleOpen = (event: React.MouseEvent<HTMLElement>) => { const handleOpen = (event: React.MouseEvent<HTMLElement>) => {
setOpen(event.currentTarget); setOpen(event.currentTarget);
@@ -67,10 +67,10 @@ export default function AccountPopover() {
}), }),
}} }}
> >
<Avatar {user && user.user.avatar_url && (<Avatar
src="https://minimal-assets-api.vercel.app/assets/images/avatars/avatar_5.jpg" src={user ? user.user.avatar_url : ''}
alt="Rayan Moran" alt={user ? user.user.full_name : ''}
/> />)}
</IconButtonAnimate> </IconButtonAnimate>
<MenuPopover <MenuPopover
@@ -89,16 +89,16 @@ export default function AccountPopover() {
> >
<Box sx={{ my: 1.5, px: 2.5 }}> <Box sx={{ my: 1.5, px: 2.5 }}>
<Typography variant="subtitle2" noWrap> <Typography variant="subtitle2" noWrap>
Rayan Moran { user ? user.user.full_name ?? 'Hi, ' : 'Hi, '}
</Typography> </Typography>
<Typography variant="body2" sx={{ color: 'text.secondary' }} noWrap> <Typography variant="body2" sx={{ color: 'text.secondary' }} noWrap>
rayan.moran@gmail.com { user ? user.user.email : 'Please Wait'}
</Typography> </Typography>
</Box> </Box>
<Divider sx={{ borderStyle: 'dashed' }} /> <Divider sx={{ borderStyle: 'dashed' }} />
<Stack sx={{ p: 1 }}> {/* <Stack sx={{ p: 1 }}>
{MENU_OPTIONS.map((option) => ( {MENU_OPTIONS.map((option) => (
<MenuItem key={option.label} onClick={handleClose}> <MenuItem key={option.label} onClick={handleClose}>
{option.label} {option.label}
@@ -106,7 +106,7 @@ export default function AccountPopover() {
))} ))}
</Stack> </Stack>
<Divider sx={{ borderStyle: 'dashed' }} /> <Divider sx={{ borderStyle: 'dashed' }} /> */}
<MenuItem sx={{ m: 1 }} onClick={handleLogout}> <MenuItem sx={{ m: 1 }} onClick={handleLogout}>
Logout Logout

View File

@@ -1,6 +1,7 @@
// @mui // @mui
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import { Box, Link, Typography, Avatar } from '@mui/material'; import { Box, Link, Typography, Avatar } from '@mui/material';
import useAuth from '../../../hooks/useAuth';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@@ -22,6 +23,10 @@ type Props = {
}; };
export default function NavbarAccount({ isCollapse }: Props) { export default function NavbarAccount({ isCollapse }: Props) {
const { user } = useAuth();
console.log('current user is ', user)
return ( return (
<Link underline="none" color="inherit"> <Link underline="none" color="inherit">
<RootStyle <RootStyle
@@ -31,10 +36,10 @@ export default function NavbarAccount({ isCollapse }: Props) {
}), }),
}} }}
> >
<Avatar {user && user.user.avatar_url && (<Avatar
src="https://minimal-assets-api.vercel.app/assets/images/avatars/avatar_5.jpg" src={user ? user.user.avatar_url : ''}
alt="Rayan Moran" alt={user ? user.user.full_name : ''}
/> />)}
<Box <Box
sx={{ sx={{
@@ -50,10 +55,10 @@ export default function NavbarAccount({ isCollapse }: Props) {
}} }}
> >
<Typography variant="subtitle2" noWrap> <Typography variant="subtitle2" noWrap>
Rayan Moran { user ? user.user.full_name ?? 'Hi, ' : 'Hi, '}
</Typography> </Typography>
<Typography variant="body2" noWrap sx={{ color: 'text.secondary' }}> <Typography variant="body2" noWrap sx={{ color: 'text.secondary', fontSize: '11px' }}>
user { user ? user.user.email : 'Please Wait'}
</Typography> </Typography>
</Box> </Box>
</RootStyle> </RootStyle>

View File

@@ -134,7 +134,7 @@ export default function DialogClaimSubmitMember({
params: { ...appliedParams, claimMember: true }, params: { ...appliedParams, claimMember: true },
}); });
setData(response.data); setData(response.data.data);
} }
})(); })();
}, [corporateValue, openDialog, appliedParams]); }, [corporateValue, openDialog, appliedParams]);

View File

@@ -409,11 +409,11 @@ export default function TableList(props: any) {
</Button> </Button>
)} )}
</TableCell> </TableCell>
<TableCell align="right"> {/* <TableCell align="right">
<IconButton> <IconButton>
<Iconify icon="ic:baseline-more-vert" /> <Iconify icon="ic:baseline-more-vert" />
</IconButton> </IconButton>
</TableCell> </TableCell> */}
</TableRow> </TableRow>
)) ))
) : ( ) : (

View File

@@ -1,3 +1,3 @@
GENERATE_SOURCEMAP=false GENERATE_SOURCEMAP=false
VITE_API_URL="https://aso-api.linksehat.dev/api/internal" VITE_API_URL="https://primecenter-api.linksehat.com/api/internal"

View File

@@ -0,0 +1 @@
VITE_API_URL="https://aso-api.linksehat.dev/api/internal"

View File

@@ -1,5 +1,4 @@
<IfModule mod_rewrite.c> <IfModule mod_rewrite.c>
Modpagespeed Off
RewriteEngine On RewriteEngine On
RewriteBase / RewriteBase /
@@ -7,3 +6,7 @@
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) /index.html [QSA,L] RewriteRule (.*) /index.html [QSA,L]
</IfModule> </IfModule>
<IfModule pagespeed_module>
ModPagespeed off
</IfModule>

View File

@@ -9,7 +9,7 @@
"lint:fix": "eslint --fix --ext .ts,.tsx ./src", "lint:fix": "eslint --fix --ext .ts,.tsx ./src",
"start": "vite --port=3000", "start": "vite --port=3000",
"build": "vite build --mode production && cp .htaccess build/.htaccess && rm -f -r ../../public/dashboard && cp -r build ../../public/dashboard", "build": "vite build --mode production && cp .htaccess build/.htaccess && rm -f -r ../../public/dashboard && cp -r build ../../public/dashboard",
"build-two": "vite build --mode production", "build-staging": "vite build --mode staging && cp .htaccess build/.htaccess && rm -f -r ../../public/dashboard-staging && cp -r build ../../public/dashboard-staging",
"serve": "vite preview", "serve": "vite preview",
"clear-all": "rm -rf build node_modules", "clear-all": "rm -rf build node_modules",
"re-start": "rm -rf build node_modules && yarn install && yarn start", "re-start": "rm -rf build node_modules && yarn install && yarn start",
@@ -38,78 +38,78 @@
] ]
}, },
"dependencies": { "dependencies": {
"@date-io/date-fns": "^2.14.0", "@date-io/date-fns": "^2.16.0",
"@emotion/cache": "^11.9.3", "@emotion/cache": "^11.10.5",
"@emotion/react": "^11.9.3", "@emotion/react": "^11.10.5",
"@emotion/styled": "^11.9.3", "@emotion/styled": "^11.10.5",
"@hookform/resolvers": "^2.9.6", "@hookform/resolvers": "^2.9.10",
"@iconify/react": "^3.2.2", "@iconify/react": "^3.2.2",
"@mui/icons-material": "^5.8.4", "@mui/icons-material": "^5.11.0",
"@mui/lab": "5.0.0-alpha.80", "@mui/lab": "5.0.0-alpha.80",
"@mui/material": "^5.9.1", "@mui/material": "^5.11.5",
"@mui/system": "^5.9.1", "@mui/system": "^5.11.5",
"@mui/x-data-grid": "^5.14.0", "@mui/x-data-grid": "^5.17.19",
"@mui/x-date-pickers": "5.0.0-beta.2", "@mui/x-date-pickers": "5.0.0-beta.2",
"@vitejs/plugin-react": "^1.3.2", "@vitejs/plugin-react": "^1.3.2",
"apexcharts": "^3.35.5", "apexcharts": "^3.36.3",
"axios": "^0.27.2", "axios": "^0.27.2",
"change-case": "^4.1.2", "change-case": "^4.1.2",
"csstype": "^3.1.0", "csstype": "^3.1.1",
"date-fns": "^2.29.1", "date-fns": "^2.29.3",
"framer-motion": "^6.5.1", "framer-motion": "^6.5.1",
"highlight.js": "^11.6.0", "highlight.js": "^11.7.0",
"history": "^5.3.0", "history": "^5.3.0",
"jsx-runtime": "^1.2.0", "jsx-runtime": "^1.2.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"notistack": "^3.0.0-alpha.7", "notistack": "3.0.0-alpha.11",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"numeral": "^2.0.6", "numeral": "^2.0.6",
"react": "^17.0.2", "react": "^17.0.2",
"react-apexcharts": "^1.4.0", "react-apexcharts": "^1.4.0",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-dropzone": "^14.2.2", "react-dropzone": "^14.2.3",
"react-helmet-async": "^1.3.0", "react-helmet-async": "^1.3.0",
"react-hook-form": "^7.33.1", "react-hook-form": "^7.42.1",
"react-intersection-observer": "^8.34.0", "react-intersection-observer": "^8.34.0",
"react-lazy-load-image-component": "^1.5.5", "react-lazy-load-image-component": "^1.5.6",
"react-quill": "2.0.0-beta.4", "react-quill": "2.0.0-beta.4",
"react-router": "^6.3.0", "react-router": "^6.7.0",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.7.0",
"simplebar": "^5.3.8", "simplebar": "^5.3.9",
"simplebar-react": "^2.4.1", "simplebar-react": "^2.4.3",
"stylis": "^4.1.1", "stylis": "^4.1.3",
"stylis-plugin-rtl": "^2.1.1", "stylis-plugin-rtl": "^2.1.1",
"vite": "^3.0.4", "vite": "^3.2.5",
"vite-plugin-svgr": "^2.2.1", "vite-plugin-svgr": "^2.4.0",
"yup": "^0.32.11" "yup": "^0.32.11"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.18.9", "@babel/core": "^7.20.12",
"@babel/eslint-parser": "^7.18.9", "@babel/eslint-parser": "^7.19.1",
"@babel/plugin-syntax-flow": "^7.18.6", "@babel/plugin-syntax-flow": "^7.18.6",
"@babel/plugin-transform-react-jsx": "^7.18.6", "@babel/plugin-transform-react-jsx": "^7.20.7",
"@types/lodash": "^4.14.182", "@types/lodash": "^4.14.191",
"@types/nprogress": "^0.2.0", "@types/nprogress": "^0.2.0",
"@types/react": "^17.0.47", "@types/react": "^17.0.53",
"@types/react-dom": "^17.0.17", "@types/react-dom": "^17.0.18",
"@types/react-lazy-load-image-component": "^1.5.2", "@types/react-lazy-load-image-component": "^1.5.2",
"@types/stylis": "^4.0.2", "@types/stylis": "^4.0.2",
"@typescript-eslint/eslint-plugin": "^5.30.7", "@typescript-eslint/eslint-plugin": "^5.48.2",
"@typescript-eslint/parser": "^5.30.7", "@typescript-eslint/parser": "^5.48.2",
"eslint": "^8.20.0", "eslint": "^8.32.0",
"eslint-config-airbnb": "19.0.4", "eslint-config-airbnb": "19.0.4",
"eslint-config-airbnb-typescript": "^16.2.0", "eslint-config-airbnb-typescript": "^16.2.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.6.0",
"eslint-config-react-app": "7.0.0", "eslint-config-react-app": "7.0.0",
"eslint-import-resolver-typescript": "^2.7.1", "eslint-import-resolver-typescript": "^2.7.1",
"eslint-plugin-flowtype": "^8.0.3", "eslint-plugin-flowtype": "^8.0.3",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsx-a11y": "6.5.1", "eslint-plugin-jsx-a11y": "6.5.1",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.30.1", "eslint-plugin-react": "^7.32.1",
"eslint-plugin-react-hooks": "4.3.0", "eslint-plugin-react-hooks": "4.3.0",
"prettier": "^2.7.1", "prettier": "^2.8.3",
"typescript": "^4.7.4", "typescript": "^4.9.4",
"vite-plugin-pwa": "^0.12.3" "vite-plugin-pwa": "^0.12.8"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -69,6 +69,13 @@ const navConfig = [
title: 'CUSTOMER SERVICES', title: 'CUSTOMER SERVICES',
children: [{ title: 'Request', path: '/cs-request' }], children: [{ title: 'Request', path: '/cs-request' }],
}, },
{
title: 'REPORT',
children: [
{ title: 'Appointment', path: '/report/appointments' },
{ title: 'Live Chat', path: '/report/live-chat' },
],
},
{ {
title: 'USER MANAGEMENT', title: 'USER MANAGEMENT',
path: '/users', path: '/users',

View File

@@ -221,8 +221,8 @@ export default function List() {
{ (row.status == 'approved' && ( { (row.status == 'approved' && (
<TableCell align="left">Approved</TableCell> <TableCell align="left">Approved</TableCell>
)) } )) }
{ (row.status == 'postponed' && ( { (row.status == 'postpone' && (
<TableCell align="left">Postpone</TableCell> <TableCell align="left">Postponed</TableCell>
)) } )) }
<TableCell align="right"> <TableCell align="right">

View File

@@ -62,12 +62,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
const onSubmit = async (data: any) => { const onSubmit = async (data: any) => {
if (!isEdit) { if (!isEdit) {
await axios await axios
.post('/corporates/' + corporate_id + '/divisions', data) .post('/corporate/' + corporate_id + '/divisions', data)
.then((res) => { .then((res) => {
enqueueSnackbar('Division created successfully', { variant: 'success' }); enqueueSnackbar('Division created successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/divisions', { replace: true }); navigate('/corporate/' + corporate_id + '/divisions', { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
if (response.status === 422) { if (response.status === 422) {
@@ -81,12 +81,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
}); });
} else { } else {
await axios await axios
.put('/corporates/' + corporate_id + '/divisions/' + currentCorporatePlan?.id, data) .put('/corporate/' + corporate_id + '/divisions/' + currentCorporatePlan?.id, data)
.then((res) => { .then((res) => {
enqueueSnackbar('Division updated successfully', { variant: 'success' }); enqueueSnackbar('Division updated successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/divisions/', { replace: true }); navigate('/corporate/' + corporate_id + '/divisions/', { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
enqueueSnackbar('Update Failed : ' + response.data.message, { variant: 'error' }); enqueueSnackbar('Update Failed : ' + response.data.message, { variant: 'error' });

View File

@@ -35,11 +35,11 @@ export default function Divisions() {
}, },
{ {
name: corporate?.name ?? '-', name: corporate?.name ?? '-',
href: '/corporates/' + corporate_id, href: '/corporate/' + corporate_id,
}, },
{ {
name: 'Benefit', name: 'Benefit',
href: '/corporates/' + corporate_id + '/benefits', href: '/corporate/' + corporate_id + '/benefits',
}, },
]} ]}
/> />

View File

@@ -60,6 +60,7 @@ import Form from './Form';
import { LaravelPaginatedData } from '../../../@types/paginated-data'; import { LaravelPaginatedData } from '../../../@types/paginated-data';
import BasePagination from '../../../components/BasePagination'; import BasePagination from '../../../components/BasePagination';
import { enqueueSnackbar } from 'notistack'; import { enqueueSnackbar } from 'notistack';
import { LoadingButton } from '@mui/lab';
export default function PlanList() { export default function PlanList() {
const { themeStretch } = useSettings(); const { themeStretch } = useSettings();
@@ -109,6 +110,7 @@ export default function PlanList() {
const createMenu = Boolean(anchorEl); const createMenu = Boolean(anchorEl);
const importPlan = useRef<HTMLInputElement>(null); const importPlan = useRef<HTMLInputElement>(null);
const [currentImportFileName, setCurrentImportFileName] = useState(null); const [currentImportFileName, setCurrentImportFileName] = useState(null);
const [importLoading, setImportLoading] = useState(false);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => { const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
@@ -144,6 +146,7 @@ export default function PlanList() {
if (importPlan.current?.files.length) { if (importPlan.current?.files.length) {
const formData = new FormData(); const formData = new FormData();
formData.append('file', importPlan.current?.files[0]); formData.append('file', importPlan.current?.files[0]);
setImportLoading(true);
axios axios
.post(`corporates/${corporate_id}/import-plan-benefit`, formData) .post(`corporates/${corporate_id}/import-plan-benefit`, formData)
.then((response) => { .then((response) => {
@@ -151,6 +154,7 @@ export default function PlanList() {
loadDataTableData(); loadDataTableData();
setImportResult(response.data); setImportResult(response.data);
// alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows'); // alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows');
setImportLoading(false);
}) })
.catch((response) => { .catch((response) => {
enqueueSnackbar( enqueueSnackbar(
@@ -158,12 +162,26 @@ export default function PlanList() {
response.message, response.message,
{ variant: 'error' } { variant: 'error' }
); );
setImportLoading(false);
}); });
} else { } else {
enqueueSnackbar('No File Selected', { variant: 'warning' }); enqueueSnackbar('No File Selected', { variant: 'warning' });
} }
}; };
const handleGetTemplate = (type :string) => {
axios.get('corporates/import-document-example/' + type)
.then((response) => {
const link = document.createElement('a');
link.href = response.data.data.file_url;
link.setAttribute('download', response.data.data.file_name);
document.body.appendChild(link);
link.click();
handleClose();
})
}
return ( return (
<div> <div>
<input <input
@@ -200,7 +218,7 @@ export default function PlanList() {
}} }}
> >
<MenuItem onClick={handleImportButton}>Import</MenuItem> <MenuItem onClick={handleImportButton}>Import</MenuItem>
<MenuItem onClick={handleClose}>Download Template</MenuItem> <MenuItem onClick={() => {handleGetTemplate('plan-benefit')}}>Download Template</MenuItem>
</Menu> </Menu>
</Stack> </Stack>
)} )}
@@ -221,15 +239,16 @@ export default function PlanList() {
</Button> </Button>
</ButtonGroup> </ButtonGroup>
<Button <LoadingButton
id="upload-button" id="upload-button"
variant="outlined" variant="outlined"
startIcon={<UploadIcon />} startIcon={<UploadIcon />}
sx={{ p: 1.8 }} sx={{ p: 1.8 }}
onClick={handleUpload} onClick={handleUpload}
loading={importLoading}
> >
Upload Upload
</Button> </LoadingButton>
</Stack> </Stack>
)} )}
{importResult && ( {importResult && (
@@ -326,7 +345,7 @@ export default function PlanList() {
</Button> </Button>
)} )}
</TableCell> </TableCell>
<TableCell align="center"> {/* <TableCell align="center">
<Button <Button
variant="outlined" variant="outlined"
color="success" color="success"
@@ -340,7 +359,7 @@ export default function PlanList() {
> >
{openEdit ? 'Save' : 'Edit'} {openEdit ? 'Save' : 'Edit'}
</Button> </Button>
</TableCell> </TableCell> */}
</TableRow> </TableRow>
{/* COLLAPSIBLE ROW */} {/* COLLAPSIBLE ROW */}
<TableRow> <TableRow>
@@ -767,9 +786,9 @@ export default function PlanList() {
<TableCell style={headStyle} align="center"> <TableCell style={headStyle} align="center">
Status Status
</TableCell> </TableCell>
<TableCell style={headStyle} align="center"> {/* <TableCell style={headStyle} align="center">
Action Action
</TableCell> </TableCell> */}
</TableRow> </TableRow>
</TableBody> </TableBody>
{dataTableIsLoading ? ( {dataTableIsLoading ? (

View File

@@ -64,12 +64,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
const onSubmit = async (data: any) => { const onSubmit = async (data: any) => {
if (!isEdit) { if (!isEdit) {
await axios await axios
.post('/corporates/' + corporate_id + '/divisions', data) .post('/corporate/' + corporate_id + '/divisions', data)
.then((res) => { .then((res) => {
enqueueSnackbar('Division created successfully', { variant: 'success' }); enqueueSnackbar('Division created successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/divisions', { replace: true }); navigate('/corporate/' + corporate_id + '/divisions', { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
if (response.status === 422) { if (response.status === 422) {
@@ -84,12 +84,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
}); });
} else { } else {
await axios await axios
.put('/corporates/' + corporate_id + '/divisions/' + currentCorporatePlan?.id , data) .put('/corporate/' + corporate_id + '/divisions/' + currentCorporatePlan?.id , data)
.then((res) => { .then((res) => {
enqueueSnackbar('Division updated successfully', { variant: 'success' }); enqueueSnackbar('Division updated successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/divisions/' , { replace: true }); navigate('/corporate/' + corporate_id + '/divisions/' , { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' }); enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' });

View File

@@ -33,11 +33,11 @@ export default function Divisions() {
}, },
{ {
name: corporate?.name ?? '-', name: corporate?.name ?? '-',
href: '/corporates/' + corporate_id, href: '/corporate/' + corporate_id,
}, },
{ {
name: 'Claim History', name: 'Claim History',
href: '/corporates/' + corporate_id + '/claim-histories', href: '/corporate/' + corporate_id + '/claim-histories',
}, },
]} ]}
/> />

View File

@@ -64,12 +64,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporateBenefit }: P
const onSubmit = async (data: any) => { const onSubmit = async (data: any) => {
if (!isEdit) { if (!isEdit) {
await axios await axios
.post('/corporates/' + corporate_id + '/corporate-benefits', data) .post('/corporate/' + corporate_id + '/corporate-benefits', data)
.then((res) => { .then((res) => {
enqueueSnackbar('Corporate Plan created successfully', { variant: 'success' }); enqueueSnackbar('Corporate Plan created successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/corporate-benefits', { replace: true }); navigate('/corporate/' + corporate_id + '/corporate-benefits', { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
if (response.status === 422) { if (response.status === 422) {
@@ -84,12 +84,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporateBenefit }: P
}); });
} else { } else {
await axios await axios
.put('/corporates/' + corporate_id + '/corporate-benefits/' + currentCorporateBenefit?.id , data) .put('/corporate/' + corporate_id + '/corporate-benefits/' + currentCorporateBenefit?.id , data)
.then((res) => { .then((res) => {
enqueueSnackbar('Corporate Benefit updated successfully', { variant: 'success' }); enqueueSnackbar('Corporate Benefit updated successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/corporate-benefits/' , { replace: true }); navigate('/corporate/' + corporate_id + '/corporate-benefits/' , { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' }); enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' });

View File

@@ -64,12 +64,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
const onSubmit = async (data: any) => { const onSubmit = async (data: any) => {
if (!isEdit) { if (!isEdit) {
await axios await axios
.post('/corporates/' + corporate_id + '/corporate-plans', data) .post('/corporate/' + corporate_id + '/corporate-plans', data)
.then((res) => { .then((res) => {
enqueueSnackbar('Corporate Plan created successfully', { variant: 'success' }); enqueueSnackbar('Corporate Plan created successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/corporate-plans', { replace: true }); navigate('/corporate/' + corporate_id + '/corporate-plans', { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
if (response.status === 422) { if (response.status === 422) {
@@ -83,12 +83,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
}); });
} else { } else {
await axios await axios
.put('/corporates/' + corporate_id + '/corporate-plans/' + currentCorporatePlan?.id, data) .put('/corporate/' + corporate_id + '/corporate-plans/' + currentCorporatePlan?.id, data)
.then((res) => { .then((res) => {
enqueueSnackbar('Corporate Plan updated successfully', { variant: 'success' }); enqueueSnackbar('Corporate Plan updated successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/corporate-plans/', { replace: true }); navigate('/corporate/' + corporate_id + '/corporate-plans/', { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
enqueueSnackbar('Update Failed : ' + response.data.message, { variant: 'error' }); enqueueSnackbar('Update Failed : ' + response.data.message, { variant: 'error' });

View File

@@ -32,11 +32,11 @@ export default function Divisions() {
}, },
{ {
name: corporate?.name ?? '-', name: corporate?.name ?? '-',
href: '/corporates/' + corporate_id, href: '/corporate/' + corporate_id,
}, },
{ {
name: 'Corporate Plan', name: 'Corporate Plan',
href: '/corporates/' + corporate_id + '/corporate-plans', href: '/corporate/' + corporate_id + '/corporate-plans',
}, },
]} ]}
/> />

View File

@@ -36,11 +36,11 @@ export default function Divisions() {
}, },
{ {
name: corporate?.name ?? '-', name: corporate?.name ?? '-',
href: '/corporates/' + corporate_id, href: '/corporate/' + corporate_id,
}, },
{ {
name: 'Diagnosis Exclusion', name: 'Diagnosis Exclusion',
href: '/corporates/' + corporate_id + '/diagnosis-exclusions', href: '/corporate/' + corporate_id + '/diagnosis-exclusions',
}, },
]} ]}
/> />

View File

@@ -52,6 +52,7 @@ import { Icd } from '../../../@types/diagnosis';
import BasePagination from '../../../components/BasePagination'; import BasePagination from '../../../components/BasePagination';
import { enqueueSnackbar } from 'notistack'; import { enqueueSnackbar } from 'notistack';
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
import { LoadingButton } from '@mui/lab';
export default function List(props: any) { export default function List(props: any) {
const { themeStretch } = useSettings(); const { themeStretch } = useSettings();
@@ -101,6 +102,7 @@ export default function List(props: any) {
const createMenu = Boolean(anchorEl); const createMenu = Boolean(anchorEl);
const importForm = useRef<HTMLInputElement>(null); const importForm = useRef<HTMLInputElement>(null);
const [currentImportFileName, setCurrentImportFileName] = useState(null); const [currentImportFileName, setCurrentImportFileName] = useState(null);
const [importLoading, setImportLoading] = useState(false);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => { const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
@@ -136,12 +138,15 @@ export default function List(props: any) {
if (importForm.current?.files.length) { if (importForm.current?.files.length) {
const formData = new FormData(); const formData = new FormData();
formData.append('file', importForm.current?.files[0]); formData.append('file', importForm.current?.files[0]);
setImportLoading(true);
axios axios
.post(`corporates/${corporate_id}/diagnosis-exclusions/import`, formData) .post(`corporates/${corporate_id}/diagnosis-exclusions/import`, formData)
.then((response) => { .then((response) => {
handleCancelImportButton(); handleCancelImportButton();
loadDataTableData(); loadDataTableData();
setImportResult(response.data); setImportResult(response.data);
setImportLoading(false);
// alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows'); // alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows');
}) })
.catch((response) => { .catch((response) => {
@@ -150,12 +155,26 @@ export default function List(props: any) {
response.message, response.message,
{ variant: 'error' } { variant: 'error' }
); );
});
setImportLoading(false);
})
} else { } else {
enqueueSnackbar('No File Selected', { variant: 'warning' }); enqueueSnackbar('No File Selected', { variant: 'warning' });
} }
}; };
const handleGetTemplate = (type :string) => {
axios.get('corporates/import-document-example/' + type)
.then((response) => {
const link = document.createElement('a');
link.href = response.data.data.file_url;
link.setAttribute('download', response.data.data.file_name);
document.body.appendChild(link);
link.click();
handleClose();
})
}
return ( return (
<div> <div>
<input <input
@@ -192,7 +211,7 @@ export default function List(props: any) {
}} }}
> >
<MenuItem onClick={handleImportButton}>Import</MenuItem> <MenuItem onClick={handleImportButton}>Import</MenuItem>
<MenuItem onClick={handleClose}>Download Template</MenuItem> <MenuItem onClick={() => {handleGetTemplate('diagnosis-exclusion')}}>Download Template</MenuItem>
</Menu> </Menu>
</Stack> </Stack>
)} )}
@@ -213,15 +232,16 @@ export default function List(props: any) {
</Button> </Button>
</ButtonGroup> </ButtonGroup>
<Button <LoadingButton
id="upload-button" id="upload-button"
variant="outlined" variant="outlined"
startIcon={<UploadIcon />} startIcon={<UploadIcon />}
sx={{ p: 1.8 }} sx={{ p: 1.8 }}
onClick={handleUpload} onClick={handleUpload}
loading={importLoading}
> >
Upload Upload
</Button> </LoadingButton>
</Stack> </Stack>
)} )}
{importResult && ( {importResult && (

View File

@@ -64,12 +64,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
const onSubmit = async (data: any) => { const onSubmit = async (data: any) => {
if (!isEdit) { if (!isEdit) {
await axios await axios
.post('/corporates/' + corporate_id + '/divisions', data) .post('/corporate/' + corporate_id + '/divisions', data)
.then((res) => { .then((res) => {
enqueueSnackbar('Division created successfully', { variant: 'success' }); enqueueSnackbar('Division created successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/divisions', { replace: true }); navigate('/corporate/' + corporate_id + '/divisions', { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
if (response.status === 422) { if (response.status === 422) {
@@ -84,12 +84,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
}); });
} else { } else {
await axios await axios
.put('/corporates/' + corporate_id + '/divisions/' + currentCorporatePlan?.id , data) .put('/corporate/' + corporate_id + '/divisions/' + currentCorporatePlan?.id , data)
.then((res) => { .then((res) => {
enqueueSnackbar('Division updated successfully', { variant: 'success' }); enqueueSnackbar('Division updated successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/divisions/' , { replace: true }); navigate('/corporate/' + corporate_id + '/divisions/' , { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' }); enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' });

View File

@@ -36,11 +36,11 @@ export default function Divisions() {
}, },
{ {
name: corporate?.name ?? '-', name: corporate?.name ?? '-',
href: '/corporates/'+corporate_id, href: '/corporate/' + corporate_id,
}, },
{ {
name: 'Division', name: 'Division',
href: '/corporates/'+corporate_id+'/divisions', href: '/corporate/' + corporate_id + '/divisions',
}, },
]} ]}
/> />

View File

@@ -188,9 +188,13 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
navigate('/corporates'); navigate('/corporates');
} catch (error: any) { } catch (error: any) {
if (error && error.response.status === 422) { 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' });
// }
for (const [key, value] of Object.entries(error.response.data.errors)) { for (const [key, value] of Object.entries(error.response.data.errors)) {
setError(key, { message: value[0] }); // setError(key, { message: value[0] });
enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' }); enqueueSnackbar(value ?? 'Failed Processing Request', { variant: 'error' });
} }
} else { } else {
enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' }); enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' });
@@ -284,6 +288,14 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
value: 'email', value: 'email',
label: 'E-Mail', label: 'E-Mail',
}, },
{
value: 'name',
label: 'Nama Lengkap',
},
{
value: 'dob',
label: 'Tanggal Lahir',
},
]; ];
const types = [ const types = [

View File

@@ -34,11 +34,11 @@ export default function CorporateFormularium() {
}, },
{ {
name: corporate?.name ?? '-', name: corporate?.name ?? '-',
href: '/corporates/' + corporate_id, href: '/corporate/' + corporate_id,
}, },
{ {
name: 'Formularium', name: 'Formularium',
href: '/corporates/' + corporate_id + '/formularium', href: '/corporate/' + corporate_id + '/formularium',
}, },
]} ]}
/> />

View File

@@ -64,12 +64,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
const onSubmit = async (data: any) => { const onSubmit = async (data: any) => {
if (!isEdit) { if (!isEdit) {
await axios await axios
.post('/corporates/' + corporate_id + '/divisions', data) .post('/corporate/' + corporate_id + '/divisions', data)
.then((res) => { .then((res) => {
enqueueSnackbar('Division created successfully', { variant: 'success' }); enqueueSnackbar('Division created successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/divisions', { replace: true }); navigate('/corporate/' + corporate_id + '/divisions', { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
if (response.status === 422) { if (response.status === 422) {
@@ -84,12 +84,12 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
}); });
} else { } else {
await axios await axios
.put('/corporates/' + corporate_id + '/divisions/' + currentCorporatePlan?.id , data) .put('/corporate/' + corporate_id + '/divisions/' + currentCorporatePlan?.id , data)
.then((res) => { .then((res) => {
enqueueSnackbar('Division updated successfully', { variant: 'success' }); enqueueSnackbar('Division updated successfully', { variant: 'success' });
}) })
.then((res) => { .then((res) => {
navigate('/corporates/' + corporate_id + '/divisions/' , { replace: true }); navigate('/corporate/' + corporate_id + '/divisions/' , { replace: true });
}) })
.catch(({ response }) => { .catch(({ response }) => {
enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' }); enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' });

View File

@@ -34,11 +34,11 @@ export default function Divisions() {
}, },
{ {
name: corporate?.name ?? '-', name: corporate?.name ?? '-',
href: '/corporates/' + corporate_id, href: '/corporate/' + corporate_id,
}, },
{ {
name: 'Hospitals', name: 'Hospitals',
href: '/corporates/' + corporate_id + '/hospitals', href: '/corporate/' + corporate_id + '/hospitals',
}, },
]} ]}
/> />

View File

@@ -4,7 +4,7 @@ import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
import Page from '../../../components/Page'; import Page from '../../../components/Page';
import useSettings from '../../../hooks/useSettings'; import useSettings from '../../../hooks/useSettings';
import CorporateTabNavigations from '../CorporateTabNavigations'; import CorporateTabNavigations from '../CorporateTabNavigations';
import DivisionsList from './List'; import MemberList from './List';
import { useContext, useEffect, useState } from 'react'; import { useContext, useEffect, useState } from 'react';
import { ConfiguredCorporateContext } from '@/contexts/ConfiguredCorporateContext'; import { ConfiguredCorporateContext } from '@/contexts/ConfiguredCorporateContext';
@@ -33,18 +33,18 @@ export default function Divisions() {
}, },
{ {
name: corporate?.name ?? '-', name: corporate?.name ?? '-',
href: '/corporates/' + corporate_id, href: '/corporate/' + corporate_id,
}, },
{ {
name: 'Member', name: 'Member',
href: '/corporates/' + corporate_id + '/members', href: '/corporate/' + corporate_id + '/members',
}, },
]} ]}
/> />
<Card> <Card>
<CorporateTabNavigations position={'members'} /> <CorporateTabNavigations position={'members'} />
<DivisionsList /> <MemberList />
</Card> </Card>
</Page> </Page>
); );

View File

@@ -33,6 +33,7 @@ import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
import AddIcon from '@mui/icons-material/Add'; import AddIcon from '@mui/icons-material/Add';
import UploadIcon from '@mui/icons-material/Upload'; import UploadIcon from '@mui/icons-material/Upload';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
// hooks // hooks
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react'; import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
import useSettings from '../../../hooks/useSettings'; import useSettings from '../../../hooks/useSettings';
@@ -44,6 +45,8 @@ import { LaravelPaginatedData } from '../../../@types/paginated-data';
import { Member } from '../../../@types/member'; import { Member } from '../../../@types/member';
import BasePagination from '../../../components/BasePagination'; import BasePagination from '../../../components/BasePagination';
import { enqueueSnackbar } from 'notistack'; import { enqueueSnackbar } from 'notistack';
import { LoadingButton } from '@mui/lab';
import DialogLog from './sections/DialogLog';
export default function CorporatePlanList() { export default function CorporatePlanList() {
const { themeStretch } = useSettings(); const { themeStretch } = useSettings();
@@ -139,6 +142,7 @@ export default function CorporatePlanList() {
const createMenu = Boolean(anchorEl); const createMenu = Boolean(anchorEl);
const importPlan = useRef<HTMLInputElement>(null); const importPlan = useRef<HTMLInputElement>(null);
const [currentImportFileName, setCurrentImportFileName] = useState(null); const [currentImportFileName, setCurrentImportFileName] = useState(null);
const [importLoading, setImportLoading] = useState(false);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => { const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
@@ -174,12 +178,14 @@ export default function CorporatePlanList() {
if (importPlan.current?.files.length) { if (importPlan.current?.files.length) {
const formData = new FormData(); const formData = new FormData();
formData.append('file', importPlan.current?.files[0]); formData.append('file', importPlan.current?.files[0]);
setImportLoading(true);
axios axios
.post(`corporates/${corporate_id}/members/import`, formData) .post(`corporates/${corporate_id}/members/import`, formData)
.then((response) => { .then((response) => {
handleCancelImportButton(); handleCancelImportButton();
loadDataTableData(); loadDataTableData();
setImportResult(response.data); setImportResult(response.data);
setImportLoading(false);
}) })
.catch((response) => { .catch((response) => {
enqueueSnackbar( enqueueSnackbar(
@@ -187,12 +193,24 @@ export default function CorporatePlanList() {
response.message, response.message,
{ variant: 'error' } { variant: 'error' }
); );
setImportLoading(false);
}); });
} else { } else {
enqueueSnackbar('No File Selected', { variant: 'warning' }); enqueueSnackbar('No File Selected', { variant: 'warning' });
} }
}; };
const handleGetTemplate = (type: string) => {
axios.get('corporates/import-document-example/' + type).then((response) => {
const link = document.createElement('a');
link.href = response.data.data.file_url;
link.setAttribute('download', response.data.data.file_name);
document.body.appendChild(link);
link.click();
handleClose();
});
};
return ( return (
<div> <div>
<input <input
@@ -229,7 +247,13 @@ export default function CorporatePlanList() {
}} }}
> >
<MenuItem onClick={handleImportButton}>Import</MenuItem> <MenuItem onClick={handleImportButton}>Import</MenuItem>
<MenuItem onClick={handleClose}>Download Template</MenuItem> <MenuItem
onClick={() => {
handleGetTemplate('member');
}}
>
Download Template
</MenuItem>
</Menu> </Menu>
</Stack> </Stack>
)} )}
@@ -250,15 +274,16 @@ export default function CorporatePlanList() {
</Button> </Button>
</ButtonGroup> </ButtonGroup>
<Button <LoadingButton
id="upload-button" id="upload-button"
variant="outlined" variant="outlined"
startIcon={<UploadIcon />} startIcon={<UploadIcon />}
sx={{ p: 1.8 }} sx={{ p: 1.8 }}
onClick={handleUpload} onClick={handleUpload}
loading={importLoading}
> >
Upload Upload
</Button> </LoadingButton>
</Stack> </Stack>
)} )}
{importResult && ( {importResult && (
@@ -308,6 +333,16 @@ export default function CorporatePlanList() {
function Row(props: { row: ReturnType<typeof createData> }) { function Row(props: { row: ReturnType<typeof createData> }) {
const { row } = props; const { row } = props;
const [open, setOpen] = React.useState(false); const [open, setOpen] = React.useState(false);
const [loadingLog, setLoadingLog] = React.useState(false);
const [dialogLogOpen, setDialogLogOpen] = React.useState(false);
// useEffect(function () {
// if (row.full_name == 'Pajri') {
// setDialogLogOpen(true);
// console.log('fuck');
// }
// }, []);
const handleActivate = (model: any, status: string) => { const handleActivate = (model: any, status: string) => {
axios axios
.put(`/members/${row.id}/activation`, { .put(`/members/${row.id}/activation`, {
@@ -334,6 +369,7 @@ export default function CorporatePlanList() {
); );
}); });
}; };
return ( return (
<React.Fragment> <React.Fragment>
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}> <TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
@@ -497,19 +533,30 @@ export default function CorporatePlanList() {
</Grid> </Grid>
</Grid> </Grid>
{/* <Typography sx={{ fontWeight: '600', mb: 1, mt: 2 }}>Sub Corporate</Typography> <Grid>
<Grid container> <LoadingButton
<Grid item xs={12}> id="upload-button"
<Grid container> variant="outlined"
<Grid item xs={6}> startIcon={<InsertDriveFileIcon />}
Sub Corporates (asdasdasdasd) // sx={{ p: 1.8 }}
</Grid> // onClick={() => {handleDownloadLog(row)}}
<Grid item xs={6}> onClick={() => {
: qweqweqweqwe setDialogLogOpen(true);
</Grid> }}
</Grid> loading={loadingLog}
</Grid> >
</Grid> */} Download LOG
</LoadingButton>
</Grid>
<DialogLog
title={{
name: `Generate LOG - ${row.full_name}`,
}}
openDialog={dialogLogOpen}
setOpenDialog={setDialogLogOpen}
data={{ member: row }}
></DialogLog>
</Box> </Box>
</Collapse> </Collapse>
</TableCell> </TableCell>
@@ -540,9 +587,9 @@ export default function CorporatePlanList() {
<TableCell style={headStyle} align="center"> <TableCell style={headStyle} align="center">
Status Status
</TableCell> </TableCell>
<TableCell style={headStyle} align="center"> {/* <TableCell style={headStyle} align="center">
Action Action
</TableCell> </TableCell> */}
</TableRow> </TableRow>
</TableBody> </TableBody>
{dataTableIsLoading ? ( {dataTableIsLoading ? (

View File

@@ -0,0 +1,203 @@
// react
import { ReactElement, useEffect, useState } from 'react';
// mui
import {
Card,
Checkbox,
Divider,
Grid,
Input,
Link,
Stack,
Table,
TableCell,
TableContainer,
TableRow,
Typography,
} from '@mui/material';
import { styled } from '@mui/material/styles';
// Component
import MuiDialog from '@/components/MuiDialog';
import { Box } from '@mui/material';
import { TextField } from '@mui/material';
import { DesktopDatePicker, LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { fPostFormat } from '@/utils/formatTime';
import { LoadingButton } from '@mui/lab';
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
import axios from '@/utils/axios';
import { enqueueSnackbar } from 'notistack';
type DataContent = {
info: string;
date: string;
time: string;
};
type MuiDialogProps = {
title?: {
name?: string;
icon?: string;
};
openDialog: boolean;
setOpenDialog: Function;
content?: ReactElement;
data?: DataContent[];
};
const ItemNotificationStyle = styled(Card)(({ theme }) => ({
boxShadow: 'none',
padding: theme.spacing(1),
borderRadius: 0.5,
color: 'black',
}));
const DialogLog = ({ title, openDialog, setOpenDialog, data }: MuiDialogProps) => {
const [openDialogClaim, setOpenDialogClaim] = useState(false);
const [dialogTitleClaim, setDialogTitleClaim] = useState('');
const [dateOfAdmission, setDateOfAdmission] = useState(new Date());
const [checkedBenefitIds, setCheckedBenefitIds] = useState([]);
const [benefitIds, setBenefitIds] = useState([]);
const [loadingLog, setLoadingLog] = useState(false);
useEffect(() => {
setBenefitIds(data.member.current_plan?.benefits.map((benefit) => benefit.id))
setCheckedBenefitIds(benefitIds)
console.log('Check All', benefitIds, 'X', data.member.current_plan?.benefits.map((benefit) => benefit.id))
}, [])
const clickHandler = () => {
setDialogTitleClaim('Claim Details');
setOpenDialogClaim(true);
};
const handleCheckAll = (event) => {
if (event.target.checked) {
setCheckedBenefitIds(benefitIds)
} else {
setCheckedBenefitIds([])
}
}
const handleCheckChange = (event, benefit) => {
if ( event.target.checked ) {
setCheckedBenefitIds([...checkedBenefitIds, benefit.id])
} else {
// setCheckedBenefitIds([])
setCheckedBenefitIds(checkedBenefitIds.filter((benefitId) => benefitId !== benefit.id))
}
}
const handleDownloadLog = (row) => {
setLoadingLog(true);
axios
.post(`generate-log/${row.id}`, {
date_of_admission : dateOfAdmission,
benefit_ids : checkedBenefitIds
}, {
responseType: 'blob',
})
.then((response) => {
window.open(URL.createObjectURL(response.data));
setLoadingLog(false);
setOpenDialog(false);
})
.catch((response) => {
enqueueSnackbar(response.message, { variant: 'error' });
setLoadingLog(false);
});
}
const getContent = () => (
<Stack sx={{ marginTop: 2 }}>
<ItemNotificationStyle>
<Stack>
<Grid container spacing={2}>
<Grid item xs={12}>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DesktopDatePicker
inputFormat="dd/MM/Y"
value={dateOfAdmission}
onChange={(value) => {
setDateOfAdmission(new Date(fPostFormat(value)));
// console.log('value')
}}
renderInput={(params) => (
<TextField
{...params}
fullWidth
label="Date of Admission"
placeholder="dd/mm/yyyy"
/>
)}
/>
</LocalizationProvider>
</Grid>
<Grid item xs={12} sx={{marginTop: 2}}>
<Stack direction="row" alignItems="center" justifyContent={'space-between'}>
<Typography variant="body1" fontWeight={800}>List Of Benefit</Typography>
<Stack direction="row" alignItems="center">
<Typography>All</Typography>
<Checkbox onChange={handleCheckAll} checked={benefitIds.length == checkedBenefitIds.length}/>
</Stack>
</Stack>
</Grid>
<Grid item xs={12}>
<Stack divider={<Divider flexItem />}>
{ data.member.current_plan?.benefits && (
data.member.current_plan?.benefits.map((benefit, index) => (
<Stack direction="row" alignItems="center" key={index}>
<Box sx={{ width: '100%' }}>
<Typography>{benefit.code} {benefit.description ? ` - ${benefit.description} ` : ''}</Typography>
</Box>
<Checkbox checked={checkedBenefitIds.includes(benefit.id)} onClick={(event) => {handleCheckChange(event, benefit)} } />
</Stack>
))
)}
</Stack>
{/* <TableContainer>
<Table>
<TableRow>
<TableCell>
ASD
</TableCell>
<TableCell>
ASD
</TableCell>
</TableRow>
</Table>
</TableContainer> */}
</Grid>
<Grid item xs={12}>
<LoadingButton
id="upload-button"
variant="outlined"
fullWidth
startIcon={<InsertDriveFileIcon />}
onClick={() => {handleDownloadLog(data.member)}}
loading={loadingLog}
>
Download LOG
</LoadingButton>
</Grid>
</Grid>
</Stack>
</ItemNotificationStyle>
</Stack>
);
return (
<>
<MuiDialog
title={title}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
/>
</>
);
};
export default DialogLog;

View File

@@ -32,11 +32,11 @@ export default function Divisions() {
}, },
{ {
name: corporate?.name ?? '-', name: corporate?.name ?? '-',
href: '/corporates/' + corporate_id, href: '/corporate/' + corporate_id,
}, },
{ {
name: 'Plan', name: 'Plan',
href: '/corporates/' + corporate_id + '/plans', href: '/corporate/' + corporate_id + '/plans',
}, },
]} ]}
/> />

View File

@@ -43,6 +43,7 @@ import { Plan } from '../../../@types/corporates';
import { LaravelPaginatedData } from '../../../@types/paginated-data'; import { LaravelPaginatedData } from '../../../@types/paginated-data';
import BasePagination from '../../../components/BasePagination'; import BasePagination from '../../../components/BasePagination';
import { enqueueSnackbar } from 'notistack'; import { enqueueSnackbar } from 'notistack';
import { LoadingButton } from '@mui/lab';
export default function CorporatePlanList() { export default function CorporatePlanList() {
const { themeStretch } = useSettings(); const { themeStretch } = useSettings();
@@ -92,6 +93,7 @@ export default function CorporatePlanList() {
const createMenu = Boolean(anchorEl); const createMenu = Boolean(anchorEl);
const importPlan = useRef<HTMLInputElement>(null); const importPlan = useRef<HTMLInputElement>(null);
const [currentImportFileName, setCurrentImportFileName] = useState(null); const [currentImportFileName, setCurrentImportFileName] = useState(null);
const [importLoading, setImportLoading] = useState(false);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => { const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
@@ -127,6 +129,8 @@ export default function CorporatePlanList() {
if (importPlan.current?.files.length) { if (importPlan.current?.files.length) {
const formData = new FormData(); const formData = new FormData();
formData.append('file', importPlan.current?.files[0]); formData.append('file', importPlan.current?.files[0]);
setImportLoading(true);
axios axios
.post(`corporates/${corporate_id}/import-plan-benefit`, formData) .post(`corporates/${corporate_id}/import-plan-benefit`, formData)
.then((response) => { .then((response) => {
@@ -134,6 +138,7 @@ export default function CorporatePlanList() {
loadDataTableData(); loadDataTableData();
setImportResult(response.data); setImportResult(response.data);
// alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows'); // alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows');
setImportLoading(false);
}) })
.catch((response) => { .catch((response) => {
enqueueSnackbar( enqueueSnackbar(
@@ -141,12 +146,25 @@ export default function CorporatePlanList() {
response.message, response.message,
{ variant: 'error' } { variant: 'error' }
); );
setImportLoading(false);
}); });
} else { } else {
enqueueSnackbar('No File Selected', { variant: 'warning' }); enqueueSnackbar('No File Selected', { variant: 'warning' });
} }
}; };
const handleGetTemplate = (type :string) => {
axios.get('corporates/import-document-example/' + type)
.then((response) => {
const link = document.createElement('a');
link.href = response.data.data.file_url;
link.setAttribute('download', response.data.data.file_name);
document.body.appendChild(link);
link.click();
handleClose();
})
}
return ( return (
<div> <div>
<input <input
@@ -183,7 +201,7 @@ export default function CorporatePlanList() {
}} }}
> >
<MenuItem onClick={handleImportButton}>Import</MenuItem> <MenuItem onClick={handleImportButton}>Import</MenuItem>
<MenuItem onClick={handleClose}>Download Template</MenuItem> <MenuItem onClick={() => {handleGetTemplate('plan-benefit')}}>Download Template</MenuItem>
</Menu> </Menu>
</Stack> </Stack>
)} )}
@@ -204,15 +222,16 @@ export default function CorporatePlanList() {
</Button> </Button>
</ButtonGroup> </ButtonGroup>
<Button <LoadingButton
id="upload-button" id="upload-button"
variant="outlined" variant="outlined"
startIcon={<UploadIcon />} startIcon={<UploadIcon />}
sx={{ p: 1.8 }} sx={{ p: 1.8 }}
onClick={handleUpload} onClick={handleUpload}
loading={importLoading}
> >
Upload Upload
</Button> </LoadingButton>
</Stack> </Stack>
)} )}
{importResult && ( {importResult && (
@@ -309,11 +328,11 @@ export default function CorporatePlanList() {
</Button> </Button>
)} )}
</TableCell> </TableCell>
<TableCell align="center"> {/* <TableCell align="center">
<Button variant="outlined" color="success" size="small"> <Button variant="outlined" color="success" size="small">
Edit Edit
</Button> </Button>
</TableCell> </TableCell> */}
</TableRow> </TableRow>
{/* COLLAPSIBLE ROW */} {/* COLLAPSIBLE ROW */}
<TableRow> <TableRow>
@@ -677,9 +696,9 @@ export default function CorporatePlanList() {
<TableCell style={headStyle} align="center"> <TableCell style={headStyle} align="center">
Status Status
</TableCell> </TableCell>
<TableCell style={headStyle} align="center"> {/* <TableCell style={headStyle} align="center">
Action Action
</TableCell> </TableCell> */}
</TableRow> </TableRow>
</TableBody> </TableBody>
{dataTableIsLoading ? ( {dataTableIsLoading ? (

View File

@@ -50,19 +50,27 @@ import Page from '../../../components/Page';
import useSettings from '../../../hooks/useSettings'; import useSettings from '../../../hooks/useSettings';
import CorporateTabNavigations from '../CorporateTabNavigations'; import CorporateTabNavigations from '../CorporateTabNavigations';
import DivisionsList from './List'; import DivisionsList from './List';
import { ChangeEvent, useEffect, useMemo, useState } from 'react'; import { ChangeEvent, useContext, useEffect, useMemo, useState } from 'react';
import axios from '../../../utils/axios'; import axios from '../../../utils/axios';
import { CorporateService } from '../../../@types/corporates'; import { Corporate, CorporateService } from '../../../@types/corporates';
import { InfoIcon } from '../../../theme/overrides/CustomIcons'; import { InfoIcon } from '../../../theme/overrides/CustomIcons';
import { includes, min, set } from 'lodash'; import { includes, min, set } from 'lodash';
import { array } from 'yup/lib/locale'; import { array } from 'yup/lib/locale';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
import { enqueueSnackbar, useSnackbar } from 'notistack'; import { enqueueSnackbar, useSnackbar } from 'notistack';
import { ConfiguredCorporateContext } from '@/contexts/ConfiguredCorporateContext';
export default function Divisions() { export default function Divisions() {
const { themeStretch } = useSettings(); const { themeStretch } = useSettings();
const { corporate_id, service_code } = useParams(); const { corporate_id, service_code } = useParams();
const [corporate, setCorporate] = useState<Corporate | null>();
const configuredCorporateContext = useContext(ConfiguredCorporateContext);
useEffect(() => {
setCorporate(configuredCorporateContext.currentCorporate);
}, [configuredCorporateContext]);
const [service, setService] = useState<CorporateService>({ const [service, setService] = useState<CorporateService>({
configurations: {}, configurations: {},
@@ -127,7 +135,7 @@ export default function Divisions() {
const handleConfigChange = (event: ChangeEvent<HTMLInputElement>, service: any) => { const handleConfigChange = (event: ChangeEvent<HTMLInputElement>, service: any) => {
axios axios
.put(`/corporates/${corporate_id}/services`, { .put(`/corporates/${corporate_id}/services`, {
service_code: service.service_code, service_code: service_code,
config_name: event.target.name, config_name: event.target.name,
config_value: event.target.checked, config_value: event.target.checked,
}) })
@@ -364,22 +372,21 @@ export default function Divisions() {
<HeaderBreadcrumbs <HeaderBreadcrumbs
heading={'Create Benefit'} heading={'Create Benefit'}
links={[ links={[
{ name: 'Dashboard', href: '/dashboard' },
{ {
name: 'Corporates', name: 'Corporates',
href: '/corporates', href: '/corporates',
}, },
{ {
name: 'Corporate Name', name: corporate?.name ?? '-',
href: '/corporates/' + corporate_id, href: '/corporate/' + corporate_id,
}, },
{ {
name: 'Services', name: 'Services',
href: '/corporates/' + corporate_id + '/services', href: '/corporate/' + corporate_id + '/services',
}, },
{ {
name: service.name ?? '-', name: service_code ?? '-',
href: '/corporates/' + corporate_id + '/services/' + service_code, href: '/corporate/' + corporate_id + '/services/' + service_code,
}, },
]} ]}
/> />
@@ -545,16 +552,12 @@ export default function Divisions() {
setSpecialityModal(true); setSpecialityModal(true);
}} }}
> >
Specialities : ( <Button variant='contained'>Specialities</Button>
{service.selected_specialities
? Object.keys(service.selected_specialities).length
: '0'}
)
</Typography> </Typography>
<Typography> <Typography sx={{mt: 2}}>
{service.selected_specialities {(service.selected_specialities && service.selected_specialities != '')
? '{' + Object.values(service.selected_specialities).join(', ') + '}' ? Object.keys(service.selected_specialities).length + ' Spesialis Diijinkan : {' + Object.values(service.selected_specialities).join(', ') + '}'
: ''} : 'Tidak Ada Spesialis yang diijinkan'}
</Typography> </Typography>
</TableCell> </TableCell>
</TableRow> </TableRow>

View File

@@ -34,11 +34,11 @@ export default function Divisions() {
}, },
{ {
name: corporate?.name ?? '-', name: corporate?.name ?? '-',
href: '/corporates/' + corporate_id, href: '/corporate/' + corporate_id,
}, },
{ {
name: 'Services', name: 'Services',
href: '/corporates/' + corporate_id + '/services', href: '/corporate/' + corporate_id + '/services',
}, },
]} ]}
/> />

View File

@@ -9,7 +9,6 @@ import Form from './Form';
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs'; import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
import axios from '../../../utils/axios'; import axios from '../../../utils/axios';
import { Practitioner } from '../../../@types/doctor'; import { Practitioner } from '../../../@types/doctor';
import ButtonBack from '../../../components/ButtonBack';
export default function Create() { export default function Create() {
const { themeStretch } = useSettings(); const { themeStretch } = useSettings();
@@ -31,7 +30,6 @@ export default function Create() {
<Page title="Membership: Create a new Dokter"> <Page title="Membership: Create a new Dokter">
<Container maxWidth={themeStretch ? false : 'xl'}> <Container maxWidth={themeStretch ? false : 'xl'}>
<Stack direction="row" alignItems="center"> <Stack direction="row" alignItems="center">
<ButtonBack />
<HeaderBreadcrumbs <HeaderBreadcrumbs
heading={!isEdit ? 'Manage a new Dokter' : 'Manage Dokter'} heading={!isEdit ? 'Manage a new Dokter' : 'Manage Dokter'}
links={[ links={[
@@ -54,40 +52,3 @@ export default function Create() {
</Page> </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>
// );
// }

View File

@@ -8,7 +8,7 @@ import Select, { SelectChangeEvent } from '@mui/material/Select';
import * as React from 'react'; import * as React from 'react';
// form // form
import { useForm } from 'react-hook-form'; import { useForm, Controller } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup'; import { yupResolver } from '@hookform/resolvers/yup';
// @mui // @mui
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
@@ -25,6 +25,7 @@ import {
Typography, Typography,
TextField, TextField,
Chip, Chip,
Autocomplete,
} from '@mui/material'; } from '@mui/material';
import CancelIcon from '@mui/icons-material/Cancel'; import CancelIcon from '@mui/icons-material/Cancel';
@@ -41,17 +42,20 @@ import {
RHFMultiCheckbox, RHFMultiCheckbox,
RHFCheckbox, RHFCheckbox,
RHFCustomMultiCheckbox, RHFCustomMultiCheckbox,
RHFSelect,
} from '../../../components/hook-form'; } from '../../../components/hook-form';
import axios from '../../../utils/axios'; import axios from '../../../utils/axios';
import { fCurrency } from '../../../utils/formatNumber'; import { fCurrency } from '../../../utils/formatNumber';
import { Practitioner } from '../../../@types/doctor'; import { Practitioner } from '../../../@types/doctor';
import AddIcon from '@mui/icons-material/Add';
import { Label, Rowing } from '@mui/icons-material'; import { Label, Rowing } from '@mui/icons-material';
import { email } from '../../../_mock/email';
const LabelStyle = styled(Typography)(({ theme }) => ({ const LabelStyle = styled(Typography)(({ theme }) => ({
...theme.typography.subtitle2, ...theme.typography.h6,
color: theme.palette.text.secondary, marginBottom: theme.spacing(2),
marginBottom: theme.spacing(1), marginTop: theme.spacing(2),
})); }));
const HeaderStyle = styled('header')(({ theme }) => ({ const HeaderStyle = styled('header')(({ theme }) => ({
@@ -66,7 +70,6 @@ const Title = styled(Typography)(({ theme }) => ({
boxShadow: 'none', boxShadow: 'none',
// paddingBottom: theme.spacing(3), // paddingBottom: theme.spacing(3),
fontWeight: 700, fontWeight: 700,
color: '#005B7F',
})); }));
interface FormValuesProps extends Partial<Practitioner> { interface FormValuesProps extends Partial<Practitioner> {
@@ -106,6 +109,8 @@ export default function PractitionerForm({ isEdit, currentPractitioner }: Props)
() => ({ () => ({
id: currentPractitioner?.id, id: currentPractitioner?.id,
name: currentPractitioner?.name || '', name: currentPractitioner?.name || '',
email: currentPractitioner?.email || '',
phone: currentPractitioner?.phone || '',
address: currentPractitioner?.address || '', address: currentPractitioner?.address || '',
birth_date: currentPractitioner?.birth_date || '', birth_date: currentPractitioner?.birth_date || '',
gender: currentPractitioner?.gender || '', gender: currentPractitioner?.gender || '',
@@ -121,6 +126,8 @@ export default function PractitionerForm({ isEdit, currentPractitioner }: Props)
[currentPractitioner] [currentPractitioner]
); );
console.log('currentPractitioner', currentPractitioner);
console.log('defaultValues', defaultValues); console.log('defaultValues', defaultValues);
function StatusLabel({ value }: { value: boolean }) { function StatusLabel({ value }: { value: boolean }) {
@@ -168,91 +175,391 @@ export default function PractitionerForm({ isEdit, currentPractitioner }: Props)
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isEdit, currentPractitioner]); }, [isEdit, currentPractitioner]);
const handleActivate = (event: React.ChangeEvent<HTMLInputElement>) => { const onSubmit = async (data: FormValuesProps) => {
setValue('active', event.target.checked); try {
const formData = new FormData();
formData.append('name', data.name);
formData.append('gender', data.gender);
formData.append('address', data.address);
formData.append('birth_place', data.birth_place);
formData.append('birth_date', data.birth_date);
formData.append('email', data.email);
formData.append('phone', data.phone);
// formData.append('active', data.active ? '1' : '0');
forms.forEach((form, index) => {
formData.append(`practices[${index}][organization_id]`, form.organizationId);
form.specialities.forEach((speciality, i) => {
formData.append(`practices[${index}][specialities][${i}][speciality_id]`, speciality);
});
});
console.log('event.target.checked', event.target.checked); if (!isEdit) {
console.log('formData', formData);
const response = await axios.post('/doctors', formData);
} else {
formData.append('_method', 'PUT');
const response = await axios.post('/doctors/' + currentPractitioner?.id ?? '', formData);
}
reset();
enqueueSnackbar(!isEdit ? 'Doctors Created Successfully!' : 'Doctors Udpated Successfully!', {
variant: 'success',
});
navigate('/master/doctors');
} catch (error: any) {
if (error && error.response.status === 422) {
console.log('error', error.response.data.errors);
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 formData = new FormData(); const ascent = document?.querySelector('ascent');
formData.append('active', event.target.checked ? '1' : '0'); if (ascent != null) {
formData.append('_method', 'PUT'); ascent.innerHTML = '';
axios.post('/doctors/' + currentPractitioner?.id ?? '', formData); }
};
enqueueSnackbar('active Updated Successfully!', { variant: 'success' }); const [organizations, setOrganizations] = useState<any>([]);
const [specialities, setSpecialities] = useState<any>([]);
useEffect(() => {
axios.get(`/search-organizations`).then((response) => {
setOrganizations(
response.data.map((item: any) => ({ ...item, name: item.name, value: item.id }))
);
});
axios.get(`/search-specialities`).then((response) => {
setSpecialities(
response.data.map((item: any) => ({ ...item, name: item.name, value: item.id }))
);
});
}, []);
// const specialities = [
// { name: 'Dentistry', id: 1 },
// { name: 'Dermatology', id: 2 },
// { name: 'General Medicine', id: 3 },
// { name: 'Pediatrics', id: 4 },
// { name: 'Surgery', id: 5 },
// ];
const practices = currentPractitioner?.practices || [];
// const practices = [
// {
// organization_id: 187,
// specialities: [
// {
// speciality_id: 7,
// },
// {
// speciality_id: 6,
// },
// ],
// },
// {
// organization_id: 181,
// specialities: [
// {
// speciality_id: 2,
// },
// ],
// },
// ];
const [forms, setForms] = useState<any>([]);
useEffect(() => {
if (practices.length > 0) {
const newForms = practices.map((practice: any) => {
return {
organizationId: practice.organization_id,
specialities: practice.specialities.map((s) => s.speciality_id),
};
});
setForms(newForms);
} else {
setForms([
{
organizationId: '',
specialities: [],
},
]);
}
}, [practices && practices.length]);
// }, []);
console.log('forms', forms);
const findValueOrganization = (organizationId) => {
if (organizationId === '' || organizationId === null) {
return { name: '', value: '' };
} else {
const organization = organizations.find((o) => o.id === organizationId);
return { name: organization?.name, value: organizationId };
}
};
// console.log('findValueOrganization', findValueOrganization(187));
// const findValueSpeciality = (specialityIds: number[]) => {
// if (specialityIds.length === 0) {
// return [];
// } else {
// const data = specialities.filter((s) => specialityIds.includes(s.id));
// return data.map((d) => ({ name: d.name, value: d.id }));
// }
// };
const findValueSpeciality = (values: any) => {
return specialities.filter((s) => values.includes(s.value));
};
// const [forms, setForms] = useState([
// {
// organizationId: '',
// specialities: [],
// },
// ]);
const addForm = () => {
setForms([
...forms,
{
organizationId: '',
specialities: [],
},
]);
};
console.log('forms', forms);
const gender = [
{
value: 'male',
label: 'Laki-Laki',
},
{
value: 'female',
label: 'Perempuan',
},
];
console.log('forms', forms);
// const handleSpecialitiesChange = (index: number, value: any) => {
// const newForms = [...forms];
// newForms[index].specialities = value.map((v: any) => ({ speciality_id: v.id }));
// setForms(newForms);
// };
// const handleSpecialitiesChange = (index: number, value: any) => {
// const updatedForms = [...forms];
// updatedForms[index].specialities = value.map((v: any) => v.speciality_id);
// setForms(updatedForms);
// };
const handleOrganizationIdChange = (index, value) => {
const updatedForms = [...forms];
updatedForms[index].organizationId = value.id;
setForms(updatedForms);
};
const handleSpecialitiesChange = (index: number, value: any) => {
setForms((forms) => {
forms[index].specialities = value.map((v: any) => v.value);
return [...forms];
});
};
// const availableOrganizations = organizations.filter(
// (org) =>
// !forms.some((f) => f.organization && f.organization.id === org.id) ||
// forms.findIndex((f) => f.organization && f.organization.id === org.id) === editIndex
// );
const availableOrganizations =
practices.length > 0
? organizations.filter(
(org) => !practices.some((practice) => practice.organization_id === org.id)
)
: organizations.filter((org) => !forms.some((f) => f.organizationId === org.id));
// const availableOrganizations = organizations.filter(
// (org) => !practices.some((p) => p.organization_id === org.id)
// );
const handleDeleteForm = (index) => {
const updatedForms = [...forms];
updatedForms.splice(index, 1);
setForms(updatedForms);
}; };
return ( return (
<FormProvider methods={methods}> <FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
<Stack spacing={3}> <Stack spacing={3}>
<Box sx={{ width: '100%' }}> <Box sx={{ width: '100%' }}>
{/* <Stack spacing={3}> */} {/* <Stack spacing={3}> */}
<Card sx={{ p: 5 }}> <Card sx={{ p: 5 }}>
<HeaderStyle> {/* <HeaderStyle>
<Grid item xs={6} md={6}> <Grid item xs={6} md={6}>
<Title>Data Dokter</Title> <Title>Data Dokter</Title>
</Grid> </Grid>
<Grid item xs={6} md={6}> <Grid item xs={6} md={6}>
{/* <Typography>Status Rumah Sakit</Typography> */} <RHFSwitch name="active" label="" />
<RHFSwitch name="active" label="" onClick={handleActivate} />
<StatusLabel value={values.active} /> <StatusLabel value={values.active} />
</Grid> </Grid>
</HeaderStyle> </HeaderStyle> */}
<Title variant="h5">Informasi Umum</Title> <Title variant="h5">Informasi Umum</Title>
<Avatar <Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }} sx={{ mt: 2 }}>
alt="Remy Sharp" <Grid item xs={12}>
src={currentPractitioner?.avatar_url} <LabelStyle>Nama Dokter</LabelStyle>
sx={{ width: 120, height: 120, marginBottom: 2 }} <RHFTextField name="name" placeholder="Tuliskan Nama Dokter" />
/>
<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>
<Grid item xs={5} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
<Span style={{ fontWeight: 'bold' }}>Jenis Kelamin</Span> <Grid item xs={6}>
<Text>{currentPractitioner?.gender ? currentPractitioner?.gender : '-'}</Text> <LabelStyle>Jenis Kelamin</LabelStyle>
<Span style={{ fontWeight: 'bold' }}>Email</Span> <RHFSelect name="gender" label="Pilih Jenis Kelamin">
<Text>{currentPractitioner?.email ? currentPractitioner?.email : '-'}</Text> <option value="" />
<Span style={{ fontWeight: 'bold' }}>Tanggal Lahir</Span> {gender.map((option, index) => (
<Text> <option key={index} value={option.value}>
{currentPractitioner?.birth_date ? currentPractitioner?.birth_date : '-'} {option.label}
</Text> </option>
))}
</RHFSelect>
</Grid>
<Grid item xs={6}>
<LabelStyle>Alamat</LabelStyle>
<RHFTextField name="address" placeholder="Tuliskan Alamat" />
</Grid>
<Grid item xs={6}>
<LabelStyle>Tempat Lahir</LabelStyle>
<RHFTextField name="birth_place" placeholder="Tuliskan Tempat Lahir" />
</Grid>
<Grid item xs={6}>
<LabelStyle>Tanggal Lahir</LabelStyle>
<RHFDatepicker name="birth_date" placeholder="Silahkan Pilih Tanggal Lahir" />
</Grid>
<Grid item xs={6}>
<LabelStyle>Email</LabelStyle>
<RHFTextField name="email" placeholder="Tuliskan Email" type="email" />
</Grid>
<Grid item xs={6}>
<LabelStyle>No. Telp</LabelStyle>
<RHFTextField name="phone" placeholder="Tuliskan Nomor Telepon" />
</Grid> </Grid>
</Grid> </Grid>
</Card> </Card>
<Card sx={{ p: 5, marginTop: 2 }}> <Card sx={{ p: 5, marginTop: 2 }}>
<Title variant="h5">Tempat Praktik</Title> <Stack spacing={3} direction="row" justifyContent="space-between">
{currentPractitioner?.organizations?.map((item, index) => ( <Title variant="h5">Tempat Praktik</Title>
<Box key={index} sx={{ mt: 3 }}> <Button
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}> variant="contained"
<Grid item xs={7}> color="primary"
<Text>{item.name}</Text> size="small"
sx={{ boxShadow: 'none' }}
onClick={addForm}
startIcon={<AddIcon />}
>
Tambah Tempat Praktik
</Button>
</Stack>
{forms.map((form, index) => (
<div key={index}>
<Box sx={{ mt: 3 }}>
<Stack spacing={3} direction="row" justifyContent="space-between">
<LabelStyle></LabelStyle>
{index !== 0 && (
<Button
sx={{ color: 'red', m: 1 }}
aria-label="close"
onClick={() => handleDeleteForm(index)}
>
Delete
</Button>
// <Button onClick={() => handleDeleteForm(index)}>Delete</Button>
)}
</Stack>
{/* <h1>{form.organizationId}</h1> */}
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
<Grid item xs={6}>
<Autocomplete
options={availableOrganizations}
value={findValueOrganization(form.organizationId) ?? ''}
getOptionLabel={(option) => option.name}
isOptionEqualToValue={(option, value) => option.value === value.value}
onChange={(event, value) => handleOrganizationIdChange(index, value)}
renderInput={(params) => (
<TextField {...params} label="Rumah Sakit" variant="outlined" />
)}
/>
{/* <Autocomplete
options={organizations}
value={findValueOrganization(form.organizationId)}
getOptionLabel={(option) =>
option.name ?? findValueOrganization(form.organizationId).name ?? ''
}
onChange={(event, value) => handleOrganizationIdChange(index, value)}
renderInput={(params) => (
<TextField {...params} label="Rumah Sakit" variant="outlined" />
)}
/> */}
</Grid>
<Grid item xs={6}>
{form.specialities && (
// <Autocomplete
// multiple
// // options={specialities}
// options={specialities}
// value={findValueSpeciality(form.specialities) ?? ''}
// getOptionLabel={(option) => option.name}
// isOptionEqualToValue={(option, value) => option.value === value.value}
// onChange={(event, value) => handleSpecialitiesChange(index, value)}
// renderInput={(params) => (
// <TextField {...params} label="Spesialis" variant="outlined" />
// )}
// />
<Autocomplete
multiple
options={specialities}
value={findValueSpeciality(form.specialities)}
getOptionLabel={(option) => option.name}
onChange={(event, value) => handleSpecialitiesChange(index, value)}
renderInput={(params) => (
<TextField {...params} label="Spesialis" variant="outlined" />
)}
/>
)}
</Grid>
</Grid> </Grid>
</Grid> </Box>
</Box> </div>
))}
</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> </Card>
<Box sx={{ width: '100%', mt: 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>
</Box> </Box>
</Stack> </Stack>
</FormProvider> </FormProvider>

View File

@@ -57,6 +57,7 @@ import { Search } from '@mui/icons-material';
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
import AddIcon from '@mui/icons-material/Add';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@@ -205,9 +206,16 @@ export default function List() {
spacing={2} spacing={2}
sx={{ p: 2, justifyContent: 'space-between', alignItems: 'center' }} sx={{ p: 2, justifyContent: 'space-between', alignItems: 'center' }}
> >
<Grid item xs={12} md={12} lg={12}> <Grid item xs={12} md={10} lg={10}>
<Filter onSearch={applyItems} /> <Filter onSearch={applyItems} />
</Grid> </Grid>
<Grid item xs={12} md={2} lg={2} sx={{ textAlign: 'right' }}>
<Link to="/master/doctors/create" style={{ textDecoration: 'none' }}>
<Button variant="outlined" startIcon={<AddIcon />} sx={{ p: 1.8 }}>
Create
</Button>
</Link>
</Grid>
</Grid> </Grid>
); );
} }
@@ -297,15 +305,22 @@ export default function List() {
<CheckStatus row={row} /> <CheckStatus row={row} />
</TableCell> */} </TableCell> */}
{/* <TableCell align="center"> <TableCell align="center">
<ButtonGroup variant="text" aria-label="text button group"> <ButtonGroup variant="text" aria-label="text button group">
<Link to={'/master/doctors/' + row.id}> <Link to={'/master/doctors/' + row.id + '/edit'}>
<Button> <Button>
<Icon icon="ph:eye-bold" style={{ width: '24px', height: '24px' }} /> <Icon icon="ph:pencil-simple-fill" style={{ width: '24px', height: '24px' }} />
</Button> </Button>
</Link> </Link>
<Button
onClick={() => {
setOpenDialog(true);
}}
>
<Icon icon="eva:trash-2-outline" style={{ width: '24px', height: '24px' }} />
</Button>
</ButtonGroup> </ButtonGroup>
</TableCell> */} </TableCell>
</TableRow> </TableRow>
{/* COLLAPSIBLE ROW */} {/* COLLAPSIBLE ROW */}
<TableRow> <TableRow>
@@ -336,7 +351,12 @@ export default function List() {
Jenis Kelamin Jenis Kelamin
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
: {row.gender ? row.gender : '-'} :{' '}
{row.gender == 'male'
? 'Laki-Laki'
: row.gender == 'female'
? 'Perempuan'
: '-'}
</Grid> </Grid>
</Grid> </Grid>
</Grid> </Grid>

View File

@@ -9,7 +9,6 @@ import Form from './Form';
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs'; import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
import axios from '../../../utils/axios'; import axios from '../../../utils/axios';
import { Organizations } from '../../../@types/organization'; import { Organizations } from '../../../@types/organization';
import ButtonBack from '../../../components/ButtonBack';
export default function Create() { export default function Create() {
const { themeStretch } = useSettings(); const { themeStretch } = useSettings();
@@ -31,25 +30,20 @@ export default function Create() {
<Page title="Membership: Create a new Rumah Sakit"> <Page title="Membership: Create a new Rumah Sakit">
<Container maxWidth={themeStretch ? false : 'xl'}> <Container maxWidth={themeStretch ? false : 'xl'}>
<Stack direction="row" alignItems="center"> <Stack direction="row" alignItems="center">
<ButtonBack />
<HeaderBreadcrumbs <HeaderBreadcrumbs
heading={!isEdit ? 'Create a new Rumah Sakit' : 'Edit Rumah Sakit'} heading={!isEdit ? 'Create a new Rumah Sakit' : 'Edit Rumah Sakit'}
links={[ links={[
{ name: 'Master', href: '/master' }, { name: 'Master', href: '/master' },
{ {
name: 'Organizations', name: 'Organizations',
href: '/master/organizations', href: '/master/hospitals',
}, },
{ name: !isEdit ? 'Create' : currentOrganizations?.name ?? '' }, { name: !isEdit ? 'Create' : currentOrganizations?.name ?? '' },
]} ]}
/> />
</Stack> </Stack>
<Form <Form isEdit={isEdit} currentOrganizations={currentOrganizations} />
// isSubmitting={isSubmitting}
isEdit={isEdit}
currentOrganizations={currentOrganizations}
/>
</Container> </Container>
</Page> </Page>
); );

View File

@@ -65,7 +65,6 @@ const LabelStyle = styled(Typography)(({ theme }) => ({
})); }));
const HeaderStyle = styled('header')(({ theme }) => ({ const HeaderStyle = styled('header')(({ theme }) => ({
padding: theme.spacing(5),
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
@@ -76,7 +75,6 @@ const Title = styled(Typography)(({ theme }) => ({
boxShadow: 'none', boxShadow: 'none',
// paddingBottom: theme.spacing(3), // paddingBottom: theme.spacing(3),
fontWeight: 700, fontWeight: 700,
color: '#005B7F',
})); }));
// const [timezone, setTimezone] = React.useState(''); // const [timezone, setTimezone] = React.useState('');
@@ -110,10 +108,6 @@ export default function OrganizationsForm({ isEdit, currentOrganizations }: Prop
const NewCorporateSchema = Yup.object().shape({ const NewCorporateSchema = Yup.object().shape({
name: Yup.string().required('Name is required'), name: Yup.string().required('Name is required'),
code: Yup.string().required('Corporate Code 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'), // file: Yup.boolean().required('Corporate Status is required'),
}); });
@@ -133,12 +127,6 @@ export default function OrganizationsForm({ isEdit, currentOrganizations }: Prop
village_id: currentOrganizations?.village_id || '', village_id: currentOrganizations?.village_id || '',
postal_code: currentOrganizations?.postal_code || '', postal_code: currentOrganizations?.postal_code || '',
description: currentOrganizations?.description || '', 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 // eslint-disable-next-line react-hooks/exhaustive-deps
[currentOrganizations] [currentOrganizations]
@@ -192,25 +180,15 @@ export default function OrganizationsForm({ isEdit, currentOrganizations }: Prop
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isEdit, currentOrganizations]); }, [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) => { const onSubmit = async (data: FormValuesProps) => {
try { try {
const formData = new FormData(); const formData = new FormData();
console.log('data', data);
formData.append('name', data.name); formData.append('name', data.name);
formData.append('code', data.code); formData.append('code', data.code);
formData.append('phone', data.phone); formData.append('phone', data.phone);
formData.append('lat', data.lat); formData.append('lat', data.lat);
formData.append('lng', data.lng); formData.append('lng', data.lng);
formData.append('address', data.address); formData.append('address', data.address);
formData.append('timezone', data.timezone);
formData.append('active', data.active ? '1' : '0'); formData.append('active', data.active ? '1' : '0');
if (data.province_id === currentOrganizations?.province_id) { if (data.province_id === currentOrganizations?.province_id) {
formData.append('province_id', data.province_id); formData.append('province_id', data.province_id);
@@ -235,21 +213,12 @@ export default function OrganizationsForm({ isEdit, currentOrganizations }: Prop
} else { } else {
formData.append('village_id', data.village_id?.value ?? ''); 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('postal_code', data.postal_code);
formData.append('description', data.description); 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) { if (!isEdit) {
console.log('formData', formData);
const response = await axios.post('/organizations', formData); const response = await axios.post('/organizations', formData);
} else { } else {
formData.append('_method', 'PUT'); formData.append('_method', 'PUT');
@@ -263,9 +232,10 @@ export default function OrganizationsForm({ isEdit, currentOrganizations }: Prop
!isEdit ? 'Organizations Created Successfully!' : 'Organizations Udpated Successfully!', !isEdit ? 'Organizations Created Successfully!' : 'Organizations Udpated Successfully!',
{ variant: 'success' } { variant: 'success' }
); );
navigate('/master/organizations'); navigate('/master/hospitals');
} catch (error: any) { } catch (error: any) {
if (error && error.response.status === 422) { if (error && error.response.status === 422) {
console.log('error', error.response.data.errors);
for (const [key, value] of Object.entries(error.response.data.errors)) { for (const [key, value] of Object.entries(error.response.data.errors)) {
setError(key, { message: value[0] }); setError(key, { message: value[0] });
enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' }); enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' });
@@ -281,34 +251,10 @@ export default function OrganizationsForm({ isEdit, currentOrganizations }: Prop
} }
}; };
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 [province, setProvince] = useState<any>([]);
const [city, setCity] = useState<any>([]); const [city, setCity] = useState<any>([]);
const [district, setDistrict] = useState<any>([]); const [district, setDistrict] = useState<any>([]);
// const [village, setVillage] = useState<any>([]); const [village, setVillage] = useState<any>([]);
useEffect(() => { useEffect(() => {
axios.get('/province').then((res) => { axios.get('/province').then((res) => {
@@ -335,17 +281,15 @@ export default function OrganizationsForm({ isEdit, currentOrganizations }: Prop
} }
}; };
// if (values.province_id) { const loadVillage = async () => {
// if (values.city_id) { if (values.district_id == currentOrganizations?.district_id) {
// loadDistrict(); const res = await axios.get('/village?district_id=' + values.district_id);
// } else { setVillage(res.data.data.map((item: any) => ({ value: item.id, label: item.name })));
// loadCity(); } else {
// } const res = await axios.get('/village?district_id=' + values.district_id?.value);
// } else { setVillage(res.data.data.map((item: any) => ({ value: item.id, label: item.name })));
// axios.get('/province').then((res) => { }
// setProvince(res.data.data.map((item: any) => ({ value: item.id, label: item.name }))); };
// });
// }
if (values.province_id) { if (values.province_id) {
loadCity(); loadCity();
@@ -354,12 +298,11 @@ export default function OrganizationsForm({ isEdit, currentOrganizations }: Prop
if (values.city_id) { if (values.city_id) {
loadDistrict(); loadDistrict();
} }
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [values.province_id, values.city_id, values.district_id]);
console.log('province', values.province_id); if (values.district_id) {
console.log('city', values.city_id); loadVillage();
console.log('district', values.district_id); }
}, [values.province_id, values.city_id, values.district_id, values.village_id]);
const findValueProvince = province.find( const findValueProvince = province.find(
(item: any) => item.value === currentOrganizations?.province_id (item: any) => item.value === currentOrganizations?.province_id
@@ -368,53 +311,8 @@ export default function OrganizationsForm({ isEdit, currentOrganizations }: Prop
const findValueDistrict = district.find( const findValueDistrict = district.find(
(item: any) => item.value === currentOrganizations?.district_id (item: any) => item.value === currentOrganizations?.district_id
); );
const findValueVillage = village.find(
console.log('findValueProvince', findValueProvince); (item: any) => item.value === currentOrganizations?.village_id
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 ( return (
@@ -431,326 +329,147 @@ export default function OrganizationsForm({ isEdit, currentOrganizations }: Prop
<StatusLabel value={values.active} /> <StatusLabel value={values.active} />
</Grid> </Grid>
</HeaderStyle> </HeaderStyle>
<Box sx={{ width: '100%', typography: 'body1' }}> <Box sx={{ width: '100%', typography: 'body1', mt: 2 }}>
<TabContext value={valueTab}> <Grid container rowSpacing={4} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
<Box <Grid item xs={12}>
sx={{ <LabelStyle>Nama Rumah Sakit</LabelStyle>
borderBottom: 1, <RHFTextField name="name" placeholder="Tuliskan Nama Rumah Sakit" />
borderColor: 'divider', </Grid>
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 <Grid item xs={12} md={6}>
name="province_id" <LabelStyle>Code Rumah Sakit</LabelStyle>
control={control} <RHFTextField name="code" placeholder="Tuliskan Code Rumah Sakit" />
render={({ field: { onChange, value } }) => ( </Grid>
<Autocomplete <Grid item xs={12} md={6}>
id="combo-box-demo" <LabelStyle>Nomor IGD</LabelStyle>
options={province} <RHFTextField name="phone" placeholder="Tuliskan No IGD" />
getOptionLabel={(option) => </Grid>
option.label ?? findValueProvince?.label ?? '' <Grid item xs={12}>
} <LabelStyle>Alamat</LabelStyle>
value={value} <RHFTextField name="address" placeholder="Tuliskan Alamat" />
onChange={(event: any, newValue: any) => { </Grid>
console.log('newValue', newValue); <Grid item xs={12} md={6}>
setValue('province_id', newValue?.value); <LabelStyle>Provinsi</LabelStyle>
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}> <Controller
<LabelStyle>Kecamatan</LabelStyle> 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 <Controller
name="district_id" name="city_id"
control={control} control={control}
render={({ field: { onChange, value } }) => ( render={({ field: { onChange, value } }) => (
<Select <Autocomplete
className="input-container" id="combo-box-demo"
size="medium" options={city}
disabled={!district?.length} getOptionLabel={(option) => option.label ?? findValueCity?.label ?? ''}
value={value} value={value}
onChange={(e: any) => { onChange={(event: any, newValue: any) => {
onChange(e); console.log('newValue', newValue);
}} setValue('city_id', newValue?.value);
fullWidth onChange(newValue);
MenuProps={{ }}
PaperProps: { renderInput={(params) => (
sx: { <TextField
maxHeight: 224, {...params}
width: 250, label="Kabupaten / Kota"
p: 1, variant="outlined"
}, fullWidth
}, />
}} )}
> />
{district?.map((item: any) => ( )}
<MenuItem key={item.value} value={item.value}> />
{item.label} </Grid>
</MenuItem>
))}
</Select>
)}
/> */}
<Controller <Grid item xs={12} md={6}>
name="district_id" <LabelStyle>Kecamatan</LabelStyle>
control={control}
render={({ field: { onChange, value } }) => ( <Controller
<Autocomplete name="district_id"
id="combo-box-demo" control={control}
options={district} render={({ field: { onChange, value } }) => (
getOptionLabel={(option) => <Autocomplete
option.label ?? findValueDistrict?.label ?? '' id="combo-box-demo"
} options={district}
value={value} getOptionLabel={(option) => option.label ?? findValueDistrict?.label ?? ''}
onChange={(event: any, newValue: any) => { value={value}
console.log('newValue', newValue); onChange={(event: any, newValue: any) => {
setValue('district_id', newValue?.value); console.log('newValue', newValue);
onChange(newValue); setValue('district_id', newValue?.value);
}} onChange(newValue);
renderInput={(params) => ( }}
<TextField renderInput={(params) => (
{...params} <TextField {...params} label="Kecamatan" variant="outlined" fullWidth />
label="Kecamatan" )}
variant="outlined" />
fullWidth )}
/> />
)} </Grid>
/> <Grid item xs={12} md={6}>
)} <LabelStyle>Desa</LabelStyle>
/>
</Grid> <Controller
<Grid item xs={12} md={6}> name="village_id"
<LabelStyle>Kode Pos</LabelStyle> control={control}
<RHFTextField name="postal_code" placeholder="Tuliskan Kode Pos" /> render={({ field: { onChange, value } }) => (
</Grid> <Autocomplete
<Grid item xs={12} md={4}> id="combo-box-demo"
<LabelStyle>Latitude</LabelStyle> options={village}
<RHFTextField name="lat" placeholder="Tuliskan Lattitude" /> getOptionLabel={(option) => option.label ?? findValueVillage?.label ?? ''}
</Grid> value={value}
<Grid item xs={12} md={4}> onChange={(event: any, newValue: any) => {
<LabelStyle>Longitude</LabelStyle> console.log('newValue', newValue);
<RHFTextField name="lng" placeholder="Tuliskan Longitude" /> setValue('village_id', newValue?.value);
</Grid> onChange(newValue);
<Grid item xs={12} md={4}> }}
<LabelStyle>Timezone</LabelStyle> renderInput={(params) => (
{/* <RHFTextField name="timezone" /> */} <TextField {...params} label="Desa" variant="outlined" fullWidth />
<RHFSelect name="timezone" label="Pilih Timezone"> )}
<option value="" /> />
{timezone.map((option, index) => ( )}
<option key={index} value={option.value}> />
{option.label} </Grid>
</option> <Grid item xs={12} md={4}>
))} <LabelStyle>Kode Pos</LabelStyle>
</RHFSelect> <RHFTextField name="postal_code" placeholder="Tuliskan Kode Pos" />
</Grid> </Grid>
</Grid> <Grid item xs={12} md={4}>
</Box> <LabelStyle>Latitude</LabelStyle>
</TabPanel> <RHFTextField name="lat" placeholder="Tuliskan Lattitude" />
<TabPanel value="2"> </Grid>
<Box sx={{ width: '100%', p: 5 }}> <Grid item xs={12} md={4}>
<Grid container rowSpacing={4} columnSpacing={{ xs: 1, sm: 2, md: 3 }}> <LabelStyle>Longitude</LabelStyle>
<Grid item xs={12}> <RHFTextField name="lng" placeholder="Tuliskan Longitude" />
<LabelStyle>Deskripsi</LabelStyle> </Grid>
<RHFEditor name="description" placeholder="Tuliskan Deskripsi" /> <Grid item xs={12}>
</Grid> <LabelStyle>Deskripsi</LabelStyle>
<Grid item xs={12}> <RHFEditor name="description" placeholder="Tuliskan Deskripsi" />
<LabelStyle>Teknologi</LabelStyle> </Grid>
<RHFEditor name="technology" placeholder="Tuliskan Teknologi" /> </Grid>
</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>
<Box sx={{ width: '100%', p: 5 }}>
<Box sx={{ width: '100%', mt: 5 }}>
<Stack <Stack
alignItems="center" alignItems="center"
justifyContent="end" justifyContent="end"

View File

@@ -23,7 +23,7 @@ export default function Organizations() {
}, },
{ {
name: 'Rumah Sakit', name: 'Rumah Sakit',
href: '/master/organizations', href: '/master/hospitals',
}, },
]} ]}
/> />

View File

@@ -147,9 +147,11 @@ export default function List() {
> >
<SearchInput onSearch={applyFilter} /> <SearchInput onSearch={applyFilter} />
{/* <Link to="/master/organizations/create/" style={{ textDecoration: 'none' }}> <Link to="/master/hospitals/create" style={{ textDecoration: 'none' }}>
<ButtonCreate /> <Button variant="outlined" startIcon={<AddIcon />} sx={{ p: 1.8 }}>
</Link> */} Create
</Button>
</Link>
</Stack> </Stack>
); );
} }
@@ -259,26 +261,26 @@ export default function List() {
</TableCell> </TableCell>
<TableCell align="left">{row.name}</TableCell> <TableCell align="left">{row.name}</TableCell>
<TableCell align="left">{row.phone}</TableCell> <TableCell align="left">{row.phone}</TableCell>
<TableCell align="left">{row.address?.text}</TableCell> <TableCell align="left">{row.address}</TableCell>
{/* <TableCell align="left"> <TableCell align="right">
<Stack direction="row"> {/* <Stack direction="row"> */}
<ButtonGroup variant="text" aria-label="text button group"> <ButtonGroup variant="text" aria-label="text button group">
<Link to={'/master/organizations/' + row.id + '/edit'}> <Link to={'/master/hospitals/' + row.id + '/edit'}>
<Button> <Button>
<Icon icon="ph:pencil-simple-fill" style={{ width: '24px', height: '24px' }} /> <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> </Button>
</ButtonGroup> </Link>
</Stack> <Button
</TableCell> */} onClick={() => {
setOpenDialog(true);
}}
>
<Icon icon="eva:trash-2-outline" style={{ width: '24px', height: '24px' }} />
</Button>
</ButtonGroup>
{/* </Stack> */}
</TableCell>
</TableRow> </TableRow>
{/* COLLAPSIBLE ROW */} {/* COLLAPSIBLE ROW */}

View 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>
// );
// }

View 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>
);
}

View 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 = 'Appointments';
return (
<Page title={pageTitle}>
<Container maxWidth={themeStretch ? false : 'xl'}>
<HeaderBreadcrumbs
heading={pageTitle}
links={[
{
name: 'Report',
href: '/report',
},
{
name: 'Appointments',
href: '/report/appointments',
},
]}
/>
<List />
</Container>
</Page>
);
}

View File

@@ -0,0 +1,416 @@
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 [searchText, setSearchText] = useState('');
//handle search
const handleSearchChange = (event: any) => {
const newSearchText = event.target.value ?? '';
setSearchText(newSearchText);
};
const handleSearchSubmit = (event: any) => {
event.preventDefault();
props.onSearch(searchText);
};
useEffect(() => {
// Trigger First Search
setSearchText(searchParams.get('search') ?? '');
}, []);
const item = [
{
id: '',
value: '',
name: 'Semua',
},
];
return (
<form style={{ width: '100%' }}>
<Grid container spacing={2} sx={{ justifyContent: 'space-between', alignItems: 'center' }}>
<Grid item xs={12} sm={12} md={12} lg={12}>
<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>
</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 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.date_created ? row.date_created : '-'}</TableCell>
<TableCell align="left">{row.date_appointment ? row.date_appointment : '-'}</TableCell>
<TableCell align="left">{row.booking_code ?? '-'}</TableCell>
<TableCell align="left">{row.patient_name ? row.patient_name : '-'}</TableCell>
<TableCell align="left">{row.health_care ? row.health_care : '-'}</TableCell>
<TableCell align="left">{row.doctor_name ? row.doctor_name : '-'}</TableCell>
<TableCell align="left">{row.type ? row.type : '-'}</TableCell>
<TableCell align="left">{row.status ? row.status : '-'}</TableCell>
<TableCell align="center">
<ButtonGroup variant="text" aria-label="text button group">
<Link to={'/report/appointments/' + row.id + '/show'}>
<Button>
<Icon icon="ph:eye-bold" style={{ width: '24px', height: '24px' }} />
</Button>
</Link>
</ButtonGroup>
</TableCell>
</TableRow>
<TableRow>
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={15}>
<Collapse in={open} timeout="auto" unmountOnExit>
<Stack>
<Grid container>
<Grid item xs={2}>Spesialisasi</Grid><Grid item xs="10">: {row.speciality}</Grid>
<Grid item xs={2}>Via</Grid><Grid item xs="10">: {row.appointment_media}</Grid>
<Grid item xs={2}>Metode Pembayaran</Grid><Grid item xs="10">: {row.payment_method}</Grid>
<Grid item xs={2}>HIS RegID</Grid><Grid item xs="10">: {row.his_detail?.sRegID}</Grid>
<Grid item xs={2}>HIS Medrec</Grid><Grid item xs="10">: {row.his_detail?.Medrec}</Grid>
<Grid item xs={2}>No HP</Grid><Grid item xs="10">: {row.patient.sPhone ?? ''}</Grid>
<Grid item xs={2}>E-mail</Grid><Grid item xs="10">: {row.patient.sEmail ?? ''}</Grid>
<Grid item xs={2}>Alamat</Grid><Grid item xs="10">: {row.patient.detail.sAlamat ?? ''}</Grid>
<Grid item xs={2}>KTP</Grid><Grid item xs="10">: {row.patient.detail.sKTP ?? ''}</Grid>
</Grid>
</Stack>
</Collapse>
</TableCell>
</TableRow>
<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('/appointments', {
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">
Tanggal Pemesanan
</TableCell>
<TableCell style={headStyle} align="left">
Tanggal Appointment
</TableCell>
<TableCell style={headStyle} align="left">
Kode Booking
</TableCell>
<TableCell style={headStyle} align="left">
Pasien
</TableCell>
<TableCell style={headStyle} align="left">
Faskes
</TableCell>
<TableCell style={headStyle} align="left">
Dokter
</TableCell>
<TableCell style={headStyle} align="left">
Jenis
</TableCell>
<TableCell style={headStyle} align="left">
Status Appointment
</TableCell>
<TableCell style={headStyle} align="left" />
{/* <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>
);
}

View File

@@ -0,0 +1,53 @@
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 View from './View';
import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs';
import axios from '../../../utils/axios';
import { Appointment } from '../../../@types/doctor';
export default function Create() {
const { themeStretch } = useSettings();
const { id } = useParams();
const isEdit = id ? true : false;
const [currentAppointment, setCurrentAppointment] = useState<Appointment>();
useEffect(() => {
if (isEdit) {
axios.get('/appointments/' + id).then((res) => {
setCurrentAppointment(res.data);
});
}
}, [id]);
return (
<Page title="Appointment">
<Container maxWidth={themeStretch ? false : 'xl'}>
<Stack direction="row" alignItems="center">
<HeaderBreadcrumbs
heading={!isEdit ? 'Appointment' : 'Appointment'}
links={[
{ name: 'Report', href: '/report' },
{
name: 'Appointments',
href: '/report/appointments',
},
]}
/>
</Stack>
<View
// isSubmitting={isSubmitting}
isEdit={isEdit}
currentAppointment={currentAppointment}
/>
</Container>
</Page>
);
}

View File

@@ -0,0 +1,275 @@
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,
Badge,
Divider,
} 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 { Appointment } from '../../../@types/doctor';
import { Label, Rowing, Spa } from '@mui/icons-material';
import { border } from '@mui/system';
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<Appointment> {
taxes: boolean;
inStock: boolean;
}
type Props = {
isEdit: boolean;
currentAppointment?: Appointment;
};
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 AppointmentForm({ isEdit, currentAppointment }: Props) {
const navigate = useNavigate();
// 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: currentAppointment?.id,
name: currentAppointment?.name || '',
address: currentAppointment?.address || '',
birth_date: currentAppointment?.birth_date || '',
gender: currentAppointment?.gender || '',
description: currentAppointment?.description || '',
birth_place: currentAppointment?.birth_place || '',
active: currentAppointment?.active === 1 ? true : false,
avatar_url: currentAppointment?.avatar_url || '',
doctor_id: currentAppointment?.doctor_id || '',
organizations: currentAppointment?.organizations || [],
specialities: currentAppointment?.specialities || [],
}),
// eslint-disable-next-line react-hooks/exhaustive-deps
[currentAppointment]
);
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 && currentAppointment) {
reset(defaultValues);
}
if (!isEdit) {
reset(defaultValues);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isEdit, currentAppointment]);
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}>
<Stack
direction="row"
divider={<Divider orientation="vertical" flexItem />}
spacing={2}
>
<Title>Data Appointment</Title>
<Chip label={currentAppointment?.status} variant="outlined" />
</Stack>
</Grid>
</HeaderStyle>
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
<Grid item xs={12}>
<Stack direction="row" spacing={2}>
<Grid item xs={6}>
<Stack direction="row" spacing={2}>
<Span style={{ fontWeight: 'bold' }}>Tanggal Booking :</Span>
<Text>
{currentAppointment?.date_created ? currentAppointment?.date_created : '-'}
</Text>
</Stack>
</Grid>
<Grid item xs={6}>
<Stack direction="row" spacing={2}>
<Span style={{ fontWeight: 'bold' }}>Tanggal Appointment :</Span>
<Text>
{currentAppointment?.date_appointment
? currentAppointment?.date_appointment
: '-'}
</Text>
</Stack>
</Grid>
</Stack>
</Grid>
<Grid item xs={6}>
<Span style={{ fontWeight: 'bold' }}>Nama Dokter</Span>
<Text>
{currentAppointment?.doctor_name ? currentAppointment?.doctor_name : '-'}
</Text>
<Span style={{ fontWeight: 'bold' }}>Faskes</Span>
<Text>
{currentAppointment?.health_care ? currentAppointment?.health_care : '-'}
</Text>
</Grid>
<Grid item xs={6} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
<Span style={{ fontWeight: 'bold' }}>Spesialis</Span>
<Text>{currentAppointment?.speciality ? currentAppointment?.speciality : '-'}</Text>
<Span style={{ fontWeight: 'bold' }}>Appointment Via Web/App</Span>
<Text>
{currentAppointment?.appointment_media
? currentAppointment?.appointment_media
: '-'}
</Text>
</Grid>
</Grid>
</Card>
<Card sx={{ mt: 5, p: 5 }}>
<HeaderStyle>
<Grid item xs={6} md={6}>
<Title>Data Pembayaran</Title>
</Grid>
</HeaderStyle>
{currentAppointment?.payment_detail !== null ? (
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
<Grid item xs={6}>
<Span style={{ fontWeight: 'bold' }}>Metode Pembayaran</Span>
<Text>
{currentAppointment?.payment_method ? currentAppointment?.payment_method : '-'}
</Text>
<Span style={{ fontWeight: 'bold' }}>Harga</Span>
<Text>
{currentAppointment?.payment_detail?.gross_amount
? currentAppointment?.payment_detail?.gross_amount
: '-'}
</Text>
<Span style={{ fontWeight: 'bold' }}>Mata Uang</Span>
<Text>
{currentAppointment?.payment_detail?.currency
? currentAppointment?.payment_detail?.currency
: '-'}
</Text>
</Grid>
<Grid item xs={6} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
<Span style={{ fontWeight: 'bold' }}>Tipe Pembayaran</Span>
<Text>
{currentAppointment?.payment_detail?.payment_type
? currentAppointment?.payment_detail?.payment_type
: '-'}
</Text>
<Span style={{ fontWeight: 'bold' }}>Waktu Transaksi</Span>
<Text>
{currentAppointment?.payment_detail?.transaction_time
? currentAppointment?.payment_detail?.transaction_time
: '-'}
</Text>
<Span style={{ fontWeight: 'bold' }}>Status</Span>
<Text>
{currentAppointment?.payment_detail?.status_message
? currentAppointment?.payment_detail?.status_message
: '-'}
</Text>
</Grid>
</Grid>
) : (
<Span>Belum ada pembayaran</Span>
)}
</Card>
</Box>
</Stack>
</FormProvider>
);
}

View 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>
// );
// }

View 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>
);
}

View 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 = 'Live Chat';
return (
<Page title={pageTitle}>
<Container maxWidth={themeStretch ? false : 'xl'}>
<HeaderBreadcrumbs
heading={pageTitle}
links={[
{
name: 'Report',
href: '/report',
},
{
name: 'Live Chat',
href: '/report/live-chat',
},
]}
/>
<List />
</Container>
</Page>
);
}

View File

@@ -0,0 +1,466 @@
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 [searchText, setSearchText] = useState('');
//handle search
const handleSearchChange = (event: any) => {
const newSearchText = event.target.value ?? '';
setSearchText(newSearchText);
};
const handleSearchSubmit = (event: any) => {
event.preventDefault();
props.onSearch(searchText);
};
useEffect(() => {
// Trigger First Search
setSearchText(searchParams.get('search') ?? '');
}, []);
const item = [
{
id: '',
value: '',
name: 'Semua',
},
];
return (
<form style={{ width: '100%' }}>
<Grid container spacing={2} sx={{ justifyContent: 'space-between', alignItems: 'center' }}>
<Grid item xs={12} sm={12} md={12} lg={12}>
<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>
</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 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.date_created ? row.date_created : '-'}</TableCell>
<TableCell align="left">{row.date_appointment ? row.date_appointment : '-'}</TableCell>
<TableCell align="left">{row.health_care ? row.health_care : '-'}</TableCell>
<TableCell align="left">{row.doctor_name ? row.doctor_name : '-'}</TableCell>
<TableCell align="left">{row.speciality ? row.speciality : '-'}</TableCell>
<TableCell align="left">{row.appointment_media ? row.appointment_media : '-'}</TableCell>
<TableCell align="left">{row.patient_media ? row.patient_media : '-'}</TableCell>
<TableCell align="left">{row.doctor_media ? row.doctor_media : '-'}</TableCell>
<TableCell align="left">
{row.status_appointment ? row.status_appointment : '-'}
</TableCell>
<TableCell align="left">{row.status_chat ? row.status_chat : '-'}</TableCell>
<TableCell align="center">
<ButtonGroup variant="text" aria-label="text button group">
<Link to={'/report/live-chat/' + row.id + '/show'}>
<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={6}
>
<Collapse in={open} timeout="auto" unmountOnExit>
<Box sx={{ margin: 1, pb: 2, pl: 4 }}>
<Grid container>
<Grid item xs={12} sx={{ padding: 2 }}>
<Grid container>
<Grid item xs={6}>
Metode Pembayaran
</Grid>
<Grid item xs={6}>
: {row.payment_method ? row.payment_method : '-'}
</Grid>
<Grid item xs={6}>
Jenis Benefit
</Grid>
<Grid item xs={6}>
: -
</Grid>
<Grid item xs={6}>
Durasi
</Grid>
<Grid item xs={6}>
: {row.duration ? row.duration : '-'}
</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('/live-chat', {
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 colSpan={8} rowSpan={1} align="center" /> */}
<TableCell style={headStyle} align="left" />
<TableCell style={headStyle} rowSpan={2} align="left">
Tanggal Booking
</TableCell>
<TableCell style={headStyle} rowSpan={2} align="left">
Tanggal Appointment
</TableCell>
<TableCell style={headStyle} rowSpan={2} align="left">
Faskes
</TableCell>
<TableCell style={headStyle} rowSpan={2} align="left">
Nama Dokter
</TableCell>
<TableCell style={headStyle} rowSpan={2} align="left">
Spesialisasi
</TableCell>
<TableCell style={headStyle} rowSpan={2} align="left">
Appointment Via App/Website
</TableCell>
<TableCell
colSpan={2}
style={headStyle}
align="center"
sx={{ borderBottom: '3px solid #d7d7d7' }}
>
Chat Via App/Website
</TableCell>
<TableCell style={headStyle} rowSpan={2} align="left">
Status Appointment
</TableCell>
<TableCell style={headStyle} rowSpan={2} align="left">
Status Chat
</TableCell>
</TableRow>
<TableRow>
<TableCell style={headStyle} align="left" />
{/* <TableCell style={headStyle} align="left">
Tanggal Booking
</TableCell>
<TableCell style={headStyle} align="left">
Tanggal Appointment
</TableCell>
<TableCell style={headStyle} align="left">
Faskes
</TableCell>
<TableCell style={headStyle} align="left">
Nama Dokter
</TableCell>
<TableCell style={headStyle} align="left">
Spesialisasi
</TableCell> */}
<TableCell style={headStyle} align="left">
Pasien
</TableCell>
<TableCell style={headStyle} align="left">
Dokter
</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>
);
}

Some files were not shown because too many files have changed in this diff Show More